Skip to content

Feature/harbor 1.0 mcp 2026 07 28 - #2

Merged
vijaydeepsinha merged 26 commits into
mainfrom
feature/harbor-1.0-mcp-2026-07-28
Sep 13, 2026
Merged

vijaydeepsinha merged 26 commits into
mainfrom
feature/harbor-1.0-mcp-2026-07-28

Conversation

@vijaydeepsinha

Copy link
Copy Markdown
Owner

Summary

Type of change

  • Bug fix
  • New feature
  • Refactor / internal change
  • Documentation
  • Other:

Test plan

Checklist

  • npm run typecheck passes
  • npm test passes (all existing tests green)
  • New tests added for new behavior
  • Apache-2.0 SPDX header on every new .ts file
  • No internal company names, hostnames, or credentials introduced
  • CHANGELOG.md updated if this is a user-visible change
  • Layer discipline respected (runtime/ does not import adapters/ directly)

Related issues

Closes #

Vijaydeep Sinha and others added 26 commits July 17, 2026 13:37
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.
@vijaydeepsinha
vijaydeepsinha merged commit 5263754 into main Sep 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant