/** * MCP Client wrapper for `@revealui/mcp`. * * Phase: Stage 0 of the MCP v1 plan (see `.jv/docs/mcp-productionization-scope.md`). * * Wraps `@modelcontextprotocol/sdk`'s `Client` with a RevealUI-shaped surface: * transport selection, capability enforcement (method throws a typed error if * the server doesn't advertise the feature), per-URI resource subscription * fan-out, and application-layer handlers for the server-initiated primitives * (sampling, elicitation, roots). * * Stage 0 completion as of PR-0.3: * PR-0.1 — resources + prompts. * PR-0.2 — sampling + elicitation + roots + completions. * PR-0.3 — logging, progress, cancellation, generic notification routing, * per-request options (signal + onProgress + timeout) threaded * through every client-initiated call. * * The hypervisor (`./hypervisor.ts`) continues to speak its custom JSON-RPC * for tool calls. Stage 1 migrates the hypervisor to route through this * client so transport abstraction (Streamable HTTP) lands cleanly. */ import type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js'; import { type StreamableHTTPClientTransportOptions, type StreamableHTTPReconnectionOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; import type { AnyObjectSchema, SchemaOutput } from '@modelcontextprotocol/sdk/server/zod-compat.js'; import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; import { type CallToolResult, type ClientCapabilities, type CompleteRequest, type CompleteResult, type CreateMessageRequest, type CreateMessageResult, type ElicitRequest, type ElicitResult, type LoggingLevel, type LoggingMessageNotification, type Progress, type Prompt, type PromptMessage, type PromptReference, type Resource, type ResourceContents, type ResourceTemplateReference, type Root, type ServerCapabilities, type Tool } from '@modelcontextprotocol/sdk/types.js'; /** * Spawn a local subprocess and talk MCP over its stdio. * Matches `StdioClientTransport` from the SDK; we surface the fields we use. */ export type StdioTransportOptions = { kind: 'stdio'; command: string; args?: string[]; env?: Record; cwd?: string; }; /** * Inject a pre-built SDK `Transport`. Intended for tests (`InMemoryTransport`) * and for experimental transports not yet first-classed in this discriminator. */ export type CustomTransportOptions = { kind: 'custom'; transport: Transport; }; /** * Talk MCP over the spec's Streamable HTTP transport. The preferred remote * transport as of the 2025 spec revision — supports request/response JSON, * SSE streaming for progress/notifications, and OAuth 2.1 for authenticated * deployments. * * Pass `authProvider` to enable OAuth 2.1 (Authorization Code + PKCE, * Dynamic Client Registration, automatic refresh). `@revealui/mcp` ships * `McpOAuthProvider` at `./oauth.js` — construct it with a * `(tenant, server, vault)` triple and a redirect URL, and attach it here. * If `authProvider` is omitted and the server requires auth, the SDK throws * `UnauthorizedError` on connect. Callers who need static bearer-token auth * instead can pass the header via `requestInit.headers`. */ export type StreamableHttpTransportOptions = { kind: 'streamable-http'; /** MCP endpoint URL (e.g. `https://example.com/mcp`). */ url: string | URL; /** Fetch `RequestInit` applied to every outgoing request. Use this for * headers, credentials, custom signals, etc. */ requestInit?: RequestInit; /** Override `fetch`. Defaults to global `fetch`. */ fetch?: typeof fetch; /** Reuse a server-issued session ID (e.g. for reconnection). */ sessionId?: string; /** SSE reconnection tuning (delays, retry ceiling). */ reconnectionOptions?: StreamableHTTPReconnectionOptions; /** * OAuth 2.1 client provider. The SDK invokes discovery, DCR, PKCE, and * refresh flows through this object, persisting state via the provider's * storage methods. See `./oauth.js` for a revvault-backed implementation. */ authProvider?: OAuthClientProvider; }; export type TransportOptions = StdioTransportOptions | CustomTransportOptions | StreamableHttpTransportOptions; export type { StreamableHTTPClientTransportOptions, StreamableHTTPReconnectionOptions }; /** * Handle a `sampling/createMessage` request FROM the server. The server is * asking the client to run an LLM completion on its behalf — typically the * client delegates to the application's configured LLM provider. * * Providing this handler causes the client to advertise the `sampling` * capability during initialize; omitting it leaves the capability absent and * the server will treat sampling as unsupported. */ export type SamplingHandler = (params: CreateMessageRequest['params']) => Promise; /** * Handle an `elicitation/create` request FROM the server. The server is * asking the client to elicit structured input from the user (form mode) or * direct them to a URL (URL mode). The handler is responsible for rendering * UI and returning the user's response. */ export type ElicitationHandler = (params: ElicitRequest['params']) => Promise; /** * Return the client's current roots (directories or URI namespaces it * exposes to the server). Called each time the server issues `roots/list`, * so the provider SHOULD return current state rather than a cached snapshot. * * Providing this advertises the `roots` capability (with `listChanged: true` * — the client can notify via `notifyRootsListChanged()`). */ export type RootsProvider = () => Root[] | Promise; /** * Per-request options applied to every client-initiated call. Mirrors the * SDK's `RequestOptions` but exposes only the fields we expect consumers to * use (we may add more as Stage 0 / 1 evolve). * * - `signal` — pass an `AbortSignal` to cancel the request mid-flight. When * aborted the SDK emits `notifications/cancelled` to the server and the * pending promise rejects with an AbortError. * - `onProgress` — subscribe to per-request progress notifications. The SDK * automatically correlates `notifications/progress` by the progress token * and invokes this callback. * - `timeout` — request-level timeout in ms. If exceeded the SDK raises a * `RequestTimeout` error. Absent = SDK default. * - `resetTimeoutOnProgress` — if true, receiving a progress notification * resets the timeout clock. Useful for long-running operations. */ export type McpRequestOptions = { signal?: AbortSignal; onProgress?: (progress: Progress) => void; timeout?: number; resetTimeoutOnProgress?: boolean; }; export type McpClientOptions = { /** Advertised to the server during `initialize`. Required by spec. */ clientInfo: { name: string; version: string; }; /** Where and how to reach the server. */ transport: TransportOptions; /** Handle `sampling/createMessage` requests from the server. */ samplingHandler?: SamplingHandler; /** Handle `elicitation/create` requests from the server. */ elicitationHandler?: ElicitationHandler; /** Provide the client's current roots in response to `roots/list`. */ rootsProvider?: RootsProvider; }; /** * Thrown when a caller invokes a method that requires a server-side capability * the server did NOT advertise during initialize. Signals a misconfiguration * or a version mismatch — not a transient failure; do not retry. */ export declare class McpCapabilityError extends Error { readonly capability: string; constructor(capability: string); } /** * Thrown when a method is called before `connect()` has resolved. */ export declare class McpNotConnectedError extends Error { constructor(method: string); } export type { CallToolResult, ClientCapabilities, CompleteRequest, CompleteResult, CreateMessageRequest, CreateMessageResult, ElicitRequest, ElicitResult, LoggingLevel, LoggingMessageNotification, Progress, Prompt, PromptMessage, PromptReference, Resource, ResourceContents, ResourceTemplateReference, Root, ServerCapabilities, Tool, }; /** Parameters delivered to a `subscribeResource` handler. */ export type ResourceUpdatedParams = { uri: string; }; /** Return shape of `getPrompt` — the spec's `GetPromptResult`, narrowed. */ export type GetPromptResult = { description?: string; messages: PromptMessage[]; }; /** Either a prompt or a resource-template reference — the two valid targets * for `completions/complete`. */ export type CompletionReference = PromptReference | ResourceTemplateReference; /** The completion result returned by `complete()`. */ export type Completion = CompleteResult['completion']; /** Parameters delivered to an `onLog` subscriber. */ export type LogMessageParams = LoggingMessageNotification['params']; export declare class McpClient { private readonly sdk; private readonly options; private connected; /** * Tracks the Streamable HTTP transport when that kind is in use, so * `finishAuth()` can delegate to it. Set by `createTransport`, cleared * on `close()`. */ private httpTransport?; private readonly resourceSubscribers; private readonly listChangedHandlers; /** * Subscribers per notification schema. First `on(schema, handler)` call for * a schema registers a single fan-out handler with the SDK; subsequent * calls just add to the Set. Removing the last subscriber keeps the SDK * handler registered (no public API to unregister by schema) — empty * fan-out is a cheap no-op. */ private readonly notificationSubscribers; constructor(options: McpClientOptions); /** * Connect the underlying transport and run MCP `initialize`. Idempotent: * calling twice is a no-op on the second call. */ connect(): Promise; /** * Close the underlying transport and invalidate the client. Idempotent. */ close(): Promise; /** * Finalize an OAuth 2.1 authorization flow initiated by an `authProvider`. * * After `connect()` triggers `OAuthClientProvider.redirectToAuthorization`, * the user completes consent at the authorization server and is redirected * back to the caller's callback URL with a `code` query parameter. The * caller passes that `code` here, which delegates to the Streamable HTTP * transport's `finishAuth`: the SDK exchanges the code (with the stored * PKCE verifier) at the token endpoint and persists the resulting token * set via the provider's `saveTokens`. Retry `connect()` afterward. * * Throws if the client is not using the `streamable-http` transport or if * `connect()` has not been called yet (the transport is constructed during * `connect`). */ finishAuth(authorizationCode: string): Promise; /** Server capabilities returned by `initialize`. Undefined before connect. */ getServerCapabilities(): ServerCapabilities | undefined; listResources(options?: McpRequestOptions): Promise; readResource(uri: string, options?: McpRequestOptions): Promise; /** * Subscribe to updates for a single resource URI. The returned function * removes this subscription (and unsubscribes on the wire once no * subscribers remain for the URI). * * Requires the server to advertise `resources.subscribe`; throws * `McpCapabilityError` otherwise. */ subscribeResource(uri: string, handler: (params: ResourceUpdatedParams) => void, options?: McpRequestOptions): Promise<() => Promise>; /** * Enumerate tools the server exposes. Requires the server to advertise the * `tools` capability. * * Returns the SDK's `Tool` shape unchanged — name, description, input JSON * Schema (as `inputSchema`), and any spec-defined annotations. */ listTools(options?: McpRequestOptions): Promise; /** * Invoke a tool by name with the supplied structured arguments. Requires * the server to advertise `tools`. Returns the full SDK `CallToolResult` * (structured content + isError flag + optional `_meta`). * * Tool failures surface as `{ isError: true, content: [...] }` rather than * thrown exceptions — the server is explicitly asked to communicate tool * errors in-band per the MCP spec. Transport-level failures still throw. */ callTool(name: string, args?: Record, options?: McpRequestOptions): Promise; listPrompts(options?: McpRequestOptions): Promise; getPrompt(name: string, args?: Record, options?: McpRequestOptions): Promise; onResourcesListChanged(handler: () => void): () => void; onPromptsListChanged(handler: () => void): () => void; onToolsListChanged(handler: () => void): () => void; /** * Notify the server that the client's roots have changed. The server will * typically re-fetch via `roots/list`, which routes to the `rootsProvider` * passed at construction. No-op if the client wasn't constructed with a * `rootsProvider` — advertising list-changed without a provider is * nonsensical, so we fail fast. */ notifyRootsListChanged(): Promise; /** * Request argument completions from the server. The reference points at a * prompt or resource-template; the server returns suggestion values for * the named argument given the current partial value. */ complete(reference: CompletionReference, argument: { name: string; value: string; }, options?: McpRequestOptions): Promise; /** * Set the minimum log level the server should emit. Requires the server to * advertise the `logging` capability. */ setLoggingLevel(level: LoggingLevel, options?: McpRequestOptions): Promise; /** * Subscribe to server-emitted log messages. Returns an unregister function. * * Implemented on top of the generic `on()` fan-out, so multiple subscribers * coexist cleanly (admin UI, CLI logger, telemetry exporter, …). */ onLog(handler: (params: LogMessageParams) => void): () => void; /** * Subscribe to arbitrary server notifications by zod schema. First * subscription per schema installs a single SDK handler that fans out to * every registered subscriber; later subscriptions join the existing fan. * Returns an unregister function. * * Typically callers use the purpose-built subscribers (`onLog`, * `onResourcesListChanged`, `subscribeResource`) rather than this. Use * `on()` for schemas the client doesn't yet expose a named subscriber for. */ on(schema: T, handler: (notification: SchemaOutput) => void): () => void; ping(options?: McpRequestOptions): Promise; private createTransport; private assertConnected; private requireCapability; private addListChanged; private fireListChanged; } //# sourceMappingURL=client.d.ts.map