Blame

d105f8 robot.wtf 2026-03-15 22:37:48
Move misplaced pages from default wiki
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.