UNPKG

mcp-framework

Version:

Framework for building Model Context Protocol (MCP) servers in Typescript

125 lines (124 loc) 4.1 kB
import { z } from 'zod'; import { Tool as SDKTool } from '@modelcontextprotocol/sdk/types.js'; import { ImageContent } from '../transports/utils/image-handler.js'; export type ToolInputSchema<T> = { [K in keyof T]: { type: z.ZodType<T[K]>; description: string; }; }; export type ToolInput<T extends ToolInputSchema<any>> = { [K in keyof T]: z.infer<T[K]['type']>; }; export type InferSchemaType<TSchema> = TSchema extends z.ZodObject<any> ? z.infer<TSchema> : TSchema extends ToolInputSchema<infer T> ? T : never; export type MCPInput<T extends MCPTool<any, any> = MCPTool<any, any>> = InferSchemaType<T['schema']>; export type TextContent = { type: 'text'; text: string; }; export type ErrorContent = { type: 'error'; text: string; }; export type ToolContent = TextContent | ErrorContent | ImageContent; export type ToolResponse = { content: ToolContent[]; }; export interface ToolProtocol extends SDKTool { name: string; description: string; toolDefinition: { name: string; description: string; inputSchema: { type: 'object'; properties?: Record<string, unknown>; required?: string[]; }; }; toolCall(request: { params: { name: string; arguments?: Record<string, unknown>; }; }): Promise<ToolResponse>; } /** * 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<this>) { * // input is fully typed from your schema * return input.message; * } * } * ``` */ export declare abstract class MCPTool<TInput extends Record<string, any> = any, TSchema = any> implements ToolProtocol { abstract name: string; abstract description: string; protected abstract schema: TSchema extends z.ZodObject<any> ? TSchema : TSchema extends ToolInputSchema<any> ? TSchema : z.ZodObject<any> | ToolInputSchema<TInput>; protected useStringify: boolean; [key: string]: unknown; /** * 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<string, unknown>; required?: string[]; }; private generateSchemaFromZodObject; private extractFieldInfo; private getJsonSchemaTypeFromZod; private generateSchemaFromLegacyFormat; get toolDefinition(): { name: string; description: string; inputSchema: { type: "object"; properties?: Record<string, unknown>; required?: string[]; }; }; protected abstract execute(input: TSchema extends z.ZodObject<any> ? z.infer<TSchema> : TInput): Promise<unknown>; toolCall(request: { params: { name: string; arguments?: Record<string, unknown>; }; }): Promise<ToolResponse>; private validateInput; private getJsonSchemaType; protected createSuccessResponse(data: unknown): ToolResponse; protected createErrorResponse(error: Error): ToolResponse; private isImageContent; private isTextContent; private isErrorContent; private isValidContent; protected fetch<T>(url: string, init?: RequestInit): Promise<T>; } /** * 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<T extends z.ZodRawShape>(shape: T): z.ZodObject<T>;