UNPKG

@tanstack/ai-mcp

Version:

Host-side Model Context Protocol client for TanStack AI: discover and run MCP server tools, resources, and prompts in any adapter's chat() loop, with generated end-to-end types.

150 lines (149 loc) • 5.12 kB
import { AuthInfo } from '@modelcontextprotocol/server'; /** * One question for the user. * `message` is the text the user sees. */ export type ToolInputRequest = { message: string; }; /** * The prompt for `ctx.context.sample`. * `messages` is the list the model reads. * Each item has `role` and `content`. */ export type SampleRequest = { messages: ReadonlyArray<{ role: string; content: string; }>; }; type WaitForInput<TAnswer> = (request: ToolInputRequest) => Promise<TAnswer>; type SampleModel<TSample> = (request: SampleRequest) => Promise<TSample>; /** The error a tool gets when the user declines or cancels an input request. */ export declare const inputDeclinedMessage = "The user did not accept the input request."; /** * Callbacks for one tool call. * * Era `2025` needs `waitForInput` and `clientSample`. * Era `2026` uses `sample` for the model result. * On a protocol 2026 retry, `inputAnswer` is the answer. * `inputDeclined` is true when the user declined or cancelled the request. */ export type ServerToolContextOptions<TAnswer, TSample> = { era: '2025'; waitForInput: WaitForInput<TAnswer>; clientSample: SampleModel<TSample>; sample?: SampleModel<TSample>; authInfo?: AuthInfo; } | { era: '2026'; inputAnswer?: TAnswer; inputDeclined?: boolean; sample?: SampleModel<TSample>; authInfo?: AuthInfo; }; /** * The tool stopped because it needs user input. * * `resultType` is `input_required`. * `request` is the object passed to `ctx.context.requestInput`. * Catch this error, then run the tool again with `inputAnswer`. * `ctx.context.requestInput` then returns that answer. * * @param request - The input request from the tool * * @example * try { * await tool(ctx) * } catch (error) { * if (error instanceof ToolInputRequiredError) { * error.request * } * } */ export declare class ToolInputRequiredError extends Error { readonly request: ToolInputRequest; readonly resultType: "input_required"; constructor(request: ToolInputRequest); } /** * The runtime context that `createMCPServer` gives a tool on `ctx.context`. * * Pass it as the context type of `.server()`, so `ctx.context.requestInput` * and `ctx.context.sample` type-check. * * @example * ```ts * const askCity = toolDefinition({ * name: 'ask_city', * description: 'Ask which city to use', * inputSchema: z.object({}), * }).server<MCPToolContext>(async (_args, ctx) => { * const city = await ctx.context.requestInput({ message: 'Which city?' }) * return { city } * }) * ``` */ export type MCPToolContext<TContext extends Record<string, unknown> = Record<never, never>> = ReturnType<typeof createServerToolContext> & TContext; /** * Builds the context for one tool call. * * On era `2025`, `requestInput` waits on `waitForInput`. * The same tool call then continues with that answer. * If `inputAnswer` is absent on era `2026`, `requestInput` throws * {@link ToolInputRequiredError}. * If you pass `inputAnswer`, the tool runs again. * Then `requestInput` returns that answer. * If you pass `inputDeclined`, `requestInput` throws an Error instead. * Code before `requestInput` runs on both calls. * * On era `2025`, `sample` calls `clientSample`. * It does not call the `sample` adapter. * On era `2026`, `sample` calls the `sample` adapter. * It does not call `clientSample`. * If `sample` is absent on era `2026`, `ctx.sample` throws an Error. * The error message contains `sample`. * * @param options - The protocol era and the callbacks for that era * * @example * const ctx = createServerToolContext({ * era: '2025', * waitForInput: async () => 'Paris', * clientSample: async () => 'A short draft', * }) * await ctx.requestInput({ message: 'Which city?' }) */ export declare function createServerToolContext<TAnswer = unknown, TSample = unknown>(options: ServerToolContextOptions<TAnswer, TSample>): { /** * The verified token of the caller, from the server `auth` option. * `undefined` when the server has no `auth`, or for * `createMCPClient({ server })`. */ authInfo: AuthInfo | undefined; /** * Asks the user for a value. * * On era `2025`, this waits on `waitForInput` and returns that answer. * If `inputAnswer` is absent on era `2026`, this throws * {@link ToolInputRequiredError}. * If `inputAnswer` is present, this returns that answer. * If the user declined or cancelled, this throws an Error. * On era `2026`, a second call in the same tool call throws an Error. * * @param request - The question for the user */ requestInput(request: ToolInputRequest): Promise<TAnswer>; /** * Asks for a model result. * * On era `2025`, this calls `clientSample`. * On era `2026`, this calls the `sample` adapter. * If that adapter is absent, this throws an Error. * The message contains `sample`. * * @param request - The prompt for the model */ sample(request: SampleRequest): Promise<TSample>; }; export {};