--- name: "mcp-server-debugging" description: "MCP server tools missing or fails to start (\"Connection closed\"): reproduce via stdio client, pin mcp<2, fix writable HOME/PATH." --- # MCP Server Debugging Diagnose and fix OpenClaw MCP servers whose tools never appear or that crash on startup. ## Trigger - A configured MCP server's tools are absent from the session, or a stdio MCP client fails `initialize` with `Connection closed`. - A newly added MCP server does not show up as `__*` tools. ## Steps 1. Read the server definition: call `gateway` with `action=config.get`, `path=mcp`; note `command`, `args`, `env`, `cwd` for the failing server. 2. Reproduce and capture the real error: run the configured command directly with stdin from `/dev/null` (e.g. `timeout 60 python3 < /dev/null 2>&1 | head -40`). Completion: stderr shows the underlying failure, not only the client-side "Connection closed". 3. Map the error to the fix: - `ModuleNotFoundError: No module named 'mcp.server.fastmcp'` → the runner pulled **mcp 2.x**, where `FastMCP` was renamed to `MCPServer`. Fix: pin 1.x, e.g. run `uvx --with "mcp<2" `, or add the pin inside the launcher's `os.execvp` call. - `Read-only file system` on a home/credentials path (launcher writes to `Path.home()/.`) → `HOME` is read-only. Fix: point `HOME` to a writable dir (e.g. `/tmp`) or change the written path. - `FileNotFoundError: uvx` → prepend the uvx directory (normally `/home/openclaw/.openclaw/bin`) to `PATH`. 4. Verify end-to-end with a minimal stdio client before declaring success: spawn the fixed command, `initialize`, `list_tools`, then call the target tool and confirm real data returns. Use `uv run --with mcp --python 3.12 python ` where the client uses `mcp.client.stdio.stdio_client` + `ClientSession`, passing `env` with the corrected `HOME`/`PATH`. 5. Route config changes through the `openclaw` tool (human approval required); never edit gateway config files directly. Report the exact old → new command. ## Tool calls fail with argument validation errors - An MCP tool returning a pydantic `Unexpected keyword argument` error means the argument names are wrong for that server, not that the server is down: read the real schema with `tool_describe` and retry with its exact parameters. - Home Assistant MCP: `ha_call_service` takes `{domain, service, entity_id, data}` (not `service_data`/`target`); `ha_search_entities` takes `{query}` only (no `domain`). A successful call reports `success: true` in `structuredContent`. - A type/filter variant that errors with `'NoneType' object has no attribute 'get'` (e.g. Spotify MCP `types=playlist`) → switch to a working type (`types=track` or `album`), act on that URI, and report the server bug instead of retrying the same call. ## Pitfalls - A session only exposes tools loaded at session start; a newly added server's tools appear as `__*` only after a gateway reload. - Test with the same `HOME`/`PATH` the gateway uses, otherwise you validate the wrong environment. - Never print secret values; check presence only (`[ -n "${VAR}" ]`).