MCP
The controller's MCP endpoint and the nomos MCP Bridge
The controller includes a server for the Model Context Protocol (MCP). Through it, AI assistants such as Claude read and control the system: devices, scenes, rooms, automations and much more.
You switch the MCP skill on in the configuration interface, which is also where you create the tokens. How to set up common clients such as Claude Desktop, Cursor or Windsurf is described in MCP in the integrator handbook. This page describes the endpoint itself.
Endpoint
| Address | http://<controller-ip>/mcp |
| Transport | Streamable HTTP: POST for JSON-RPC, answers as text/event-stream, GET for the notification stream, DELETE ends the session |
| Authentication | header Authorization: Bearer <token> |
| Session | header Mcp-Session-Id from the answer to initialize |
| Reachable | local network only |
The status codes help with troubleshooting:
| Code | Meaning |
|---|---|
| 404 | The MCP skill is switched off. |
| 401 | The token is missing (Missing or invalid Authorization header) or unknown or disabled (Invalid token). |
| 511 | The request came through remote access. MCP is only reachable in the local network. |
| 400 | A request without a valid session that is not an initialize. |
Permissions
A token is not tied to a nomos user. Whoever holds it works with administrator rights; room and scene permissions do not apply. Some areas are deliberately not offered by the server: users can only be read, and restoring a backup, factory reset, port forwarding and remote access remain reserved to the configuration interface.
Treat tokens like passwords: one token per client, and delete tokens you no longer need. Administrators manage them over the API with addMCPToken, getMCPTokens, setMCPToken and removeMCPToken.
What the server offers
- Tools for components, scenes, rooms, zones, automations, skills and system functions. Read-only tools carry the hint
readOnlyHint. - Resources such as
nomos://components/all,nomos://scenes/allornomos://rooms/all. - Prompts for frequent tasks, such as a status report or guided scene creation.
- Instructions in the answer to
initializethat explain the data model to the model.
The server itself returns the current list through tools/list, resources/list and prompts/list. When it changes, it notifies the connected clients.
Trying it with curl
This is the flow without an MCP client. Answers come as server-sent events, i.e. as lines event: message and data: {…}.
TOKEN='<token>'
curl -si http://<controller-ip>/mcp \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'HTTP/1.1 200 OK
content-type: text/event-stream
mcp-session-id: 6f0c…
event: message
data: {"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{"listChanged":true},"resources":{"listChanged":true},"completions":{},"prompts":{"listChanged":true}},"serverInfo":{"name":"nomos-mcp",…Continue with the session ID from the header: first the confirmation, then a tool call, and finally close the session.
SESSION='<mcp-session-id>'
H=(-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json'
-H 'Accept: application/json, text/event-stream'
-H "Mcp-Session-Id: $SESSION" -H 'MCP-Protocol-Version: 2025-06-18')
curl -s http://<controller-ip>/mcp "${H[@]}" \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
curl -s http://<controller-ip>/mcp "${H[@]}" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"component_get_by_id","arguments":{"cid":"C5"}}}'
curl -s -X DELETE http://<controller-ip>/mcp "${H[@]}"event: message
data: {"result":{"content":[{"type":"text","text":"{\n \"name\": \"Switch\",\n \"cid\": \"C5\",…Setting up clients
Claude Code speaks Streamable HTTP itself and connects directly:
claude mcp add --transport http nomos http://<controller-ip>/mcp \
--header "Authorization: Bearer <token>"nomos MCP Bridge: To work with several controllers, use the nomos MCP Bridge. It runs as a local stdio server (Node.js 18 or later), passes through the tools, resources and prompts of the selected controller and switches between controllers on request.
claude mcp add nomos -- npx -y nomos-mcp-bridgeThe bridge keeps the controllers in ~/.config/nomos-mcp/controllers.json, with address (http://<controller-ip>/mcp) and token. The tokens are stored there in plain text; protect the file accordingly. To add controllers, the bridge opens a setup page on http://localhost:18900 (or the next free port if that one is taken), reachable only from your own computer.
The configuration for Claude Desktop, Cursor, Windsurf and other clients is in the integrator handbook.
HTTP or HTTPS
The endpoint is also reachable at https://<controller-ip>/mcp. The controller's certificate, however, is self-signed and does not name the controller's address. Clients based on Node.js, the bridge among them, therefore reject it. The bridge's README suggests NODE_TLS_REJECT_UNAUTHORIZED=0 for this; with it, the whole process stops checking certificates altogether, for other servers as well. We do not recommend that.
In the local network, use http:// instead. The token then travels unencrypted; only use MCP in a network you trust. How to trust exactly this certificate in your own programs is described under HTTPS and certificate.