Blame
|
1 | --- |
||||||
| 2 | category: reference |
|||||||
| 3 | tags: [tasks, mcp, bug, multi-tenant] |
|||||||
| 4 | last_updated: 2026-03-15 |
|||||||
| 5 | confidence: high |
|||||||
| 6 | --- |
|||||||
| 7 | ||||||||
| 8 | # MCP Wiki Routing Bug |
|||||||
| 9 | ||||||||
| 10 | ## Problem |
|||||||
| 11 | ||||||||
| 12 | The MCP sidecar calls the otterwiki REST API at `http://localhost:8000` without a Host header. The TenantResolver on port 8000 treats requests without a wiki subdomain as the default wiki (`_default`). All MCP reads and writes go to the wrong wiki. |
|||||||
| 13 | ||||||||
| 14 | This means: |
|||||||
| 15 | - Pages written via MCP go to `/srv/wikis/_default/`, not the intended wiki |
|||||||
| 16 | - Pages read via MCP return content from `_default`, not the wiki the user connected to |
|||||||
| 17 | - Semantic search queries search the wrong index |
|||||||
| 18 | - The three `Tasks/` pages created today via MCP are in the `_default` wiki, not the dev wiki |
|||||||
| 19 | ||||||||
| 20 | ## Root cause |
|||||||
| 21 | ||||||||
| 22 | The MCP server (otterwiki-mcp) creates a `WikiClient` with `OTTERWIKI_API_URL=http://localhost:8000`. When it makes HTTP requests to the REST API, it doesn't set a Host header. The TenantResolver sees `localhost` and falls through to the default wiki. |
|||||||
| 23 | ||||||||
| 24 | On 3gw (single-tenant), this works because there's only one wiki. On robot.wtf (multi-tenant), the MCP sidecar needs to forward the wiki context. |
|||||||
| 25 | ||||||||
| 26 | ## Fix |
|||||||
| 27 | ||||||||
| 28 | The MCP sidecar receives requests on wiki subdomains (e.g., `dev.robot.wtf/mcp`). It needs to: |
|||||||
| 29 | ||||||||
| 30 | 1. Extract the wiki slug from the incoming request's Host header |
|||||||
| 31 | 2. Pass `Host: {slug}.robot.wtf` on its API calls to `http://localhost:8000` |
|||||||
| 32 | 3. This way TenantResolver resolves the correct wiki for each API call |
|||||||
| 33 | ||||||||
| 34 | The `WikiClient` in `otterwiki_mcp/api_client.py` needs to accept a `host_header` parameter and include it in all requests. The MCP tool handlers need to know the current wiki slug (from the incoming request context) and pass it to the client. |
|||||||
| 35 | ||||||||
| 36 | ## Complication |
|||||||
| 37 | ||||||||
| 38 | FastMCP's tool handlers are async functions registered with `@mcp.tool()`. They don't have direct access to the HTTP request context (Host header). The wiki slug needs to be threaded through somehow — either via a context variable, or by creating a per-request WikiClient. |
|||||||
| 39 | ||||||||
| 40 | The V5 consent flow already extracts the wiki slug in the `/authorize/callback` handler. A similar pattern can be used for tool calls. |
|||||||