Smart Home Server
БесплатноНе проверенControls TAPO L530E smart light bulbs via MCP, supporting on/off, brightness, and color temperature, with local and remote AWS deployment.
Описание
Controls TAPO L530E smart light bulbs via MCP, supporting on/off, brightness, and color temperature, with local and remote AWS deployment.
README
A personal learning exercise for exploring MCP (Model Context Protocol) and agent development. Uses smart home control (TAPO L530E light bulbs) as a hands-on example for building and testing MCP servers and local agents.
Control Paths
| Path | Status | Description |
|---|---|---|
| Local MCP | ✅ Done | FastMCP server as Claude Desktop subprocess, LAN control |
| Remote MCP | ✅ Done | AgentCore Gateway + Cognito + Lambda + IoT Core |
| Local Agent | ✅ Done | OpenClaw-inspired agent loop with Markdown memory, hybrid search, and device skills |
Features
MCP Paths
- Turn lights on/off, set brightness, get bulb status (on/off, brightness, color temp)
- Real bulb control via
tapolibrary over local network - Mock fallback — automatically uses a mock when credentials are missing or the bulb is unreachable
- Persistent state — bulb state survives server restarts
- DynamoDB state logging — fire-and-forget, never blocks MCP tools
- AWS IoT Core integration — MQTT bridge with Device Shadow for state sync
- AgentCore Gateway — remote MCP server with Cognito OAuth for Claude web app
- Multi-device support — single bridge manages multiple devices via
DeviceRegistry - Device-agnostic architecture —
BaseDeviceinterface makes adding new device types straightforward
Local Agent
- Interactive CLI and Slack bot — two front-ends sharing the same agent loop, memory, and skills
- Slack Socket Mode — per-thread sessions,
@mentionin channels, direct messages; idle sessions auto-evict after 30 min with memory flush - Multi-provider LLM support — swap between Anthropic (Claude) and Google Gemini by passing
--model; provider auto-detected from the model name prefix - Persistent memory, no cloud dependency — Markdown files + SQLite index, runs entirely on-device
- Hybrid memory search — BM25 (FTS5) + vector embeddings (ollama) merged via Reciprocal Rank Fusion
- Pluggable skills — drop a
SKILL.mdintoskills/<name>/— no Python scripts, no boilerplate, zero changes to the loop - Progressive skill disclosure — only a skill index (name + description) is in the system prompt at startup; full docs load on first use via
describe_skill, then stay injected for the session - Direct command execution —
run_commandtool lets the model run any shell command and parse JSON output; skills are pure documentation that describe which commands to run - Color temperature control —
set_color_temp(2500–6500 K) via the agent skill - Heartbeat scheduler —
HeartbeatSchedulerfires time-based automations fromSCHEDULE.md; tasks store a shell command (cmd) and run as subprocesses; Claude manages tasks viaschedule_task(add/remove/list), changes persist across restarts
Project Structure
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)
│ └── bulb_cli.py # CLI entry point for agent skills (outputs JSON, reads TAPO_MOCK)
├── 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: provider-agnostic tool-use loop + 6 built-in tools
├── scheduler.py # HeartbeatScheduler: fires SCHEDULE.md cmd tasks as subprocesses
├── skill_loader.py # Discovers skills/*/SKILL.md, builds system prompt index
├── slack_adapter.py # Slack channel adapter (Socket Mode, per-thread sessions)
├── providers/ # LLM provider abstraction
│ ├── types.py # NeutralTool, ToolCall, ToolResult, ProviderResponse
│ ├── base.py # Abstract LLMProvider
│ ├── anthropic.py # AnthropicProvider
│ └── google.py # GoogleProvider (Gemini)
├── 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: commands to run via bulb_cli.py
└── trading-journal/
└── SKILL.md # Skill docs: analytics pipeline commands
scripts/aws/ # AWS provisioning and operation scripts
docs/ # Setup guides and architecture notes
tests/ # Unit tests (200 tests, all passing)
How It Works
Local MCP (Claude Desktop)
Claude Desktop runs the FastMCP server as a local subprocess:
Claude Desktop → FastMCP server (subprocess) → TapoBulb / MockTapoBulb
Tools exposed: turn_on, turn_off, set_brightness(level), get_status
On first tool call the server tries to connect to a real bulb using credentials from ~/.smarthome/.env. Falls back to mock automatically if credentials are missing or the bulb is unreachable.
Remote MCP (Claude Web App)
Claude Web App
→ AgentCore Gateway (Cognito JWT auth)
→ Lambda (smarthome-gateway-handler)
→ IoT Core MQTT
→ IoT Bridge (local network)
→ TapoBulb
See docs/claude-web-oauth.md for the OAuth flow details and docs/mcp-setup.md for full provisioning steps.
Local Agent
An OpenClaw-inspired agent loop that runs entirely locally — no cloud dependency. Two front-ends share the same AgentLoop, memory, and skills:
CLI input → AgentLoop → LLMProvider (Anthropic or Google Gemini)
Slack input ↗ ├── memory/ ~/.smarthome/memory/ — MEMORY.md, USER.md, SOUL.md, daily logs
└── skills/ light-control, trading-journal — SKILL.md only, no scripts
Front-ends:
- CLI — interactive REPL, one session per process
- Slack (
--slack) — Socket Mode bot; one session per(channel, thread), responds to@mentionin channels and all messages in DMs; idle sessions auto-evict after 30 min with memory flush
6 built-in tools the model can call:
run_command(cmd)— run any shell command; parses JSON stdout; lifts Slack blocksdescribe_skill(skill_name)— loads full skill docs once; injected into system prompt for the sessionmemory_search(query)— hybrid BM25 + vector search (Reciprocal Rank Fusion)memory_write(path, content, mode)— persists to Markdown filesschedule_task(action, name, hour, minute, cmd)— add/remove/list scheduled automations inSCHEDULE.md
Provider abstraction: tools and conversation history are stored in a neutral format. AnthropicProvider and GoogleProvider each serialize to their own wire format on every call. Provider-specific data that must survive conversation round-trips (e.g. Gemini's thought signatures when thinking is enabled) is carried opaquely in ProviderResponse.assistant_replay.
Memory is stored in ~/.smarthome/memory/ as Markdown files (MEMORY.md, USER.md, SOUL.md, daily logs), indexed in SQLite with FTS5 and optional sqlite-vec embeddings. Embeddings use ollama; BM25-only fallback if unavailable.
Adding a skill: drop a folder under skills/, write SKILL.md with frontmatter (name, description) and shell command examples. No Python scripts, no boilerplate. Zero changes to loop.py.
Device Layer
All devices implement BaseDevice:
execute(action, parameters)— dispatch any action (turn_on, set_brightness, …)apply_desired_state(desired)— apply state from IoT Shadow deltaget_shadow_state()— report current state to shadow
TapoBulb connects to real hardware. MockTapoBulb simulates a bulb in memory, optionally persisting state to ~/.smarthome/tapo_bulb_state.json.
Setup
See docs/mcp-setup.md for full step-by-step instructions covering both paths.
Quick start — Local MCP
Create
~/.smarthome/.envwith bulb credentials (or skip — mock mode works without it):TAPO_USERNAME=your_tapo_email TAPO_PASSWORD=your_tapo_password TAPO_IP_ADDRESS=192.168.x.xAdd to Claude Desktop config (
~/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"] } } }Restart Claude Desktop.
Quick start — Local Agent
Add your API key(s) to
~/.smarthome/.env:mkdir -p ~/.smarthome # Anthropic (default model: claude-sonnet-4-6) echo 'ANTHROPIC_API_KEY=sk-ant-...' >> ~/.smarthome/.env # Google Gemini (optional — use with --model gemini-*) echo 'GEMINI_API_KEY=AIza...' >> ~/.smarthome/.envSeed memory files (optional but recommended):
mkdir -p ~/.smarthome/memory echo "# Memory" > ~/.smarthome/memory/MEMORY.md echo "# User Preferences" > ~/.smarthome/memory/USER.mdRun with mock bulb (no hardware needed):
uv run python -m smarthome.agent --mock # Claude (default) uv run python -m smarthome.agent --mock --model gemini-3.1-flash-lite # Google GeminiRun with real bulb — add
TAPO_USERNAME,TAPO_PASSWORD,TAPO_IP_ADDRESSto~/.smarthome/.env, then:uv run python -m smarthome.agent uv run python -m smarthome.agent --model gemini-3.1-flash-liteRun as a Slack bot — add
SLACK_BOT_TOKEN,SLACK_APP_TOKEN,SLACK_SIGNING_SECRETto~/.smarthome/.env, then:uv run python -m smarthome.agent --slack --mock # mock bulb uv run python -m smarthome.agent --slack # real bulb
Quick start — Remote MCP (AWS)
Run provisioning scripts in order (requires AWS profile 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
Testing
# 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
Key Dependencies
Dependencies are split so the local agent can be installed without the AWS/MCP stack.
Core (local agent):
| Package | Purpose |
|---|---|
anthropic |
Claude API SDK |
google-genai |
Google Gemini API SDK |
tapo |
TAPO device control over local network |
slack-bolt |
Slack Socket Mode bot |
sqlite-vec |
Vector search extension for SQLite |
httpx |
Async HTTP client (ollama embeddings) |
aiohttp, pydantic, python-dotenv |
HTTP, validation, env config |
aws-mcp extra (MCP paths only):
| Package | Purpose |
|---|---|
fastmcp |
MCP server framework |
boto3 |
AWS SDK (DynamoDB, IoT Core, Lambda, Cognito) |
awsiotsdk |
AWS IoT Core MQTT client |
Dev:
| Package | Purpose |
|---|---|
moto[dynamodb] |
In-memory AWS mock for tests |
pytest, pytest-asyncio |
Test runner |
Install for each environment:
uv sync --no-dev # Raspberry Pi — local agent only
uv sync --extra aws-mcp # Dev machine — everything
What's Next
- Local MCP via Claude Desktop
- Remote MCP via AgentCore Gateway + Cognito OAuth
- Multi-device support via
DeviceRegistry - Local agent loop with Markdown memory
- Bulb control as an agent skill
- Color temperature control
- Heartbeat scheduler with
SCHEDULE.mdandschedule_tasktool - Multi-provider LLM support (Anthropic + Google Gemini)
- Interoperable skills — SKILL.md-only, executable via
run_command(no Python scripts required) - Additional device types (smart plugs, sensors)
- Device auto-discovery on local network
License
MIT
Установка Smart Home Server
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/jui-hung-yuan/smarthome-mcp-labFAQ
Smart Home Server MCP бесплатный?
Да, Smart Home Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Smart Home Server?
Нет, Smart Home Server работает без API-ключей и переменных окружения.
Smart Home Server — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Smart Home Server в Claude Desktop, Claude Code или Cursor?
Открой Smart Home Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Smart Home Server with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
