- Mcp Server For Deconz Server
Mcp Server For Deconz Server
deConz MCP Server
An MCP (Model Context Protocol) server that exposes the deCONZ REST API to AI assistants. Control Zigbee lights, sensors, groups, scenes, rules, and schedules through natural language.
Supports stdio, SSE, and Streamable HTTP transports. HTTP transports are protected by a configurable bearer token.
Requirements
- Python ≥ 3.10
- uv (recommended) or pip
- A running deCONZ / Phoscon gateway with a ConBee or RaspBee adapter
- A valid deCONZ REST API key (see Obtaining an API key)
Installation
# Clone the repository
git clone https://github.com/your-org/deconz-mcp.git
cd deconz-mcp
# Install with uv (creates an isolated virtual environment)
uv sync
# Or install with pip into your environment
pip install -e .
Obtaining an API key
- Open the Phoscon App in your browser (usually
http://<gateway-ip>/pwa). - Go to Menu → Settings → Gateway → Advanced.
- Click Authenticate app — this opens the network for 60 seconds.
- Within those 60 seconds, run:
curl -s -X POST http://<gateway-ip>/api \
-H "Content-Type: application/json" \
-d '{"devicetype": "deconz-mcp"}'
The response contains your API key:
[{"success": {"username": "YOUR-API-KEY-HERE"}}]
Store it as DECONZ_API_KEY.
Quick start
stdio (Claude Desktop)
DECONZ_HOST=192.168.1.10 DECONZ_API_KEY=abc123def deconz-mcp
Streamable HTTP with bearer auth
DECONZ_HOST=192.168.1.10 \
DECONZ_API_KEY=abc123def \
MCP_AUTH_TOKEN=my-mcp-secret \
deconz-mcp --transport streamable-http --host 0.0.0.0 --port 8080
Combined SSE + Streamable HTTP
DECONZ_HOST=192.168.1.10 \
DECONZ_API_KEY=abc123def \
MCP_AUTH_TOKEN=my-mcp-secret \
deconz-mcp --transport server --host 0.0.0.0 --port 8080
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
DECONZ_HOST | Yes* | — | IP or hostname of the deCONZ gateway |
DECONZ_PORT | No | 80 | HTTP port of the deCONZ gateway |
DECONZ_API_KEY | Yes* | — | deCONZ REST API key |
DECONZ_TLS | No | false | Set true to use HTTPS |
MCP_AUTH_TOKEN | No† | — | Bearer token clients must send to this MCP server |
MCP_BASE_URL | No | http://<host>:<port> | Public base URL (used as OAuth issuer URL) |
* Not required when using stdio and calling configure_deconz at runtime.
† Strongly recommended for HTTP transports exposed beyond localhost.
CLI reference
usage: deconz-mcp [--transport {stdio,sse,streamable-http,server}]
[--host HOST] [--port PORT]
[--log-level {DEBUG,INFO,WARNING,ERROR}]
[--auth-token TOKEN] [--base-url URL]
| Flag | Default | Description |
|---|---|---|
--transport | stdio | Transport mode |
--host | 127.0.0.1 | Bind address (HTTP transports) |
--port | 8000 | Listen port (HTTP transports) |
--log-level | INFO | Logging verbosity |
--auth-token | $MCP_AUTH_TOKEN | MCP bearer token |
--base-url | $MCP_BASE_URL | OAuth issuer URL |
Transport modes
| Mode | Endpoint(s) | Description |
|---|---|---|
stdio | stdin/stdout | Pipe-based — for Claude Desktop and local use |
sse | /sse, /messages/ | Legacy SSE (MCP pre-2025-03-26) |
streamable-http | /mcp | Modern Streamable HTTP (MCP 2025-03-26) |
server | all of the above | SSE + Streamable HTTP on one port |
Authentication
deCONZ API key
The deCONZ REST API key is a gateway credential that travels as part of the URL path (/api/<apikey>/...). It is configured server-side via DECONZ_API_KEY and is never exposed to MCP clients.
MCP bearer token
The MCP_AUTH_TOKEN / --auth-token option protects the MCP server itself. Every HTTP request from an MCP client must include:
Authorization: Bearer <token>
The token is verified with a constant-time comparison to prevent timing attacks. When running over localhost only (default bind 127.0.0.1), bearer auth is optional but recommended.
Tools
Connection / configuration
| Tool | Description |
|---|---|
configure_deconz | Point the server at a deCONZ gateway at runtime (host, port, API key) |
get_gateway_config | Read gateway name, firmware, Zigbee channel, IP, WebSocket port |
set_permit_join | Open the Zigbee network for new device pairing (0–255 seconds) |
Lights
| Tool | Description |
|---|---|
list_lights | List all lights with on/off, brightness, and reachability |
get_light | Full JSON details for a single light |
set_light_state | Control power, brightness, hue, saturation, colour temp, xy, effect, alert |
rename_light | Rename a light |
delete_light | Remove a light from the gateway |
Groups
| Tool | Description |
|---|---|
list_groups | List all groups with member count and action state |
get_group | Full JSON details for a single group |
create_group | Create a new group (optionally pre-populate with lights) |
set_group_action | Control all lights in a group simultaneously |
modify_group | Rename a group or change its member lights |
delete_group | Delete a group (lights remain) |
Scenes
| Tool | Description |
|---|---|
list_scenes | List all scenes for a group |
get_scene | Full JSON details for a scene |
create_scene | Create a scene (captures current group state) |
recall_scene | Activate a scene |
store_scene | Overwrite a scene with the current group state |
rename_scene | Rename a scene |
delete_scene | Delete a scene |
Sensors
| Tool | Description |
|---|---|
list_sensors | List all sensors with latest readings and battery levels |
get_sensor | Full JSON details for a single sensor |
rename_sensor | Rename a sensor |
set_sensor_config | Update sensor config (enabled, battery level, sensitivity) |
delete_sensor | Remove a sensor from the gateway |
Rules (automations)
| Tool | Description |
|---|---|
list_rules | List all automation rules with status and trigger counts |
get_rule | Full JSON details (conditions + actions) for a rule |
create_rule | Create a new rule with conditions and actions |
set_rule_status | Enable or disable a rule |
delete_rule | Delete a rule |
Schedules
| Tool | Description |
|---|---|
list_schedules | List all timed schedules |
get_schedule | Full JSON details for a schedule |
create_schedule | Create a new schedule with ISO 8601 time expression |
set_schedule_status | Enable or disable a schedule |
delete_schedule | Delete a schedule |
Touchlink
| Tool | Description |
|---|---|
touchlink_scan | Start a Touchlink scan (~10 s) to find nearby Zigbee devices |
get_touchlink_results | Return results from the last Touchlink scan |
touchlink_identify | Make a Touchlink device blink for identification |
touchlink_reset | Factory-reset a Touchlink device |
Resources
Resources are read-only, cacheable snapshots that MCP clients can fetch without issuing tool calls.
| URI | Description |
|---|---|
deconz://config | Gateway configuration JSON |
deconz://lights | All lights with state JSON |
deconz://groups | All groups with action state JSON |
deconz://sensors | All sensors with state JSON |
deconz://rules | All automation rules JSON |
deconz://schedules | All schedules JSON |
deconz://state | Complete gateway state (all resources combined) |
Prompts
Prompts are pre-built conversation starters that guide the AI through common workflows.
| Prompt | Arguments | Description |
|---|---|---|
home_overview | — | Full status report: all lights, sensors, reachability, anomalies |
control_lights | room (optional) | Turn lights on/off, set brightness or colour |
manage_scenes | group_id (optional) | Create, recall, update, or delete scenes |
add_device | — | Step-by-step guide to pair a new Zigbee device |
setup_automation | — | Create a rule triggered by a sensor event |
diagnose_device | device_name (optional) | Diagnose unreachable or misbehaving devices |
evening_routine | bedtime (default 23:00) | Activate an evening scene and schedule lights off |
Claude Desktop configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"deconz": {
"command": "deconz-mcp",
"env": {
"DECONZ_HOST": "192.168.1.10",
"DECONZ_API_KEY": "your-api-key-here"
}
}
}
}
Or if installed in a virtual environment:
{
"mcpServers": {
"deconz": {
"command": "/path/to/deconz-mcp/.venv/bin/deconz-mcp",
"env": {
"DECONZ_HOST": "192.168.1.10",
"DECONZ_API_KEY": "your-api-key-here"
}
}
}
}
HTTP client configuration
For Streamable HTTP transport:
{
"mcpServers": {
"deconz": {
"url": "http://localhost:8080/mcp",
"headers": {
"Authorization": "Bearer my-mcp-secret"
}
}
}
}
For legacy SSE transport:
{
"mcpServers": {
"deconz": {
"url": "http://localhost:8080/sse",
"headers": {
"Authorization": "Bearer my-mcp-secret"
}
}
}
}
Docker
A pre-built multi-platform image (linux/amd64 + linux/arm64) is published to the registry:
registry.mne.pl/deconz-mcp:latest
registry.mne.pl/deconz-mcp:0.1.0
A multi-stage Dockerfile is also included if you prefer to build locally. The builder stage uses the official uv image to install dependencies and compile the package as a wheel; the runtime stage is python:3.12-slim (57 MB total).
Pull
docker pull registry.mne.pl/deconz-mcp:latest
Build locally
# Single-platform (current machine)
docker build -t deconz-mcp:latest .
# Multi-platform push (requires a buildx builder with multi-platform support)
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag registry.mne.pl/deconz-mcp:latest \
--tag registry.mne.pl/deconz-mcp:0.1.0 \
--push .
Run — HTTP server (SSE + Streamable HTTP)
docker run -p 8000:8000 \
-e DECONZ_HOST=192.168.1.10 \
-e DECONZ_API_KEY=abc123def \
-e MCP_AUTH_TOKEN=my-mcp-secret \
registry.mne.pl/deconz-mcp:latest
Run — stdio
docker run -i \
-e DECONZ_HOST=192.168.1.10 \
-e DECONZ_API_KEY=abc123def \
registry.mne.pl/deconz-mcp:latest --transport stdio
Docker Compose
A ready-to-use Compose file is in docs/docker-compose.yml. It defines two services:
| Service | Transport | Started by default |
|---|---|---|
deconz-mcp | server (SSE + Streamable HTTP) on port 8000 | Yes |
deconz-mcp-stdio | stdio | No — requires --profile stdio |
# Copy and edit the environment file
cp .env.example .env # set DECONZ_HOST, DECONZ_API_KEY, MCP_AUTH_TOKEN
# Start the HTTP server
docker compose -f docs/docker-compose.yml up
# Run a one-shot stdio session
docker compose -f docs/docker-compose.yml --profile stdio run --rm deconz-mcp-stdio
Use the stdio service in Claude Desktop:
{
"mcpServers": {
"deconz": {
"command": "docker",
"args": ["compose", "-f", "/path/to/docs/docker-compose.yml",
"--profile", "stdio", "run", "--rm", "deconz-mcp-stdio"],
"env": {
"DECONZ_HOST": "192.168.1.10",
"DECONZ_API_KEY": "your-api-key-here"
}
}
}
}
Kubernetes
The manifest at k8s/deployment.yaml contains all resources needed to run the server in a cluster:
| Resource | Purpose |
|---|---|
Namespace | deconz-mcp — isolates all resources |
Secret | DECONZ_API_KEY and MCP_AUTH_TOKEN (base64-encoded) |
ConfigMap | DECONZ_HOST, DECONZ_PORT, DECONZ_TLS, MCP_BASE_URL |
Deployment | 1 replica, non-root, read-only root FS, resource limits |
Service | ClusterIP on port 80 → pod 8000 |
Ingress | Commented-out template for nginx / cert-manager |
Deploy
# 1. Encode your secrets
echo -n 'your-api-key' | base64 # → paste into Secret.DECONZ_API_KEY
echo -n 'your-mcp-token' | base64 # → paste into Secret.MCP_AUTH_TOKEN
# 2. Edit the ConfigMap (DECONZ_HOST, MCP_BASE_URL) in k8s/deployment.yaml
# 3. Apply
kubectl apply -f k8s/deployment.yaml
# 4. Verify
kubectl -n deconz-mcp get pods
kubectl -n deconz-mcp logs -f deploy/deconz-mcp
Health check
kubectl -n deconz-mcp port-forward svc/deconz-mcp 8000:80
curl http://localhost:8000/health
# {"status": "ok", "deconz_configured": true}
The Deployment configures both a liveness probe and a readiness probe against /health, so Kubernetes automatically restarts the pod if the server becomes unresponsive.
Ingress (optional)
Uncomment the Ingress section at the bottom of k8s/deployment.yaml and set your hostname. TLS termination happens at the ingress controller; the pod always speaks plain HTTP internally.
Health check
HTTP transports expose a liveness probe:
curl http://localhost:8080/health
# {"status": "ok", "deconz_configured": true}
Project structure
deConz-mcp/
├── Dockerfile # Multi-stage image build
├── pyproject.toml # Package metadata and dependencies
├── uv.lock # Locked dependency versions
├── README.md
├── docs/
│ └── docker-compose.yml # Compose services (HTTP + stdio)
├── k8s/
│ └── deployment.yaml # Kubernetes: Namespace, Secret, ConfigMap,
│ # Deployment, Service, Ingress (template)
└── src/
└── deconz_mcp/
├── __init__.py
├── __main__.py # CLI entrypoint and transport wiring
├── client.py # Async deCONZ REST API HTTP client
└── server.py # FastMCP server: tools, resources, prompts
deCONZ API overview
The server covers these API categories:
| Category | Endpoints |
|---|---|
| Config | GET /config, PUT /config (permit join) |
| Lights | GET /lights, GET /lights/<id>, PUT /lights/<id>/state, DELETE /lights/<id> |
| Groups | GET /groups, POST /groups, PUT /groups/<id>/action, DELETE /groups/<id> |
| Scenes | Full CRUD under /groups/<id>/scenes/<sid> incl. recall and store |
| Sensors | GET /sensors, PUT /sensors/<id>/config, DELETE /sensors/<id> |
| Rules | Full CRUD under /rules/<id> |
| Schedules | Full CRUD under /schedules/<id> |
| Touchlink | POST /touchlink/scan, identify, reset |
For the full API reference, see the deCONZ REST API documentation.
Data & Privacy
Preliminary assessment only — not legal advice. See full notes below.
Personal home use
When this server runs in a private household and is accessed only by the residents, processing of smart-home device data is likely covered by the household exemption (GDPR Recital 18). In that scenario the GDPR does not apply and no additional compliance steps are required.
Commercial or shared deployments
Deploying this server in offices, rental properties, hotels, co-working spaces, or any environment where you process data on behalf of other people takes you outside the household exemption. In those cases:
- Presence and motion sensor data constitutes personal behavioral data (Art. 4(1) GDPR). Establish a documented lawful basis (Art. 6) before processing it.
- Conduct a Data Protection Impact Assessment (Art. 35) if the deployment involves systematic monitoring of occupants on a large scale.
- Provide a privacy notice to data subjects describing what is collected, for how long, and under what legal basis.
Security recommendations
| Risk | Recommendation |
|---|---|
| API key exposed in URL paths and server access logs | Rotate the deCONZ API key periodically; restrict access to gateway logs |
| Unencrypted transport | Enable TLS for any network-facing deployment (DECONZ_TLS=true); use a reverse proxy with a valid certificate |
| MCP endpoint publicly accessible | Always set MCP_AUTH_TOKEN when binding to a non-loopback address |
What this software does NOT do
- No data is sent to third parties, analytics services, or cloud providers.
- No telemetry, tracking pixels, or consent libraries are present in this codebase.
- All communication stays between the MCP client, this server, and the local deCONZ gateway.
Legal notice
This GDPR assessment was generated as a preliminary, exploratory evaluation. It does not constitute legal advice and does not replace a legal audit. For binding guidance, consult a qualified data protection lawyer in your jurisdiction.
License
Apache 2.0 — see LICENSE.
Disclaimer
This software is not affiliated with or endorsed by Dresden Elektronik. Use at your own risk. It does not come with any warranty of any kind. There is no liability for the developer. This software is a personal project that I maintain in my free time. Refer to the licence for more information.
Server Config
{
"mcpServers": {
"deconz": {
"command": "deconz-mcp",
"env": {
"DECONZ_HOST": "192.168.1.10",
"DECONZ_API_KEY": "your-api-key-here"
}
}
}
}