gateway
connect({ prior: { kind: 'modern', discover } }) — zero-round-trip connect for gateways and distributed clients (protocol revision 2026-07-28).
pnpm --filter @mcp-examples/gateway server -- --http --port 3000
pnpm --filter @mcp-examples/gateway client -- --http http://127.0.0.1:3000/
The 2026 protocol is stateless on HTTP: every request carries the per-request _meta envelope (protocol version, client info, client capabilities), so once you know the server's DiscoverResult there is nothing left to negotiate. A gateway, proxy, or worker fleet that
fronts the same server should not re-probe per worker — it probes once and every subsequent connect is free.
The pattern
// 1. Bootstrap: probe once.
const bootstrap = new Client({ name: 'bootstrap', version: '1.0.0' }, { versionNegotiation: { mode: 'auto' } });
await bootstrap.connect(new StreamableHTTPClientTransport(url));
const persisted = JSON.stringify(bootstrap.getDiscoverResult()); // → write to Redis / config / process-local cache
await bootstrap.close();
// 2. Every worker: zero-round-trip connect from the persisted blob.
const worker = new Client({ name: 'worker', version: '1.0.0' });
await worker.connect(new StreamableHTTPClientTransport(url), { prior: { kind: 'modern', discover: JSON.parse(persisted) } });
await worker.callTool({ name: 'echo', arguments: { text: 'hi' } }); // first wire traffic
getDiscoverResult() is populated by the 'auto'/pinned probe path, by client.discover(), and by a modern-verdict connect({ prior }) (a legacy verdict leaves it undefined). The value round-trips through JSON.stringify/JSON.parse.
What this story asserts
The server exposes a request_count tool returning how many MCP requests reached the process (createMcpHandler builds one server instance per request). The client asserts:
- after the bootstrap probe + one
request_countcall, the count is 2; - after three worker
connect({ prior })calls + onerequest_countcall, the count is 3 — proving the three connects sent zero requests; - each worker can
callToolimmediately; - after three
echocalls + onerequest_countcall, the count is 7.
When to use prior
- A gateway/proxy that holds a long-lived connection pool to one server and constructs a fresh
Clientper downstream request. - A horizontally-scaled host where one worker's probe should seed the fleet (persist the blob to a shared cache).
- Reconnecting after a transient transport drop without re-probing.
Security: same-credential reuse only
Only reuse a persisted DiscoverResult across workers that present the same authorization context as the bootstrap client (key the blob on a credential hash). Adopting a wider prior does not grant access — the server authorizes every request — but it can mislead
client-side capability gating.
The modern verdict — prior: { kind: 'modern', discover } wrapping a persisted DiscoverResult — is modern-only: no mutual 2026-07-28+ revision → SdkError(EraNegotiationFailed). For a server known to be legacy, pass the negative verdict instead — prior: { kind: 'legacy' } skips the probe and goes straight to initialize. Freshness is the host's responsibility: date cached legacy verdicts in your own storage and stop supplying them past your policy horizon (a stale one succeeds silently against an upgraded server; with no prior, a mode: 'auto' client re-probes).
Source: examples/gateway/README.md