Skip to main content
Glama
mahi080808

mcp-smart-home-server

by mahi080808
README.md
# MCP Server for Smart Home & IoT Orchestration

An MCP (Model Context Protocol) server that gives any MCP-compatible AI client (Claude, etc.) safe, structured access to control smart devices via Home Assistant and query local sensors over MQTT — turning natural-language instructions into validated device actions.

## Architecture
```
AI client (Claude Desktop, etc.)
     │  MCP protocol (stdio/SSE)
     ▼
FastMCP server ──► Home Assistant REST/WebSocket API (device control)
     │
     └────────────► MQTT broker (sensor reads, local automation triggers)
```

## Tools exposed
- `list_devices()` — enumerate controllable entities from Home Assistant
- `get_device_state(entity_id)` — read current state
- `set_device_state(entity_id, state, **attrs)` — **guarded**: checks an allowlist before executing
- `read_sensor(topic)` — read latest value from an MQTT sensor topic
- `run_automation(name)` — trigger a pre-defined Home Assistant automation (never arbitrary scripts)

## Tech stack
FastMCP (Python MCP server framework), Home Assistant REST/WebSocket API, MQTT (paho-mqtt).

## Getting started
```bash
pip install -r requirements.txt
cp .env.example .env   # HA_URL, HA_TOKEN, MQTT_BROKER
python src/server.py
```
Then point your MCP client's config at this server (stdio transport by default — see `docs/CLIENT_SETUP.md`).

## Safety design
- `set_device_state` checks `ALLOWED_ENTITIES` in `config.py` before sending any command — nothing outside an explicit allowlist can be controlled, by design, to prevent an LLM from accidentally (or via a malicious prompt) unlocking doors, disabling alarms, etc.
- `run_automation` only triggers automations pre-defined in Home Assistant, never arbitrary code.
- All tool calls are logged to `logs/mcp_actions.log` for auditability.

## Status
Server scaffold, tool definitions, and the Home Assistant client wrapper are implemented. You must populate `ALLOWED_ENTITIES` for your own home before deploying — it ships empty (deny-by-default) on purpose.

## License
MIT