import type { Stream } from 'node:stream'; import { MastraBase } from '@mastra/core/base'; import type { Tool } from '@mastra/core/tools'; import type { GetPromptResult, ListPromptsResult, ListResourcesResult, ListResourceTemplatesResult, ReadResourceResult } from '@modelcontextprotocol/client'; import { ProgressClientActions } from './actions/progress.js'; import { PromptClientActions } from './actions/prompt.js'; import { ResourceClientActions } from './actions/resource.js'; import type { ProgressHandler, InternalMastraMCPClientOptions, MCPServerImplementation, SerializableMCPToolDefinition } from './types.js'; export type { LoggingLevel, LogMessage, LogHandler, ProgressHandler, MastraFetchLike, MastraMCPServerDefinition, MCPClientCapabilities, MCPClientProtocolVersion, MCPInputRequest, MCPInputRequestHandler, InternalMastraMCPClientOptions, RequireToolApproval, RequireToolApprovalFn, RequireToolApprovalContext, SerializableMCPToolDefinition, } from './types.js'; /** * OAuth authorization state of an MCP server connection. * * - `needs-auth`: the server rejected the connection with a 401 and interactive * authorization is required (see MCPClient.authenticate) * - `authorized`: the server accepted the configured authProvider's credentials * * Servers without an authProvider never carry an auth state. */ export type MCPServerAuthState = 'needs-auth' | 'authorized'; /** * Non-enumerable metadata attached to structured tool execute results so * `toModelOutput` can read MCP `content` without changing the execute return shape. * * When a tool has an `outputSchema` and the server returns `structuredContent`, * `execute()` returns that structured value directly. The rest of the * CallToolResult envelope is preserved on non-enumerable symbols: * - {@link MCP_CALL_TOOL_CONTENT} holds the MCP `content` blocks (model-facing text). * - {@link MCP_CALL_TOOL_META} holds the result-level `_meta` (e.g. `ui.resourceUri` * used by MCP Apps hosts), with `ui.serverId` stamped by the client. * * Read them with {@link getMcpCallToolContent} and {@link getMcpCallToolMeta}. * Note: scalar or `null` structured results cannot carry properties, so these * channels are only available when `structuredContent` is an object or array. */ export declare const MCP_CALL_TOOL_CONTENT: unique symbol; /** Non-enumerable result-level `_meta` attached to structured tool execute results. */ export declare const MCP_CALL_TOOL_META: unique symbol; /** * Read the MCP `content` blocks preserved on a structured tool execute result. * Returns `undefined` for scalar results or results without a hidden content channel. */ export declare function getMcpCallToolContent(output: unknown): unknown; /** * Read the result-level `_meta` preserved on a structured tool execute result * (e.g. `_meta.ui.resourceUri` for MCP Apps detection). Returns `undefined` for * scalar results or results whose CallToolResult had no `_meta`. */ export declare function getMcpCallToolMeta(output: unknown): Record | undefined; /** * Internal MCP client implementation for connecting to a single MCP server. * * Probes the server with `server/discover` unless `protocolVersion` pins a * revision, then speaks whichever revision was negotiated. On 2026-07-28 there is * no session, embedded input requests are answered through the configured * `inputRequests` handler, and change notifications arrive on one managed * `subscriptions/listen` stream (see {@link subscribeResource}). Those two * facilities fail on a legacy negotiation; everything else works on either revision. * * @internal */ export declare class InternalMastraMCPClient extends MastraBase { name: string; private client; private readonly timeout; private logHandler?; private readonly serverLogLevel?; private enableProgressTracking; private serverConfig; private transport?; private pendingAuthTransport?; private clientBaseOnClose?; private clientConnectionOnClose?; private _authState?; private operationContextStore; private exitHookUnsubscribe?; private sigTermHandler?; private sigHupHandler?; private serverInstructions?; private serverImplementation?; /** The verdict of the last successful probe, reused so reconnects skip it. */ private priorDiscovery?; private readonly requireToolApproval; private readonly onToolError; private jsonSchemaValidator?; private jsonSchemaValidatorPromise?; /** Provides access to resource operations (list, read, notifications) */ readonly resources: ResourceClientActions; /** Provides access to prompt operations (list, get, notifications) */ readonly prompts: PromptClientActions; /** Provides access to progress operations (notifications) */ readonly progress: ProgressClientActions; /** * @internal */ constructor({ name, version, server, timeout }: InternalMastraMCPClientOptions); /** * Log a message at the specified level */ private log; /** * Request metadata every outgoing request carries: the per-request log-level * opt-in (when enabled) and the W3C trace fields resolved for this request, * merged under caller-supplied keys. */ private requestMeta; private buildStdioEnv; private connectStdio; private connectHttp; /** * Detaches whatever transport is still attached to the underlying SDK Client. * * The SDK assigns its internal `_transport` before `transport.start()` and never * clears it when `start()` throws, so a stale transport can remain attached and * make every subsequent `client.connect()` throw "Already connected to a * transport". Mastra's own `this.transport` is only assigned after a successful * connect, so disconnect/forceReconnect never see the stale one. */ private detachStaleClientTransport; /** * Severs the mutual references between the SDK client and a stale transport * without closing it, so a later close() of the stale transport cannot reach * into the SDK client and clear the state of a newer live connection. */ private severClientTransportLink; /** * Closes and clears any transport retained from an unfinished authorization * flow. Safe to call when nothing is pending. */ private closePendingAuthTransport; /** * Records that the server rejected the connection with a 401 and keeps the * transport that started the authorization flow so finishAuth can complete it. */ private markNeedsAuth; /** * OAuth authorization state of this server connection, when it has an authProvider. * * @internal */ get authState(): MCPServerAuthState | undefined; /** * Completes a pending OAuth authorization-code flow. * * Exchanges the authorization code captured at the redirect URI on the same * transport that started the flow, then leaves the client ready to connect(). * The RFC 9207 `iss` captured at the redirect is validated against the * discovered authorization server before the code is exchanged. * * @internal */ finishAuth(authorizationCode: string, issuer?: string): Promise; private isConnected; private reconnectPromise; /** * Change notifications the caller has asked for. The client keeps exactly one * `subscriptions/listen` stream open for this interest set, replaces it when the * set changes and reopens it after a reconnect. */ private subscriptionInterest; private subscriptionStream?; private subscriptionUpdate; private lifecycleGeneration; /** * Connects to the MCP server using the configured transport. * * Safe to call multiple times - returns existing connection if already connected. * * @internal */ connect(): Promise; /** * Installs the process-exit and signal handlers that tear this client down when the * host process goes away. Idempotent, so repeated connects add at most one of each. */ private registerProcessHooks; /** * Removes whatever {@link registerProcessHooks} installed. Keyed on the handlers this * client actually registered rather than on connection state, so a client that never * reached a transport still releases its process listeners. */ private unregisterProcessHooks; /** * Gets the stderr stream of the child process, if using stdio transport with `stderr: 'pipe'`. * * @internal */ get stderr(): Stream | null; get instructions(): string | undefined; /** The identity (`serverInfo`) the server announced on connect; `undefined` until connected or if the server announced none. */ get serverInfo(): MCPServerImplementation | undefined; /** The protocol revision negotiated with the server; `undefined` until connected. */ get negotiatedProtocolVersion(): string | undefined; private rememberNegotiation; /** Fails a call that only the 2026-07-28 revision supports when the server negotiated an older one. */ private assertCurrentRevision; get forwardInstructions(): boolean; get instructionsMaxLength(): number; disconnect(): Promise; /** * Forces a reconnection to the MCP server by disconnecting and reconnecting. * * @internal */ forceReconnect(): Promise; private reconnectAfterTransportFailure; listResources(): Promise; readResource(uri: string): Promise; listResourceTemplates(): Promise; /** * Fetch the list of available prompts from the MCP server. */ listPrompts(): Promise; /** * Get a prompt and its dynamic messages from the server. */ getPrompt({ name, args }: { name: string; args?: Record; }): Promise; private hasSubscriptionInterest; private subscriptionFilter; /** Serializes stream replacements so concurrent mutations apply in order. */ private enqueueSubscriptionUpdate; /** * Opens a `subscriptions/listen` stream for the current interest set, then closes the * previous one so no notification is lost between filters. Resource subscriptions the * server declines are an error; declined list-changed bits only mean the server has * nothing to announce. */ private replaceSubscriptionStream; private closeSubscriptionStream; /** Applies an interest change to the live stream when connected; otherwise connect() opens it. */ private applySubscriptionInterest; /** * Subscribes to `notifications/resources/updated` for a resource. The subscription is * carried on the client's single `subscriptions/listen` stream and survives reconnects. */ subscribeResource(uri: string): Promise; unsubscribeResource(uri: string): Promise; private updateResourceSubscriptions; setPromptListChangedNotificationHandler(handler: () => void): Promise; setToolListChangedNotificationHandler(handler: () => void): Promise; setResourceUpdatedNotificationHandler(handler: (params: { uri: string; }) => void): void; setResourceListChangedNotificationHandler(handler: () => void): Promise; setProgressNotificationHandler(handler: ProgressHandler): void; private getJsonSchemaValidator; private convertInputSchema; /** * Wraps the output schema with a validator that always succeeds. The tool's execute wrapper * returns the full CallToolResult envelope when there is no structuredContent (and for * in-band errors with `onToolError: 'return'`), which would never match the advertised * outputSchema — so enforcement happens inside the execute wrapper, scoped to the * structuredContent path (see buildToolFromListEntry). The JSON schema is surfaced here * for documentation. */ private convertOutputSchema; /** * Returns the server's tool catalog as plain, serializable definitions. */ toolDefinitions(): Promise>; private toSerializableDefinition; /** * Rebuilds an executable Mastra tool from a cached {@link SerializableMCPToolDefinition}. * The client connects lazily on the first execution. */ toolFromDefinition({ definition }: { definition: SerializableMCPToolDefinition; }): Tool; tools(): Promise>>; /** * Single conversion path shared by live discovery and cached hydration, so hydrated * tools behave identically to discovered ones. */ private buildToolFromListEntry; private stampServerIdInMeta; } //# sourceMappingURL=client.d.ts.map