Deconz Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Deconz Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
# 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 .http://<gateway-ip>/pwa).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.
DECONZ_HOST=192.168.1.10 DECONZ_API_KEY=abc123def deconz-mcpDECONZ_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 8080DECONZ_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| 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.
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 |
| 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 |
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.
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.
| 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) |
| 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 |
| 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) |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 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 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 |
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"
}
}
}
}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"
}
}
}
}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.0A 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).
docker pull registry.mne.pl/deconz-mcp:latest# 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 .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:latestdocker run -i \
-e DECONZ_HOST=192.168.1.10 \
-e DECONZ_API_KEY=abc123def \
registry.mne.pl/deconz-mcp:latest --transport stdioA 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-stdioUse 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"
}
}
}
}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 |
# 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-mcpkubectl -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.
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.
HTTP transports expose a liveness probe:
curl http://localhost:8080/health
# {"status": "ok", "deconz_configured": true}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, promptsThe 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.
Preliminary assessment only — not legal advice. See full notes below.
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.
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:
| 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 |
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.
Apache 2.0 — see LICENSE.
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.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.