deConz MCP

Máy chủ MCP cho máy chủ deConz do Dresden Elektronik phát triển (cầu nối giữa các nền tảng tự động hóa nhà thông minh và mạng Zigbee không dây)

GitHubDùng thử MCP nàyĐược tài trợ

Tài liệu

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/marcinn2/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

  1. Open the Phoscon App in your browser (usually http://<gateway-ip>/pwa).
  2. Go to Menu → Settings → Gateway → Advanced.
  3. Click Authenticate app — this opens the network for 60 seconds.
  4. 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

VariableRequiredDefaultDescription
DECONZ_HOSTYes*—IP or hostname of the deCONZ gateway
DECONZ_PORTNo80HTTP port of the deCONZ gateway
DECONZ_API_KEYYes*—deCONZ REST API key
DECONZ_TLSNofalseSet true to use HTTPS
DECONZ_TLS_VERIFYNotruefalse accepts a self-signed gateway certificate; any other value is a path to a CA bundle
DECONZ_ALLOW_RUNTIME_CONFIGNosee‡Set true to expose configure_deconz even when the gateway comes from the environment
MCP_AUTH_TOKENNo†—Bearer token clients must send to this MCP server
MCP_BASE_URLNohttp://<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.
‡ Defaults to enabled only when DECONZ_HOST / DECONZ_API_KEY are absent. Once the gateway is configured from the environment, the tool is withheld so that a client cannot repoint this server at another host.


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]
FlagDefaultDescription
--transportstdioTransport mode
--host127.0.0.1Bind address (HTTP transports)
--port8000Listen port (HTTP transports)
--log-levelINFOLogging verbosity
--auth-token$MCP_AUTH_TOKENMCP bearer token
--base-url$MCP_BASE_URLOAuth issuer URL

Transport modes

ModeEndpoint(s)Description
stdiostdin/stdoutPipe-based — for Claude Desktop and local use
sse/sse, /messages/Legacy SSE (MCP pre-2025-03-26)
streamable-http/mcpModern Streamable HTTP (MCP 2025-03-26)
serverall of the aboveSSE + 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: request URLs are kept out of tool errors, and the HTTP client's request logging is silenced because it would otherwise write the key to stderr on every call.

Resource IDs supplied by a client (light, group, scene, sensor, rule, schedule, and Touchlink IDs) are validated before they are placed in a request path, so a crafted ID cannot escape its resource and reach, for example, the gateway's configuration or its list of API keys.

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

ToolDescription
configure_deconzPoint the server at a deCONZ gateway at runtime (host, port, API key). Registered only when the gateway is not configured from the environment, or when DECONZ_ALLOW_RUNTIME_CONFIG=true
get_gateway_configRead gateway name, firmware, Zigbee channel, IP, WebSocket port
set_permit_joinOpen the Zigbee network for new device pairing (0–255 seconds)

Lights

ToolDescription
list_lightsList all lights with on/off, brightness, and reachability
get_lightFull JSON details for a single light
set_light_stateControl power, brightness, hue, saturation, colour temp, xy, effect, alert
rename_lightRename a light
delete_lightRemove a light from the gateway

Groups

ToolDescription
list_groupsList all groups with member count and action state
get_groupFull JSON details for a single group
create_groupCreate a new group (optionally pre-populate with lights)
set_group_actionControl all lights in a group simultaneously
modify_groupRename a group or change its member lights
delete_groupDelete a group (lights remain)

Scenes

ToolDescription
list_scenesList all scenes for a group
get_sceneFull JSON details for a scene
create_sceneCreate a scene (captures current group state)
recall_sceneActivate a scene
store_sceneOverwrite a scene with the current group state
rename_sceneRename a scene
delete_sceneDelete a scene

Sensors

ToolDescription
list_sensorsList all sensors with latest readings and battery levels
get_sensorFull JSON details for a single sensor
rename_sensorRename a sensor
set_sensor_configUpdate sensor config (enabled, battery level, sensitivity)
delete_sensorRemove a sensor from the gateway

Rules (automations)

ToolDescription
list_rulesList all automation rules with status and trigger counts
get_ruleFull JSON details (conditions + actions) for a rule
create_ruleCreate a new rule with conditions and actions
set_rule_statusEnable or disable a rule
delete_ruleDelete a rule

Schedules

ToolDescription
list_schedulesList all timed schedules
get_scheduleFull JSON details for a schedule
create_scheduleCreate a new schedule with ISO 8601 time expression
set_schedule_statusEnable or disable a schedule
delete_scheduleDelete a schedule

Touchlink

ToolDescription
touchlink_scanStart a Touchlink scan (~10 s) to find nearby Zigbee devices
get_touchlink_resultsReturn results from the last Touchlink scan
touchlink_identifyMake a Touchlink device blink for identification
touchlink_resetFactory-reset a Touchlink device

Resources

Resources are read-only, cacheable snapshots that MCP clients can fetch without issuing tool calls.

URIDescription
deconz://configGateway configuration JSON
deconz://lightsAll lights with state JSON
deconz://groupsAll groups with action state JSON
deconz://sensorsAll sensors with state JSON
deconz://rulesAll automation rules JSON
deconz://schedulesAll schedules JSON
deconz://stateComplete gateway state (all resources combined)

Prompts

Prompts are pre-built conversation starters that guide the AI through common workflows.

PromptArgumentsDescription
home_overview—Full status report: all lights, sensors, reachability, anomalies
control_lightsroom (optional)Turn lights on/off, set brightness or colour
manage_scenesgroup_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_devicedevice_name (optional)Diagnose unreachable or misbehaving devices
evening_routinebedtime (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 multi-platform image (linux/amd64 + linux/arm64) is published to GitHub Container Registry by the release workflow whenever a version tag is pushed:

ghcr.io/marcinn2/deconz-mcp:latest
ghcr.io/marcinn2/deconz-mcp:0.2
ghcr.io/marcinn2/deconz-mcp:0.2.1

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.14-slim and runs as the unprivileged user app (uid 1000).

Pull

docker pull ghcr.io/marcinn2/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).
# Releases do this automatically; this is for pushing to another registry by hand.
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag registry.mne.pl/deconz-mcp:latest \
  --tag registry.mne.pl/deconz-mcp:0.2.1 \
  --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 \
  ghcr.io/marcinn2/deconz-mcp:latest

Run — stdio

docker run -i \
  -e DECONZ_HOST=192.168.1.10 \
  -e DECONZ_API_KEY=abc123def \
  ghcr.io/marcinn2/deconz-mcp:latest --transport stdio

Docker Compose

A ready-to-use Compose file is in docs/docker-compose.yml. It defines two services:

ServiceTransportStarted by default
deconz-mcpserver (SSE + Streamable HTTP) on port 8000Yes
deconz-mcp-stdiostdioNo — 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 (--env-file is required: the compose file lives in docs/,
# so a repository-root .env is not picked up automatically)
docker compose --env-file .env -f docs/docker-compose.yml up

# Run a one-shot stdio session
docker compose --env-file .env -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 docs/k8s-deployment.yaml contains all resources needed to run the server in a cluster:

ResourcePurpose
Namespacedeconz-mcp — isolates all resources
SecretDECONZ_API_KEY and MCP_AUTH_TOKEN (base64-encoded)
ConfigMapDECONZ_HOST, DECONZ_PORT, DECONZ_TLS, MCP_BASE_URL
Deployment1 replica, non-root, read-only root FS, resource limits
ServiceClusterIP on port 80 → pod 8000
IngressCommented-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 docs/k8s-deployment.yaml

# 3. Apply
kubectl apply -f docs/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 docs/k8s-deployment.yaml and set your hostname. Do not add a rewrite-target annotation: the endpoints live at /mcp, /sse and /messages/ and must reach the pod with their paths intact. 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 (runs as uid 1000)
├── pyproject.toml                  # Package metadata and dependencies
├── uv.lock                         # Locked dependency versions (committed)
├── .env.example                    # Template for docker compose
├── README.md
├── docs/
│   ├── docker-compose.yml          # Compose services (HTTP + stdio)
│   └── k8s-deployment.yaml         # Kubernetes: Namespace, Secret, ConfigMap,
│                                   #   Deployment, Service, Ingress (template)
├── tests/
│   └── test_smoke.py               # Client, credential-handling and MCP surface tests
└── 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:

CategoryEndpoints
ConfigGET /config, PUT /config (permit join)
LightsGET /lights, GET /lights/<id>, PUT /lights/<id>/state, DELETE /lights/<id>
GroupsGET /groups, POST /groups, PUT /groups/<id>/action, DELETE /groups/<id>
ScenesFull CRUD under /groups/<id>/scenes/<sid> incl. recall and store
SensorsGET /sensors, PUT /sensors/<id>/config, DELETE /sensors/<id>
RulesFull CRUD under /rules/<id>
SchedulesFull CRUD under /schedules/<id>
TouchlinkPOST /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

RiskRecommendation
API key travels in URL paths, so the gateway's own access logs record itRotate the deCONZ API key periodically; restrict access to gateway logs. This server keeps the key out of its own logs and out of the errors it returns to clients
Unencrypted transportEnable TLS for any network-facing deployment (DECONZ_TLS=true); use a reverse proxy with a valid certificate. Set DECONZ_TLS_VERIFY=false only for a self-signed gateway certificate on a trusted network
MCP endpoint publicly accessibleAlways 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.


Releasing

Releases are cut by pushing a version tag. .github/workflows/release.yml then:

  1. Checks that the tag matches the version in pyproject.toml and fails early if it does not.
  2. Runs the full CI workflow (lint, format, type-check, tests on Python 3.10–3.12).
  3. Builds the image for linux/amd64 and linux/arm64, with an SBOM and build provenance, and pushes it to ghcr.io/marcinn2/deconz-mcp.
  4. Creates the GitHub release with generated notes, the image digest, and the built wheel and sdist attached.
# bump version = "0.3.0" in pyproject.toml first, then:
git tag -a v0.3.0 -m "v0.3.0"
git push origin v0.3.0

A tag containing a hyphen, such as v0.3.0-rc.1, is published as a pre-release and does not move the latest image tag.

Image tags produced for v0.3.0: 0.3.0, 0.3, and latest.

No secrets need to be configured: the workflow authenticates to GHCR with the built-in GITHUB_TOKEN. After the first release, set the package visibility under Packages → deconz-mcp → Package settings if the image should be pullable anonymously.


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.