Skip to main content

Type Alias: MCPProtocolOptions

MCPProtocolOptions = ProtocolOptions & object

Defined in: node_modules/.bun/@modelcontextprotocol+client@2.2.0/node_modules/@modelcontextprotocol/client/dist/index.d.mts:1891

Type Declaration​

cachePartition?​

optional cachePartition?: string

Opaque per-principal identifier for response-cache writes whose server-reported cacheScope is 'private' (the spec's "MUST NOT share across authorization contexts"). Within the connected server's namespace, 'public'-scoped entries live at the shared [serverIdentity, ''] partition and 'private'-scoped entries at [serverIdentity, cachePartition]. Set this to a stable identity of the authorization context (e.g. the auth subject) when one responseCacheStore backs several principals; with the default '' every entry — public or private — lives at the server's shared partition, which is the safe single-tenant posture.

capabilities?​

optional capabilities?: ClientCapabilities

Capabilities to advertise as being supported by this client.

defaultCacheTtlMs?​

optional defaultCacheTtlMs?: number

TTL (ms) applied when a cacheable result arrives without a ttlMs field. Default 0 — a result without an explicit hint is never served from cache (every call refetches), but it is still stored so the tools/list-derived index that Client.callTool | callTool's SEP-2243 mirroring and output-schema validation read keeps working regardless. The spec defines absent-or-≤0 as "immediately stale".

inputRequired?​

optional inputRequired?: InputRequiredOptions

Multi-round-trip auto-fulfilment (protocol revision 2026-07-28).

On the 2026-07-28 era, servers obtain client input (elicitation, sampling, roots) by answering tools/call, prompts/get, or resources/read with an input_required result instead of sending a server→client request. By default the client fulfils those embedded requests automatically through the SAME handlers registered via Client.setRequestHandler | setRequestHandler (e.g. elicitation/create), then retries the original call with the collected inputResponses and a byte-exact echo of the opaque requestState, on a fresh request id, up to maxRounds rounds. client.callTool() (and its siblings) keep returning their plain result type — the interactive rounds happen inside the call.

Set autoFulfill: false for manual mode: an input_required response then surfaces as a typed error unless the individual call passes allowInputRequired: true (pair it with withInputRequired() on the explicit-schema path to type both outcomes).

Has no effect on 2025-era connections, which have no input_required vocabulary.

jsonSchemaValidator?​

optional jsonSchemaValidator?: jsonSchemaValidator

JSON Schema validator for tool output validation.

The validator is used to validate structured content returned by tools against their declared output schemas.

Default​

Runtime-selected validator (AJV-backed on Node.js, @cfworker/json-schema-backed on browser/workerd runtimes)

listChanged?​

optional listChanged?: ListChangedHandlers

Configure handlers for list changed notifications (tools, prompts, resources).

Example​

const client = new Client(
{ name: 'my-client', version: '1.0.0' },
{
listChanged: {
tools: {
onChanged: (error, tools) => {
if (error) {
console.error('Failed to refresh tools:', error);
return;
}
console.log('Tools updated:', tools);
}
},
prompts: {
onChanged: (error, prompts) => console.log('Prompts updated:', prompts)
}
}
}
);

listMaxPages?​

optional listMaxPages?: number

Cap on the number of pages the auto-aggregating Client.listTools | listTools() / Client.listPrompts | listPrompts() / Client.listResources | listResources() / Client.listResourceTemplates | listResourceTemplates() walk fetches before throwing (a defence against a server whose nextCursor never converges). 0 disables the cap. Default: 64. Applies only to the no-argument auto-aggregate path; an explicit-cursor per-page call is never capped.

responseCacheStore?​

optional responseCacheStore?: ResponseCacheStore

The response-cache store backing the client's derived views (the cached tools/list result that Client.callTool | callTool's output validation and SEP-2243 header mirroring read) and the SEP-2549 cache-hint serving on the cacheable verbs. Defaults to a fresh InMemoryResponseCacheStore per client.

Entries are automatically scoped by connected-server identity (derived from serverInfo after connect) AND, for 'private'-scoped results, by cachePartition — encoded collision-free via JSON.stringify, so a server cannot craft a serverInfo that bleeds into another server's namespace or another principal's slot. One store may therefore back several clients (e.g. a host pool against the same server, or one persistent KV across servers); list_changed evictions are scoped to the connected server's partitions, so co-tenants are unaffected. Set cachePartition to your principal identifier (e.g. the auth subject) when sharing across principals. Note serverInfo is self-reported — a server that deliberately impersonates another's name/version shares its 'public' slot; the per-principal isolation via cachePartition holds regardless.

versionNegotiation?​

optional versionNegotiation?: VersionNegotiationOptions

Opt-in protocol version negotiation (protocol revision 2026-07-28 and later).

The default is 'legacy': absent (or mode: 'legacy'), connect() runs the plain 2025 sequence, byte-identical to today's behavior (no probe, no new headers). Opt into 'auto' or pin to talk to a 2026-07-28 server.

  • mode: 'auto' — connect() probes the server with server/discover first: definitive modern evidence selects the modern era; definitive legacy signals (and anything unrecognized) fall back to the plain legacy initialize handshake, byte-equivalent to a 2025 client. On the SDK's own stdio transport (the base StdioClientTransport exactly; subclasses probe in place) the probe runs on a short-lived sibling process spawned from the same parameters (one extra spawn per connect; its stderr is discarded) and the caller's transport starts once, after the era is known; HTTP — and custom or subclassed stdio-shaped transports — probe on the connection itself. A network outage rejects with a typed connect error. A probe timeout is transport-aware: on stdio it indicates a legacy server (some legacy servers never answer unknown pre-initialize requests) and falls back to initialize; on HTTP it rejects with a typed timeout error (silence on a deployed server is an outage, not a legacy signal).
  • mode: { pin: '2026-07-28' } — modern era at exactly the pinned revision; no probe-and-fallback: anything else fails loudly.

Probe policy lives under probe: { timeoutMs?, maxRetries? }; the probe inherits the client's standard request timeout unless overridden, and maxRetries (default 0) governs timeout re-sends only — the spec-mandated -32022 corrective continuation is never counted against it.

Once a modern era is negotiated, the client automatically attaches the per-request _meta envelope (the reserved protocol-version / client-info / client-capabilities keys) to every outgoing request and notification; user-supplied _meta keys take precedence over the auto-attached ones.