import { CallToolResult as CallToolResult$1, OAuthClientProvider, OAuthClientMetadata, OAuthClientInformationContext, StoredOAuthClientInformation, StoredOAuthTokens, OAuthDiscoveryState, ClientAuthMethod, Transport, Implementation, ClientCapabilities, VersionNegotiationOptions, PriorDiscovery, InputRequiredOptions, ResponseCacheStore, ProtocolEra, ServerCapabilities } from '@modelcontextprotocol/client'; export { ClientCapabilities } from '@modelcontextprotocol/client'; import { CreateMessageResult, CreateMessageResultWithTools, CreateMessageRequestParams, LoggingLevel, ElicitRequestParams, ElicitResult, Tool, Resource, Prompt, ResourceTemplateType, TextResourceContents, BlobResourceContents, GetPromptResult, OAuthClientMetadata as OAuthClientMetadata$1, Root, ContentBlock, ModelPreferences, SamplingMessage, ToolChoice } from '@modelcontextprotocol/server'; export { BlobResourceContents, ContentBlock, CreateMessageRequestParams, CreateMessageResult, CreateMessageResultWithTools, ElicitRequestParams, ElicitResult, GetPromptResult, LoggingLevel, ModelPreferences, Prompt, PromptArgument, PromptMessage, Resource, ResourceContents, ResourceTemplateType as ResourceTemplate, Root, SamplingMessage, TextResourceContents, Tool, ToolChoice, ToolResultContent, ToolUseContent } from '@modelcontextprotocol/server'; import { Skill, SkillFile } from '@modelcontextprotocol/client/ext/skills'; export { SKILLS_EXTENSION_ID, Skill, SkillFile, SkillFrontmatter } from '@modelcontextprotocol/client/ext/skills'; import Anthropic from '@anthropic-ai/sdk'; import OpenAI from 'openai'; import { GoogleGenAI } from '@google/genai'; /** A skill read by `Client.readSkill()`: its entry and every file, verified against it. */ interface SkillContents { skill: Skill; files: SkillFile[]; } /** Union of the two sampling result shapes the MCP protocol defines. */ type AnySamplingResult = CreateMessageResult | CreateMessageResultWithTools; /** * The SDK's CallToolResult with a typed generic for structuredContent. * The intersection retains its open extension fields while narrowing the two * values FastMCP normalizes. */ type CallToolResult = CallToolResult$1 & { structuredContent: TData | null; isError: boolean; }; type CompletionResult = { values: string[]; total?: number; hasMore?: boolean; }; type LogMessage = { level: LoggingLevel; logger?: string; data: unknown; }; type LogHandler = (message: LogMessage) => void | Promise; type ProgressHandler = (progress: number, total?: number, message?: string) => void | Promise; type SamplingHandler = (params: CreateMessageRequestParams) => AnySamplingResult | Promise; type ElicitationHandler = (params: ElicitRequestParams) => ElicitResult | Promise; type ResourceUpdateHandler = (uri: string) => void | Promise; /** * Config for receiving server-initiated list-change notifications. * Set debounceMs: 0 in tests for instant delivery. */ type ListChangedHandler = { onChanged: (error: Error | null, items: T[] | null) => void | Promise; /** Whether to auto-fetch the updated list before calling onChanged. Default: true. */ autoRefresh?: boolean; /** Debounce window in ms. Default: 300. Set to 0 to disable. */ debounceMs?: number; }; interface ClientHandlers { log?: LogHandler; progress?: ProgressHandler; sampling?: SamplingHandler; elicitation?: ElicitationHandler; onToolsListChanged?: ListChangedHandler; onResourcesListChanged?: ListChangedHandler; onPromptsListChanged?: ListChangedHandler; } declare function defaultLogHandler(message: LogMessage): void; declare function defaultProgressHandler(progress: number, total?: number, message?: string): void; interface RequestOptions { /** Per-request timeout in seconds. Overrides client-level defaultOptions. */ timeout?: number; /** AbortSignal for caller-controlled cancellation. */ signal?: AbortSignal; } interface CallToolOptions extends RequestOptions { /** Per-call progress handler, overrides the client-level handler for this call. */ onProgress?: ProgressHandler; } interface IToolsClient { listTools(options?: RequestOptions): Promise; callTool(name: string, args?: Record, options?: CallToolOptions): Promise>; } interface IResourcesClient { listResources(options?: RequestOptions): Promise; listResourceTemplates(options?: RequestOptions): Promise; readResource(uri: string, options?: RequestOptions): Promise>; subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise; unsubscribeResource(uri: string, options?: RequestOptions): Promise; } interface IPromptsClient { listPrompts(options?: RequestOptions): Promise; getPrompt(name: string, args?: Record, options?: RequestOptions): Promise; } interface IClient extends IToolsClient, IResourcesClient, IPromptsClient { connect(): Promise; close(): Promise; isConnected(): boolean; ping(options?: RequestOptions): Promise; complete(ref: { type: 'ref/prompt'; name: string; } | { type: 'ref/resource'; uri: string; }, argument: { name: string; value: string; }, context?: { arguments?: Record; }, options?: RequestOptions): Promise; setLogLevel(level: LoggingLevel, options?: RequestOptions): Promise; [Symbol.asyncDispose](): Promise; } type OAuthToken = { access_token: string; token_type?: string; refresh_token?: string; /** Unix timestamp in milliseconds (normalized internally). */ expires_at?: number; /** Seconds until expiry — used to compute expires_at on receipt. */ expires_in?: number; scope?: string; }; /** * An auth provider that acquires a token asynchronously and injects it as a * request header per request. {@link ClientCredentials}, {@link JwtBearerAuth}, * and {@link EnterpriseManagedAuth} all implement it. The transport recognizes * these by their `kind` discriminant and injects `getHeaders()` on every * request via a custom fetch wrapper (unlike static `BearerAuth`, whose header * never changes, or interactive `OAuth`, which the SDK transport drives itself). */ interface AsyncHeaderAuth { readonly kind: string; getHeaders(): Promise>; } type KeyValueStore = { get(key: string): Promise; set(key: string, value: string): Promise; delete(key: string): Promise; }; declare class InMemoryStore implements KeyValueStore { private readonly _map; get(key: string): Promise; set(key: string, value: string): Promise; delete(key: string): Promise; } declare class FileTokenStorage implements KeyValueStore { private readonly _explicitPath?; private _resolvedPath?; constructor(path?: string); private _path; private _readAll; private _writeAll; get(key: string): Promise; set(key: string, value: string): Promise; delete(key: string): Promise; } interface OAuthOptions { /** Pre-registered client ID. When set, Dynamic Client Registration is skipped. */ clientId?: string; /** Pre-registered client secret. */ clientSecret?: string; /** Requested OAuth scopes (space-separated string or array). */ scopes?: string | string[]; /** Client name used in Dynamic Client Registration. Default: "FastMCP Client". */ clientName?: string; /** Persistent key-value store for tokens, client info, and discovery state. Default: in-memory. */ store?: KeyValueStore; /** * Port for the local OAuth callback server. Default: 8765. * The port must be consistent across calls because it is registered as the * redirect_uri during Dynamic Client Registration. */ callbackPort?: number; /** * Override how the authorization URL is opened. When not provided the * system browser is launched. Inject a no-op or mock here for testing. */ onRedirect?: (url: URL) => void | Promise; /** * Client ID Metadata Document URL (SEP-991 / CIMD) — an HTTPS URL, with a * non-root path, that serves this client's metadata document. When the * authorization server advertises `client_id_metadata_document_supported`, * the SDK's `auth()` orchestrator uses this URL directly as the `client_id` * and skips Dynamic Client Registration entirely. Falls back to normal DCR * (or `clientId`, if set) when the server doesn't support CIMD. Validated * eagerly in the constructor. */ clientMetadataUrl?: string; } declare class OAuth implements OAuthClientProvider { private _serverUrl; private readonly _clientId?; private readonly _clientSecret?; private readonly _scopes?; private readonly _clientName; private readonly _store; private readonly _callbackPort; private readonly _onRedirect?; readonly clientMetadataUrl?: string; private _codeVerifier; protected _callbackPromise: Promise | null; protected _callbackResolve: ((params: URLSearchParams) => void) | null; protected _callbackReject: ((err: Error) => void) | null; private _callbackServer; private _actualCallbackPort; constructor(options?: OAuthOptions); /** * Binds the MCP server URL so that all storage keys are namespaced by it. * Called by Client before connecting. */ _bind(serverUrl: string): void; get redirectUrl(): string | URL; get clientMetadata(): OAuthClientMetadata; clientInformation(ctx?: OAuthClientInformationContext): Promise; saveClientInformation(info: StoredOAuthClientInformation, ctx?: OAuthClientInformationContext): Promise; tokens(ctx?: OAuthClientInformationContext): Promise; saveTokens(tokens: StoredOAuthTokens, ctx?: OAuthClientInformationContext): Promise; redirectToAuthorization(authorizationUrl: URL): Promise; /** * Creates the pending-callback promise that {@link waitForCallback} awaits. * Subclasses (e.g. BrowserOAuth) call this before opening their own redirect. */ protected _armCallbackPromise(): void; /** Resolves the pending callback with the full authorization callback params. */ protected _resolveCallback(params: URLSearchParams): void; /** Rejects the pending callback with an error. */ protected _rejectCallback(err: Error): void; /** * Races the pending callback promise against a timeout and clears the * promise state. Subclasses reuse this and add their own teardown. */ protected _awaitCallback(timeoutMs: number): Promise; saveCodeVerifier(codeVerifier: string): void; codeVerifier(): string; invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise; saveDiscoveryState(state: OAuthDiscoveryState): Promise; discoveryState(): Promise; /** * Returns the actual port the callback server bound to. * Only populated after redirectToAuthorization() has been called. */ get callbackServerPort(): number | null; /** * Waits for the OAuth authorization code to arrive via the callback server, * then stops the server and resolves with the full callback `URLSearchParams` * (including `code` and, when present, the RFC 9207 `iss` parameter). * * Must be called after the UnauthorizedError thrown by connect() is caught. * Pass the result directly to the transport's `finishAuth(callbackParams)`. */ waitForCallback(timeoutMs?: number): Promise; private _key; /** Storage key for the "last issuer seen for this server" pointer (SEP-2352). */ private _issuerPointerKey; /** * Remembers the resolved authorization-server issuer for this MCP server, * so later no-ctx reads (e.g. the transport's per-request bearer-token read) * know which issuer-keyed credential set to return. */ private _rememberIssuer; private _lastIssuer; private _startCallbackServer; private _stopCallbackServer; } declare class BearerAuth { private readonly _token; constructor(token: string); getHeaders(): Record; } /** Token-endpoint authentication method for a shared client secret. */ type ClientSecretAuthMethod = 'client_secret_post' | 'client_secret_basic'; /** Fields common to every {@link ClientCredentials} configuration. */ interface ClientCredentialsBaseOptions { tokenEndpoint: string; clientId: string; scope?: string; /** * Persistent token store. Default: in-memory. The cache key is derived from * `tokenEndpoint` alone, with no client identity in it — use one store per * credential identity. Do not share a persistent `store` across two * `ClientCredentials` instances that have different `clientId`/`clientSecret`/ * `privateKey` but the same `tokenEndpoint`; they will read and overwrite * each other's cached tokens. */ store?: KeyValueStore; /** How many seconds before expiry to proactively re-fetch. Default: 60. */ refreshBufferSeconds?: number; } /** * Shared-secret configuration for {@link ClientCredentials}. * * `authMethod` selects how the secret reaches the token endpoint: * - `client_secret_post` (default) — `client_id` and `client_secret` in the * POST body. Unchanged from earlier releases. * - `client_secret_basic` — an RFC 6749 §2.3.1 HTTP Basic `Authorization` * header. Nothing secret goes in the body. */ interface ClientSecretCredentialsOptions extends ClientCredentialsBaseOptions { clientSecret: string; /** Token-endpoint authentication method. Default: `client_secret_post`. */ authMethod?: ClientSecretAuthMethod; privateKey?: never; algorithm?: never; } /** * `private_key_jwt` configuration for {@link ClientCredentials} (RFC 7523 / * SEP-1046): the client proves its identity with a signed JWT `client_assertion` * instead of a shared secret. The assertion is signed by the SDK's own * `private_key_jwt` machinery — no secret is ever sent to the token endpoint. */ interface PrivateKeyJwtCredentialsOptions extends ClientCredentialsBaseOptions { /** Signing key: a PEM (PKCS#8) string, its bytes, or a JWK object. */ privateKey: string | Uint8Array | Record; /** JWS signing algorithm, e.g. `ES256` or `RS256`. */ algorithm: string; /** * The assertion's `aud` claim. Required — there is no safe default, because * this provider does no discovery and cannot learn the authorization server's * identity on its own. RFC 7523 §3 recommends the authorization server's * `issuer` identifier; some servers instead verify against the token endpoint * URL. Set whichever your server checks (issuer is the more common choice). */ audience: string; /** Assertion lifetime in seconds. Default: 300. */ jwtLifetimeSeconds?: number; /** Extra claims merged over the standard `iss`/`sub`/`aud`/`exp`/`iat`/`jti`. */ claims?: Record; clientSecret?: never; authMethod?: never; } /** * Configuration for {@link ClientCredentials}. A discriminated union: supply * either a `clientSecret` (with an optional `authMethod`) or a `privateKey` * (with its `algorithm`) — the two are mutually exclusive and enforced at * compile time. */ type ClientCredentialsOptions = ClientSecretCredentialsOptions | PrivateKeyJwtCredentialsOptions; declare class ClientCredentials implements AsyncHeaderAuth { readonly kind: "client_credentials"; private readonly _tokenEndpoint; private readonly _clientId; private readonly _scope?; private readonly _authMethod; /** Set for `client_secret_post` / `client_secret_basic`. */ private readonly _clientSecret?; /** * Set for `private_key_jwt`. The SDK's `createPrivateKeyJwtAuth` signs the * assertion and stamps `client_assertion` / `client_assertion_type` onto the * token-request params — we reuse it verbatim instead of hand-rolling JOSE. */ private readonly _addClientAssertion?; private readonly _cache; constructor(options: ClientCredentialsOptions); getHeaders(): Promise>; private _fetchToken; } /** A workload assertion: a signed JWT string, or an (async) factory for one. */ type AssertionSource = string | (() => string | Promise); /** * Configuration for {@link JwtBearerAuth}. * * The client presents a pre-issued, signed JWT (`assertion`) directly to the * token endpoint under `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer` * (RFC 7523 §2.1). No interactive authorization, no client secret by default — * this is the workload-identity-federation shape (SEP-1933): a workload proves * its identity with a JWT its runtime already minted (a Kubernetes projected * service-account token, a cloud instance-identity JWT, etc.). */ interface JwtBearerOptions { /** The authorization server's token endpoint. */ tokenEndpoint: string; /** * The workload assertion (a signed JWT). Pass a string for a fixed assertion, * or a callback to mint/read a fresh one each time a token is fetched (the * usual case — workload JWTs are short-lived). */ assertion: AssertionSource; /** The client identifier registered for this workload. */ clientId?: string; /** * Token-endpoint client authentication. Default: `none` (public client — the * assertion itself is the credential, so no separate client secret is sent). */ authMethod?: ClientAuthMethod; /** Client secret, when `authMethod` is `client_secret_basic`/`_post`. */ clientSecret?: string; /** Requested scopes (space-separated). */ scope?: string; /** * Persistent token store. Default: in-memory. The cache key is derived from * `tokenEndpoint` alone, with no client identity in it — use one store per * credential identity. Do not share a persistent `store` across two * `JwtBearerAuth` instances that have different `clientId`/`assertion` but * the same `tokenEndpoint`; they will read and overwrite each other's * cached tokens. */ store?: KeyValueStore; /** How many seconds before expiry to proactively re-fetch. Default: 60. */ refreshBufferSeconds?: number; } declare class JwtBearerAuth implements AsyncHeaderAuth { readonly kind: "jwt_bearer"; private readonly _tokenEndpoint; private readonly _assertion; private readonly _clientId?; private readonly _authMethod; private readonly _clientSecret?; private readonly _scope?; private readonly _cache; constructor(options: JwtBearerOptions); getHeaders(): Promise>; private _fetchToken; /** * Wraps fetch to fix up the token-request body the SDK helper builds: * appends `scope` when configured (RFC 7523 §2.1 allows it alongside the * assertion), and drops an empty `client_id` when no client identifier is set * (the helper's public-client path always writes one — we send no `client_id` * at all rather than `client_id=`). */ private _rewriteBody; } /** * Configuration for {@link EnterpriseManagedAuth} (SEP-990, Enterprise-Managed * Authorization / Cross-App Access). * * The flow is two hops, both stable RFCs: * 1. **Token exchange** (RFC 8693) at the enterprise IdP: exchange the user's * OpenID Connect ID token for an *identity assertion JWT authorization * grant* (ID-JAG) scoped to the target MCP server. * 2. **JWT-bearer grant** (RFC 7523) at the MCP server's authorization server: * present the ID-JAG under `grant_type=jwt-bearer` to obtain the access * token. */ interface EnterpriseManagedOptions { /** The MCP server's authorization-server token endpoint (step 2). */ tokenEndpoint: string; /** The MCP client identifier registered with the authorization server. */ clientId: string; /** The MCP client secret (default client auth is `client_secret_basic`). */ clientSecret?: string; /** Client-authentication method for step 2. Default: `client_secret_basic`. */ authMethod?: ClientAuthMethod; /** * The ID-JAG audience — the target authorization server's identifier. The * authorization server verifies the ID-JAG `aud` against this. */ audience: string; /** * The protected-resource identifier of the target MCP server (RFC 9728). The * authorization server verifies the ID-JAG `resource` against this. */ resource: string; /** The enterprise IdP's token endpoint (step 1). */ idpTokenEndpoint: string; /** The client identifier registered with the IdP for token exchange. */ idpClientId: string; /** The client secret for the IdP token exchange, if the IdP requires one. */ idpClientSecret?: string; /** * The user's OpenID Connect ID token (the `subject_token` of the exchange). * Pass a string, or a callback to read a fresh one each fetch. */ idToken: AssertionSource; /** Requested scopes (space-separated). */ scope?: string; /** * Persistent token store. Default: in-memory. The cache key is derived from * `tokenEndpoint` alone, with no client identity in it — use one store per * credential identity. Do not share a persistent `store` across two * `EnterpriseManagedAuth` instances that have different `clientId`/`idToken` * but the same `tokenEndpoint`; they will read and overwrite each other's * cached tokens. */ store?: KeyValueStore; /** How many seconds before expiry to proactively re-fetch. Default: 60. */ refreshBufferSeconds?: number; } declare class EnterpriseManagedAuth implements AsyncHeaderAuth { readonly kind: "enterprise_managed"; private readonly _options; private readonly _cache; constructor(options: EnterpriseManagedOptions); getHeaders(): Promise>; private _fetchToken; } /** * KeyValueStore backed by `localStorage`. Synchronous and simple; suitable for * OAuth tokens and client registration state in single-page apps. Keys are * namespaced by a prefix to avoid collisions with other app state. */ declare class LocalStorageStore implements KeyValueStore { private readonly _prefix; constructor(prefix?: string); get(key: string): Promise; set(key: string, value: string): Promise; delete(key: string): Promise; } /** * KeyValueStore backed by IndexedDB. Preferred when tokens should survive * outside the synchronous, size-limited localStorage (e.g. larger payloads or * stricter persistence). Opens the database per operation and closes it again. */ declare class IndexedDBStore implements KeyValueStore { private readonly _dbName; private readonly _storeName; constructor(opts?: { dbName?: string; storeName?: string; }); private _open; private _tx; get(key: string): Promise; set(key: string, value: string): Promise; delete(key: string): Promise; } interface BrowserOAuthOptions extends Omit { /** * Redirect URI registered with the provider. Must serve a page that calls * {@link handleOAuthCallback} (popup mode) or is your app route that reads the * returned `?code=` (redirect mode). */ redirectUri: string; /** * 'popup' (default) opens the authorization URL in a popup window and listens * for a postMessage from the callback page. 'redirect' navigates the whole * tab; resume with {@link BrowserOAuth.resumeFromRedirect} on return. */ mode?: 'popup' | 'redirect'; /** `window.open` features string for popup mode. */ popupFeatures?: string; } declare class BrowserOAuth extends OAuth { private readonly _redirectUri; private readonly _mode; private readonly _popupFeatures; private _popup; private _messageHandler; constructor(options: BrowserOAuthOptions); get redirectUrl(): string; get clientMetadata(): OAuthClientMetadata$1; redirectToAuthorization(authorizationUrl: URL): Promise; waitForCallback(timeoutMs?: number): Promise; /** * Redirect-mode resume: parse the authorization callback params from a * returned URL (defaults to the current location). Returns the full * `URLSearchParams` (including `code` and, when present, `iss`) — pass * directly to `finishAuth()` — or `null` if there is no `code`. Throws if * the provider returned an error. */ resumeFromRedirect(href?: string): URLSearchParams | null; private _teardown; } /** * Call from the redirect_uri page (popup mode) to deliver the authorization * code back to the opener window and close the popup. */ declare function handleOAuthCallback(opts?: { targetOrigin?: string; }): void; interface McpServerLike { connect(transport: Transport): Promise; /** * Optional modern-era (2026-07-28) in-process fetch entrypoint, for servers * built on `createMcpHandler` (e.g. `FastMCP`'s own `_modernFetch`). * `InMemoryTransport` — used by `connect()` above — is 2025-era only (the * legacy `Server`/session model); there is no in-process equivalent of a * real HTTP round trip for the modern era's stateless-per-request dispatch. * When present, and the caller pins modern era via * `versionNegotiation: { mode: { pin: '2026-07-28' } }`, the client builds a * `StreamableHTTPClientTransport` whose `fetch` calls this function directly * — no sockets, but otherwise the same code path a real HTTP connection * takes. Not used for `'auto'` or `'legacy'` modes: this server-side hook is * modern-only (mirrors `createMcpHandler(..., { legacy: 'reject' })`), so * auto-negotiation (which must be able to fall back to legacy) still goes * through `connect()` + `InMemoryTransport`, and stays legacy-only for * in-process servers until a dual-era in-process bridge exists. */ _modernFetch?(request: Request, options?: unknown): Promise; } type McpServerEntry = { url: string; headers?: Record; auth?: BearerAuth | OAuth | AsyncHeaderAuth | string; } | { command: string; args?: string[]; env?: Record; auth?: BearerAuth | OAuth | AsyncHeaderAuth | string; }; /** Values accepted in mcpServers: either a config object or an in-process server. */ type McpServerValue = McpServerEntry | McpServerLike; type McpConfig = { mcpServers: Record; }; declare class StdioTransport { readonly command: string; readonly args: string[]; readonly env?: Record; readonly cwd?: string; constructor(command: string, args?: string[], options?: { env?: Record; cwd?: string; }); } type ClientTransportInput = string | McpServerLike | McpConfig | StdioTransport | Transport; interface ClientDefaultOptions { /** Global fallback timeout in seconds for all requests. */ timeout?: number; tool?: { timeout?: number; }; resource?: { timeout?: number; }; prompt?: { timeout?: number; }; } /** A single element of the roots option: a URI string or a full Root object. */ type RootInput = string | Root; /** * Static list of roots, or an async callback invoked on each roots/list request. * URI strings are normalised to file:// URIs automatically; relative paths are * resolved against process.cwd(). */ type RootsValue = RootInput[] | (() => RootInput[] | Promise); interface ClientOptions { /** * Authentication to attach to HTTP requests. * A plain string is treated as a Bearer token. */ auth?: BearerAuth | OAuth | AsyncHeaderAuth | string; /** * Identity to advertise to the MCP server. Defaults to `fastmcp-ts` at the * installed package version. Set this when FastMCP is embedded in another * application. */ clientInfo?: Implementation; handlers?: ClientHandlers; /** * Additional capabilities to advertise to the server. FastMCP preserves * their settings while adding capabilities inferred from handlers and roots. */ capabilities?: ClientCapabilities; /** * Filesystem roots to advertise to the server. * Accepts a static array of strings / Root objects, or an async callback * invoked on each roots/list request (useful for dynamic root sets). */ roots?: RootsValue; /** * When true (default), the MCP initialize handshake is performed * automatically inside connect(). */ autoInitialize?: boolean; defaultOptions?: ClientDefaultOptions; /** * Protocol version negotiation (protocol revision 2026-07-28 and later). * The default is `{ mode: 'auto' }`: connect() probes the server once with * `server/discover` and uses the modern (2026-07-28) era on definitive * modern evidence, falling back to the plain legacy `initialize` handshake * on anything else (a method-not-found answer, silence on a local stdio * pipe, a probe child that exits). The probe is stall-safe in the SDK: on * stdio it runs against a short-lived sibling process and a timeout falls * back to legacy, while on HTTP — where silence means an outage — a probe * timeout rejects with a typed error instead of hanging. Pass * `{ mode: 'legacy' }` to opt out: no probe, the 2025 sequence * byte-identical to prior behavior. Pass `{ mode: { pin: '2026-07-28' } }` * to require the modern era outright — connect() throws if the server * cannot speak it. See `getProtocolEra()` to read the negotiated result * after connecting. */ versionNegotiation?: VersionNegotiationOptions; /** * A cached era verdict from a previous connection to the same server, so * connect() can skip the `server/discover` probe entirely. Takes precedence * over `versionNegotiation`. `{ kind: 'modern', discover }` adopts a prior * `DiscoverResult` with zero round trips; `{ kind: 'legacy' }` skips the probe * and runs the plain legacy `initialize` handshake. Freshness is the caller's * responsibility — a stale modern verdict fails loudly at the first request; a * stale legacy verdict succeeds silently forever. Reuse only within one * authorization context. */ prior?: PriorDiscovery; /** * Multi-round-trip auto-fulfilment (protocol revision 2026-07-28). On the * modern era, servers obtain client input (elicitation, sampling, roots) by * answering a request with an `input_required` result instead of a * server→client request. By default the client fulfils these automatically * through the same `handlers.sampling`/`handlers.elicitation` callbacks, * retrying up to `maxRounds` times. Set `autoFulfill: false` for manual mode. * Has no effect on legacy-era connections. Passed through verbatim to the SDK * client. */ inputRequired?: InputRequiredOptions; /** * The response-cache store backing cacheable results (SEP-2549 `ttlMs`/ * `cacheScope` hints on `listTools`/`listResources`/`listResourceTemplates`/ * `listPrompts`/`readResource`). Defaults to a fresh in-memory store per * client (the SDK's own default) when omitted. Passed through verbatim. */ responseCacheStore?: ResponseCacheStore; /** * Opaque per-principal identifier for response-cache writes whose * server-reported `cacheScope` is `'private'`. Set this to a stable identity * of the authorization context (e.g. the auth subject) when one * `responseCacheStore` backs several principals. Passed through verbatim. */ cachePartition?: string; /** * TTL (ms) applied when a cacheable result arrives without a `ttlMs` field. * Default `0` (never served from cache, but still stored). Passed through * verbatim. */ defaultCacheTtlMs?: number; /** * Allow the deprecated SSE transport when a target URL's path indicates SSE * (e.g. ends in `/sse`). Default `false` — such URLs throw a clear error * pointing at Streamable HTTP and this flag, rather than silently connecting * over a transport the MCP SDK itself marks `@deprecated`. When enabled, a * one-time deprecation warning is logged via `console.warn`. */ legacySSE?: boolean; } interface MultiServerOptions { /** * Identity to advertise to every MCP server. Defaults to `fastmcp-ts` at the * installed package version. Set this when FastMCP is embedded in another * application. */ clientInfo?: Implementation; handlers?: ClientHandlers; /** * Additional capabilities to advertise to every server. FastMCP combines * them with capabilities inferred from handlers and roots. */ capabilities?: ClientCapabilities; /** file:// URIs to advertise to all servers as accessible roots. */ roots?: string[]; defaultOptions?: ClientDefaultOptions; /** * Protocol version negotiation, applied identically to every server in the * config (protocol revision 2026-07-28 and later). See * `ClientOptions.versionNegotiation` on the single-server `Client` — same * semantics, just applied per sub-client here since each connected server * negotiates its own era independently. Default `{ mode: 'auto' }`: each * sub-client probes its server once and falls back to legacy when the * server offers no modern era; `{ mode: 'legacy' }` opts every connection * out of the probe. */ versionNegotiation?: VersionNegotiationOptions; } declare class MultiServerClient implements IClient { private _clients; private _connectPromise; private _connected; /** URI (or namespaced template URI) → server name, populated by list calls */ private _uriMap; private readonly _config; private readonly _clientInfo; private readonly _handlers; private readonly _roots; private readonly _capabilities; private readonly _defaultOptions; private readonly _versionNegotiation; private _resourceSubscriptions; /** Modern-era (2026-07-28) subscriptions/listen streams, one per server that * currently has active resource subscriptions — see Client's own field of the * same purpose for the full rationale. Keyed by server name since each * connected server negotiates its own era independently. */ private _resourceListenSubscriptions; /** Per-server log level set by setLogLevel() for servers negotiated to modern * era — see Client's own field of the same purpose for the full rationale. * Keyed by server name since each connected server negotiates its own era * independently and may therefore need (or not need) meta-threading. */ private _logLevels; constructor(config: McpConfig, options?: MultiServerOptions); connect(): Promise; private _doConnect; close(): Promise; [Symbol.asyncDispose](): Promise; isConnected(): boolean; static connect(config: McpConfig, options?: MultiServerOptions): Promise; /** * The protocol era negotiated with a specific named server: `'modern'` for * 2026-07-28, `'legacy'` for 2025-11-25 and earlier, `undefined` if the * server name is unknown or not yet connected. See * `MultiServerOptions.versionNegotiation` — the same mode is requested of * every server, but each negotiates (and may land on) its own era * independently, so this is necessarily per-server rather than a single * client-wide value. */ getProtocolEra(serverName: string): ProtocolEra | undefined; /** See Client.ping's docs — the same era-routing applies here, per server, * since each connected server negotiates its own era independently. */ ping(options?: RequestOptions): Promise; listTools(options?: RequestOptions): Promise; callTool(name: string, args?: Record, options?: CallToolOptions): Promise>; callToolRaw(name: string, args?: Record, options?: CallToolOptions): Promise>; listResources(options?: RequestOptions): Promise; listResourceTemplates(options?: RequestOptions): Promise; readResource(uri: string, options?: RequestOptions): Promise>; listPrompts(options?: RequestOptions): Promise; getPrompt(name: string, args?: Record, options?: RequestOptions): Promise; /** See Client.subscribeResource's docs — the same era-routing applies here, * per server, since each connected server negotiates its own era. */ subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise; unsubscribeResource(uri: string, options?: RequestOptions): Promise; /** Re-opens server-scoped listen stream for its currently-subscribed URIs — see * Client's own private method of the same purpose for the full rationale. */ private _refreshResourceListenSubscriptionForServer; complete(ref: { type: 'ref/prompt'; name: string; } | { type: 'ref/resource'; uri: string; }, argument: { name: string; value: string; }, context?: { arguments?: Record; }, options?: RequestOptions): Promise; /** See Client.setLogLevel's docs — the same era-routing applies here, per * server: legacy sends the real `logging/setLevel` RPC; modern records the * level and threads it into `_meta` on that server's subsequent requests via * `_metaParamsFor`, since `logging/setLevel` is absent from the modern wire * registry (SEP-2577). */ setLogLevel(level: LoggingLevel, options?: RequestOptions): Promise; private _assertConnected; private _parseNamespacedName; private _sdkForServer; private _buildSdkClient; private _registerHandlers; /** See Client._metaParams's docs — the same purpose, per server name, since * each connected server may be on a different era and have a different * recorded log level (or none). */ private _metaParamsFor; private _toSdkOptions; } declare class ToolCallError extends Error { readonly content: ContentBlock[]; constructor(message: string, content: ContentBlock[]); } declare class Client implements IClient { private _sdkClient; private _refCount; private _connectPromise; private readonly _resourceSubscriptions; /** The modern-era (2026-07-28) `subscriptions/listen` stream backing all active * resource subscriptions — resources/subscribe and resources/unsubscribe are * 2025-only RPCs, physically absent from the modern method registry. Unused * (stays undefined) on a legacy connection. */ private _resourceListenSubscription; /** The live SDK transport captured at connect(). Its `finishAuth()` redeems the * authorization code both during connect-time recovery and a post-connect * step-up re-authorization. */ private _transport; /** Single-flight guard for a post-connect re-authorization round: concurrent * interactive-OAuth 401s share one `waitForCallback`→`finishAuth` round rather * than each opening its own. Cleared when the round settles. */ private _reauthPromise; /** Max post-connect re-authorization rounds per request (see `_reauthRetry`): * 1 for ordinary step-up, 2 to also cover SEP-2352 authorization-server * migration (the AS changes mid-request). Bounded so a genuinely unauthorized * request cannot loop forever. */ private static readonly _MAX_REAUTH_ROUNDS; private readonly _input; private readonly _auth; private readonly _clientInfo; private readonly _handlers; private readonly _roots; private readonly _capabilities; private readonly _autoInitialize; private readonly _versionNegotiation; private readonly _prior; private readonly _inputRequired; private readonly _responseCacheStore; private readonly _cachePartition; private readonly _defaultCacheTtlMs; private readonly _legacySSE; /** Set by setLogLevel() on a modern-era connection (where logging/setLevel is * not a wire method) — threaded into `_meta[LOG_LEVEL_META_KEY]` on every * subsequent request. Unused on legacy era, where setLogLevel() still sends * the real `logging/setLevel` RPC. */ private _logLevel; private readonly _defaultOptions; constructor(input: ClientTransportInput, options?: ClientOptions); connect(): Promise; private _doConnect; private _extractServerUrl; close(): Promise; [Symbol.asyncDispose](): Promise; isConnected(): boolean; /** Creates a connected MultiServerClient when given a multi-entry McpConfig. */ static connect(input: McpConfig, options?: MultiServerOptions): Promise; /** Creates a connected Client for a single-server transport. Use with `await using` for automatic cleanup. */ static connect(input: ClientTransportInput, options?: ClientOptions): Promise; /** * Liveness check. On a legacy-era connection this sends the `ping` RPC. On a * modern (2026-07-28) connection `ping` is not a wire method — the era's * registry deliberately excludes it — so this sends `server/discover` * instead: any successful response is equally strong liveness evidence, and * `discover()` is the SDK-native modern equivalent (rather than a * hand-rolled substitute). Returns `false` only on legacy `ping`'s own * result; a modern-era failure throws, matching `ping()`'s existing * throw-on-failure contract. */ ping(options?: RequestOptions): Promise; /** * The protocol era negotiated at connect(): `'modern'` for 2026-07-28 (per-request * envelope), `'legacy'` for 2025-11-25 and earlier (the `initialize` handshake). * `undefined` before connect(). See `ClientOptions.versionNegotiation`. */ getProtocolEra(): ProtocolEra | undefined; /** * The connected server's self-reported identity (`serverInfo`: name, version, * and optional title / websiteUrl / icons), when it identified itself. On a * legacy connection it comes from the `initialize` result, where it is * required. On a modern (2026-07-28) connection it comes from the * `server/discover` result's metadata — FastMCP servers advertise it there, * but an anonymous modern server may omit it, leaving this `undefined`. * `undefined` before connect(). */ getServerInfo(): Implementation | undefined; /** * The server's `instructions` string, when the server provided one — from * the legacy `initialize` result or, on a modern (2026-07-28) connection, * from the `server/discover` result. `undefined` otherwise and before * connect(). */ getInstructions(): string | undefined; /** * The capabilities the server advertised during connection — on the legacy * `initialize` result, or on the `server/discover` result for a modern * (2026-07-28) connection. `undefined` before connect(). */ getServerCapabilities(): ServerCapabilities | undefined; listTools(options?: RequestOptions): Promise; callTool(name: string, args?: Record, options?: CallToolOptions): Promise>; /** Returns the full result including isError without throwing. */ callToolRaw(name: string, args?: Record, options?: CallToolOptions): Promise>; listResources(options?: RequestOptions): Promise; listResourceTemplates(options?: RequestOptions): Promise; readResource(uri: string, options?: RequestOptions): Promise>; /** Returns the raw SDK ReadResourceResult without unwrapping. */ readResourceRaw(uri: string, options?: RequestOptions): Promise<{ [x: string]: unknown; contents: ({ uri: string; text: string; mimeType?: string | undefined; _meta?: { [x: string]: unknown; } | undefined; } | { uri: string; blob: string; mimeType?: string | undefined; _meta?: { [x: string]: unknown; } | undefined; })[]; _meta?: { [x: string]: unknown; "io.modelcontextprotocol/serverInfo"?: { version: string; name: string; websiteUrl?: string | undefined; description?: string | undefined; icons?: { src: string; mimeType?: string | undefined; sizes?: string[] | undefined; theme?: "light" | "dark" | undefined; }[] | undefined; title?: string | undefined; } | undefined; } | undefined; }>; /** * Subscribes to change notifications for a resource URI. `handler` fires whenever * the server sends a matching update, on either protocol era: on a legacy * (2025-era) connection via the `resources/subscribe` RPC and unsolicited * `notifications/resources/updated` push, or on a modern (2026-07-28) connection * via a `subscriptions/listen` stream opted into `resourceSubscriptions` — both * dispatch to the same `notifications/resources/updated` handler registered in * `_registerHandlers`, so this method is the only era-aware part. * * On a modern connection this rejects when the server's acknowledged filter does * not include the URI — that is how a server without the `resources.subscribe` * capability declines per-resource subscriptions, and registering a handler that * can never fire would fail silently instead. */ subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise; unsubscribeResource(uri: string, options?: RequestOptions): Promise; /** * Re-opens the modern-era resource-subscription listen stream with the current * set of subscribed URIs. `listen()` has no in-place filter update, so every * subscribe/unsubscribe on a modern connection closes the existing stream (if * any) and opens a fresh one — `subscribeResource`/`unsubscribeResource` are not * expected to be called at a high frequency, so this is not a hot path. */ private _refreshResourceListenSubscription; listPrompts(options?: RequestOptions): Promise; getPrompt(name: string, args?: Record, options?: RequestOptions): Promise; /** True when the connection is modern and both sides advertise {@link SKILLS_EXTENSION_ID}. */ supportsSkills(): boolean; /** Lists every skill the server publishes. */ listSkills(options?: RequestOptions): Promise; /** Fetches one skill entry by the URI of its `SKILL.md` resource. */ getSkill(uri: string, options?: RequestOptions): Promise; /** Reads every file of a skill, each verified against the skill's entry. */ readSkill(uri: string, options?: RequestOptions): Promise; private _skills; private _skillsUnavailableReason; complete(ref: { type: 'ref/prompt'; name: string; } | { type: 'ref/resource'; uri: string; }, argument: { name: string; value: string; }, context?: { arguments?: Record; }, options?: RequestOptions): Promise; /** * Sets the minimum severity level for log messages sent by the server. On a * legacy-era connection this sends the `logging/setLevel` RPC, unchanged. On * a modern (2026-07-28) connection `logging/setLevel` is deprecated (SEP-2577) * and physically absent from the era's registry — there is no RPC to send. * Instead, the level is recorded and threaded into * `_meta['io.modelcontextprotocol/logLevel']` on every subsequent request via * `_metaParams()`, per request; user-supplied `_meta` still wins if a caller * passes one explicitly (there is no such call site in this class today). */ setLogLevel(level: LoggingLevel, options?: RequestOptions): Promise; private _sdk; /** * Runs a post-connect SDK request and, when it rejects with the SDK's * `UnauthorizedError` under an interactive {@link OAuth} provider, performs a * bounded number of step-up re-authorization rounds — the same * `waitForCallback`→`finishAuth` machinery `connect()` uses — retrying the * request after each. * * This closes the post-connect gap for interactive OAuth: a request that 401s * (missing/expired token) or 403s with an `insufficient_scope` challenge (a * broader scope is required for that operation) drives the SDK transport to * issue a fresh, scope-honoring authorization request and re-throw * `UnauthorizedError` — the transport picks the challenged/union scope itself * (`extractWWWAuthenticateParams` + `computeScopeUnion`); this wrapper only * completes the interrupted round and retries. * * The bound is {@link Client._MAX_REAUTH_ROUNDS}. One round covers ordinary * step-up (a single 401/403). Two rounds cover SEP-2352 authorization-server * migration: the first authenticated request flips the MCP server to a new * authorization server (its Protected Resource Metadata now lists a different * issuer), so the very next request 401s and must re-discover, re-register, and * re-authorize at the NEW server — a second round on the same wrapped request. * Beyond the bound the `UnauthorizedError` propagates, so a genuinely * unauthorized request never loops forever. * * Each round is single-flight: concurrent 401s share one `_reauthPromise`, and * each caller retries its own request after it resolves — a burst never opens * multiple browsers. * * Non-interactive auth is never re-authorized here — the original error * propagates unchanged. `BearerAuth` and custom headers carry no interactive * step, and a {@link ClientCredentials} scope failure is a machine-to-machine * misconfiguration (no user, no browser), not a step-up flow. * `MultiServerClient` configures no interactive OAuth by design, so this path * stays inert there. * * Every outbound request method routes through this wrapper, with one * exception: {@link Client.notifyRootsChanged} calls the SDK directly. It sends * a notification, not a request, so there is no response to 401/403 and * nothing to retry. * * `BrowserOAuth` (`extends OAuth`) is covered by the same guard, and its * `waitForCallback` is sound for a post-connect round — `redirectToAuthorization` * arms the callback promise before the transport re-throws. Two browser-only * caveats apply, honestly: in **popup** mode `window.open` needs a user gesture, * so a step-up fired from a request not within one is blocked and the re-auth * error propagates (call from a click); **redirect** mode navigates the whole * tab away (`window.location.assign`), destroying this in-flight retry — the app * recovers via `resumeFromRedirect()` on the return load and a fresh request, * not by this wrapper. The migration second round inherits the popup caveat: it * runs outside the original user gesture, so under `BrowserOAuth` popup mode it * hits the user-gesture block and surfaces as that error rather than opening a * second popup. */ private _reauthRetry; /** Single-flight wrapper around one re-authorization round. */ private _reauthorize; /** * One re-authorization round: await the authorization callback the SDK * transport already armed (its 401/403 handling ran discovery + opened the * browser with the challenged scope), then `finishAuth()` redeems the code for * the broader-scope token on the live transport. The very next request reads * that token via the transport's per-request bearer-token bridge. * * After redeeming, the cached discovery state is invalidated so that the NEXT * authorization leg re-discovers the Protected Resource Metadata from scratch. * The SDK's `auth()` otherwise pins to the authorization server it first cached * and re-fetches PRM only when it has none — so it never notices a SEP-2352 * migration (PRM `authorization_servers` changing to a new issuer). Clearing it * here (after the current round's callback leg has already consumed it) makes a * subsequent 401 re-run discovery, land on the new server, and register there. * Re-discovery is idempotent when the server has NOT migrated, so ordinary * step-up and token-refresh rounds are unaffected beyond one extra metadata * fetch. */ private _doReauthorize; /** * Redeems the authorization callback params for tokens on `transport`, if it * exposes `finishAuth` (StreamableHTTP and SSE do). Shared by connect-time * recovery and post-connect step-up. Passing `URLSearchParams` (not a bare * code) lets the SDK validate the RFC 9207 `iss` before redeeming. */ private _finishAuth; /** * The `_meta` override to merge into an outbound request's params — carries * `_logLevel` (set by setLogLevel() on a modern-era connection) so it rides * along on every subsequent request. Returns `undefined` (not `{}`) when * there is nothing to attach, so `{...this._metaParams()}` is a no-op and * callers that pass no params at all can keep passing `undefined` unchanged. */ private _metaParams; private _toSdkOptions; private _buildListChangedConfig; private _registerHandlers; /** * Notify the connected server that the client's roots list has changed. * The server should re-issue a roots/list request to get the updated list. */ notifyRootsChanged(): Promise; } type Result = { ok: true; value: T; } | { ok: false; error: E; }; declare function toResult(fn: Promise | (() => Promise)): Promise>; /** * Resolve a concrete model name from the server's modelPreferences. * A plain string always uses that model; a function inspects the preferences. */ type ModelSelector = string | ((prefs: ModelPreferences | undefined) => string); /** Called with each text token as it is streamed from the provider. */ type OnTokenCallback = (token: string) => void; interface SamplingAdapterOptions { /** Override or replace the model selection logic. */ modelSelector?: ModelSelector; /** Fired for each streamed text token. Tool-use deltas are not surfaced. */ onToken?: OnTokenCallback; } /** Implemented by all sampling adapters. */ interface SamplingAdapter { asHandler(): SamplingHandler; } interface GenericCompletionParams { model: string; messages: SamplingMessage[]; system?: string; /** Defaulted to 1024 when absent in the original request. */ maxTokens: number; temperature?: number; stopSequences?: string[]; tools?: Tool[]; toolChoice?: ToolChoice; onToken?: OnTokenCallback; } type GenericCompletionFn = (params: GenericCompletionParams) => Promise; /** * Contribution template. Wraps any async function into a SamplingHandler. * * The adapter resolves the model from modelPreferences, defaults maxTokens, * and threads onToken through. Message format conversion, tool translation, * and streaming are the caller's responsibility. * * Example: * ```ts * const adapter = new GenericSamplingAdapter(async ({ model, messages }) => { * const text = await myLlm.complete(model, messages) * return { role: 'assistant', content: { type: 'text', text }, model, stopReason: 'endTurn' } * }) * ``` */ declare class GenericSamplingAdapter implements SamplingAdapter { private readonly _fn; private readonly _options; constructor(fn: GenericCompletionFn, options?: SamplingAdapterOptions & { defaultModel?: string; }); asHandler(): SamplingHandler; } declare class AnthropicSamplingAdapter implements SamplingAdapter { private readonly _client; private readonly _options; constructor(client: Anthropic, options?: SamplingAdapterOptions & { defaultModel?: string; }); asHandler(): SamplingHandler; } declare class OpenAISamplingAdapter implements SamplingAdapter { private readonly _client; private readonly _options; constructor(client: OpenAI, options?: SamplingAdapterOptions & { defaultModel?: string; }); asHandler(): SamplingHandler; } declare class GoogleSamplingAdapter implements SamplingAdapter { private readonly _client; private readonly _options; constructor(client: GoogleGenAI, options?: SamplingAdapterOptions & { defaultModel?: string; }); asHandler(): SamplingHandler; } export { AnthropicSamplingAdapter, type AnySamplingResult, type AssertionSource, type AsyncHeaderAuth, BearerAuth, BrowserOAuth, type BrowserOAuthOptions, type CallToolOptions, type CallToolResult, Client, ClientCredentials, type ClientCredentialsOptions, type ClientDefaultOptions, type ClientHandlers, type ClientOptions, type ClientSecretAuthMethod, type ClientSecretCredentialsOptions, type ClientTransportInput, type CompletionResult, type ElicitationHandler, EnterpriseManagedAuth, type EnterpriseManagedOptions, FileTokenStorage, type GenericCompletionFn, type GenericCompletionParams, GenericSamplingAdapter, GoogleSamplingAdapter, type IClient, type IPromptsClient, type IResourcesClient, type IToolsClient, InMemoryStore, IndexedDBStore, JwtBearerAuth, type JwtBearerOptions, type KeyValueStore, type ListChangedHandler, LocalStorageStore, type LogHandler, type LogMessage, type McpConfig, type McpServerEntry, type McpServerLike, type McpServerValue, type ModelSelector, MultiServerClient, type MultiServerOptions, OAuth, type OAuthOptions, type OAuthToken, type OnTokenCallback, OpenAISamplingAdapter, type PrivateKeyJwtCredentialsOptions, type ProgressHandler, type RequestOptions, type ResourceUpdateHandler, type Result, type RootInput, type RootsValue, type SamplingAdapter, type SamplingAdapterOptions, type SamplingHandler, type SkillContents, StdioTransport, ToolCallError, defaultLogHandler, defaultProgressHandler, handleOAuthCallback, toResult };