Smart Home MCP Server
Provides MQTT bridge with AWS IoT Core Device Shadow for state synchronization between the MCP server and IoT core.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Smart Home MCP Serverturn on the kitchen light"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Smart Home MCP Lab
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 |
Related MCP server: IntelliGlow
Features
MCP Paths
Turn lights on/off, set brightness, get bulb status (on/off, brightness, color temp)
Real bulb control via
tapolibrary over local networkMock 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
DeviceRegistryDevice-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 flushMulti-provider LLM support — swap between Anthropic (Claude) and Google Gemini by passing
--model; provider auto-detected from the model name prefixPersistent 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 loopProgressive 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 sessionDirect command execution —
run_commandtool lets the model run any shell command and parse JSON output; skills are pure documentation that describe which commands to runColor temperature control —
set_color_temp(2500–6500 K) via the agent skillHeartbeat 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 / MockTapoBulbTools 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)
→ TapoBulbSee 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 scriptsFront-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.pyTesting
# 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.pyKey Dependencies
Dependencies are split so the local agent can be installed without the AWS/MCP stack.
Core (local agent):
Package | Purpose |
| Claude API SDK |
| Google Gemini API SDK |
| TAPO device control over local network |
| Slack Socket Mode bot |
| Vector search extension for SQLite |
| Async HTTP client (ollama embeddings) |
| HTTP, validation, env config |
aws-mcp extra (MCP paths only):
Package | Purpose |
| MCP server framework |
| AWS SDK (DynamoDB, IoT Core, Lambda, Cognito) |
| AWS IoT Core MQTT client |
Dev:
Package | Purpose |
| In-memory AWS mock for tests |
| Test runner |
Install for each environment:
uv sync --no-dev # Raspberry Pi — local agent only
uv sync --extra aws-mcp # Dev machine — everythingWhat's Next
Local MCP via Claude Desktop
Remote MCP via AgentCore Gateway + Cognito OAuth
Multi-device support via
DeviceRegistryLocal agent loop with Markdown memory
Bulb control as an agent skill
Color temperature control
Heartbeat scheduler with
SCHEDULE.mdandschedule_tasktoolMulti-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
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jui-hung-yuan/smarthome-mcp-lab'
If you have feedback or need assistance with the MCP directory API, please join our Discord server