diff --git a/CLAUDE.md b/CLAUDE.md index 14a67ff..0417a19 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -64,7 +64,7 @@ make dashboard # Observable preview on :3000 make check # curl /state/health ``` -The MCP server is registered in `.mcp.json` at the repo root. After `make install` creates `.venv`, restart Claude Code for `/mcp` to show `state-hub`. +The MCP server runs as a persistent SSE service (`make mcp-http`, port 8001). Registered at user scope via `claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:8001/sse"}'`. Restart the MCP server independently — no Claude Code restart needed. ### Docker Setup (WSL2, one-time) diff --git a/state-hub/Makefile b/state-hub/Makefile index 4567d68..9016020 100644 --- a/state-hub/Makefile +++ b/state-hub/Makefile @@ -25,11 +25,11 @@ migrate: seed: uv run python scripts/seed.py -## MCP server in SSE/HTTP mode for remote Claude Code sessions (e.g. COULOMBCORE). -## Exposes the same tools as the stdio server over HTTP at http://127.0.0.1:8001/sse -## Remote clients connect via the ops-bridge tunnel (port 18001 on the remote host). -## Registration on the remote: claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:18001/sse"}' +## Start (or restart) the MCP SSE server on :8001 — primary transport for Claude Code. +## Remote clients (e.g. COULOMBCORE) connect via the ops-bridge tunnel (port 18001). +## Registration: claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:8001/sse"}' mcp-http: + @fuser -k 8001/tcp 2>/dev/null && echo "Stopped running MCP server" || true MCP_TRANSPORT=sse MCP_PORT=8001 uv run python mcp_server/server.py dashboard: diff --git a/state-hub/README.md b/state-hub/README.md index eb35140..f3c2301 100644 --- a/state-hub/README.md +++ b/state-hub/README.md @@ -1,6 +1,6 @@ # State Hub v0.1 -The operational brain of the Custodian: a local PostgreSQL database, FastAPI REST service, FastMCP stdio server for Claude Code, Observable Framework dashboard, and a `custodian` CLI. +The operational brain of the Custodian: a local PostgreSQL database, FastAPI REST service, FastMCP SSE server for Claude Code, Observable Framework dashboard, and a `custodian` CLI. --- @@ -10,7 +10,7 @@ The operational brain of the Custodian: a local PostgreSQL database, FastAPI RES |-------|-----------|------| | Database | PostgreSQL 16-alpine (Docker) | `127.0.0.1:5432` | | API | FastAPI + SQLAlchemy 2.0 async + asyncpg | `127.0.0.1:8000` | -| MCP server | FastMCP stdio (Claude Code native) | stdio | +| MCP server | FastMCP SSE | `127.0.0.1:8001` | | Dashboard | Observable Framework | `127.0.0.1:3000` | | CLI | `custodian` (Python, uv entry point) | — | @@ -147,15 +147,22 @@ Returns a full snapshot in one call — used by both the MCP server and dashboar ## MCP Server -Registered in `~/.claude.json` at user scope. Config in `.mcp.json` (repo root). +Runs as a persistent SSE service on `:8001`, independent of the Claude Code session. +Restart it anytime without restarting Claude Code. -Uses absolute path + `PYTHONPATH` so `cwd` is not required: +```bash +make mcp-http # start (or restart) the MCP SSE server on :8001 +``` + +Registered at user scope in `~/.claude.json`: ```json -{ - "command": "/home/worsch/the-custodian/state-hub/.venv/bin/python", - "args": ["/home/worsch/the-custodian/state-hub/mcp_server/server.py"], - "env": { "PYTHONPATH": "/home/worsch/the-custodian/state-hub", "API_BASE": "http://127.0.0.1:8000" } -} +{ "type": "sse", "url": "http://127.0.0.1:8001/sse" } +``` + +To re-register from scratch: +```bash +claude mcp remove state-hub -s user 2>/dev/null || true +claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:8001/sse"}' ``` See `mcp_server/TOOLS.md` for the full tool reference card (30 lines, faster than reading `server.py`). @@ -202,7 +209,7 @@ Prints API health, totals, and any blocking decisions. | Script | Purpose | |--------|---------| | `scripts/register_project.sh` | Shell version of `custodian register-project` | -| `scripts/patch_mcp_cwd.py` | Patches `cwd` into `~/.claude.json` after `claude mcp add-json` drops it | +| `scripts/patch_mcp_cwd.py` | Legacy: patched `cwd` for the old stdio registration (no longer needed) | | `scripts/project_claude_md.template` | CLAUDE.md template with `{PROJECT_NAME}`, `{DOMAIN}`, `{TOPIC_ID}` | | `scripts/seed.py` | Insert the 6 canonical topics into a fresh database | | `scripts/pull_image.py` | WSL2 workaround: pull Docker images via Python urllib with Range-request chunking | @@ -231,5 +238,5 @@ rm -rf dashboard/src/.observablehq/cache/ ## Known Issues / WSL2 Notes - **TLS bad record MAC on large downloads**: WSL2 corrupts packets on big TCP transfers. Use `scripts/pull_image.py` instead of `docker pull` for future image pulls. -- **`claude mcp add-json` drops `cwd`**: Known Claude Code bug. Run `python3 scripts/patch_mcp_cwd.py` after any re-registration. The current `.mcp.json` uses absolute path + `PYTHONPATH` so `cwd` is not strictly needed. +- **MCP server is now SSE, not stdio**: Re-registration is `claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:8001/sse"}'`. The `patch_mcp_cwd.py` script and `.mcp.json` config are legacy artifacts from the old stdio setup. - **AsyncSession concurrency**: SQLAlchemy 2.0 async sessions don't support concurrent operations. All queries in `/state/summary` run sequentially on a single session.