智能家居MCP实验室
探索MCP(模型上下文协议)和代理开发的个人学习练习。使用智能家居控制(TAPO L530E灯泡)作为构建和测试MCP服务器和本地代理的实践示例。
控制路径
| 路径 | 状态 | 描述 |
|---|---|---|
| 本地MCP | ✅ 完成 | FastMCP服务器作为Claude Desktop子进程,LAN控制 |
| 远程MCP | ✅ 完成 | 代理核心网关+Cognito+Lambda+物联网核心 |
| 本地代理 | ✅ 完成 | 基于OpenClaw的代理循环,具有Markdown内存、混合搜索和设备技能 |
特性
MCP路径
- 打开/关闭灯, 设置亮度, 获取灯泡状态 (开/关、亮度、色温)
- 真实灯泡控制 通过
tapo局域网图书馆 - 模拟回退 --当凭据丢失或灯泡无法访问时,自动使用模拟
- 持久状态 --灯泡状态在服务器重启后仍然存在
- DynamoDB状态日志记录 -即发即弃,从不阻挡MCP工具
- AWS物联网核心集成 --带设备影子的MQTT网桥用于状态同步
- AgentCore网关 --用于Claude web应用程序的Cognito OAuth远程MCP服务器
- 多设备支持 --单网桥通过以下方式管理多个设备
DeviceRegistry - 设备无关架构 —
BaseDevice界面使添加新设备类型变得简单
本地代理
- 交互式CLI和Slack机器人 --两个前端共享相同的代理循环、内存和技能
- 松弛插座模式 --每个线程会话,
@mention在渠道中,直接信息;空闲会话在30分钟后自动退出,并刷新内存 - 持久内存,无云依赖 --Markdown文件+SQLite索引,完全在设备上运行
- 混合内存搜索 --BM25(FTS5)+通过互易秩融合合并的向量嵌入(ollama)
- 可插拔技能 --将文件夹放入
skills/,写SKILL.md--循环无变化 - 渐进式技能披露 --启动时,系统提示中只有技能索引(姓名+描述);首次使用时通过加载完整文档
describe_skill,然后在疗程中继续注射 - 色温控制 —
set_color_temp(2500–6500 K)通过代理技能 - 心跳调度程序 —
HeartbeatScheduler从以下位置启动基于时间的自动化SCHEDULE.md克劳德通过schedule_task工具(添加/删除/列出),更改在重新启动后仍然存在
项目结构
src/smarthome/
├── devices/ # Shared device layer (all paths use this)
│ ├── base.py # BaseDevice ABC: execute(), apply_desired_state(), get_shadow_state()
│ ├── device_registry.py # Manages multiple devices by ID
│ └── tapo_bulb.py # TapoBulb (real hardware) + MockTapoBulb (testing/fallback)
├── aws_mcp/ # AWS path: Local MCP server + Lambda + IoT bridge
│ ├── bridge/ # IoT Core MQTT bridge (config, iot_bridge, shadow_manager)
│ ├── cloud/ # Lambda-side IoT helpers (iot_commands)
│ ├── logging/ # DynamoDB state logger
│ ├── mcp_servers/ # FastMCP server (light_server.py)
│ └── lambda_handler.py # AgentCore Gateway Lambda entry point
└── agent/ # Local-first agent loop (CLI + Slack)
├── __main__.py # Entry: `python -m smarthome.agent [--mock|--slack]`
├── config.py # AgentConfig: paths, model, mock flag
├── loop.py # AgentLoop: Claude tool-use loop + 5 built-in tools
├── scheduler.py # HeartbeatScheduler: fires SCHEDULE.md tasks on a periodic tick
├── skill_loader.py # Discovers skills/*/SKILL.md, dynamic dispatch
├── slack_adapter.py # Slack channel adapter (Socket Mode, per-thread sessions)
├── memory/
│ ├── manager.py # MemoryManager: search, write, sync, session context
│ ├── schema.py # SQLite schema: files, chunks, FTS5, vec, device_events
│ ├── chunker.py # Markdown → overlapping chunks (~400 tokens)
│ └── embedder.py # OllamaEmbedder: async HTTP → ollama /api/embed
└── skills/
└── light-control/
├── SKILL.md # Skill docs + frontmatter (name, description)
└── scripts/
└── bulb.py # execute(action, params) wraps TapoBulb/MockTapoBulb
scripts/aws/ # AWS provisioning and operation scripts
docs/ # Setup guides and architecture notes
tests/ # Unit tests (188 tests, all passing)运作原理
本地MCP(克劳德桌面)
Claude Desktop将FastMCP服务器作为本地子进程运行:
Claude Desktop → FastMCP server (subprocess) → TapoBulb / MockTapoBulb暴露的工具: turn_on, turn_off, set_brightness(level), get_status
在第一次工具调用时,服务器尝试使用来自的凭据连接到真实灯泡 ~/.smarthome/.env。如果凭据丢失或灯泡无法访问,则自动回退到模拟。
远程MCP(克劳德网络应用程序)
Claude Web App
→ AgentCore Gateway (Cognito JWT auth)
→ Lambda (smarthome-gateway-handler)
→ IoT Core MQTT
→ IoT Bridge (local network)
→ TapoBulb看 docs/claude-web-oauth.md 有关OAuth流的详细信息和 docs/mcp-setup.md 用于完整的配置步骤。
本地代理
一个受OpenClaw启发的代理循环,完全在本地运行,不依赖于云。两个前端共享同一个 AgentLoop、记忆和技能:
CLI input → AgentLoop
Slack input ↗ ├── memory/ ~/.smarthome/memory/ — MEMORY.md, USER.md, SOUL.md, daily logs
└── skills/ light-control — wraps TapoBulb / MockTapoBulb前端:
- 命令行界面 --交互式REPL,每个进程一个会话
- Slack (
--slack)——Socket模式机器人;每次一次会议(channel, thread),回应@mention在信道和DM中的所有消息中;空闲会话在30分钟后自动退出,并刷新内存
5个内置工具 克劳德可以打电话:
execute_skill(skill_name, action, params)--分派给任何负载技能describe_skill(skill_name)--一次性加载完整的技能文档;注入会话的系统提示符中memory_search(query)--混合BM25+向量搜索(互序融合)memory_write(path, content, mode)--持久化为Markdown文件schedule_task(action, ...)--在中添加/删除/列出计划的自动化SCHEDULE.md
内存存储在 ~/.smarthome/memory/ 作为Markdown文件(MEMORY.md, USER.md, SOUL.md,每日日志),在SQLite中使用FTS5和可选的SQLite-vec嵌入进行索引。嵌入使用 ollama;BM25仅在不可用时回退。
添加技能:在下面放置一个文件夹 skills/,写 SKILL.md + scripts/*.py 随着 execute(action, params) → dict.零变化 loop.py.
设备层
所有设备均已实施 BaseDevice:
execute(action, parameters)--分派任何动作(turn_on、set_bright、…)apply_desired_state(desired)--从IoT Shadow delta应用状态get_shadow_state()--向影子报告当前状态
TapoBulb 连接到真实的硬件。 MockTapoBulb 在内存中模拟灯泡,可选择将状态持久化到 ~/.smarthome/tapo_bulb_state.json.
设置
看 docs/mcp-setup.md 了解涵盖这两条路径的完整分步说明。
快速入门--本地MCP
- 创建
~/.smarthome/.env使用灯泡凭据(或跳过--mock模式在没有灯泡凭据的情况下工作):
TAPO_USERNAME=your_tapo_email
TAPO_PASSWORD=your_tapo_password
TAPO_IP_ADDRESS=192.168.x.x- 添加到Claude桌面配置(
~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"smarthome": {
"command": "uv",
"args": ["run", "--directory", "/path/to/smarthome",
"fastmcp", "run",
"src/smarthome/aws_mcp/mcp_servers/light_server.py"]
}
}
}- 重新启动克劳德桌面。
快速入门--本地代理
- 添加您的Anthropic API密钥:
mkdir -p ~/.smarthome
echo 'ANTHROPIC_API_KEY=sk-...' >> ~/.smarthome/.env- 种子内存文件(可选但推荐):
mkdir -p ~/.smarthome/memory
echo "# Memory" > ~/.smarthome/memory/MEMORY.md
echo "# User Preferences" > ~/.smarthome/memory/USER.md- 使用模拟灯泡运行(无需硬件):
uv run python -m smarthome.agent --mock- 用真正的灯泡运行——添加
TAPO_USERNAME,TAPO_PASSWORD,TAPO_IP_ADDRESS到~/.smarthome/.env那么:
uv run python -m smarthome.agent- 以Slack机器人模式运行——添加
SLACK_BOT_TOKEN,SLACK_APP_TOKEN,SLACK_SIGNING_SECRET到~/.smarthome/.env那么:
uv run python -m smarthome.agent --slack --mock # mock bulb
uv run python -m smarthome.agent --slack # real bulb快速启动——远程MCP(AWS)
按顺序运行配置脚本(需要AWS配置文件 self):
AWS_PROFILE=self uv run python scripts/aws/create_bridge_thing.py
AWS_PROFILE=self uv run python scripts/aws/create_cognito.py
uv run python scripts/aws/package_lambda.py
AWS_PROFILE=self uv run python scripts/aws/create_lambda.py
AWS_PROFILE=self uv run python scripts/aws/create_agentcore_gateway.py
# Start the local bridge (keep running on-premises)
uv run python scripts/aws/run_bridge.py
# Test end-to-end
AWS_PROFILE=self uv run python scripts/aws/test_gateway.py测试
# Unit tests
uv run pytest tests/ -v
# Interactive MCP dev UI (localhost:6274)
uv run fastmcp dev src/smarthome/aws_mcp/mcp_servers/light_server.py关键依赖关系
依赖关系被拆分,因此可以在没有AWS/MCP堆栈的情况下安装本地代理。
核心(本地代理):
| 包装 | 用途 |
|---|---|
anthropic | Claude API SDK(代理循环) |
tapo | 本地网络上的TAPO设备控制 |
slack-bolt | Slack套接字模式机器人 |
sqlite-vec | SQLite的矢量搜索扩展 |
httpx | 异步HTTP客户端(ollama嵌入) |
aiohttp, pydantic, python-dotenv | HTTP、验证、环境配置 |
aws-mcp 额外(仅限MCP路径):
| 包装 | 用途 |
|---|---|
fastmcp | MCP服务器框架 |
boto3 | AWS SDK(DynamoDB、物联网核心、Lambda、Cognito) |
awsiotsdk | AWS物联网核心MQTT客户端 |
开发人员:
| 包装 | 用途 |
|---|---|
moto[dynamodb] | 用于测试的内存AWS模拟 |
pytest, pytest-asyncio | 试验转轮 |
为每个环境安装:
uv sync --no-dev # Raspberry Pi — local agent only
uv sync --extra aws-mcp # Dev machine — everything接下来是什么
- \[x\] 通过Claude Desktop实现本地MCP
- \[x\] 通过AgentCore网关+Cognito OAuth实现远程MCP
- \[x\] 通过以下方式支持多设备
DeviceRegistry - \[x\] 带Markdown内存的本地代理循环
- \[x\] 灯泡控制作为一种代理技能
- \[x\] 色温控制
- \[x\] 心跳调度程序
SCHEDULE.md和schedule_task工具 - \[\]其他设备类型(智能插头、传感器)
- \[\]本地网络上的设备自动发现
许可证
麻省理工学院
