Hosted MCP: deterministic keyless and account endpoints - #308
Conversation
0cf0442 to
3f2ac9f
Compare
Add the hosted Streamable HTTP MCP runtime with OAuth token introspection, API-key fallback, anonymous keyless sessions, and safe request identity handling. Constrain keyless sessions to the scrape/search/parse boundary, derive account-tool recovery and requires_auth metadata from the registered tool complement, keep account-only tools behind authenticated sessions, and emit safe action metadata without logging request payloads or secrets. Preserve anonymous /v2/mcp behavior while allowing invalid presented credentials to fail with a clear invalid-token challenge.
Document the hosted MCP endpoints and configure the service image for the hosted HTTP transport. Add nginx routing for keyless /v2/mcp, account /v2/mcp-oauth, well-known OAuth metadata, deprecated API-key MCP compatibility, legacy /mcp compatibility, readiness, and health paths. Document account connector setup on /v2/mcp-oauth, keyless/local usage on /v2/mcp, and headless API-key headers.
Add contract and smoke coverage for anonymous keyless /v2/mcp, exact keyless tool listing, registered account-tool recovery metadata, stale hidden tool calls, OAuth audience enforcement, account-door /v2/mcp-oauth behavior, and structured recovery payloads. Record local client evidence proving keyless /v2/mcp initialization does not trigger automatic browser OAuth. Cover nginx route ordering, service image config, and CI workflow expectations so deployability remains testable through the service image.
Upgrade CI and image publishing gates to Node 22 with frozen pnpm installs, lint, typecheck, manifest validation, full tests, hosted auth replay coverage, and Docker service-image smoke tests. Keep image publishing tied to same-SHA verification before mutable tags are pushed, and make Docker smoke reusable locally through scripts/docker-smoke.sh and npm run test:docker-smoke. Update package and MCP registry metadata for the hosted MCP release.
3f2ac9f to
968497a
Compare
|
Stage 1 local E2E follow-up at
Verification:
No PR was merged or deployed. The draft remains for human review; staging E2E is still required before release. |
|
Independent-review follow-up is closed at
Final evidence on this head:
All Stage 1 PRs remain open drafts. Nothing was merged or deployed. Human review and staging E2E remain mandatory. |
erikengervall
left a comment
There was a problem hiding this comment.
Overall looks good. Approving with two non-blocking findings:
-
Search profile skips the tool wrapper (
src/index.ts:3208-3224)The primary FastMCP instance wraps
server.addToolso invalid credentials receive an emptytools/listand structured recovery ontools/call. The search sidecar uses a freshsearchServerwithout that wrapper. BecauseauthenticateRequestcan succeed withcredentialError,/v2/mcp-searchmay expose its full tool catalog to revoked or malformed keys. -
Nginx rewrites ignore the configured OAuth endpoint (
docker/nginx.conf:121-134)The legacy
/mcpand/{apiKey}/v2/mcproutes always rewrite to/v2/mcp. Account deployments configureFASTMCP_ENDPOINT=/v2/mcp-oauthand only bind there, so legacy URLs reaching an account pod can return 404 instead of reaching the OAuth or API-key handler.
|
Addressed the review at
Verification: lint passed, build passed, and the full MCP suite passed 31/31. Nothing was merged or deployed. |
|
Security follow-up coordinated with Core #3973: delegated Fresh validation: build and all 31 MCP tests pass. Production must provision the same 32+ character delegation secret to Core and both hosted MCP processes before rollout. |
Summary
Splits the hosted MCP onboarding surface into deterministic keyless-first and account-connected identities without breaking existing clients.
Endpoint behavior
/v2/mcptools/listsucceed without opening OAuth;/v2/mcp-oauth/v2/mcpOAuth audiences are accepted only through the explicit legacy bridge;/v2/mcp-oauthtokens cannot replay against/v2/mcp.The existing search-profile process remains owned by the keyless/full process; the OAuth process does not start a second search listener.
Runtime and safety changes
/mcpaliases remain intentionally bound to/v2/mcp; ingress routes only/v2/mcp-oauthto the account deployment, so a misroute fails closed rather than changing OAuth identity;Dependencies and rollout
DB #216, Core #3973, and Web #2767 deploy before this runtime is publicly routed. Infra #303 provides the separate process, routing, image, canary, and rollback boundary.
Verification
Real deployed-client checks remain a release gate. Nothing in this PR merges or deploys automatically.