fix(mcp): don't strip /mcp prefix; FastMCP's handler is mounted there
The dispatch wrapper was rewriting scope['path'] from '/mcp' to '/' before handing off to FastMCP. But FastMCP's streamable_http_app mounts the JSON-RPC handler at '/mcp' (its default), so the rewritten '/' had no matching route and FastMCP returned 404. Auth middleware was correctly firing first (a no-auth request still gets 401), the bug was only on the post-auth path. Symptom: `claude mcp add ...` succeeds, registration shows in `claude mcp list`, but connection fails because the initialize handshake returns 404 instead of an MCP capabilities response. Fix: pass the scope through unmodified. FastMCP's own routing matches the '/mcp' path. Also tightened the integration test that should have caught this — it was asserting `status != 401`, which a 404 trivially passes. Now asserts `== 200`, the actual expected response for initialize. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,10 +78,12 @@ def mount_mcp(app: Quart) -> None:
|
||||
if scope["type"] == "http":
|
||||
path = scope.get("path", "")
|
||||
if path == "/mcp" or path.startswith("/mcp/"):
|
||||
sub_scope = dict(scope)
|
||||
sub_scope["path"] = path[len("/mcp"):] or "/"
|
||||
sub_scope["root_path"] = scope.get("root_path", "") + "/mcp"
|
||||
return await auth_wrapped(sub_scope, receive, send)
|
||||
# Don't rewrite the path: FastMCP's streamable_http_app mounts
|
||||
# its handler at /mcp by default. If we strip the prefix to "/",
|
||||
# FastMCP's internal routing returns 404 because there's no
|
||||
# handler at "/" — only at "/mcp". Pass the scope through
|
||||
# untouched and let FastMCP's own routing match.
|
||||
return await auth_wrapped(scope, receive, send)
|
||||
return await original_asgi(scope, receive, send)
|
||||
|
||||
app.asgi_app = dispatch
|
||||
|
||||
Reference in New Issue
Block a user