MCP server for controlling HomeMatic smart home devices via the CCU JSON-RPC API
claude mcp add ccu-mcp -- npx -y ccu-mcp{
"mcpServers": {
"ccu-mcp": {
"command": "npx",
"args": ["-y", "ccu-mcp"],
"env": {
"CCU_HOST": "<ccu_host>",
"CCU_PASSWORD": "<ccu_password>",
"MCP_AUTH_TOKEN": "<mcp_auth_token>",
"MCP_HOST": "<mcp_host>"
}
}
}
}CCU_HOSTCCU_PASSWORDMCP_AUTH_TOKENMCP_HOSTResumen de MCP Servers
# ccu-mcp
Talk to your HomeMatic smart home from Claude, Cursor, or any MCP client.
<a href="https://glama.ai/mcp/servers/claymore666/ccu-mcp">
<img width="380" height="200" src="https://glama.ai/mcp/servers/claymore666/ccu-mcp/badge" alt="ccu-mcp MCP server" />
</a>
ccu-mcp connects to the CCU's built-in JSON-RPC API and exposes your devices, rooms, programs, and system variables as MCP tools. No addons, no XML-API, no cloud — just a direct connection to the CCU on your local network.
Works with any HomeMatic CCU: [debmatic](https://github.com/alexreinert/debmatic) (HomeMatic on Debian), a CCU3, or [OpenCCU](https://github.com/OpenCCU/OpenCCU) (formerly RaspberryMatic) — anything that exposes the standard `/api/homematic.cgi` endpoint.
## What can it do?
Ask your AI assistant things like:
- "What's the temperature in the bathroom?"
- "Are any windows open?"
- "Set the living room heating to 21 degrees"
- "Show me all devices with low battery"
- "What's the gas meter reading?"
- "Which devices have low battery or haven't been seen in a long time?"
- "Find all channels whose names don't match their device name"
- "Rename all devices to follow a consistent naming convention with floor labels (UG/OG/EG)"
- "Which room is the window sensor in?"
The MCP server handles device discovery, type resolution, session management, and value conversion — the AI just calls the tools.
## Prerequisites
- A running HomeMatic CCU (debmatic, CCU3, or OpenCCU — formerly RaspberryMatic) reachable on your network
- The CCU's admin username and password (the same credentials you use to log into the WebUI)
- Node.js 24+ (for running from source or stdio mode) or Docker
## Quick start
```bash
export CCU_HOST=your-ccu-hostname-or-ip
export CCU_PASSWORD=your-ccu-admin-password
npx ccu-mcp --stdio
```
If it prints `server_ready` to stderr, it's working. Press Ctrl+C to stop. Now set it up in your MCP client — see below.
## Installation
There are two ways to run this: **stdio** (the server runs as a subprocess of your MCP client) or **HTTP** (the server runs standalone in Docker and clients connect over the network). Pick one.
### Option A: stdio (direct, simplest)
This is the easiest setup. Your MCP client (Claude Code, Cursor, etc.) starts the server as a child process — no Docker, no network config, no auth tokens.
For Claude Code, create a `.mcp.json` file in your project directory (or any directory where you'll use Claude Code):
```json
{
"mcpServers": {
"ccu-mcp": {
"command": "npx",
"args": ["ccu-mcp", "--stdio"],
"env": {
"CCU_HOST": "your-ccu-hostname-or-ip",
"CCU_PASSWORD": "your-ccu-admin-password"
}
}
}
}
```
Replace `your-ccu-hostname-or-ip` with your CCU's hostname (like `homematic-ccu3`) or IP (like `192.168.1.50`), and `your-ccu-admin-password` with the password you use to log into the CCU WebUI.
Restart Claude Code. Run `/mcp` to check it connected. You should see `ccu-mcp` in the list.
Alternatively, use the Claude Code CLI:
```bash
claude mcp add ccu-mcp -- npx ccu-mcp --stdio
```
### Option B: Docker (standalone HTTP server)
Use this if you want the server running independently — for example on a home server, accessible to multiple clients, or when your MCP client supports HTTP remotes.
**1. Start the container:**
```bash
git clone https://github.com/claymore666/ccu-mcp.git && cd ccu-mcp
docker build -t ccu-mcp .
docker run -d \
--name ccu-mcp \
-e CCU_HOST=your-ccu-hostname-or-ip \
-e CCU_PASSWORD=your-ccu-admin-password \
-e MCP_ALLOWED_HOSTS=your-server-ip:3000 \
-v ccu-data:/data \
-p 3000:3000 \
ccu-mcp
```
> **`MCP_ALLOWED_HOSTS` is required for remote clients.** The server's
> DNS-rebinding protection rejects any request whose `Host` header isn't on
> the allowlist — by default only `localhost`/`127.0.0.1`/`[::1]` on the MCP
> port. Set it to every name/IP clients will use to reach the server
> (comma-separated, `host:port`). Without it, the local health check works
> but every remote MCP request gets **403 Invalid Host header**.
**2. Get the auth token.** The server generates a random bearer token on first startup and saves it inside the container's data volume. You need this token to authenticate your MCP client. Grab it with:
```bash
docker exec ccu-mcp grep MCP_AUTH_TOKEN /data/.env
```
This prints something like `MCP_AUTH_TOKEN=e96suzi1iG0H-GPif6K2...`. The part after `=` is your token.
**3. Configure your MCP client.** If your client uses `.mcp.json`, add the HTTP server:
```json
{
"mcpServers": {
"ccu-mcp": {
"url": "http://your-server-ip:3000",
"headers": {
"Authorization": "Bearer PASTE-YOUR-TOKEN-HERE"
}
}
}
}
```
To inject the token automatically (requires `jq`):
```bash
TOKEN=$(docker exec ccu-mcp grep MCP_AUTH_TOKEN /data/.env | cut -d= -f2)
jq --arg t "$TOKEN" '.mcpServers["ccu-mcp"].headers.Authorization = "Bearer " + $t' .mcp.json > .mcp.json.tmp && mv .mcp.json.tmp .mcp.json
```
This only updates the `ccu-mcp` entry — other servers in your `.mcp.json` are left alone.
**4. Check it's healthy:**
```bash
curl http://localhost:3000/health
```
#### Browser-based clients (CORS)
By default the HTTP server sends **no** CORS headers, so a random web page can't drive a local instance. To let browser-based MCP clients like [MCP Inspector](https://github.com/modelcontextprotocol/inspector) connect directly, set `MCP_ALLOWED_ORIGINS` to a comma-separated allowlist of trusted origins (e.g. `https://app.example,http://localhost:6274`). A request whose `Origin` is on the list gets that **exact** origin reflected in `Access-Control-Allow-Origin` — never the wildcard `*`, which would let any site drive a local instance that controls real CCU hardware. A request from any other origin gets no CORS headers (the browser blocks it) and is rejected server-side by DNS-rebinding protection. Authentication is always enforced regardless: every MCP request needs the bearer token.
The HTTP transport also has **DNS-rebinding protection** on by default: it rejects requests whose `Host` header isn't `localhost`/`127.0.0.1`/`[::1]` on the configured port. If you reach the server under another hostname or IP (reverse proxy, container DNS name, the server's LAN address), list those hosts in `MCP_ALLOWED_HOSTS` or legitimate requests get a `403`.
**TLS.** The bearer token travels in the request, so anything beyond loopback should be encrypted. You have two options: terminate TLS at a reverse proxy (Caddy/nginx) in front and bind the server to loopback (`MCP_HOST=127.0.0.1`), or let the server serve HTTPS itself by setting `MCP_TLS_CERT` and `MCP_TLS_KEY` to a PEM cert/key pair. Plain HTTP is still fully supported — it stays the zero-config default — but the server logs a warning at startup when it's serving the token over unencrypted HTTP on a non-loopback bind; set `MCP_ALLOW_PLAINTEXT=true` to acknowledge that and silence it.
**Token rotation & expiry.** By default the bearer token lives forever. Two optional, composable controls let you rotate it without dropping clients:
- *Auto-generated token* — set `MCP_AUTH_TOKEN_TTL_DAYS` (fractional days allowed) to give the generated token a lifetime. The server rotates it **automatically at runtime** shortly before it lapses (no restart needed; also on startup if it expired while the server was down), prints the new token on stderr, and keeps the just-replaced token validating for `MCP_AUTH_TOKEN_GRACE_HOURS` (default 24) so in-flight clients survive the swap. To force a rotation sooner, delete `$CACHE_DIR/.env` (or just its `MCP_AUTH_TOKEN` line) and restart.
- *Explicit token* — when you set `MCP_AUTH_TOKEN` yourself, you own its lifetime (TTL doesn't apply). To rotate, put the new token in `MCP_AUTH_TOKEN`, move the old one to `MCP_AUTH_TOKEN_PREVIOUS`, and restart; both are accepted during the overlap. Drop `MCP_AUTH_TOKEN_PREVIOUS` and restart once every client is on the new token. Comparison stays timing-safe across every currently-valid token.
**Brute-force protection (fail2ban).** The auto-generated token is 256 bits of randomness, so guessing it is infeasible. If you set `MCP_AUTH_TOKEN` yourself, **make it long and random** (e.g. `openssl rand -base64 32`) — a short or guessable token is the one case brute force matters. The server does **not** rate-limit or lock out failed logins in-process; that job belongs to a firewall-level tool like [fail2ban](https://www.fail2ban.org/), which bans the source IP before the request ever reaches the server. To make that easy, every rejected request logs a structured line to stderr:
```json
{"ts":"2026-06-18T17:28:00.370Z","level":"warn","msg":"auth_failed","client":"203.0.113.7","hadToken":true}
```
Ready-to-use fail2ban config ships in [`fail2ban/`](fail2ban/): copy `filter.d/ccu-mcp.conf` to `/etc/fail2ban/filter.d/` and the jail in `jail.d/ccu-mcp.local` to `/etc/fail2ban/jail.d/` (it defaults to 5 failures in 10 minutes → 1-hour ban). The server logs to stderr, so point fail2ban at wherever you collect it — the journal (`backend = systemd`) when run as a unit, or a file when you redirect stderr/`docker logs`; both are spelled out in the jail file. Requires `LOG_LEVEL=warn` or lower (`info`, the default, is fine; `error` suppresses the line). Behind a reverse proxy the logged IP is the proxy's, so run fail2ban against the proxy's access log instead.
CORS support was first implemented by [@marcinn2](https://github.com/marcinn2) in his fork [marcinn2/debmatic-mcp](https://github.com/marcinn2/debmatic-mcp) — thanks!
### HTTPS
If your CCU uses HTTPS (self-signed certificates are fine), add these environment variables:
```bash
CCU_HTTPS=true
CCU_PORT=443
```
The server accepts self-signed certificates automatically — certificate verification is **off by default** because CCUs ship with self-signed certs (the server logs a warning when running unverified). To actually verify the connectioLo que la gente pregunta sobre ccu-mcp
¿Qué es claymore666/ccu-mcp?
+
claymore666/ccu-mcp es mcp servers para el ecosistema de Claude AI. MCP server for controlling HomeMatic smart home devices via the CCU JSON-RPC API Tiene 4 estrellas en GitHub y se actualizó por última vez today.
¿Cómo se instala ccu-mcp?
+
Puedes instalar ccu-mcp clonando el repositorio (https://github.com/claymore666/ccu-mcp) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar claymore666/ccu-mcp?
+
claymore666/ccu-mcp aún no ha sido auditado por nuestro agente de seguridad. Revisa el repositorio original en GitHub antes de usarlo en producción.
¿Quién mantiene claymore666/ccu-mcp?
+
claymore666/ccu-mcp es mantenido por claymore666. La última actividad registrada en GitHub es de today, con 1 issues abiertos.
¿Hay alternativas a ccu-mcp?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega ccu-mcp en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/claymore666-ccu-mcp)<a href="https://claudewave.com/repo/claymore666-ccu-mcp"><img src="https://claudewave.com/api/badge/claymore666-ccu-mcp" alt="Featured on ClaudeWave: claymore666/ccu-mcp" width="320" height="64" /></a>Más MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!