import { z } from 'zod'; import { CreateMessageRequest, CreateMessageResult, CreateMessageResultWithTools, CreateMessageRequestParamsWithTools, Tool as SDKTool, ToolChoice, ElicitResult, ElicitRequestFormParams, ElicitRequestURLParams } from '@modelcontextprotocol/sdk/types.js'; import { ImageContent } from '../transports/utils/image-handler.js'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js'; import type { ToolAppConfig } from '../apps/types.js'; import type { ResourceDefinition } from '../resources/BaseResource.js'; /** * Schema definition for a single field in an elicitation form. * Only flat objects with primitive properties are supported per the MCP spec. */ export type ElicitationFieldSchema = { /** Mark this field as not required. Defaults to required if omitted. */ optional?: boolean; } & ({ type: 'string'; title?: string; description?: string; minLength?: number; maxLength?: number; format?: 'email' | 'uri' | 'date' | 'date-time'; default?: string; } | { type: 'string'; title?: string; description?: string; enum: string[]; default?: string; } | { type: 'string'; title?: string; description?: string; oneOf: { const: string; title: string; }[]; default?: string; } | { type: 'number' | 'integer'; title?: string; description?: string; minimum?: number; maximum?: number; default?: number; } | { type: 'boolean'; title?: string; description?: string; default?: boolean; } | { type: 'array'; title?: string; description?: string; minItems?: number; maxItems?: number; items: { type: 'string'; enum: string[]; } | { anyOf: { const: string; title: string; }[]; }; default?: string[]; }); export { ElicitResult, ElicitRequestFormParams, ElicitRequestURLParams }; export { CreateMessageResultWithTools, CreateMessageRequestParamsWithTools, ToolChoice }; /** * Convenience alias for ElicitResult from the SDK. * Contains action ('accept' | 'decline' | 'cancel') and optional content. */ export type ElicitationResult = ElicitResult; /** * A tool definition for use in sampling requests. * Describes a tool that the LLM can invoke during sampling. */ export interface SamplingTool { name: string; description?: string; inputSchema: { type: 'object'; properties?: Record; required?: string[]; [key: string]: unknown; }; } /** * Controls tool usage behavior in sampling requests. */ export interface SamplingToolChoice { mode?: 'auto' | 'required' | 'none'; } /** * Represents a root directory or URI returned by the client. */ export interface Root { uri: string; name?: string; } export type ToolInputSchema = { [K in keyof T]: { type: z.ZodType; description: string; }; }; export type ToolInput> = { [K in keyof T]: z.infer; }; export type InferSchemaType = TSchema extends z.ZodObject ? z.infer : TSchema extends ToolInputSchema ? T : never; export type MCPInput = MCPTool> = InferSchemaType; export interface MCPIcon { src: string; mimeType?: string; sizes?: string[]; } export interface ToolAnnotations { title?: string; readOnlyHint?: boolean; destructiveHint?: boolean; idempotentHint?: boolean; openWorldHint?: boolean; } export interface ToolExecution { taskSupport?: 'forbidden' | 'optional' | 'required'; } export interface ContentAnnotations { audience?: ('user' | 'assistant')[]; priority?: number; lastModified?: string; } export type TextContent = { type: 'text'; text: string; annotations?: ContentAnnotations; }; export interface AudioContent { type: 'audio'; data: string; mimeType: string; annotations?: ContentAnnotations; } export interface ResourceLinkContent { type: 'resource_link'; uri: string; name?: string; description?: string; mimeType?: string; annotations?: ContentAnnotations; } export interface EmbeddedResourceContent { type: 'resource'; resource: { uri: string; mimeType?: string; text?: string; blob?: string; annotations?: ContentAnnotations; }; } export type ToolContent = TextContent | ImageContent | AudioContent | ResourceLinkContent | EmbeddedResourceContent; export type ToolResponse = { content: ToolContent[]; structuredContent?: Record; isError?: boolean; }; export interface ToolProtocol extends SDKTool { name: string; description: string; toolDefinition: { name: string; description: string; inputSchema: { type: 'object'; properties?: Record; required?: string[]; }; title?: string; icons?: MCPIcon[]; annotations?: ToolAnnotations; execution?: ToolExecution; outputSchema?: Record; _meta?: Record; }; toolCall(request: { params: { name: string; arguments?: Record; }; }): Promise; injectServer(server: Server): void; setProgressToken(token?: string | number): void; setAbortSignal(signal?: AbortSignal): void; } /** * Base class for MCP tools using Zod schemas for input validation and type inference. * * Define your tool schema using Zod with descriptions: * ```typescript * const schema = z.object({ * message: z.string().describe("The message to process") * }); * * class MyTool extends MCPTool { * name = "my_tool"; * description = "My tool description"; * schema = schema; * * async execute(input: McpInput) { * // input is fully typed from your schema * return input.message; * } * } * ``` */ export declare abstract class MCPTool = any, TSchema = any> implements ToolProtocol { abstract name: string; abstract description: string; protected abstract schema: TSchema extends z.ZodObject ? TSchema : TSchema extends ToolInputSchema ? TSchema : z.ZodObject | ToolInputSchema; protected useStringify: boolean; /** Optional MCP App configuration. When set, the tool's definition * includes _meta.ui linking it to an auto-registered UI resource. */ protected app?: ToolAppConfig; title?: string; icons?: MCPIcon[]; annotations?: ToolAnnotations; execution?: ToolExecution; protected outputSchemaShape?: z.ZodObject; [key: string]: unknown; private server; private _progressToken?; private _abortSignal?; /** * Sets the progress token for this tool call. * Called by MCPServer before executing the tool. */ setProgressToken(token?: string | number): void; /** * Sets the abort signal for this tool call. * Called by MCPServer before executing the tool. */ setAbortSignal(signal?: AbortSignal): void; /** * Returns the abort signal for the current tool invocation, if available. * Tools can check this signal to detect cancellation and abort long-running work. * * @example * ```typescript * async execute(input: MCPInput) { * for (const item of items) { * if (this.abortSignal?.aborted) { * return "Operation cancelled"; * } * await processItem(item); * } * } * ``` */ protected get abortSignal(): AbortSignal | undefined; /** * Report progress for the current tool invocation. * Only sends a notification if a progress token was provided by the client. * * @param progress - Current progress value (MUST increase with each call) * @param total - Optional total value for progress calculation * @param message - Optional human-readable progress message * * @example * ```typescript * async execute(input: MCPInput) { * for (let i = 0; i < items.length; i++) { * await this.reportProgress(i + 1, items.length, `Processing item ${i + 1}`); * await processItem(items[i]); * } * } * ``` */ protected reportProgress(progress: number, total?: number, message?: string): Promise; /** * Send a logging message to the client via the MCP logging protocol. * Uses the SDK server's sendLoggingMessage method if available. * * @param level - The log level (debug, info, notice, warning, error, critical, alert, emergency) * @param data - The data to log (string, object, etc.) * @param loggerName - Optional logger name; defaults to this tool's name */ protected log(level: 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency', data: unknown, loggerName?: string): Promise; /** * Injects the server into this tool to allow sampling requests. * Automatically called by the MCP server when registering the tool. * In multi-transport mode, the server reference is updated per-invocation * so that progress/sampling/roots route through the correct transport. */ injectServer(server: Server): void; /** * Submit a sampling request to the client via the MCP sampling protocol. * Can only be called from within a tool's execute() method after the server * has been injected. * * @example * ```typescript * const result = await this.samplingRequest({ * messages: [{ role: "user", content: { type: "text", text: "Hello!" } }], * maxTokens: 100 * }); * ``` */ protected samplingRequest(request: CreateMessageRequest['params'], options?: RequestOptions): Promise; /** * Submit a sampling request with tool support to the client via the MCP sampling protocol. * The client's LLM may invoke the provided tools during sampling, returning tool_use * content blocks in the response. * * Can only be called from within a tool's execute() method after the server * has been injected. * * @param request Sampling parameters including messages, maxTokens, and tools. * @param options Optional request options (timeout, signal, etc.). * @returns The sampling result, which may contain tool_use content blocks. * * @example * ```typescript * const result = await this.samplingRequestWithTools({ * messages: [{ role: "user", content: { type: "text", text: "What is the weather?" } }], * maxTokens: 500, * tools: [{ * name: "get_weather", * description: "Get weather for a location", * inputSchema: { type: "object", properties: { city: { type: "string" } }, required: ["city"] } * }], * toolChoice: { mode: "auto" } * }); * ``` */ protected samplingRequestWithTools(request: CreateMessageRequestParamsWithTools, options?: RequestOptions): Promise; /** * Request structured input from the user via form-based elicitation. * Can only be called from within a tool's execute() method after the server * has been injected. The client must support elicitation capabilities. * * Only flat objects with primitive properties are supported per the MCP spec. * Do NOT request sensitive data (passwords, API keys) via form mode -- use * elicitUrl() for sensitive data instead. * * @param message A human-readable message explaining why the input is needed. * @param schema A record of field names to their schema definitions. * @param options Optional request options (timeout, signal, etc.). * @returns The elicitation result with action ('accept', 'decline', 'cancel') and optional content. * * @example * ```typescript * const result = await this.elicit("Please provide your details", { * name: { type: "string", description: "Your full name" }, * age: { type: "number", description: "Your age", minimum: 18 } * }); * * if (result.action === 'accept') { * console.log(result.content?.name); * } * ``` */ protected elicit(message: string, schema: Record, options?: RequestOptions): Promise; /** * Request the user to visit a URL for sensitive out-of-band interaction. * Use this for passwords, OAuth flows, payments, or anything that should NOT * pass through the MCP client. * * The client will ask the user for consent before opening the URL. * An 'accept' response means the user agreed to open the URL, NOT that * the interaction is complete. * * @param message A human-readable message explaining why the URL visit is needed. * @param url The URL the user should navigate to. * @param elicitationId A unique identifier for this elicitation (used for completion notifications). * @param options Optional request options (timeout, signal, etc.). * @returns The elicitation result with action ('accept', 'decline', 'cancel'). * * @example * ```typescript * const result = await this.elicitUrl( * "Please authorize access to your account", * "https://auth.example.com/authorize?state=abc123", * "auth-flow-abc123" * ); * * if (result.action === 'accept') { * // User agreed to open the URL -- wait for completion * } * ``` */ protected elicitUrl(message: string, url: string, elicitationId: string, options?: RequestOptions): Promise; /** * Request the list of root URIs from the connected client. * Roots represent the top-level directories or URIs that the client * has made available to the server. * * Can only be called from within a tool's execute() method after the server * has been injected. The client must support roots capability. * * @param options Optional request options (timeout, signal, etc.). * @returns An array of root objects with uri and optional name. * * @example * ```typescript * const roots = await this.getRoots(); * for (const root of roots) { * console.log(`Root: ${root.name ?? root.uri}`); * } * ``` */ protected getRoots(options?: RequestOptions): Promise; /** * Validates the tool schema. This is called automatically when the tool is registered * with an MCP server, but can also be called manually for testing. */ validate(): void; private isZodObjectSchema; get inputSchema(): { type: 'object'; properties?: Record; required?: string[]; }; private generateSchemaFromZodObject; private extractFieldInfo; private getJsonSchemaTypeFromZod; private generateSchemaFromLegacyFormat; get toolDefinition(): { _meta?: { ui: { visibility?: import("../apps/types.js").AppToolVisibility | undefined; resourceUri: string; }; } | undefined; outputSchema?: Record | undefined; execution?: ToolExecution | undefined; annotations?: ToolAnnotations | undefined; icons?: MCPIcon[] | undefined; title?: string | undefined; name: string; description: string; inputSchema: { type: "object"; properties?: Record; required?: string[]; }; }; private generateOutputSchema; protected abstract execute(input: TSchema extends z.ZodObject ? z.infer : TInput): Promise; toolCall(request: { params: { name: string; arguments?: Record; }; }): Promise; private validateInput; private getJsonSchemaType; private isFieldOptional; protected createSuccessResponse(data: unknown): ToolResponse; protected createErrorResponse(error: Error): ToolResponse; private isImageContent; private isTextContent; private isAudioContent; private isResourceLinkContent; private isEmbeddedResourceContent; private isValidContent; /** Returns true if this tool has an attached MCP App. */ get hasApp(): boolean; /** Returns the ResourceDefinition for the attached app, or undefined. */ get appResourceDefinition(): ResourceDefinition | undefined; /** Reads the attached app's HTML content. Throws if no app is configured. */ readAppContent(): Promise; protected fetch(url: string, init?: RequestInit): Promise; } /** * Helper function to define tool schemas with required descriptions. * This ensures all fields have descriptions at build time. * * @example * const schema = defineSchema({ * name: z.string().describe("User's name"), * age: z.number().describe("User's age") * }); */ export declare function defineSchema(shape: T): z.ZodObject;