# EVOLV MCP services — Docker stack Three MCP services Claude Code uses to close real loops during EVOLV work: | Service | What it does | Tools exposed | |---|---|---| | `mcp-node-red-admin` | Wraps the Node-RED HTTP admin API | `getFlows`, `postFlow`, `getFlow`, `inject`, `listNodes`, `restartFlow` | | `mcp-influxdb` | Queries the telemetry bucket | `query`, `assertSeriesExists`, `assertRecentWrite`, `listMeasurements` | | `mcp-browser` | Headless Playwright against the FlowFuse dashboard | `loadDashboard`, `screenshot`, `consoleLogs`, `waitForChart`, `getChartData` | ## Why these Each closes a verification loop Claude currently cannot close: - **Node-RED admin** — today Claude pushes flows via raw `curl`; the MCP lets Claude deploy + fire injects + read live state in one conversational turn. - **InfluxDB** — today Claude cannot verify "did the telemetry land?" beyond reading source. The MCP closes the loop after a deploy. - **Browser** — today Claude cannot see the rendered dashboard. The MCP catches the failure mode behind the η-null crash + the blank-ui-chart bug + the editor pile-up bug at the only layer where they're visible. ## Migration plan These run locally **now** (we're in the middle of an infra migration). Once the central MCP server is provisioned (target Q3 2026), each service moves to shared infra by lifting the entry from this `docker-compose.yml` plus the matching `tools/mcp//Dockerfile` and pointing every developer's Claude Code at the central endpoint instead of `localhost`. **The compose file stays here as the canonical definition.** ## Usage ```bash # build the three images (one-off, ~3 min) cd tools docker compose --profile mcp build # start them docker compose --profile mcp up -d # wire Claude Code to them — add to your user-level .mcp.json { "mcpServers": { "evolv-node-red-admin": { "type": "stdio", "command": "docker", "args": ["exec", "-i", "evolv-mcp-node-red-admin", "node", "server.mjs"] }, "evolv-influxdb": { "type": "stdio", "command": "docker", "args": ["exec", "-i", "evolv-mcp-influxdb", "node", "server.mjs"] }, "evolv-browser": { "type": "stdio", "command": "docker", "args": ["exec", "-i", "evolv-mcp-browser", "node", "server.mjs"] } } } ``` The repo-level `.mcp.json` is deliberately **not** committed (each developer has different host endpoints / tokens). Use a user-level config or `~/.claude.json`. ## Required environment `tools/.env` (gitignored) with: ```dotenv NODE_RED_HOST=http://host.docker.internal:1880 NODE_RED_TOKEN=… # optional, only if Node-RED has admin auth on INFLUX_URL=http://host.docker.internal:8086 INFLUX_TOKEN=… INFLUX_ORG=wbd INFLUX_BUCKET=telemetry DASHBOARD_URL=http://host.docker.internal:1880/dashboard ``` ## Status | Service | Dockerfile | Server impl | Status | |---|---|---|---| | `mcp-node-red-admin` | placeholder | **TODO** — see `mcp/node-red-admin/ROADMAP.md` | not runnable yet | | `mcp-influxdb` | placeholder | **TODO** | not runnable yet | | `mcp-browser` | placeholder | **TODO** — wrap `@playwright/test` | not runnable yet | The compose file is the **target shape**. The Dockerfile + server implementation per service is a follow-up (each is ~200–400 LOC of MCP protocol + the wrapped client). When a service lands, flip its row above to `runnable` and remove the placeholder. ## When to use these — required reading `CLAUDE.md` § "Tooling (Docker-first, local now, central later)" lists the operating doctrine: **always prefer these tools over ad-hoc curl/grep/manual checks**. Each tool exists because of a specific bug class we've already paid for. Skipping them re-opens those bugs. ## Future: OPC-UA / PLC MCP Out of scope for this round; will be revisited later. When added it follows the same pattern: `tools/mcp/opcua/` with its own Dockerfile and a row in this README.