Feature/harbor 1.0 mcp 2026 07 28 - #2
Merged
Merged
Conversation
Replace the monolithic @modelcontextprotocol/sdk with @modelcontextprotocol/server and @modelcontextprotocol/node so Harbor can use createMcpHandler and serveStdio.
Switch McpServer imports to the v2 package and read correlation/session ids from ServerContext instead of the legacy SDK extra bag.
Replace hand-wired v1 Streamable HTTP transport with SDK v2 createMcpHandler (legacy: reject) and toNodeHandler. Extract shared McpServerFactory for HTTP and stdio; bearer auth attaches pass-through authInfo before MCP dispatch.
Mock createMcpHandler and toNodeHandler in http-gateway tests, migrate tool test imports, and align correlation/session extractors with ServerContext.
Replace initialize/initialized handshake with server/discover, add per-request _meta envelope and Mcp-Method/Mcp-Name/MCP-Protocol-Version headers on every POST.
MCP SDK v2 registers tool schemas via Standard Schema, which requires Zod 4.
The v2 registerTool API expects z.object(...) rather than a raw Zod shape record.
Add makeServerCtx helper and inspect ZodObject.shape when asserting tool schemas.
Update tool-layer and getting-started curl examples for the 2026 envelope and required headers; bump package version to 1.0.0.
Attach mandatory io.modelcontextprotocol/serverInfo to every tool response _meta (spec §10) via mcpSuccess/mcpError chokepoints, and add an optional application-level _meta channel (spec §11) kept strictly out of model-visible content. Reserved serverInfo key cannot be spoofed by app metadata. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Info Add readRequestMeta (spec §9): surfaces the negotiated protocolVersion, clientInfo and clientCapabilities that the SDK lifts onto ctx.mcpReq.envelope (params _meta fallback). Strictly advisory for logging/telemetry — never used for authorization. Defensive against missing/malformed values. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Configure the per-request McpServer with explicit ServerOptions (spec
§15/§16): capabilities advertise only { tools: {} } (Harbor exposes no
prompts/resources/logging), real 5-tool workflow instructions surfaced
via server/discover, and conservative private/ttlMs:0 cache hints for
the two cacheable operations Harbor serves (tools/list, server/discover).
No aggressive TTL invented. Server version now sourced from
GATEWAY_VERSION.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read MCP-Protocol-Version/Mcp-Method/Mcp-Name (spec §13/§14) into an advisory McpRequestIdentity for routing/observability, wired into the gateway dispatch log. The SDK owns header validation and JSON-RPC reconciliation, so Harbor does not duplicate it; identity is never used for authentication (auth stays keyed to the bearer token, §19). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MCP 2026-07-28 authorization hardening (RFC 8707 resource indicators): the resource server MUST reject access tokens not bound to it. The OAuth 2.1 discovery strategy previously left `audience` optional, so a token minted for another resource behind the same authorization server would be accepted (confused-deputy / token pass-through). Make `audience` (the gateway's canonical resource identifier) required on the OAuth 2.1 path and fail closed at construction and wiring when absent. JWT / introspection / static-token providers are unchanged — the pluggable auth architecture and existing providers are preserved (§18).
Harbor speaks exactly one MCP protocol version (2026-07-28) and rejects legacy clients at the transport (`legacy: 'reject'`). Surface that version explicitly on the health endpoint so operators and monitoring can assert which protocol the gateway serves, instead of it being implicit in the transport config. Wires up the previously-unused MCP_PROTOCOL_VERSION constant.
Add docs/mcp-2026-07-28-compatibility.md (Requirements.md §28 matrix + §39 A-H final output) built from actual Harbor code, and note the required audience/resource binding on the oauth-2.1 path in the OAuth guide (spec §17, RFC 8707). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…xecute Adds live CI coverage for the MCP 2026-07-28 §17 / RFC 8707 token resource-binding change on the oauth-2.1 path. Per-service JWT audience validation only fires inside api_execute (not server/discover or tools/list), so the confused-deputy case must be exercised there. - examples/demo/billing-service.js: minimal :3004 backend for the billing service so a validated token reaches a real 200 and a rejected token never does. - mock-oauth2-config.json: mints a same-AS, same-signature, wrong-audience JWT for scope=confused-deputy while preserving the default correct-aud client_credentials mapping. - demo_e2e.py: wrong-aud JWT helper, billing backend lifecycle in phase-2, and resource-binding assertions — correct-aud api_execute(billing) returns live invoices; wrong-aud is rejected (isError, TOKEN_INVALID, no data leak). Runs in CI via the existing demo_e2e.py --docker-oauth step. E2E: 105/105.
- actions/checkout@v4.2.2 -> v5, actions/setup-node@v4.4.0 -> v5 (run on Node 24 natively; drop the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 workaround) to resolve the Node 20 deprecation warning. - npm audit fix: bump transitive deps (axios, js-yaml, nanoid, postcss, brace-expansion, fast-uri) to clear all 6 high-severity advisories so the 'npm audit --audit-level=high' CI gate passes. Only 1 low (esbuild dev server, Windows-only) remains, below the gate threshold. typecheck/lint clean; 345 unit+integration tests pass.
Add [Unreleased] entries for the RFC 8707 required-audience change (breaking for oauth-2.1 configs without an audience), its live E2E coverage, and the high-severity npm audit cleanup.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Type of change
Test plan
Checklist
npm run typecheckpassesnpm testpasses (all existing tests green).tsfileruntime/does not importadapters/directly)Related issues
Closes #