import { Client, Transport, ServerCapabilities, Implementation, ProtocolEra, CacheableRequestOptions, ListToolsResult as ListToolsResult$1, CallToolRequestOptions, CallToolResult, Request, RequestOptions, StandardSchemaV1, ListResourcesResult, ReadResourceResult, ListResourceTemplatesResult, ListPromptsResult, GetPromptResult, CompleteRequest, CompleteResult, EmptyResult, SubscriptionFilter, McpSubscription, LoggingLevel, OAuthClientProvider, OAuthClientMetadata, OAuthTokens, ClientOptions, StreamableHTTPClientTransportOptions, SSEClientTransportOptions, ListTasksResult, Task, CacheScope, CacheMode, Tool as Tool$1, ElicitRequest, ElicitResult } from '@modelcontextprotocol/client'; import { M as McpProtocolVersion } from './types-HXAijHji.js'; import { StdioServerParameters } from '@modelcontextprotocol/client/stdio'; import { ToolSet } from 'ai'; /** * `ManagedMcpClient` is the surface area `MCPClientManager` calls into for * every server connection. It exists so the manager can swap between the * legacy upstream `Client` (via `OfficialSdkClientAdapter`) and the * stateless 2026-07-28 preview transport * (`StatelessMcpHttpPreviewClient`) without per-call branching. Selection * is driven by the per-server `mcpProtocolVersion` pin (`McpProtocolVersion` * in `./mcp-protocol-version.ts`) — the factory uses * `isStatelessProtocolVersion` to route. * * **Coverage rationale.** The shape below was derived by grepping * `MCPClientManager.ts` for every `client.*` call site, plus * `elicitation.ts`'s `removeRequestHandler(ElicitRequestMethod)` cleanup * and the manager's `subscribeResource` / `unsubscribeResource` * passthrough. Omitting any method would crash the manager — there is no * `client?.foo()` fallback for unknown surface. * * **Disposable-by-design.** When upstream `@modelcontextprotocol/client` * adds stateless support, replacement is a one-line factory swap to a * new `OfficialSdkClientAdapter` configured for the new wire literal. * No manager-side churn, no product / UI / config unwind. */ /** * Connect-time options accepted by both adapters. Mirror of the upstream * `ClientOptions.connect` second argument; we don't tighten it to keep * the legacy adapter a pure pass-through. */ interface ManagedMcpClientConnectOptions { timeout?: number; resumptionToken?: string; onresumptiontoken?: (token: string) => void; } /** * Notification / request handlers the manager registers. Both are * method-string keyed (`"elicitation/create"`, `"notifications/progress"`, * …); the underlying client dispatches on incoming `jsonrpc.method`. * * These are declared explicitly rather than derived from * `Parameters` because beta.4 made those * methods **overloaded** (a typed method-literal form and a Standard-Schema * form). `Parameters<>` of an overload resolves to the *last* signature — the * schema-object form — which is not how the manager registers handlers. The * manager keys by method string and reads `.params` off a loose payload; the * `OfficialSdkClientAdapter` casts to upstream's typed form at the boundary. */ type ManagedMcpClientNotificationMethod = string; interface ManagedMcpClientNotification { method: string; params?: Record; } type ManagedMcpClientNotificationHandler = (notification: ManagedMcpClientNotification) => void; type ManagedMcpClientRequestMethod = string; interface ManagedMcpClientIncomingRequest { method: string; params?: Record; } type ManagedMcpClientRequestHandler = (request: ManagedMcpClientIncomingRequest) => unknown | Promise; /** * The single surface the manager talks to. Every method here corresponds * to a verified call site in the SDK: * * - `connect` / `close` / `onerror` / `onclose` — lifecycle, around * `MCPClientManager.ts:1170-1192, 1267, 1362`. * - `getServerCapabilities` / `getServerVersion` / `getInstructions` — * manager state mirror at `:276, :317-319`. * - `listTools` / `callTool` / `request` / `listResources` / * `readResource` / `listResourceTemplates` / `listPrompts` / * `getPrompt` / `ping` — RPC fan-out methods. * - `subscribeResource` / `unsubscribeResource` — manager passthrough * at `:700, :716`. * - `setLoggingLevel` — manager auto-call at `:1225`. * - `setNotificationHandler` / `setRequestHandler` — notification * wiring + `applyToClient` paths. * - `removeRequestHandler` — `elicitation.ts:168` close cleanup. * * Stateless preview behaviors (`StatelessMcpHttpPreviewClient`) are * documented per-method in that file. The interface itself stays * behavior-agnostic so it never has to know which adapter is wired. */ interface ManagedMcpClient { /** * The client this one delegates to: the upstream `Client` for * `OfficialSdkClientAdapter`, the wrapped `ManagedMcpClient` for a decorator * such as `LogLevelMetaClient`. OPTIONAL — a hand-rolled implementation or a * test double may bottom out with no delegate at all. * * Declared so the delegation chain is a stated seam rather than a private * detail each consumer re-guesses. `tasks-ext-era-gate.ts` walks it to find * the upstream instance whose outbound era gate must be shadowed, so that a * directly-constructed adapter behaves like one built by * `managed-mcp-client-factory.ts`. Consumers MUST treat an absent `inner` as * "the chain ends here" and degrade, never throw. */ readonly inner?: ManagedMcpClient | Client; connect(transport: Transport, options?: ManagedMcpClientConnectOptions): Promise; close(): Promise; onerror?: (error: Error) => void; onclose?: () => void; getServerCapabilities(): ServerCapabilities | undefined; getServerVersion(): Implementation | undefined; getInstructions(): string | undefined; /** * The negotiated protocol era (`"legacy"` | `"modern"`), or `undefined` * before `initialize` completes. OPTIONAL because not every adapter can * report it — only the `OfficialSdkClientAdapter` passes it through from * upstream `Client.getProtocolEra()`. Consumers (the `LogLevelMetaClient` * decorator, the `getLoggingMechanism` helper) MUST treat an absent method * or `undefined` as "era unknown — do not apply modern-only behavior". */ getProtocolEra?(): ProtocolEra | undefined; /** * The negotiated protocol version wire literal (e.g. `"2025-11-25"`), or * `undefined` before `initialize` completes. OPTIONAL for the same reason * as `getProtocolEra()`: only adapters over an upstream `Client` can report * it (upstream `Client.getNegotiatedProtocolVersion()`, client * `index.d.mts:2047`). Consumers MUST treat an absent method or * `undefined` as "version unknown" and fail closed rather than assuming a * version — never read the private `transport._protocolVersion`. */ getNegotiatedProtocolVersion?(): string | undefined; listTools(params?: { cursor?: string; }, options?: CacheableRequestOptions): Promise; callTool(params: { name: string; arguments?: Record; }, options?: CallToolRequestOptions): Promise; request(req: Request, options?: RequestOptions): Promise; /** * Explicit-schema request — the type-correct path for the modern * multi-round-trip (`input_required`) loop. Forwards to upstream * `Protocol.request`'s second overload * (`request(request, resultSchema, options)`, client `index.d.mts:2198`), * which validates a *complete* result against `resultSchema` while surfacing * a non-complete `input_required` result untouched (paired with * `withInputRequired(resultSchema)` + `options.allowInputRequired`). * * NEW seam (2026-07-28). It exists alongside — never replacing — the generic * `request` above, whose method-dispatch typing cannot express an * `input_required` union (the SDK deliberately does not widen `ResultTypeMap` * for requesters). Decorators MUST forward it: `LogLevelMetaClient` injects * the modern per-request logging `_meta` here exactly as it does for the * other request-bearing methods. */ requestWithSchema(req: Request, resultSchema: TSchema, options?: RequestOptions): Promise>; listResources(params?: { cursor?: string; }, options?: CacheableRequestOptions): Promise; readResource(params: { uri: string; }, options?: CacheableRequestOptions): Promise; listResourceTemplates(params?: { cursor?: string; }, options?: CacheableRequestOptions): Promise; listPrompts(params?: { cursor?: string; }, options?: CacheableRequestOptions): Promise; getPrompt(params: { name: string; arguments?: Record; }, options?: RequestOptions): Promise; complete(params: CompleteRequest["params"], options?: RequestOptions): Promise; ping(options?: RequestOptions): Promise; /** * `server/discover` (2026-07-28+): the modern era's only universally * available request, and therefore its liveness probe — `ping` was removed * from the 2026 vocabulary, so the upstream client refuses to send it on a * modern-classified connection (`MethodNotSupportedByProtocolVersion`). * Optional because non-upstream adapters (test doubles) may not carry it; * `MCPClientManager.pingServer` era-gates before reaching for it. */ discover?(options?: RequestOptions): Promise; subscribeResource(params: { uri: string; }, options?: RequestOptions): Promise; unsubscribeResource(params: { uri: string; }, options?: RequestOptions): Promise; /** * Opens a 2026-07-28 `subscriptions/listen` stream. OPTIONAL: only adapters * over an upstream `Client` can provide it, and it throws a typed * `SdkErrorCode.MethodNotSupportedByProtocolVersion` on a legacy connection. * Consumers MUST treat an absent method as "this connection has no modern * subscription stream" and fall back to the legacy per-URI RPCs — see * `SubscriptionCoordinator` in `./subscription-coordinator.ts`. */ listen?(filter: SubscriptionFilter, options?: RequestOptions): Promise; setLoggingLevel(level: LoggingLevel, options?: RequestOptions): Promise; setNotificationHandler(method: ManagedMcpClientNotificationMethod, handler: ManagedMcpClientNotificationHandler): void; setRequestHandler(method: ManagedMcpClientRequestMethod, handler: ManagedMcpClientRequestHandler): void; removeRequestHandler(method: ManagedMcpClientRequestMethod): void; } interface RetryPolicy { retries: number; retryDelayMs: number; } declare const DEFAULT_RETRY_POLICY: RetryPolicy; interface RetryExecutionOptions { policy?: RetryPolicy; signal?: AbortSignal; operation: (attempt: number) => Promise; shouldRetryError?: (error: unknown, attempt: number) => boolean; shouldRetryResult?: (result: T, attempt: number) => boolean; onRetry?: (input: { attempt: number; error?: unknown; result?: T; }) => Promise | void; } declare function normalizeRetryPolicy(policy?: RetryPolicy): RetryPolicy; declare function isRetryableTransientError(error: unknown): boolean; declare function retryWithPolicy({ policy, signal, operation, shouldRetryError, shouldRetryResult, onRetry, }: RetryExecutionOptions): Promise; declare class RefreshTokenOAuthProvider implements OAuthClientProvider { private readonly _clientId; private readonly _clientSecret?; private currentRefreshToken; private currentTokens?; constructor(_clientId: string, refreshToken: string, _clientSecret?: string | undefined); get redirectUrl(): undefined; get clientMetadata(): OAuthClientMetadata; clientInformation(): { client_id: string; client_secret: string; } | { client_id: string; client_secret?: undefined; }; tokens(): { access_token: string; token_type: string; id_token?: string | undefined; expires_in?: number | undefined; scope?: string | undefined; refresh_token?: string | undefined; } | undefined; saveTokens(tokens: OAuthTokens): void; prepareTokenRequest(): URLSearchParams; redirectToAuthorization(): void; saveCodeVerifier(): void; codeVerifier(): string; } /** * W3C trace-context values as they ride MCP `_meta`. * * The 2026-07-28 spec reserves three `_meta` keys — `traceparent`, * `tracestate`, and `baggage` — as an EXCEPTION to the `_meta` prefix rule * (they are deliberately NOT under `io.modelcontextprotocol/`, so that MCP * matches the OpenTelemetry semantic conventions and existing tracing * middleware). The spec's only normative statement about them is a format * one: "When present, their values MUST follow W3C Trace Context and W3C * Baggage formats respectively." Emitting them at all is a documented * convention, not a requirement — a client that has no trace to propagate * sends nothing, which is exactly what MCPJam does by default. * * This module is the format layer, shared by both directions: * * - **Outbound** (`TraceContextMetaClient`): a caller-supplied context is * validated here before it is allowed onto the wire. A malformed value is * dropped rather than forwarded — the spec's MUST is about the value, so * propagating garbage would be worse than propagating nothing. * * - **Inbound** (debugger surfaces): a trace context observed on a server's * result `_meta` is read back through {@link extractTraceContext} so the * UI can show the user which trace their call joined. * * **`baggage` is untrusted.** It is arbitrary server- or user-authored * key/value data. It is validated for shape and length here and rendered * verbatim in the UI, but it MUST NOT be forwarded to analytics * (PostHog/Axiom) or any other export path. */ /** * The three reserved key names, spelled locally rather than imported from * `@modelcontextprotocol/client`. This module is reachable from the * browser entry, which must stay free of that package's runtime graph (it * pulls Node builtins); the names are literal W3C header names, not * MCP-prefixed identifiers, so there is nothing to derive. Parity with the * upstream `TRACEPARENT_META_KEY` / `TRACESTATE_META_KEY` / * `BAGGAGE_META_KEY` constants is asserted in `trace-context.test.ts`. */ declare const TRACEPARENT_META_KEY = "traceparent"; declare const TRACESTATE_META_KEY = "tracestate"; declare const BAGGAGE_META_KEY = "baggage"; /** * A validated W3C trace context. `traceparent` is the only required member: * `tracestate` and `baggage` have no meaning without a parent to attach to, * and the spec gives no way to send them alone. */ interface TraceContext { /** W3C `traceparent`, e.g. `00-<32 hex>-<16 hex>-01`. */ traceparent: string; /** W3C `tracestate` vendor list, when the caller has one. */ tracestate?: string; /** W3C `baggage` list. UNTRUSTED — display only, never export. */ baggage?: string; } /** * Live accessor for the ambient trace context to propagate on outbound * requests. Returning `undefined` means "no trace" — no `_meta` keys are * injected. Read fresh on every call so a caller whose tracer changes spans * per operation gets the current one without reconnecting. * * MCPJam ships NO implementation of this: we do not run an OpenTelemetry * tracer, so the default is "no provider → no keys emitted". The seam exists * for SDK embedders that do. */ type TraceContextProvider = (serverId: string) => TraceContext | undefined; /** The `version-format` of a `traceparent`, decomposed. */ interface ParsedTraceparent { /** Two lowercase hex digits. `00` is the only version defined today. */ version: string; /** 32 lowercase hex digits, never all-zero. */ traceId: string; /** 16 lowercase hex digits, never all-zero. Also called the parent id. */ spanId: string; /** Two lowercase hex digits of trace-flags. */ flags: string; /** Bit 0 of `flags` — the caller sampled this trace. */ sampled: boolean; } /** * Parse a `traceparent`, or `undefined` if it is not a valid one. * * Rejects, per W3C Trace Context §3.2.2.x: a wrong shape, version `ff` * (reserved / forbidden), an all-zero trace id, and an all-zero parent id. * Versions above `00` are rejected rather than best-effort parsed: the * forward-compatible parse rule ("ignore trailing fields") is for RECEIVERS * that will mutate and re-emit the header, and we neither mutate nor need it * — no such version exists yet. */ declare function parseTraceparent(value: string | undefined): ParsedTraceparent | undefined; /** Whether `value` is a well-formed `traceparent`. */ declare function isValidTraceparent(value: string | undefined): boolean; /** * Whether `value` is a well-formed `tracestate` list. Empty members are * permitted between commas (§3.3.1 allows them for deletion), but a member * that is present must be a valid `key=value`. */ declare function isValidTracestate(value: string | undefined): boolean; /** * Whether `value` is a well-formed `baggage` list. * * Shape and size only — the CONTENT is untrusted by definition. Passing this * check says the string is safe to render and to put on the wire; it says * nothing about whether the values are safe to log or export (they are not). */ declare function isValidBaggage(value: string | undefined): boolean; /** * Narrow an arbitrary candidate to the subset of it that is safe to put on * the wire, or `undefined` when there is nothing to send. * * A malformed `traceparent` drops the WHOLE context: `tracestate` and * `baggage` describe a trace we would then not be identifying. A malformed * `tracestate` or `baggage` drops only itself — the parent is still useful, * and the alternative (dropping a valid parent because a vendor list was * mangled) loses the more important half. */ declare function sanitizeTraceContext(candidate: TraceContext | undefined): TraceContext | undefined; /** * Read a trace context back out of a `_meta` bag (a result's, a request's, a * notification's). Same validation as the outbound path, so a server that * sends a malformed `traceparent` surfaces as "no trace context" rather than * as a bogus trace id in the UI. */ declare function extractTraceContext(meta: Record | undefined | null): TraceContext | undefined; /** * The `_meta` fragment for a sanitized context: the three reserved keys, each * present only when it has a value. Absence is semantic — we never write a * key with an empty string. */ declare function traceContextToMeta(context: TraceContext): Record; /** * The Streamable HTTP "request metadata" headers — the body fields the * transport mirrors into HTTP so intermediaries can route without parsing the * body (SEP-2243, integrated into `2026-07-28`). * * Pure data + pure functions, no transport and no Node built-ins, so this * module is safe to re-export from the browser entry: the Tracing panel does * the same decode/cross-check a server does, on headers captured on the wire. * * Scope note: `MCP-Protocol-Version` exists from `2025-06-18` onward and the * session/resumption headers exist ONLY in `2025-03-26`..`2025-11-25`. This * module therefore classifies every era's headers, and gates only the * *modern-only* assertions (required `Mcp-Method`/`Mcp-Name`, header/body * agreement) on a modern protocol version. */ /** Sentinel wrapper for header values that cannot ride as plain ASCII. */ declare const MCP_HEADER_SENTINEL_PREFIX = "=?base64?"; declare const MCP_HEADER_SENTINEL_SUFFIX = "?="; /** Prefix for the per-argument mirrored headers driven by `x-mcp-header`. */ declare const MCP_PARAM_HEADER_PREFIX = "mcp-param-"; /** * Which mirrored family a header belongs to, or `undefined` for an ordinary * header (`content-type`, `authorization`, …). */ type McpHeaderFamily = "protocol-version" | "method" | "name" | "param" | "session" | "resumption"; /** * Classifies a header name. RFC 9110 field names are case-insensitive and the * spec requires case-insensitive comparison, so callers may pass any casing — * note the spec text itself writes `Mcp-Session-Id` in `2025-06-18` and * `MCP-Session-Id` in `2025-11-25`. */ declare function classifyMcpHeader(name: string): McpHeaderFamily | undefined; type DecodedMcpHeaderValue = { /** The value exactly as it appeared on the wire. */ raw: string; /** True when `raw` carried the `=?base64?…?=` sentinel. */ encoded: boolean; /** The comparison value: decoded when encoded, otherwise `raw`. */ value: string; /** Set when the sentinel was present but the payload would not decode. */ decodeError?: string; }; /** * Decodes the sentinel form. Applies to `Mcp-Name` as well as * `Mcp-Param-{Name}` — a non-ASCII tool name is carried encoded, so a UI that * decodes params but not names shows a conforming request as gibberish. * * The markers are case-sensitive and MUST appear exactly as lowercase, so a * value that merely resembles them is left alone. */ declare function decodeMcpHeaderValue(raw: string): DecodedMcpHeaderValue; /** * The values the request BODY carries for the mirrored headers. Captured at * request time so the cross-check can run later without ever storing the body. */ type MirroredBodyValues = { /** JSON-RPC `method`. */ method?: string; /** `params.name`, or `params.uri` for `resources/read`. */ name?: string; /** `_meta["io.modelcontextprotocol/protocolVersion"]`. */ protocolVersion?: string; }; /** * The `io.modelcontextprotocol/tasks` methods that MUST carry * `Mcp-Name: ` (SEP-2663, "Streamable HTTP: Routing Headers"). * * A second required-name set rather than an addition to the one above: the * source field differs (`params.taskId`, not `params.name`), and the * requirement comes from the extension, which is versioned independently of * core. `transport-utils` sends these headers; this module judges them, and * both read the set from here so the two halves cannot drift. */ declare const TASK_ROUTED_METHODS: Set; type McpHeaderIssue = { kind: "mismatch"; header: string; headerValue: string; bodyValue: string; } | { kind: "missing"; header: string; bodyValue: string; } | { kind: "undecodable"; header: string; headerValue: string; } /** A `Mcp-Param-*` the tool never declared. Only reported when the caller * supplied declarations to judge against. */ | { kind: "undeclared"; header: string; headerValue: string; }; /** * The outcome of the header/body cross-check for one header. * * `unchecked` is the honest answer for anything outside the modern standard * three: a legacy request mirrors nothing, and `Mcp-Param-*` values are not * captured, so no verdict can be claimed for them UNLESS the caller supplies * the call's arguments and the tool's declarations (see * {@link McpParamCrossCheck}). */ type McpHeaderStatus = "match" | "mismatch" | "missing" | "not-required" | "undecodable" | "unchecked" /** * A `Mcp-Param-*` header the tool's `inputSchema` never declared. Distinct * from `mismatch`: there is no body value to disagree with, and the defect * is the header's EXISTENCE. Only ever produced when the caller supplied * declarations — without them, an unrecognized param header is honestly * `unchecked`. */ | "undeclared"; type McpHeaderAssessment = { /** Wire casing when the header was sent; canonical lowercase when it wasn't. */ name: string; family: McpHeaderFamily; status: McpHeaderStatus; /** The value as it appeared on the wire. Absent when the header was not sent. */ raw?: string; /** Set only when `raw` carried a sentinel that decoded — never on `undecodable`. */ decoded?: string; /** The body field this header mirrors, when a cross-check ran. */ bodyField?: string; /** The body's value, on `mismatch` / `missing`. */ bodyValue?: string; }; /** * The extra facts that let `Mcp-Param-*` rows be JUDGED rather than merely * listed. * * Capture deliberately never stores request bodies (see `http-exchange-log.ts`), * so a mirrored argument's expected value cannot come from the exchange. It * comes from the caller instead — a debugger that has already correlated the * JSON-RPC frame holds `params.arguments`, and the tool's `inputSchema` yields * the declarations. Supply both and every declared param gets a real * match/mismatch/missing verdict; supply neither and the rows stay `unchecked`, * exactly as before. * * Partial input is honest input: `declarations` without `arguments` still * decides "was this header even declared", which is the check that catches a * stale schema. */ type McpParamCrossCheck = { /** * The `tools/call` request's `params.arguments`. * * PRESENCE of the key is the signal, not the value: a no-argument call * legitimately has `arguments: undefined`, so `{ declarations, arguments: * undefined }` means "the call passed nothing" while `{ declarations }` * alone means "we do not have the arguments". Only the first can decide * whether an omitted header was correct — the second leaves declared rows * `unchecked`, because calling a header wrong on evidence that lacks the * body it mirrors would be inventing a defect. */ arguments?: unknown; /** * The tool's VALIDATED `x-mcp-header` declarations — i.e. the * `declarations` of a `{ valid: true }` {@link scanXMcpHeaderDeclarations} * result. An invalid scan yields no verdicts on purpose: the spec's answer * to a bad declaration is that the tool definition is invalid, not that some * of its headers are wrong. */ declarations?: readonly XMcpHeaderDeclaration[]; }; /** * Per-header verdicts for the mirrored `Mcp-*` headers — the display form of * the same validation `findMcpHeaderIssues` reports as a defect list. * * A verdict list rather than a defect list is what a debugger needs: a header * shown without the body value it is supposed to equal cannot be judged, and an * ABSENT header is ambiguous until it says whether the spec required it here * (`Mcp-Name` is required only for `tools/call`, `resources/read`, * `prompts/get`). Both cases therefore get an explicit row. * * Era-gated exactly like `findMcpHeaderIssues`: before `2026-07-28` nothing is * mirrored, so every present header comes back `unchecked` rather than judged * against rules its version never had. * * `paramCheck` is what upgrades the `Mcp-Param-*` rows from listed to judged; * without it they stay `unchecked`, which is all a caller holding only the * captured headers can honestly say. See {@link McpParamCrossCheck}. */ declare function evaluateMcpHeaders(headers: Record, body: MirroredBodyValues | undefined, paramCheck?: McpParamCrossCheck): McpHeaderAssessment[]; /** * Runs the server-side validation a `-32020 HeaderMismatch` reports, locally, * against the captured headers. Covers all three failure conditions the spec * lists: a required standard header missing, a value disagreeing with the * body, and a value that will not decode. * * Returns an empty list for any non-modern request: `Mcp-Method`/`Mcp-Name` * are not required before `2026-07-28`, so asserting them on a `2025-11-25` * connection would invent failures. * * Pass `paramCheck` to have `Mcp-Param-*` judged too — including the * `undeclared` case, which has no analogue among the standard three. */ declare function findMcpHeaderIssues(headers: Record, body: MirroredBodyValues | undefined, paramCheck?: McpParamCrossCheck): McpHeaderIssue[]; /** One validated `x-mcp-header` declaration found on a tool's `inputSchema`. */ type XMcpHeaderDeclaration = { /** Property path from the schema root, through `properties` keys only. */ path: string[]; /** The declared header name, in the casing the schema used. */ headerName: string; /** The declared JSON Schema primitive type. */ type: string; }; type XMcpHeaderScan = { valid: true; declarations: XMcpHeaderDeclaration[]; } | { valid: false; reason: string; }; /** * Scan a tool's `inputSchema` for `x-mcp-header` declarations, validating * every constraint the spec places on them. Returns the collected * declarations (possibly empty) or the first violated constraint. * * The walk descends `properties` at any depth (the spec's "any nesting depth" * clause). The static-reachability MUST is enforced structurally: every * position the chain MUST NOT pass through is visited too, and a declaration * found anywhere on such a path invalidates the tool definition rather than * being silently ignored. */ declare function scanXMcpHeaderDeclarations(inputSchema: unknown): XMcpHeaderScan; /** * Return `inputSchema` with every `x-mcp-header` annotation removed, so a * schema handed to upstream `callTool` as `CallToolRequestOptions.toolDefinition` * yields NO `Mcp-Param-*` headers. * * This is how `mirrorToolParamHeaders: false` is honored on the plain * (non-MRTR) call path: upstream mirrors inside `callTool` with no disable * knob, but it reads the schema from `toolDefinition` "instead of (and without * consulting) the cached tools/list result" — so a stripped copy is the only * seam that silences it without lying about anything else. * * Structural, not semantic: it walks EVERY subschema position (the same set * `scanXMcpHeaderDeclarations` walks, reachable or not), because a declaration * parked under `oneOf` must not survive into the copy either. Nodes with * nothing to strip are returned by reference, so an ordinary tool costs one * walk and no allocation. Only the annotation key is dropped — types, * `required`, descriptions and every other keyword are preserved verbatim, so * argument validation sees the schema the server published. */ declare function stripXMcpHeaderAnnotations(inputSchema: unknown): unknown; /** * Encode a string as an HTTP field value: a safe plain-ASCII value passes * through unchanged, anything else is wrapped as `=?base64?{utf8-b64}?=`. * The exact inverse of {@link decodeMcpHeaderValue}. */ declare function encodeMcpHeaderValue(value: string): string; /** * Build the `Mcp-Param-{Name}` headers for one `tools/call` from a scan of the * tool's `inputSchema` and the call's `arguments`. * * A declaration whose value is absent or `null` in `arguments` is omitted (the * spec's "client MUST omit the header" rows), as is one whose value is not a * primitive of the declared kind — the server cross-checks header against * body, so a header it cannot match is worse than no header. */ declare function buildMcpParamHeaders(declarations: readonly XMcpHeaderDeclaration[], args: unknown): Record; /** * HTTP-exchange capture for the wire log. * * The JSON-RPC log (`rpcLogger`) carries message bodies only. From * `2026-07-28` the Streamable HTTP transport mirrors routing and cross-check * metadata into HTTP *headers* (`Mcp-Method`, `Mcp-Name`, `Mcp-Param-*`, * `MCP-Protocol-Version`), so a body-only log cannot explain a * `-32020 HeaderMismatch` — the body looks fine and the disagreeing header is * invisible. This module captures the header halves of each exchange. * * Placement: this wrapper must be the INNERMOST fetch so it records the bytes * that actually leave — after `wrapFetchForTaskRouting` has injected the * SEP-2663 routing headers. * * Bodies are deliberately NOT captured. The request body is already in the * JSON-RPC log, and reading the response body here would consume the stream * the transport is about to parse. The one thing derived from the request * body is the small set of values the mirrored headers are supposed to equal, * so the cross-check can run later without retaining the body. */ /** One HTTP exchange, headers only. */ type HttpExchangeLogEvent = { serverId: string; request: { method: string; url: string; headers: Record; }; response?: { status: number; statusText: string; headers: Record; }; /** Set when the fetch itself rejected (DNS, TLS, abort) — no response. */ error?: string; durationMs: number; /** Present only when the request body was a single JSON-RPC request. */ bodyValues?: MirroredBodyValues; }; type HttpExchangeLogger = (event: HttpExchangeLogEvent) => void; /** * A single local cache-serve event, reported by `ObservableResponseCache` to * {@link CacheEventLogger} when a cacheable verb is answered from a still-fresh * cached entry (a `get` whose `expiresAt > now`). * * This is a LOCAL event with no wire counterpart — it MUST NOT be conflated * with {@link RpcLogger} traffic. A cache hit is precisely the case where NO * JSON-RPC request left the process, so injecting it into the rpc/wire log * would make an invisible serve masquerade as a real request. */ interface CacheHitEvent { /** The server whose connection served the entry. */ serverId: string; /** The cacheable method (`"tools/list"`, `"resources/read"`, …). */ method: string; /** Canonical params key (`""` for the list verbs, the `uri` for reads). */ params?: string; /** * Age of the served entry in milliseconds (now − store time). Best-effort; * see `ObservableResponseCache` for the heuristic's known imprecision. */ ageMs: number; /** Server-reported cache scope (`"public"` / `"private"`), if present. */ scope?: CacheScope; } /** * Callback invoked for each fresh cache-serve. Distinct channel from * {@link RpcLogger}: cache hits never appear on the wire, so they surface * here — never as rpc log entries. Absence of an emission is NOT proof a call * hit the wire; see `ObservableResponseCache`. */ type CacheEventLogger = (event: CacheHitEvent) => void; /** * The negotiation mode a connection actually requested of the underlying * client. Auto-negotiation is unconditional, so an unconfigured connection is * always probed: * - `"auto"` — unconfigured connection (always probed); * - `"modern-pin"` — an explicit modern (`2026-07-28`) pin; * - `"legacy"` — the exact legacy `initialize` handshake, from an explicit * legacy pin. */ type ConfiguredNegotiationMode = "auto" | "modern-pin" | "legacy"; /** * One connection-attempt outcome, emitted by the manager for Phase 5 * auto-negotiation-activation telemetry. This is a LOCAL provenance channel * (like {@link CacheEventLogger}) — the manager NEVER emits analytics itself; * each surface wires this to its own PostHog/Axiom pipeline and stamps the * `surface` dimension there. * * The fields are exactly the activation-checklist telemetry requirement: * configured mode + negotiated era + transport + outcome + failure class. * (`surface` is added by the consumer.) It carries NO request payloads. */ interface NegotiationOutcomeEvent { /** The server whose connection was attempted. */ serverId: string; /** Transport the attempt used. */ transport: "http" | "stdio"; /** The negotiation mode the client was actually asked to use. */ configuredMode: ConfiguredNegotiationMode; /** Whether the connection established or failed. */ outcome: "connected" | "failed"; /** Negotiated era once connected (`undefined` on failure / unknown). */ negotiatedEra?: "legacy" | "modern"; /** Negotiated wire protocol version once connected (`undefined` on failure). */ negotiatedProtocolVersion?: string; /** * Coarse, non-PII failure class on failure — the era-negotiation-unwrapped * error's `name` (or `code`), e.g. `"UnauthorizedError"`, * `"EraNegotiationFailed"`, `"TypeError"`. `undefined` on success. */ failureClass?: string; } /** * Callback invoked once per connection attempt with its negotiation outcome. * Distinct channel from {@link RpcLogger}/{@link CacheEventLogger}; never * throws into the connect path (the manager guards it). Unset ⇒ no telemetry * and byte-identical connect behavior. */ type NegotiationOutcomeLogger = (event: NegotiationOutcomeEvent) => void; /** * MCPJam response-cache POLICY (SEP-2549). This is the single source of truth * for how the debugger disposes of the client's response cache; the code above * and the raw-evidence surfaces (`server-snapshot`, `server-doctor`, * `mcp-conformance`) implement it. * * 1. **Default UI reads use `"use"`.** A default read MAY be served from cache * — but ONLY when (a) the server sent `ttlMs > 0` (so the entry is fresh) * AND (b) MCPJam surfaces the serve's provenance and age to the operator * (via {@link CacheEventLogger}). A serve the operator cannot see is * indistinguishable from a fabricated wire response and is forbidden. * 2. **`defaultCacheTtlMs` stays `0`.** A result WITHOUT a server `ttlMs` is * stored (so the client's `tools/list`-derived index keeps working) but is * NEVER served. Invisible serving therefore happens EXACTLY when a server * opts in with `ttlMs > 0`. * 3. **"Refresh" ⇒ `cacheMode: "refresh"`.** The refresh affordance always * fetches and re-stores. * 4. **Raw / conformance ⇒ `cacheMode: "bypass"`.** Evidence surfaces neither * consult nor write the cache. * * ### Explicitly DEFERRED: persisted-discovery (`prior`) reconnect * * The upstream client supports a zero-round-trip reconnect by adopting a prior * {@link import("@modelcontextprotocol/client").DiscoverResult} on `connect` * (`ConnectOptions.prior`). MCPJam does NOT implement this here — it is * deferred pending owner sign-off on how to display the provenance of an * adopted-without-a-handshake connection. When implemented, the persisted * `DiscoverResult` MUST be keyed by the full authorization/negotiation context * so a cached discovery is never reused across a different principal or a * different negotiated shape. The intended key spec is: * * - server ORIGIN (scheme + host + port of the MCP endpoint), * - AUTH / TENANT context (the same identity that scopes the response cache * partition — e.g. the auth subject / `cachePartition`), and * - NEGOTIATION INPUTS (proposed protocol-version accept-list + advertised * client capabilities) that produced the `DiscoverResult`. * * Do NOT reuse a `prior` across any change in those inputs. */ /** * Client capability options extracted from MCP SDK ClientOptions */ type ClientCapabilityOptions = NonNullable; /** * Base configuration shared by all server types */ type BaseServerConfig = { /** Legacy merge-style client capabilities to advertise to this server */ capabilities?: ClientCapabilityOptions; /** * Exact client capabilities to advertise to this server. * When provided, this bypasses manager defaults and legacy capability merging. */ clientCapabilities?: ClientCapabilityOptions; /** * Era-conditional capability overlays, applied once the connection's era is * actually KNOWN — the post-negotiation re-resolution seam. * * Capabilities are resolved at connect time, before negotiation has run, so * the base set must be honest under the most conservative era the connection * could land on (a capability the legacy bridge cannot fulfil must not ride * an `initialize` that a 2025 server holds for the whole session). That * forces auto-negotiated connections to under-advertise on the modern era — * e.g. url-mode elicitation, perfectly fulfillable on 2026-07-28, stayed * undeclared because the connect-time resolver couldn't rule out a legacy * landing. * * `modern` is a merge-style overlay (same semantics as `capabilities`) * merged over the connect-time set exactly ONCE, immediately after era * classification, when the connection lands on a 2026-era revision: * * - The 2026 wire re-sends capabilities on EVERY request (the `_meta` * envelope reads the live set), so the widened declaration simply flows * outward from the next request on; the only frames that carried the * narrow set are the negotiation probe itself. * - After that single application the declaration is STABLE for the * connection's lifetime — MRTR rounds of one logical operation always * see one consistent set. * - A connection that lands on a 2025 era never applies the overlay, and * its `initialize` already carried the conservative base: fail-closed. * * The overlay's `elicitation` key is subject to the same advertise=enforce * gate as the runtime-added one: it is dropped unless an elicitation * handler or MRTR input collector is actually registered. * * Ignored entirely when `clientCapabilities` (an EXACT set) is configured — * widening a pinned declaration would defeat the point of pinning one. */ eraCapabilities?: { /** Overlay merged when the connection classifies as 2026-era (stateless). */ modern?: ClientCapabilityOptions; }; /** Request timeout in milliseconds */ timeout?: number; /** Client version to report */ version?: string; /** * Per-server override of `clientInfo` sent in MCP `initialize`. When set, * takes precedence over the manager's `defaultClientName` / * `defaultClientVersion` and the per-server `version`. Extra fields * (e.g. `title`) are passed through verbatim so future spec additions * land here without an SDK bump. * * Wired into the inspector via `hostConfig.mcpProfile.initialize.clientInfo`. * Leaving this undefined means "use the manager defaults" (which is what * historical callers expect). */ clientInfo?: { name?: string; version?: string; } & Record; /** * Supported protocol versions accept-list passed into the upstream Client * as `ClientOptions.supportedProtocolVersions`. The Client sends * `supportedProtocolVersions[0]` as `initialize.params.protocolVersion` * and accepts any of the listed versions in the server's response. * * Wired into the inspector verbatim from * `hostConfig.mcpProfile.initialize.supportedProtocolVersions`. Order is * semantic — preserve it. A pin like `["2025-11-25", "2025-06-18"]` * proposes the newer version but still accepts the older one if the * server negotiates it; the prior shape (`proposedProtocolVersion: * string`) collapsed this to a singleton and silently broke that case. */ supportedProtocolVersions?: string[]; /** * Whether `tools/call` mirrors the tool's `x-mcp-header`-annotated * arguments into `Mcp-Param-{Name}` request headers (SEP-2243, `2026-07-28` * Streamable HTTP: "clients **MUST** mirror the designated parameter values * into HTTP headers"). * * `undefined` (the default) and `true` both mirror. `false` deliberately * simulates a NON-CONFORMING client that never sends them, so a server can * be exercised against one — a conforming server should answer * `-32020 HeaderMismatch`, and MCPJam surfaces that failure unmasked rather * than recovering from it. * * Wired into the inspector via * `hostConfig.mcpProfile.toolParamHeaderMirroring` (`"mirror"` | `"omit"`). * Streamable-HTTP + modern-era only, like the mirroring itself: stdio and * 2025-era connections never mirror, so the flag is inert there. */ mirrorToolParamHeaders?: boolean; /** * Whether the client walks a paginated list to exhaustion, or reads page * one and stops. * * `undefined` (the default) and `false` both walk every page. `true` * deliberately simulates the real hosts that read only the first page, so a * server author can see what their server looks like through one — tools * beyond page one are invisible, and (on `2026-07-28`) a `tools/call` on * such a tool carries no mirrored `Mcp-Param-*`, because the SEP-2243 * mirroring source is the page-one-only aggregate the client cached. * * Wired into the inspector via `hostConfig.mcpProfile.paginationTraversal` * (`"full"` | `"firstPageOnly"`). Applies on every era and every transport — * pagination predates 2026 and is not HTTP-specific. Only the cursor-less * aggregation is truncated; an explicit-cursor request (the debugger's own * manual paging) is left alone. */ firstPageOnly?: boolean; /** * Whether the client opens the server→client notification channel at all. * * `undefined` (the default) and `false` both open it. `true` simulates a * client that never does — ChatGPT measures this way — so a server author * can see that its `notifications/*` never reach that host, no matter what * the server declares. * * On Streamable HTTP this refuses the standalone GET SSE stream the * upstream client opens after `notifications/initialized`. On the legacy * HTTP+SSE transport the GET stream IS the connection, so this cannot * apply — a real client on that transport cannot not-listen either. * * Wired via `hostConfig.mcpProfile.toolListChanged.listens === false`. */ suppressListenChannel?: boolean; /** * Whether the client acts on `notifications/tools/list_changed`. * * `undefined` (the default) and `false` both act on it. `true` simulates a * client that ignores it: the notification is dropped before the client * sees it, so its `tools/list` cache is never evicted and the stale list * stays in use — exactly what a server author sees from such a host. * * Wired via `hostConfig.mcpProfile.toolListChanged.refetches === false`. */ dropToolListChanged?: boolean; /** * Whether the client drives MRTR (`resultType: "input_required"`) retry * rounds at all. * * `undefined` (the default) and `true` both drive them. `false` simulates a * client that never implemented the 2026 pattern: it stops advertising * `elicitation` on a modern connection — where the MRTR bridge is the only * fulfiller, so advertising would be a capability nothing can honor — and * an `input_required` result surfaces as the upstream client's * `UNSUPPORTED_RESULT_TYPE` error instead of silently looping. * * Wired into the inspector via `hostConfig.mcpProfile.mrtrSupport` * (`"full"` | `"none"`). Modern-era only: MRTR does not exist before * `2026-07-28`, and a legacy connection keeps fulfilling elicitation * through the inbound `elicitation/create` bridge, which this knob does not * touch. WHICH elicitation modes an MRTR-capable client fulfills is a * separate, already-modeled fact (`clientCapabilities.elicitation`). */ supportsMrtr?: boolean; /** Error handler for this server */ onError?: (error: unknown) => void; /** Enable simple console logging of JSON-RPC traffic */ logJsonRpc?: boolean; /** Custom logger for JSON-RPC traffic (overrides logJsonRpc) */ rpcLogger?: RpcLogger; /** * Custom sink for HTTP exchanges (headers only). A DISTINCT channel from * `rpcLogger`: that one carries JSON-RPC bodies, this one carries the HTTP * envelope those bodies rode in — the `Mcp-*` mirrored headers a * `-32020 HeaderMismatch` is about. HTTP transports only; stdio never * reaches a fetch, so it emits nothing. */ httpLogger?: HttpExchangeLogger; /** * The `fetch` the HTTP transport dials through, replacing the global one. * * WHY THIS EXISTS: hosted runs must not reach a private address, and * checking the URL the caller NAMED is not the same as checking the address * we end up dialling — a target can answer `302 Location: * http://169.254.169.254/`. Handing a DNS-pinned fetch * (`@mcpjam/sdk/oauth/node`'s `createPinnedStreamingFetch`) in here is what * puts the one real MCP connection under the same guard as the raw probes * beside it; before this existed, that connection followed redirects * unchecked and the conformance suite documented the hole in a comment. * * It is the INNERMOST fetch: the task-routing and HTTP-logging wrappers are * layered on top, so the bytes this sees are the bytes that leave. Ignored * by stdio, which never reaches a fetch. Absent ⇒ `globalThis.fetch`, * byte-identical to the behavior before this field. */ baseFetch?: typeof fetch; }; /** * Configuration for stdio-based MCP servers (subprocess) */ type StdioServerConfig = BaseServerConfig & { /** Command to execute */ command: string; /** Command arguments */ args?: string[]; /** Environment variables */ env?: Record; /** Child process stderr handling. Defaults to inherit when unspecified. */ stderr?: StdioServerParameters["stderr"]; /** Working directory for the stdio server process. */ cwd?: StdioServerParameters["cwd"]; url?: never; accessToken?: never; requestInit?: never; eventSourceInit?: never; authProvider?: never; reconnectionOptions?: never; sessionId?: never; preferSSE?: never; disableSseFallback?: never; refreshToken?: never; clientId?: never; clientSecret?: never; onUnauthorized?: never; }; type UnauthorizedRefreshResult = { accessToken: string; }; type UnauthorizedRefreshHandler = (args: { serverId: string; error: unknown; }) => Promise; /** * Configuration for HTTP-based MCP servers (SSE or Streamable HTTP) */ type HttpServerConfig = BaseServerConfig & { /** Server URL */ url: string; /** * Access token for Bearer authentication. * If provided, adds `Authorization: Bearer ` header to requests. */ accessToken?: string; /** Additional request initialization options */ requestInit?: StreamableHTTPClientTransportOptions["requestInit"]; /** SSE-specific event source options */ eventSourceInit?: SSEClientTransportOptions["eventSourceInit"]; /** OAuth auth provider */ authProvider?: StreamableHTTPClientTransportOptions["authProvider"]; /** Refresh token for OAuth token exchange. Mutually exclusive with accessToken and authProvider. */ refreshToken?: string; /** OAuth client ID. Required when refreshToken is set. */ clientId?: string; /** OAuth client secret. Optional, used with refreshToken. */ clientSecret?: string; /** * Optional 401 recovery hook. When provided for access-token based HTTP * configs, MCPClientManager calls it once after an operation fails with a * strict HTTP 401, then rebuilds the transport with the returned token. */ onUnauthorized?: UnauthorizedRefreshHandler; /** Reconnection options for Streamable HTTP */ reconnectionOptions?: StreamableHTTPClientTransportOptions["reconnectionOptions"]; /** Session ID for Streamable HTTP */ sessionId?: StreamableHTTPClientTransportOptions["sessionId"]; /** Prefer SSE transport over Streamable HTTP */ preferSSE?: boolean; /** * Opt out of the silent Streamable-HTTP → SSE downgrade. By default a * failed Streamable HTTP connect falls back to SSE, which is right for * ad-hoc URLs but wrong for a server whose transport was DECLARED * streamable-http (e.g. an Agent Plugins manifest): connecting over SSE * would misrepresent the server under test. When set, the Streamable HTTP * failure surfaces instead of being retried over SSE. Meaningful only when * Streamable HTTP is attempted first — inert alongside `preferSSE`, which * makes SSE the declared transport rather than a fallback. */ disableSseFallback?: boolean; /** * Pinned MCP protocol version (wire literal that lands in `_meta` + * `MCP-Protocol-Version` header). Absent → SDK default at request * time. Stateful values (per `isStatelessProtocolVersion`) use the * legacy upstream Client + initialize handshake; stateless values * select the preview Streamable HTTP POST transport * (`StatelessMcpHttpPreviewClient`) and are incompatible with * `preferSSE`. Already validated by `isKnownProtocolVersion` at the * trust boundary (`local-server-resolver.ts` + Convex validator); * the manager does not re-validate. Resolved upstream (per-server * override > host default > undefined) and stamped onto the config * passed to `MCPClientManager`. */ mcpProtocolVersion?: McpProtocolVersion; command?: never; args?: never; env?: never; stderr?: never; cwd?: never; }; /** * Union type for all server configurations */ type MCPServerConfig = StdioServerConfig | HttpServerConfig; /** * Configuration map for multiple servers (serverId -> config) */ type MCPClientManagerConfig = Record; /** * Connection status for a server */ type MCPConnectionStatus = "connected" | "connecting" | "disconnected"; /** * Summary information for a server */ type ServerSummary = { id: string; status: MCPConnectionStatus; config?: MCPServerConfig; }; /** * Shared state for managed client connections. * * `client` is typed as the `ManagedMcpClient` interface so the manager * can swap between the legacy upstream `Client` (via * `OfficialSdkClientAdapter`) and the stateless preview * (`StatelessMcpHttpPreviewClient`) without per-call branching. * `transport` is `undefined` for the stateless preview path — the * preview owns its own fetch and has no separate Transport object. */ interface BaseClientState { client?: ManagedMcpClient; transport?: Transport; authProvider?: RefreshTokenOAuthProvider; } /** * Persistent server registration/configuration state. */ interface RegisteredServerState { config: MCPServerConfig; timeout: number; } /** * Live connection state for a registered server. */ interface LiveClientState extends BaseClientState { stdioStderrCleanup?: () => void; connectPromise?: Promise; retryPromise?: Promise; initializedClientCapabilities?: ClientCapabilityOptions; } /** * Event passed to RPC loggers */ type RpcLogEvent = { direction: "send" | "receive"; message: unknown; serverId: string; }; /** * Function type for JSON-RPC logging */ type RpcLogger = (event: RpcLogEvent) => void; /** * Progress event from server operations */ type ProgressEvent = { serverId: string; progressToken: string | number; progress: number; total?: number; message?: string; }; /** * Function type for progress handling */ type ProgressHandler = (event: ProgressEvent) => void; /** * Options for MCPClientManager constructor */ interface MCPClientManagerOptions { /** Default client name to report to servers */ defaultClientName?: string; /** Default client version to report */ defaultClientVersion?: string; /** * Default `clientInfo` extra fields (e.g. `title`) to advertise to servers. * Per-server `clientInfo.name` / `clientInfo.version` override this. Extra * keys here are merged into the per-server clientInfo at connect time so * future MCP spec additions don't require an SDK bump. */ defaultClientInfoExtras?: Record; /** * Default supported protocol versions accept-list. Per-server * `supportedProtocolVersions` overrides this. When neither is set, the * upstream Client's built-in `SUPPORTED_PROTOCOL_VERSIONS` default is * used and historical behavior is preserved verbatim. */ defaultSupportedProtocolVersions?: string[]; /** Default capabilities to advertise */ defaultCapabilities?: ClientCapabilityOptions; /** Default request timeout in milliseconds */ defaultTimeout?: number; /** Enable JSON-RPC logging for all servers by default */ defaultLogJsonRpc?: boolean; /** Global JSON-RPC logger */ rpcLogger?: RpcLogger; /** Global HTTP-exchange (headers-only) logger. See `httpLogger` on the * server config for why this is a separate channel from `rpcLogger`. */ httpLogger?: HttpExchangeLogger; /** Default transport `fetch` for every HTTP server. Per-server `baseFetch` * overrides it. See `baseFetch` on the server config. */ baseFetch?: typeof fetch; /** Global progress handler */ progressHandler?: ProgressHandler; /** * Optional provenance sink for LOCAL cache serves. When set, every managed * connection is given an `ObservableResponseCache` (wrapping a fresh * in-memory store) and this callback fires whenever a cacheable verb is * answered from a still-fresh cached entry — a serve that costs ZERO wire * exchange. This is a DISTINCT channel from `rpcLogger`: cache hits never * touch the wire, so they must never be injected into the rpc/wire log * (that would make an invisible serve look like a real request). * * When unset, connections use the upstream default store and behavior is * byte-identical to not wiring a cache observer. */ cacheEventLogger?: CacheEventLogger; /** * Optional per-connection negotiation-outcome sink (Phase 5 activation * telemetry). Fires once per connection attempt with the configured * negotiation mode, negotiated era/version, transport, outcome, and failure * class. The manager guards it (never throws into connect). Unset ⇒ no * telemetry, byte-identical connect behavior. The consumer stamps the * `surface` dimension and forwards to PostHog/Axiom. */ negotiationOutcomeLogger?: NegotiationOutcomeLogger; /** * Optional accessor for the ambient OpenTelemetry trace context to * propagate into request `_meta` (the 2026-07-28 reserved `traceparent` / * `tracestate` / `baggage` keys). Called per request with the server id, so * an embedder whose tracer changes spans per operation gets the current one * without reconnecting. * * Propagation only. Returning `undefined` — the default, since MCPJam runs * no OpenTelemetry tracer — means the keys are ABSENT on the wire; the * manager never mints a trace or span id to fill them. Injection happens on * the modern era only, and a malformed value is dropped rather than * forwarded. See `trace-context.ts`. */ traceContextProvider?: TraceContextProvider; /** Default retry policy for retryable manager operations */ retryPolicy?: RetryPolicy; /** * Extra time budget (ms) granted to a `tools/call` while an elicitation is * pending for that server. The per-request timeout is a *server* budget: a * tool call blocked on a human must not die at it, but a hung server must. * * When any elicitation handler is installed for a server, `executeTool` * enforces the base timeout with its own watchdog that only accumulates * time while NO elicitation is pending, and separately caps the total time * spent suspended across all elicitations in that call at this value. * * Defaults to {@link DEFAULT_ELICITATION_TIMEOUT_EXTENSION_MS} (10 minutes). * Has no effect on servers without an elicitation handler. */ elicitationTimeoutExtensionMs?: number; /** * When true, do not connect in the constructor; callers must use connectToServer * (e.g. connectReplayManagerServers) to avoid racing eager connects. */ lazyConnect?: boolean; } /** * Arguments passed to tool execution */ type ExecuteToolArguments = Record; /** * Options for task-augmented tool calls */ type TaskOptions = { /** Time-to-live for the task in milliseconds */ ttl?: number; }; /** * Preferred executeTool options shape. */ interface ExecuteToolRequest { /** Request options for the tool call */ request?: ClientRequestOptions; /** Task options for task-augmented tool calls (2025-11-25 legacy wire only) */ task?: TaskOptions; /** * SEP-2663 extension wire (2026-07-28+): declare, for THIS call, that the * client can handle a `CreateTaskResult`. The server decides whether to use * it; a plain result is still valid. There is no TTL — the server owns it. * Ignored on the legacy wire; an error on `wire: "none"`. */ allowTaskResult?: boolean; /** Explicit retry policy for tool execution */ retry?: RetryPolicy; } /** * Handler for server-specific elicitation requests */ type ElicitationHandler = (params: ElicitRequest["params"]) => Promise | ElicitResult; /** * Elicitation mode (MCP spec 2025-11-25). Absent on the wire ⇒ `"form"`. */ type ElicitationMode = "form" | "url"; /** * Request passed to global elicitation callback */ type ElicitationCallbackRequest = { requestId: string; message: string; schema: unknown; /** Task ID if this elicitation is related to a task (MCP Tasks spec 2025-11-25) */ relatedTaskId?: string; /** * The server that issued this elicitation. Always populated by * `ElicitationManager.applyToClient`; optional so existing callback * implementations keep type-checking. */ serverId?: string; /** * Elicitation mode. Absent ⇒ `"form"` (legacy behavior: every * pre-2025-11-25 elicitation is form mode). */ mode?: ElicitationMode; /** URL to present to the user. URL mode only. */ url?: string; /** * Server-chosen elicitation id, used by the server to correlate a * `notifications/elicitation/complete`. URL mode only. Never treat this * as a trusted key — it is chosen by the server. */ elicitationId?: string; }; /** * Global callback for handling elicitation requests */ type ElicitationCallback = (request: ElicitationCallbackRequest) => Promise | ElicitResult; /** * Task status values */ type MCPTaskStatus = Task["status"]; /** * MCP Task object */ type MCPTask = Task; /** * Result from listing tasks */ type MCPListTasksResult = ListTasksResult; /** * Request options accepted by the manager's read verbs. Extends the upstream * `RequestOptions` with the SEP-2549 `cacheMode` so a caller can pick the * per-call cache disposition; ignored by verbs that are not cacheable (e.g. * `callTool`). See {@link CacheMode}. */ type ClientRequestOptions = RequestOptions & { cacheMode?: CacheMode; }; type ListResourcesParams = Parameters[0]; type ListResourceTemplatesParams = Parameters[0]; type ReadResourceParams = Parameters[0]; type SubscribeResourceParams = Parameters[0]; type UnsubscribeResourceParams = Parameters[0]; type ListPromptsParams = Parameters[0]; type GetPromptParams = Parameters[0]; type ListToolsResult = Awaited>; type MCPPromptListResult = Awaited>; type MCPPrompt = MCPPromptListResult["prompts"][number]; type MCPGetPromptResult = Awaited>; type MCPResourceListResult = Awaited>; type MCPResource = MCPResourceListResult["resources"][number]; type MCPReadResourceResult = Awaited>; type MCPResourceTemplateListResult = Awaited>; type MCPResourceTemplate = MCPResourceTemplateListResult["resourceTemplates"][number]; type MCPServerSummary = ServerSummary; /** * An MCP tool with an execute function pre-wired to call the manager. * Extends the official MCP SDK Tool type. * Returned by MCPClientManager.getTools(). */ /** Options for tool execution */ interface ToolExecuteOptions { /** Abort signal for cancellation */ signal?: AbortSignal; } interface Tool extends Tool$1 { /** Execute the tool with the given arguments */ execute: (args: Record, options?: ToolExecuteOptions) => Promise; _meta?: { _serverId: string; [key: string]: unknown; }; } /** * AI SDK compatible tool set (Record). * Returned by MCPClientManager.getToolsForAiSdk(). * Can be passed directly to AI SDK's generateText(). */ type AiSdkTool = ToolSet; export { isValidTracestate as $, TRACEPARENT_META_KEY as A, BAGGAGE_META_KEY as B, type ClientCapabilityOptions as C, type DecodedMcpHeaderValue as D, type ExecuteToolArguments as E, TRACESTATE_META_KEY as F, type TaskOptions as G, type HttpServerConfig as H, type TraceContext as I, type TraceContextProvider as J, type XMcpHeaderScan as K, type ListToolsResult as L, type MCPServerConfig as M, buildMcpParamHeaders as N, classifyMcpHeader as O, type ParsedTraceparent as P, decodeMcpHeaderValue as Q, type RpcLogger as R, type ServerSummary as S, TASK_ROUTED_METHODS as T, encodeMcpHeaderValue as U, evaluateMcpHeaders as V, extractTraceContext as W, type XMcpHeaderDeclaration as X, findMcpHeaderIssues as Y, isValidBaggage as Z, isValidTraceparent as _, type RetryPolicy as a, parseTraceparent as a0, sanitizeTraceContext as a1, scanXMcpHeaderDeclarations as a2, stripXMcpHeaderAnnotations as a3, traceContextToMeta as a4, type CacheEventLogger as a5, type Tool as a6, type AiSdkTool as a7, type CacheHitEvent as a8, type ConfiguredNegotiationMode as a9, type ReadResourceParams as aA, type SubscribeResourceParams as aB, type UnsubscribeResourceParams as aC, type ListResourceTemplatesParams as aD, type ListPromptsParams as aE, type GetPromptParams as aF, DEFAULT_RETRY_POLICY as aa, type ElicitationCallback as ab, type ElicitationCallbackRequest as ac, type ElicitationHandler as ad, type ExecuteToolRequest as ae, type HttpExchangeLogger as af, type LiveClientState as ag, type MCPClientManagerOptions as ah, type MCPServerSummary as ai, type NegotiationOutcomeEvent as aj, type NegotiationOutcomeLogger as ak, type ProgressEvent as al, type ProgressHandler as am, type RegisteredServerState as an, type RpcLogEvent as ao, type ToolExecuteOptions as ap, type UnauthorizedRefreshHandler as aq, type UnauthorizedRefreshResult as ar, isRetryableTransientError as as, normalizeRetryPolicy as at, retryWithPolicy as au, type ManagedMcpClientNotificationMethod as av, type ManagedMcpClientNotificationHandler as aw, type ManagedMcpClient as ax, type ClientRequestOptions as ay, type ListResourcesParams as az, type MCPPrompt as b, type MCPResourceTemplate as c, type MCPResource as d, type BaseServerConfig as e, type HttpExchangeLogEvent as f, type MCPClientManagerConfig as g, type MCPConnectionStatus as h, type MCPGetPromptResult as i, type MCPListTasksResult as j, type MCPPromptListResult as k, type MCPReadResourceResult as l, type MCPResourceListResult as m, type MCPResourceTemplateListResult as n, type MCPTask as o, type MCPTaskStatus as p, MCP_HEADER_SENTINEL_PREFIX as q, MCP_HEADER_SENTINEL_SUFFIX as r, MCP_PARAM_HEADER_PREFIX as s, type McpHeaderAssessment as t, type McpHeaderFamily as u, type McpHeaderIssue as v, type McpHeaderStatus as w, type McpParamCrossCheck as x, type MirroredBodyValues as y, type StdioServerConfig as z };