fastmcp 1.19.1 → 1.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/FastMCP.js CHANGED
@@ -719,7 +719,7 @@ var FastMCP = class extends FastMCPEventEmitter {
719
719
  });
720
720
  }
721
721
  });
722
- console.error(
722
+ console.info(
723
723
  `server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`
724
724
  );
725
725
  } else {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/FastMCP.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ClientCapabilities,\n CompleteRequestSchema,\n CreateMessageRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListResourceTemplatesRequestSchema,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n Root,\n RootsListChangedNotificationSchema,\n ServerCapabilities,\n SetLevelRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { z } from \"zod\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { readFile } from \"fs/promises\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { EventEmitter } from \"events\";\nimport Fuse from \"fuse.js\";\nimport { startSSEServer } from \"mcp-proxy\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport parseURITemplate from \"uri-templates\";\n\nexport type SSEServer = {\n close: () => Promise<void>;\n};\n\ntype FastMCPEvents = {\n connect: (event: { session: FastMCPSession }) => void;\n disconnect: (event: { session: FastMCPSession }) => void;\n};\n\ntype FastMCPSessionEvents = {\n rootsChanged: (event: { roots: Root[] }) => void;\n error: (event: { error: Error }) => void;\n};\n\n/**\n * Generates an image content object from a URL, file path, or buffer.\n */\nexport const imageContent = async (\n input: { url: string } | { path: string } | { buffer: Buffer },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n if (\"url\" in input) {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image from URL: ${response.statusText}`);\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } else if (\"path\" in input) {\n rawData = await readFile(input.path);\n } else if (\"buffer\" in input) {\n rawData = input.buffer;\n } else {\n throw new Error(\n \"Invalid input: Provide a valid 'url', 'path', or 'buffer'\",\n );\n }\n\n const mimeType = await fileTypeFromBuffer(rawData);\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n type: \"image\",\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n } as const;\n};\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\nexport class UnexpectedStateError extends FastMCPError {\n public extras?: Extras;\n\n public constructor(message: string, extras?: Extras) {\n super(message);\n this.name = new.target.name;\n this.extras = extras;\n }\n}\n\n/**\n * An error that is meant to be surfaced to the user.\n */\nexport class UserError extends UnexpectedStateError {}\n\ntype ToolParameters = z.ZodTypeAny;\n\ntype Literal = boolean | null | number | string | undefined;\n\ntype SerializableValue =\n | Literal\n | SerializableValue[]\n | { [key: string]: SerializableValue };\n\ntype Progress = {\n /**\n * The progress thus far. This should increase every time progress is made, even if the total is unknown.\n */\n progress: number;\n /**\n * Total number of items to process (or total progress required), if known.\n */\n total?: number;\n};\n\ntype Context = {\n reportProgress: (progress: Progress) => Promise<void>;\n log: {\n debug: (message: string, data?: SerializableValue) => void;\n error: (message: string, data?: SerializableValue) => void;\n info: (message: string, data?: SerializableValue) => void;\n warn: (message: string, data?: SerializableValue) => void;\n };\n};\n\ntype TextContent = {\n type: \"text\";\n text: string;\n};\n\nconst TextContentZodSchema = z\n .object({\n type: z.literal(\"text\"),\n /**\n * The text content of the message.\n */\n text: z.string(),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n type: \"image\";\n data: string;\n mimeType: string;\n};\n\nconst ImageContentZodSchema = z\n .object({\n type: z.literal(\"image\"),\n /**\n * The base64-encoded image data.\n */\n data: z.string().base64(),\n /**\n * The MIME type of the image. Different providers may support different image types.\n */\n mimeType: z.string(),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype Content = TextContent | ImageContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n]) satisfies z.ZodType<Content>;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType<ContentResult>;\n\ntype Completion = {\n values: string[];\n total?: number;\n hasMore?: boolean;\n};\n\n/**\n * https://github.com/modelcontextprotocol/typescript-sdk/blob/3164da64d085ec4e022ae881329eee7b72f208d4/src/types.ts#L983-L1003\n */\nconst CompletionZodSchema = z.object({\n /**\n * An array of completion values. Must not exceed 100 items.\n */\n values: z.array(z.string()).max(100),\n /**\n * The total number of completion options available. This can exceed the number of values actually sent in the response.\n */\n total: z.optional(z.number().int()),\n /**\n * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.\n */\n hasMore: z.optional(z.boolean()),\n}) satisfies z.ZodType<Completion>;\n\ntype Tool<Params extends ToolParameters = ToolParameters> = {\n name: string;\n description?: string;\n parameters?: Params;\n execute: (\n args: z.infer<Params>,\n context: Context,\n ) => Promise<string | ContentResult | TextContent | ImageContent>;\n};\n\ntype ResourceResult =\n | {\n text: string;\n }\n | {\n blob: string;\n };\n\ntype InputResourceTemplateArgument = Readonly<{\n name: string;\n description?: string;\n complete?: ArgumentValueCompleter;\n}>;\n\ntype ResourceTemplateArgument = Readonly<{\n name: string;\n description?: string;\n complete?: ArgumentValueCompleter;\n}>;\n\ntype ResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n uriTemplate: string;\n name: string;\n description?: string;\n mimeType?: string;\n arguments: Arguments;\n complete?: (name: string, value: string) => Promise<Completion>;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n};\n\ntype ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {\n [K in T[number][\"name\"]]: string;\n};\n\ntype InputResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n uriTemplate: string;\n name: string;\n description?: string;\n mimeType?: string;\n arguments: Arguments;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n};\n\ntype Resource = {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n load: () => Promise<ResourceResult | ResourceResult[]>;\n complete?: (name: string, value: string) => Promise<Completion>;\n};\n\ntype ArgumentValueCompleter = (value: string) => Promise<Completion>;\n\ntype InputPromptArgument = Readonly<{\n name: string;\n description?: string;\n required?: boolean;\n complete?: ArgumentValueCompleter;\n enum?: string[];\n}>;\n\ntype PromptArgumentsToObject<T extends { name: string; required?: boolean }[]> =\n {\n [K in T[number][\"name\"]]: Extract<\n T[number],\n { name: K }\n >[\"required\"] extends true\n ? string\n : string | undefined;\n };\n\ntype InputPrompt<\n Arguments extends InputPromptArgument[] = InputPromptArgument[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n name: string;\n description?: string;\n arguments?: InputPromptArgument[];\n load: (args: Args) => Promise<string>;\n};\n\ntype PromptArgument = Readonly<{\n name: string;\n description?: string;\n required?: boolean;\n complete?: ArgumentValueCompleter;\n enum?: string[];\n}>;\n\ntype Prompt<\n Arguments extends PromptArgument[] = PromptArgument[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: PromptArgument[];\n complete?: (name: string, value: string) => Promise<Completion>;\n description?: string;\n load: (args: Args) => Promise<string>;\n name: string;\n};\n\ntype ServerOptions = {\n name: string;\n version: `${number}.${number}.${number}`;\n};\n\ntype LoggingLevel =\n | \"debug\"\n | \"info\"\n | \"notice\"\n | \"warning\"\n | \"error\"\n | \"critical\"\n | \"alert\"\n | \"emergency\";\n\nconst FastMCPSessionEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;\n} = EventEmitter;\n\nclass FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}\n\ntype SamplingResponse = {\n model: string;\n stopReason?: \"endTurn\" | \"stopSequence\" | \"maxTokens\" | string;\n role: \"user\" | \"assistant\";\n content: TextContent | ImageContent;\n};\n\nexport class FastMCPSession extends FastMCPSessionEventEmitter {\n #capabilities: ServerCapabilities = {};\n #clientCapabilities?: ClientCapabilities;\n #loggingLevel: LoggingLevel = \"info\";\n #prompts: Prompt[] = [];\n #resources: Resource[] = [];\n #resourceTemplates: ResourceTemplate[] = [];\n #roots: Root[] = [];\n #server: Server;\n\n constructor({\n name,\n version,\n tools,\n resources,\n resourcesTemplates,\n prompts,\n }: {\n name: string;\n version: string;\n tools: Tool[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n prompts: Prompt[];\n }) {\n super();\n\n if (tools.length) {\n this.#capabilities.tools = {};\n }\n\n if (resources.length || resourcesTemplates.length) {\n this.#capabilities.resources = {};\n }\n\n if (prompts.length) {\n for (const prompt of prompts) {\n this.addPrompt(prompt);\n }\n\n this.#capabilities.prompts = {};\n }\n\n this.#capabilities.logging = {};\n\n this.#server = new Server(\n { name: name, version: version },\n { capabilities: this.#capabilities },\n );\n\n this.setupErrorHandling();\n this.setupLoggingHandlers();\n this.setupRootsHandlers();\n this.setupCompleteHandlers();\n\n if (tools.length) {\n this.setupToolHandlers(tools);\n }\n\n if (resources.length || resourcesTemplates.length) {\n for (const resource of resources) {\n this.addResource(resource);\n }\n\n this.setupResourceHandlers(resources);\n\n if (resourcesTemplates.length) {\n for (const resourceTemplate of resourcesTemplates) {\n this.addResourceTemplate(resourceTemplate);\n }\n\n this.setupResourceTemplateHandlers(resourcesTemplates);\n }\n }\n\n if (prompts.length) {\n this.setupPromptHandlers(prompts);\n }\n }\n\n private addResource(inputResource: Resource) {\n this.#resources.push(inputResource);\n }\n\n private addResourceTemplate(inputResourceTemplate: InputResourceTemplate) {\n const completers: Record<string, ArgumentValueCompleter> = {};\n\n for (const argument of inputResourceTemplate.arguments ?? []) {\n if (argument.complete) {\n completers[argument.name] = argument.complete;\n }\n }\n\n const resourceTemplate = {\n ...inputResourceTemplate,\n complete: async (name: string, value: string) => {\n if (completers[name]) {\n return await completers[name](value);\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#resourceTemplates.push(resourceTemplate);\n }\n\n private addPrompt(inputPrompt: InputPrompt) {\n const completers: Record<string, ArgumentValueCompleter> = {};\n const enums: Record<string, string[]> = {};\n\n for (const argument of inputPrompt.arguments ?? []) {\n if (argument.complete) {\n completers[argument.name] = argument.complete;\n }\n\n if (argument.enum) {\n enums[argument.name] = argument.enum;\n }\n }\n\n const prompt = {\n ...inputPrompt,\n complete: async (name: string, value: string) => {\n if (completers[name]) {\n return await completers[name](value);\n }\n\n if (enums[name]) {\n const fuse = new Fuse(enums[name], {\n keys: [\"value\"],\n });\n\n const result = fuse.search(value);\n\n return {\n values: result.map((item) => item.item),\n total: result.length,\n };\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#prompts.push(prompt);\n }\n\n public get clientCapabilities(): ClientCapabilities | null {\n return this.#clientCapabilities ?? null;\n }\n\n public get server(): Server {\n return this.#server;\n }\n\n #pingInterval: ReturnType<typeof setInterval> | null = null;\n\n public async requestSampling(\n message: z.infer<typeof CreateMessageRequestSchema>[\"params\"],\n ): Promise<SamplingResponse> {\n return this.#server.createMessage(message);\n }\n\n public async connect(transport: Transport) {\n if (this.#server.transport) {\n throw new UnexpectedStateError(\"Server is already connected\");\n }\n\n await this.#server.connect(transport);\n\n let attempt = 0;\n\n while (attempt++ < 10) {\n const capabilities = await this.#server.getClientCapabilities();\n\n if (capabilities) {\n this.#clientCapabilities = capabilities;\n\n break;\n }\n\n await delay(100);\n }\n\n if (!this.#clientCapabilities) {\n console.warn('[warning] FastMCP could not infer client capabilities')\n }\n\n if (this.#clientCapabilities?.roots) {\n const roots = await this.#server.listRoots();\n\n this.#roots = roots.roots;\n }\n\n this.#pingInterval = setInterval(async () => {\n try {\n await this.#server.ping();\n } catch (error) {\n this.emit(\"error\", {\n error: error as Error,\n });\n }\n }, 1000);\n }\n\n public get roots(): Root[] {\n return this.#roots;\n }\n\n public async close() {\n if (this.#pingInterval) {\n clearInterval(this.#pingInterval);\n }\n\n await this.#server.close();\n }\n\n private setupErrorHandling() {\n this.#server.onerror = (error) => {\n console.error(\"[MCP Error]\", error);\n };\n }\n\n public get loggingLevel(): LoggingLevel {\n return this.#loggingLevel;\n }\n\n private setupCompleteHandlers() {\n this.#server.setRequestHandler(CompleteRequestSchema, async (request) => {\n if (request.params.ref.type === \"ref/prompt\") {\n const prompt = this.#prompts.find(\n (prompt) => prompt.name === request.params.ref.name,\n );\n\n if (!prompt) {\n throw new UnexpectedStateError(\"Unknown prompt\", {\n request,\n });\n }\n\n if (!prompt.complete) {\n throw new UnexpectedStateError(\"Prompt does not support completion\", {\n request,\n });\n }\n\n const completion = CompletionZodSchema.parse(\n await prompt.complete(\n request.params.argument.name,\n request.params.argument.value,\n ),\n );\n\n return {\n completion,\n };\n }\n\n if (request.params.ref.type === \"ref/resource\") {\n const resource = this.#resourceTemplates.find(\n (resource) => resource.uriTemplate === request.params.ref.uri,\n );\n\n if (!resource) {\n throw new UnexpectedStateError(\"Unknown resource\", {\n request,\n });\n }\n\n if (!(\"uriTemplate\" in resource)) {\n throw new UnexpectedStateError(\"Unexpected resource\");\n }\n\n if (!resource.complete) {\n throw new UnexpectedStateError(\n \"Resource does not support completion\",\n {\n request,\n },\n );\n }\n\n const completion = CompletionZodSchema.parse(\n await resource.complete(\n request.params.argument.name,\n request.params.argument.value,\n ),\n );\n\n return {\n completion,\n };\n }\n\n throw new UnexpectedStateError(\"Unexpected completion request\", {\n request,\n });\n });\n }\n\n private setupRootsHandlers() {\n this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server.listRoots().then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n });\n },\n );\n }\n\n private setupLoggingHandlers() {\n this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {\n this.#loggingLevel = request.params.level;\n\n return {};\n });\n }\n\n private setupToolHandlers(tools: Tool[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: tools.map((tool) => {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters\n ? zodToJsonSchema(tool.parameters)\n : undefined,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = tools.find((tool) => tool.name === request.params.name);\n\n if (!tool) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n let args: any = undefined;\n\n if (tool.parameters) {\n const parsed = tool.parameters.safeParse(request.params.arguments);\n\n if (!parsed.success) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `Invalid ${request.params.name} parameters`,\n );\n }\n\n args = parsed.data;\n }\n\n const progressToken = request.params?._meta?.progressToken;\n\n let result: ContentResult;\n\n try {\n const reportProgress = async (progress: Progress) => {\n await this.#server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"debug\",\n data: {\n message,\n context,\n },\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"error\",\n data: {\n message,\n context,\n },\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"info\",\n data: {\n message,\n context,\n },\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"warning\",\n data: {\n message,\n context,\n },\n });\n },\n };\n\n const maybeStringResult = await tool.execute(args, {\n reportProgress,\n log,\n });\n\n if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ type: \"text\", text: maybeStringResult }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ type: \"text\", text: error.message }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: `Error: ${error}` }],\n isError: true,\n };\n }\n\n return result;\n });\n }\n\n private setupResourceHandlers(resources: Resource[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => {\n return {\n uri: resource.uri,\n name: resource.name,\n mimeType: resource.mimeType,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request) => {\n if (\"uri\" in request.params) {\n const resource = resources.find(\n (resource) =>\n \"uri\" in resource && resource.uri === request.params.uri,\n );\n\n if (!resource) {\n for (const resourceTemplate of this.#resourceTemplates) {\n const uriTemplate = parseURITemplate(\n resourceTemplate.uriTemplate,\n );\n\n const match = uriTemplate.fromUri(request.params.uri);\n\n if (!match) {\n continue;\n }\n\n const uri = uriTemplate.fill(match);\n\n const result = await resourceTemplate.load(match);\n\n return {\n contents: [\n {\n uri: uri,\n mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n ...result,\n },\n ],\n };\n }\n\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown resource: ${request.params.uri}`,\n );\n }\n\n if (!(\"uri\" in resource)) {\n throw new UnexpectedStateError(\"Resource does not support reading\");\n }\n\n let maybeArrayResult: Awaited<ReturnType<Resource[\"load\"]>>;\n\n try {\n maybeArrayResult = await resource.load();\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error reading resource: ${error}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n if (Array.isArray(maybeArrayResult)) {\n return {\n contents: maybeArrayResult.map((result) => ({\n uri: resource.uri,\n mimeType: resource.mimeType,\n name: resource.name,\n ...result,\n })),\n };\n } else {\n return {\n contents: [\n {\n uri: resource.uri,\n mimeType: resource.mimeType,\n name: resource.name,\n ...maybeArrayResult,\n },\n ],\n };\n }\n }\n\n throw new UnexpectedStateError(\"Unknown resource request\", {\n request,\n });\n },\n );\n }\n\n private setupResourceTemplateHandlers(resourceTemplates: ResourceTemplate[]) {\n this.#server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async () => {\n return {\n resourceTemplates: resourceTemplates.map((resourceTemplate) => {\n return {\n name: resourceTemplate.name,\n uriTemplate: resourceTemplate.uriTemplate,\n };\n }),\n };\n },\n );\n }\n\n private setupPromptHandlers(prompts: Prompt[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n name: prompt.name,\n description: prompt.description,\n arguments: prompt.arguments,\n complete: prompt.complete,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = prompts.find(\n (prompt) => prompt.name === request.params.name,\n );\n\n if (!prompt) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown prompt: ${request.params.name}`,\n );\n }\n\n const args = request.params.arguments;\n\n for (const arg of prompt.arguments ?? []) {\n if (arg.required && !(args && arg.name in args)) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Missing required argument: ${arg.name}`,\n );\n }\n }\n\n let result: Awaited<ReturnType<Prompt[\"load\"]>>;\n\n try {\n result = await prompt.load(args as Record<string, string | undefined>);\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error loading prompt: ${error}`,\n );\n }\n\n return {\n description: prompt.description,\n messages: [\n {\n role: \"user\",\n content: { type: \"text\", text: result },\n },\n ],\n };\n });\n }\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents>;\n} = EventEmitter;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP extends FastMCPEventEmitter {\n #options: ServerOptions;\n #prompts: InputPrompt[] = [];\n #resources: Resource[] = [];\n #resourcesTemplates: InputResourceTemplate[] = [];\n #sessions: FastMCPSession[] = [];\n #sseServer: SSEServer | null = null;\n #tools: Tool[] = [];\n\n constructor(public options: ServerOptions) {\n super();\n\n this.#options = options;\n }\n\n public get sessions(): FastMCPSession[] {\n return this.#sessions;\n }\n\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<Params>) {\n this.#tools.push(tool as unknown as Tool);\n }\n\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource) {\n this.#resources.push(resource);\n }\n\n /**\n * Adds a resource template to the server.\n */\n public addResourceTemplate<\n const Args extends InputResourceTemplateArgument[],\n >(resource: InputResourceTemplate<Args>) {\n this.#resourcesTemplates.push(resource);\n }\n\n /**\n * Adds a prompt to the server.\n */\n public addPrompt<const Args extends InputPromptArgument[]>(\n prompt: InputPrompt<Args>,\n ) {\n this.#prompts.push(prompt);\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options:\n | { transportType: \"stdio\" }\n | {\n transportType: \"sse\";\n sse: { endpoint: `/${string}`; port: number };\n } = {\n transportType: \"stdio\",\n },\n ) {\n if (options.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n const session = new FastMCPSession({\n name: this.#options.name,\n version: this.#options.version,\n tools: this.#tools,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n prompts: this.#prompts,\n });\n\n await session.connect(transport);\n\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n\n } else if (options.transportType === \"sse\") {\n this.#sseServer = await startSSEServer<FastMCPSession>({\n endpoint: options.sse.endpoint as `/${string}`,\n port: options.sse.port,\n createServer: async () => {\n return new FastMCPSession({\n name: this.#options.name,\n version: this.#options.version,\n tools: this.#tools,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n prompts: this.#prompts,\n });\n },\n onClose: (session) => {\n this.emit(\"disconnect\", {\n session,\n });\n },\n onConnect: async (session) => {\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n },\n });\n\n console.error(\n `server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,\n );\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#sseServer) {\n this.#sseServer.close();\n }\n }\n}\n\nexport type { Context };\nexport type { Tool, ToolParameters };\nexport type { Content, TextContent, ImageContent, ContentResult };\nexport type { Progress, SerializableValue };\nexport type { Resource, ResourceResult };\nexport type { ResourceTemplate, ResourceTemplateArgument };\nexport type { Prompt, PromptArgument };\nexport type { InputPrompt, InputPromptArgument };\nexport type { ServerOptions, LoggingLevel };\nexport type { FastMCPEvents, FastMCPSessionEvents };\n"],"mappings":"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","names":["prompt","resource","tool"]}
1
+ {"version":3,"sources":["../src/FastMCP.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ClientCapabilities,\n CompleteRequestSchema,\n CreateMessageRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListResourceTemplatesRequestSchema,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n Root,\n RootsListChangedNotificationSchema,\n ServerCapabilities,\n SetLevelRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { z } from \"zod\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { readFile } from \"fs/promises\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { EventEmitter } from \"events\";\nimport Fuse from \"fuse.js\";\nimport { startSSEServer } from \"mcp-proxy\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport parseURITemplate from \"uri-templates\";\n\nexport type SSEServer = {\n close: () => Promise<void>;\n};\n\ntype FastMCPEvents = {\n connect: (event: { session: FastMCPSession }) => void;\n disconnect: (event: { session: FastMCPSession }) => void;\n};\n\ntype FastMCPSessionEvents = {\n rootsChanged: (event: { roots: Root[] }) => void;\n error: (event: { error: Error }) => void;\n};\n\n/**\n * Generates an image content object from a URL, file path, or buffer.\n */\nexport const imageContent = async (\n input: { url: string } | { path: string } | { buffer: Buffer },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n if (\"url\" in input) {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image from URL: ${response.statusText}`);\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } else if (\"path\" in input) {\n rawData = await readFile(input.path);\n } else if (\"buffer\" in input) {\n rawData = input.buffer;\n } else {\n throw new Error(\n \"Invalid input: Provide a valid 'url', 'path', or 'buffer'\",\n );\n }\n\n const mimeType = await fileTypeFromBuffer(rawData);\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n type: \"image\",\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n } as const;\n};\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\nexport class UnexpectedStateError extends FastMCPError {\n public extras?: Extras;\n\n public constructor(message: string, extras?: Extras) {\n super(message);\n this.name = new.target.name;\n this.extras = extras;\n }\n}\n\n/**\n * An error that is meant to be surfaced to the user.\n */\nexport class UserError extends UnexpectedStateError {}\n\ntype ToolParameters = z.ZodTypeAny;\n\ntype Literal = boolean | null | number | string | undefined;\n\ntype SerializableValue =\n | Literal\n | SerializableValue[]\n | { [key: string]: SerializableValue };\n\ntype Progress = {\n /**\n * The progress thus far. This should increase every time progress is made, even if the total is unknown.\n */\n progress: number;\n /**\n * Total number of items to process (or total progress required), if known.\n */\n total?: number;\n};\n\ntype Context = {\n reportProgress: (progress: Progress) => Promise<void>;\n log: {\n debug: (message: string, data?: SerializableValue) => void;\n error: (message: string, data?: SerializableValue) => void;\n info: (message: string, data?: SerializableValue) => void;\n warn: (message: string, data?: SerializableValue) => void;\n };\n};\n\ntype TextContent = {\n type: \"text\";\n text: string;\n};\n\nconst TextContentZodSchema = z\n .object({\n type: z.literal(\"text\"),\n /**\n * The text content of the message.\n */\n text: z.string(),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n type: \"image\";\n data: string;\n mimeType: string;\n};\n\nconst ImageContentZodSchema = z\n .object({\n type: z.literal(\"image\"),\n /**\n * The base64-encoded image data.\n */\n data: z.string().base64(),\n /**\n * The MIME type of the image. Different providers may support different image types.\n */\n mimeType: z.string(),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype Content = TextContent | ImageContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n]) satisfies z.ZodType<Content>;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType<ContentResult>;\n\ntype Completion = {\n values: string[];\n total?: number;\n hasMore?: boolean;\n};\n\n/**\n * https://github.com/modelcontextprotocol/typescript-sdk/blob/3164da64d085ec4e022ae881329eee7b72f208d4/src/types.ts#L983-L1003\n */\nconst CompletionZodSchema = z.object({\n /**\n * An array of completion values. Must not exceed 100 items.\n */\n values: z.array(z.string()).max(100),\n /**\n * The total number of completion options available. This can exceed the number of values actually sent in the response.\n */\n total: z.optional(z.number().int()),\n /**\n * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.\n */\n hasMore: z.optional(z.boolean()),\n}) satisfies z.ZodType<Completion>;\n\ntype Tool<Params extends ToolParameters = ToolParameters> = {\n name: string;\n description?: string;\n parameters?: Params;\n execute: (\n args: z.infer<Params>,\n context: Context,\n ) => Promise<string | ContentResult | TextContent | ImageContent>;\n};\n\ntype ResourceResult =\n | {\n text: string;\n }\n | {\n blob: string;\n };\n\ntype InputResourceTemplateArgument = Readonly<{\n name: string;\n description?: string;\n complete?: ArgumentValueCompleter;\n}>;\n\ntype ResourceTemplateArgument = Readonly<{\n name: string;\n description?: string;\n complete?: ArgumentValueCompleter;\n}>;\n\ntype ResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n uriTemplate: string;\n name: string;\n description?: string;\n mimeType?: string;\n arguments: Arguments;\n complete?: (name: string, value: string) => Promise<Completion>;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n};\n\ntype ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {\n [K in T[number][\"name\"]]: string;\n};\n\ntype InputResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n uriTemplate: string;\n name: string;\n description?: string;\n mimeType?: string;\n arguments: Arguments;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n};\n\ntype Resource = {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n load: () => Promise<ResourceResult | ResourceResult[]>;\n complete?: (name: string, value: string) => Promise<Completion>;\n};\n\ntype ArgumentValueCompleter = (value: string) => Promise<Completion>;\n\ntype InputPromptArgument = Readonly<{\n name: string;\n description?: string;\n required?: boolean;\n complete?: ArgumentValueCompleter;\n enum?: string[];\n}>;\n\ntype PromptArgumentsToObject<T extends { name: string; required?: boolean }[]> =\n {\n [K in T[number][\"name\"]]: Extract<\n T[number],\n { name: K }\n >[\"required\"] extends true\n ? string\n : string | undefined;\n };\n\ntype InputPrompt<\n Arguments extends InputPromptArgument[] = InputPromptArgument[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n name: string;\n description?: string;\n arguments?: InputPromptArgument[];\n load: (args: Args) => Promise<string>;\n};\n\ntype PromptArgument = Readonly<{\n name: string;\n description?: string;\n required?: boolean;\n complete?: ArgumentValueCompleter;\n enum?: string[];\n}>;\n\ntype Prompt<\n Arguments extends PromptArgument[] = PromptArgument[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: PromptArgument[];\n complete?: (name: string, value: string) => Promise<Completion>;\n description?: string;\n load: (args: Args) => Promise<string>;\n name: string;\n};\n\ntype ServerOptions = {\n name: string;\n version: `${number}.${number}.${number}`;\n};\n\ntype LoggingLevel =\n | \"debug\"\n | \"info\"\n | \"notice\"\n | \"warning\"\n | \"error\"\n | \"critical\"\n | \"alert\"\n | \"emergency\";\n\nconst FastMCPSessionEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;\n} = EventEmitter;\n\nclass FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}\n\ntype SamplingResponse = {\n model: string;\n stopReason?: \"endTurn\" | \"stopSequence\" | \"maxTokens\" | string;\n role: \"user\" | \"assistant\";\n content: TextContent | ImageContent;\n};\n\nexport class FastMCPSession extends FastMCPSessionEventEmitter {\n #capabilities: ServerCapabilities = {};\n #clientCapabilities?: ClientCapabilities;\n #loggingLevel: LoggingLevel = \"info\";\n #prompts: Prompt[] = [];\n #resources: Resource[] = [];\n #resourceTemplates: ResourceTemplate[] = [];\n #roots: Root[] = [];\n #server: Server;\n\n constructor({\n name,\n version,\n tools,\n resources,\n resourcesTemplates,\n prompts,\n }: {\n name: string;\n version: string;\n tools: Tool[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n prompts: Prompt[];\n }) {\n super();\n\n if (tools.length) {\n this.#capabilities.tools = {};\n }\n\n if (resources.length || resourcesTemplates.length) {\n this.#capabilities.resources = {};\n }\n\n if (prompts.length) {\n for (const prompt of prompts) {\n this.addPrompt(prompt);\n }\n\n this.#capabilities.prompts = {};\n }\n\n this.#capabilities.logging = {};\n\n this.#server = new Server(\n { name: name, version: version },\n { capabilities: this.#capabilities },\n );\n\n this.setupErrorHandling();\n this.setupLoggingHandlers();\n this.setupRootsHandlers();\n this.setupCompleteHandlers();\n\n if (tools.length) {\n this.setupToolHandlers(tools);\n }\n\n if (resources.length || resourcesTemplates.length) {\n for (const resource of resources) {\n this.addResource(resource);\n }\n\n this.setupResourceHandlers(resources);\n\n if (resourcesTemplates.length) {\n for (const resourceTemplate of resourcesTemplates) {\n this.addResourceTemplate(resourceTemplate);\n }\n\n this.setupResourceTemplateHandlers(resourcesTemplates);\n }\n }\n\n if (prompts.length) {\n this.setupPromptHandlers(prompts);\n }\n }\n\n private addResource(inputResource: Resource) {\n this.#resources.push(inputResource);\n }\n\n private addResourceTemplate(inputResourceTemplate: InputResourceTemplate) {\n const completers: Record<string, ArgumentValueCompleter> = {};\n\n for (const argument of inputResourceTemplate.arguments ?? []) {\n if (argument.complete) {\n completers[argument.name] = argument.complete;\n }\n }\n\n const resourceTemplate = {\n ...inputResourceTemplate,\n complete: async (name: string, value: string) => {\n if (completers[name]) {\n return await completers[name](value);\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#resourceTemplates.push(resourceTemplate);\n }\n\n private addPrompt(inputPrompt: InputPrompt) {\n const completers: Record<string, ArgumentValueCompleter> = {};\n const enums: Record<string, string[]> = {};\n\n for (const argument of inputPrompt.arguments ?? []) {\n if (argument.complete) {\n completers[argument.name] = argument.complete;\n }\n\n if (argument.enum) {\n enums[argument.name] = argument.enum;\n }\n }\n\n const prompt = {\n ...inputPrompt,\n complete: async (name: string, value: string) => {\n if (completers[name]) {\n return await completers[name](value);\n }\n\n if (enums[name]) {\n const fuse = new Fuse(enums[name], {\n keys: [\"value\"],\n });\n\n const result = fuse.search(value);\n\n return {\n values: result.map((item) => item.item),\n total: result.length,\n };\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#prompts.push(prompt);\n }\n\n public get clientCapabilities(): ClientCapabilities | null {\n return this.#clientCapabilities ?? null;\n }\n\n public get server(): Server {\n return this.#server;\n }\n\n #pingInterval: ReturnType<typeof setInterval> | null = null;\n\n public async requestSampling(\n message: z.infer<typeof CreateMessageRequestSchema>[\"params\"],\n ): Promise<SamplingResponse> {\n return this.#server.createMessage(message);\n }\n\n public async connect(transport: Transport) {\n if (this.#server.transport) {\n throw new UnexpectedStateError(\"Server is already connected\");\n }\n\n await this.#server.connect(transport);\n\n let attempt = 0;\n\n while (attempt++ < 10) {\n const capabilities = await this.#server.getClientCapabilities();\n\n if (capabilities) {\n this.#clientCapabilities = capabilities;\n\n break;\n }\n\n await delay(100);\n }\n\n if (!this.#clientCapabilities) {\n console.warn('[warning] FastMCP could not infer client capabilities')\n }\n\n if (this.#clientCapabilities?.roots) {\n const roots = await this.#server.listRoots();\n\n this.#roots = roots.roots;\n }\n\n this.#pingInterval = setInterval(async () => {\n try {\n await this.#server.ping();\n } catch (error) {\n this.emit(\"error\", {\n error: error as Error,\n });\n }\n }, 1000);\n }\n\n public get roots(): Root[] {\n return this.#roots;\n }\n\n public async close() {\n if (this.#pingInterval) {\n clearInterval(this.#pingInterval);\n }\n\n await this.#server.close();\n }\n\n private setupErrorHandling() {\n this.#server.onerror = (error) => {\n console.error(\"[MCP Error]\", error);\n };\n }\n\n public get loggingLevel(): LoggingLevel {\n return this.#loggingLevel;\n }\n\n private setupCompleteHandlers() {\n this.#server.setRequestHandler(CompleteRequestSchema, async (request) => {\n if (request.params.ref.type === \"ref/prompt\") {\n const prompt = this.#prompts.find(\n (prompt) => prompt.name === request.params.ref.name,\n );\n\n if (!prompt) {\n throw new UnexpectedStateError(\"Unknown prompt\", {\n request,\n });\n }\n\n if (!prompt.complete) {\n throw new UnexpectedStateError(\"Prompt does not support completion\", {\n request,\n });\n }\n\n const completion = CompletionZodSchema.parse(\n await prompt.complete(\n request.params.argument.name,\n request.params.argument.value,\n ),\n );\n\n return {\n completion,\n };\n }\n\n if (request.params.ref.type === \"ref/resource\") {\n const resource = this.#resourceTemplates.find(\n (resource) => resource.uriTemplate === request.params.ref.uri,\n );\n\n if (!resource) {\n throw new UnexpectedStateError(\"Unknown resource\", {\n request,\n });\n }\n\n if (!(\"uriTemplate\" in resource)) {\n throw new UnexpectedStateError(\"Unexpected resource\");\n }\n\n if (!resource.complete) {\n throw new UnexpectedStateError(\n \"Resource does not support completion\",\n {\n request,\n },\n );\n }\n\n const completion = CompletionZodSchema.parse(\n await resource.complete(\n request.params.argument.name,\n request.params.argument.value,\n ),\n );\n\n return {\n completion,\n };\n }\n\n throw new UnexpectedStateError(\"Unexpected completion request\", {\n request,\n });\n });\n }\n\n private setupRootsHandlers() {\n this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server.listRoots().then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n });\n },\n );\n }\n\n private setupLoggingHandlers() {\n this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {\n this.#loggingLevel = request.params.level;\n\n return {};\n });\n }\n\n private setupToolHandlers(tools: Tool[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: tools.map((tool) => {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters\n ? zodToJsonSchema(tool.parameters)\n : undefined,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = tools.find((tool) => tool.name === request.params.name);\n\n if (!tool) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n let args: any = undefined;\n\n if (tool.parameters) {\n const parsed = tool.parameters.safeParse(request.params.arguments);\n\n if (!parsed.success) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `Invalid ${request.params.name} parameters`,\n );\n }\n\n args = parsed.data;\n }\n\n const progressToken = request.params?._meta?.progressToken;\n\n let result: ContentResult;\n\n try {\n const reportProgress = async (progress: Progress) => {\n await this.#server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"debug\",\n data: {\n message,\n context,\n },\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"error\",\n data: {\n message,\n context,\n },\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"info\",\n data: {\n message,\n context,\n },\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"warning\",\n data: {\n message,\n context,\n },\n });\n },\n };\n\n const maybeStringResult = await tool.execute(args, {\n reportProgress,\n log,\n });\n\n if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ type: \"text\", text: maybeStringResult }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ type: \"text\", text: error.message }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: `Error: ${error}` }],\n isError: true,\n };\n }\n\n return result;\n });\n }\n\n private setupResourceHandlers(resources: Resource[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => {\n return {\n uri: resource.uri,\n name: resource.name,\n mimeType: resource.mimeType,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request) => {\n if (\"uri\" in request.params) {\n const resource = resources.find(\n (resource) =>\n \"uri\" in resource && resource.uri === request.params.uri,\n );\n\n if (!resource) {\n for (const resourceTemplate of this.#resourceTemplates) {\n const uriTemplate = parseURITemplate(\n resourceTemplate.uriTemplate,\n );\n\n const match = uriTemplate.fromUri(request.params.uri);\n\n if (!match) {\n continue;\n }\n\n const uri = uriTemplate.fill(match);\n\n const result = await resourceTemplate.load(match);\n\n return {\n contents: [\n {\n uri: uri,\n mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n ...result,\n },\n ],\n };\n }\n\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown resource: ${request.params.uri}`,\n );\n }\n\n if (!(\"uri\" in resource)) {\n throw new UnexpectedStateError(\"Resource does not support reading\");\n }\n\n let maybeArrayResult: Awaited<ReturnType<Resource[\"load\"]>>;\n\n try {\n maybeArrayResult = await resource.load();\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error reading resource: ${error}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n if (Array.isArray(maybeArrayResult)) {\n return {\n contents: maybeArrayResult.map((result) => ({\n uri: resource.uri,\n mimeType: resource.mimeType,\n name: resource.name,\n ...result,\n })),\n };\n } else {\n return {\n contents: [\n {\n uri: resource.uri,\n mimeType: resource.mimeType,\n name: resource.name,\n ...maybeArrayResult,\n },\n ],\n };\n }\n }\n\n throw new UnexpectedStateError(\"Unknown resource request\", {\n request,\n });\n },\n );\n }\n\n private setupResourceTemplateHandlers(resourceTemplates: ResourceTemplate[]) {\n this.#server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async () => {\n return {\n resourceTemplates: resourceTemplates.map((resourceTemplate) => {\n return {\n name: resourceTemplate.name,\n uriTemplate: resourceTemplate.uriTemplate,\n };\n }),\n };\n },\n );\n }\n\n private setupPromptHandlers(prompts: Prompt[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n name: prompt.name,\n description: prompt.description,\n arguments: prompt.arguments,\n complete: prompt.complete,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = prompts.find(\n (prompt) => prompt.name === request.params.name,\n );\n\n if (!prompt) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown prompt: ${request.params.name}`,\n );\n }\n\n const args = request.params.arguments;\n\n for (const arg of prompt.arguments ?? []) {\n if (arg.required && !(args && arg.name in args)) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Missing required argument: ${arg.name}`,\n );\n }\n }\n\n let result: Awaited<ReturnType<Prompt[\"load\"]>>;\n\n try {\n result = await prompt.load(args as Record<string, string | undefined>);\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error loading prompt: ${error}`,\n );\n }\n\n return {\n description: prompt.description,\n messages: [\n {\n role: \"user\",\n content: { type: \"text\", text: result },\n },\n ],\n };\n });\n }\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents>;\n} = EventEmitter;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP extends FastMCPEventEmitter {\n #options: ServerOptions;\n #prompts: InputPrompt[] = [];\n #resources: Resource[] = [];\n #resourcesTemplates: InputResourceTemplate[] = [];\n #sessions: FastMCPSession[] = [];\n #sseServer: SSEServer | null = null;\n #tools: Tool[] = [];\n\n constructor(public options: ServerOptions) {\n super();\n\n this.#options = options;\n }\n\n public get sessions(): FastMCPSession[] {\n return this.#sessions;\n }\n\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<Params>) {\n this.#tools.push(tool as unknown as Tool);\n }\n\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource) {\n this.#resources.push(resource);\n }\n\n /**\n * Adds a resource template to the server.\n */\n public addResourceTemplate<\n const Args extends InputResourceTemplateArgument[],\n >(resource: InputResourceTemplate<Args>) {\n this.#resourcesTemplates.push(resource);\n }\n\n /**\n * Adds a prompt to the server.\n */\n public addPrompt<const Args extends InputPromptArgument[]>(\n prompt: InputPrompt<Args>,\n ) {\n this.#prompts.push(prompt);\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options:\n | { transportType: \"stdio\" }\n | {\n transportType: \"sse\";\n sse: { endpoint: `/${string}`; port: number };\n } = {\n transportType: \"stdio\",\n },\n ) {\n if (options.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n const session = new FastMCPSession({\n name: this.#options.name,\n version: this.#options.version,\n tools: this.#tools,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n prompts: this.#prompts,\n });\n\n await session.connect(transport);\n\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n\n } else if (options.transportType === \"sse\") {\n this.#sseServer = await startSSEServer<FastMCPSession>({\n endpoint: options.sse.endpoint as `/${string}`,\n port: options.sse.port,\n createServer: async () => {\n return new FastMCPSession({\n name: this.#options.name,\n version: this.#options.version,\n tools: this.#tools,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n prompts: this.#prompts,\n });\n },\n onClose: (session) => {\n this.emit(\"disconnect\", {\n session,\n });\n },\n onConnect: async (session) => {\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n },\n });\n\n console.info(\n `server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,\n );\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#sseServer) {\n this.#sseServer.close();\n }\n }\n}\n\nexport type { Context };\nexport type { Tool, ToolParameters };\nexport type { Content, TextContent, ImageContent, ContentResult };\nexport type { Progress, SerializableValue };\nexport type { Resource, ResourceResult };\nexport type { ResourceTemplate, ResourceTemplateArgument };\nexport type { Prompt, PromptArgument };\nexport type { InputPrompt, InputPromptArgument };\nexport type { ServerOptions, LoggingLevel };\nexport type { FastMCPEvents, FastMCPSessionEvents };\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,SAAS;AAClB,SAAS,cAAc,aAAa;AACpC,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AAEnC,SAAS,oBAAoB;AAC7B,OAAO,UAAU;AACjB,SAAS,sBAAsB;AAE/B,OAAO,sBAAsB;AAmBtB,IAAM,eAAe,OAC1B,UAC0B;AAC1B,MAAI;AAEJ,MAAI,SAAS,OAAO;AAClB,UAAM,WAAW,MAAM,MAAM,MAAM,GAAG;AAEtC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,mCAAmC,SAAS,UAAU,EAAE;AAAA,IAC1E;AAEA,cAAU,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AAAA,EACpD,WAAW,UAAU,OAAO;AAC1B,cAAU,MAAM,SAAS,MAAM,IAAI;AAAA,EACrC,WAAW,YAAY,OAAO;AAC5B,cAAU,MAAM;AAAA,EAClB,OAAO;AACL,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,mBAAmB,OAAO;AAEjD,QAAM,aAAa,QAAQ,SAAS,QAAQ;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU,UAAU,QAAQ;AAAA,EAC9B;AACF;AAEA,IAAe,eAAf,cAAoC,MAAM;AAAA,EACjC,YAAY,SAAkB;AACnC,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AAAA,EACzB;AACF;AAMO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EAC9C;AAAA,EAEA,YAAY,SAAiB,QAAiB;AACnD,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AACvB,SAAK,SAAS;AAAA,EAChB;AACF;AAKO,IAAM,YAAN,cAAwB,qBAAqB;AAAC;AAqCrD,IAAM,uBAAuB,EAC1B,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA,EAItB,MAAM,EAAE,OAAO;AACjB,CAAC,EACA,OAAO;AAQV,IAAM,wBAAwB,EAC3B,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA,EAIvB,MAAM,EAAE,OAAO,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAIxB,UAAU,EAAE,OAAO;AACrB,CAAC,EACA,OAAO;AAIV,IAAM,mBAAmB,EAAE,mBAAmB,QAAQ;AAAA,EACpD;AAAA,EACA;AACF,CAAC;AAOD,IAAM,yBAAyB,EAC5B,OAAO;AAAA,EACN,SAAS,iBAAiB,MAAM;AAAA,EAChC,SAAS,EAAE,QAAQ,EAAE,SAAS;AAChC,CAAC,EACA,OAAO;AAWV,IAAM,sBAAsB,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAInC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG;AAAA;AAAA;AAAA;AAAA,EAInC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA,EAIlC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;AACjC,CAAC;AAwID,IAAM,iCAEF;AAEJ,IAAM,6BAAN,cAAyC,+BAA+B;AAAC;AASlE,IAAM,iBAAN,cAA6B,2BAA2B;AAAA,EAC7D,gBAAoC,CAAC;AAAA,EACrC;AAAA,EACA,gBAA8B;AAAA,EAC9B,WAAqB,CAAC;AAAA,EACtB,aAAyB,CAAC;AAAA,EAC1B,qBAAyC,CAAC;AAAA,EAC1C,SAAiB,CAAC;AAAA,EAClB;AAAA,EAEA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAOG;AACD,UAAM;AAEN,QAAI,MAAM,QAAQ;AAChB,WAAK,cAAc,QAAQ,CAAC;AAAA,IAC9B;AAEA,QAAI,UAAU,UAAU,mBAAmB,QAAQ;AACjD,WAAK,cAAc,YAAY,CAAC;AAAA,IAClC;AAEA,QAAI,QAAQ,QAAQ;AAClB,iBAAW,UAAU,SAAS;AAC5B,aAAK,UAAU,MAAM;AAAA,MACvB;AAEA,WAAK,cAAc,UAAU,CAAC;AAAA,IAChC;AAEA,SAAK,cAAc,UAAU,CAAC;AAE9B,SAAK,UAAU,IAAI;AAAA,MACjB,EAAE,MAAY,QAAiB;AAAA,MAC/B,EAAE,cAAc,KAAK,cAAc;AAAA,IACrC;AAEA,SAAK,mBAAmB;AACxB,SAAK,qBAAqB;AAC1B,SAAK,mBAAmB;AACxB,SAAK,sBAAsB;AAE3B,QAAI,MAAM,QAAQ;AAChB,WAAK,kBAAkB,KAAK;AAAA,IAC9B;AAEA,QAAI,UAAU,UAAU,mBAAmB,QAAQ;AACjD,iBAAW,YAAY,WAAW;AAChC,aAAK,YAAY,QAAQ;AAAA,MAC3B;AAEA,WAAK,sBAAsB,SAAS;AAEpC,UAAI,mBAAmB,QAAQ;AAC7B,mBAAW,oBAAoB,oBAAoB;AACjD,eAAK,oBAAoB,gBAAgB;AAAA,QAC3C;AAEA,aAAK,8BAA8B,kBAAkB;AAAA,MACvD;AAAA,IACF;AAEA,QAAI,QAAQ,QAAQ;AAClB,WAAK,oBAAoB,OAAO;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,YAAY,eAAyB;AAC3C,SAAK,WAAW,KAAK,aAAa;AAAA,EACpC;AAAA,EAEQ,oBAAoB,uBAA8C;AACxE,UAAM,aAAqD,CAAC;AAE5D,eAAW,YAAY,sBAAsB,aAAa,CAAC,GAAG;AAC5D,UAAI,SAAS,UAAU;AACrB,mBAAW,SAAS,IAAI,IAAI,SAAS;AAAA,MACvC;AAAA,IACF;AAEA,UAAM,mBAAmB;AAAA,MACvB,GAAG;AAAA,MACH,UAAU,OAAO,MAAc,UAAkB;AAC/C,YAAI,WAAW,IAAI,GAAG;AACpB,iBAAO,MAAM,WAAW,IAAI,EAAE,KAAK;AAAA,QACrC;AAEA,eAAO;AAAA,UACL,QAAQ,CAAC;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAEA,SAAK,mBAAmB,KAAK,gBAAgB;AAAA,EAC/C;AAAA,EAEQ,UAAU,aAA0B;AAC1C,UAAM,aAAqD,CAAC;AAC5D,UAAM,QAAkC,CAAC;AAEzC,eAAW,YAAY,YAAY,aAAa,CAAC,GAAG;AAClD,UAAI,SAAS,UAAU;AACrB,mBAAW,SAAS,IAAI,IAAI,SAAS;AAAA,MACvC;AAEA,UAAI,SAAS,MAAM;AACjB,cAAM,SAAS,IAAI,IAAI,SAAS;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb,GAAG;AAAA,MACH,UAAU,OAAO,MAAc,UAAkB;AAC/C,YAAI,WAAW,IAAI,GAAG;AACpB,iBAAO,MAAM,WAAW,IAAI,EAAE,KAAK;AAAA,QACrC;AAEA,YAAI,MAAM,IAAI,GAAG;AACf,gBAAM,OAAO,IAAI,KAAK,MAAM,IAAI,GAAG;AAAA,YACjC,MAAM,CAAC,OAAO;AAAA,UAChB,CAAC;AAED,gBAAM,SAAS,KAAK,OAAO,KAAK;AAEhC,iBAAO;AAAA,YACL,QAAQ,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI;AAAA,YACtC,OAAO,OAAO;AAAA,UAChB;AAAA,QACF;AAEA,eAAO;AAAA,UACL,QAAQ,CAAC;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAEA,SAAK,SAAS,KAAK,MAAM;AAAA,EAC3B;AAAA,EAEA,IAAW,qBAAgD;AACzD,WAAO,KAAK,uBAAuB;AAAA,EACrC;AAAA,EAEA,IAAW,SAAiB;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,gBAAuD;AAAA,EAEvD,MAAa,gBACX,SAC2B;AAC3B,WAAO,KAAK,QAAQ,cAAc,OAAO;AAAA,EAC3C;AAAA,EAEA,MAAa,QAAQ,WAAsB;AACzC,QAAI,KAAK,QAAQ,WAAW;AAC1B,YAAM,IAAI,qBAAqB,6BAA6B;AAAA,IAC9D;AAEA,UAAM,KAAK,QAAQ,QAAQ,SAAS;AAEpC,QAAI,UAAU;AAEd,WAAO,YAAY,IAAI;AACrB,YAAM,eAAe,MAAM,KAAK,QAAQ,sBAAsB;AAE9D,UAAI,cAAc;AAChB,aAAK,sBAAsB;AAE3B;AAAA,MACF;AAEA,YAAM,MAAM,GAAG;AAAA,IACjB;AAEA,QAAI,CAAC,KAAK,qBAAqB;AAC7B,cAAQ,KAAK,uDAAuD;AAAA,IACtE;AAEA,QAAI,KAAK,qBAAqB,OAAO;AACnC,YAAM,QAAQ,MAAM,KAAK,QAAQ,UAAU;AAE3C,WAAK,SAAS,MAAM;AAAA,IACtB;AAEA,SAAK,gBAAgB,YAAY,YAAY;AAC3C,UAAI;AACF,cAAM,KAAK,QAAQ,KAAK;AAAA,MAC1B,SAAS,OAAO;AACd,aAAK,KAAK,SAAS;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,GAAG,GAAI;AAAA,EACT;AAAA,EAEA,IAAW,QAAgB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAa,QAAQ;AACnB,QAAI,KAAK,eAAe;AACtB,oBAAc,KAAK,aAAa;AAAA,IAClC;AAEA,UAAM,KAAK,QAAQ,MAAM;AAAA,EAC3B;AAAA,EAEQ,qBAAqB;AAC3B,SAAK,QAAQ,UAAU,CAAC,UAAU;AAChC,cAAQ,MAAM,eAAe,KAAK;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,IAAW,eAA6B;AACtC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,wBAAwB;AAC9B,SAAK,QAAQ,kBAAkB,uBAAuB,OAAO,YAAY;AACvE,UAAI,QAAQ,OAAO,IAAI,SAAS,cAAc;AAC5C,cAAM,SAAS,KAAK,SAAS;AAAA,UAC3B,CAACA,YAAWA,QAAO,SAAS,QAAQ,OAAO,IAAI;AAAA,QACjD;AAEA,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI,qBAAqB,kBAAkB;AAAA,YAC/C;AAAA,UACF,CAAC;AAAA,QACH;AAEA,YAAI,CAAC,OAAO,UAAU;AACpB,gBAAM,IAAI,qBAAqB,sCAAsC;AAAA,YACnE;AAAA,UACF,CAAC;AAAA,QACH;AAEA,cAAM,aAAa,oBAAoB;AAAA,UACrC,MAAM,OAAO;AAAA,YACX,QAAQ,OAAO,SAAS;AAAA,YACxB,QAAQ,OAAO,SAAS;AAAA,UAC1B;AAAA,QACF;AAEA,eAAO;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAEA,UAAI,QAAQ,OAAO,IAAI,SAAS,gBAAgB;AAC9C,cAAM,WAAW,KAAK,mBAAmB;AAAA,UACvC,CAACC,cAAaA,UAAS,gBAAgB,QAAQ,OAAO,IAAI;AAAA,QAC5D;AAEA,YAAI,CAAC,UAAU;AACb,gBAAM,IAAI,qBAAqB,oBAAoB;AAAA,YACjD;AAAA,UACF,CAAC;AAAA,QACH;AAEA,YAAI,EAAE,iBAAiB,WAAW;AAChC,gBAAM,IAAI,qBAAqB,qBAAqB;AAAA,QACtD;AAEA,YAAI,CAAC,SAAS,UAAU;AACtB,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,cACE;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,cAAM,aAAa,oBAAoB;AAAA,UACrC,MAAM,SAAS;AAAA,YACb,QAAQ,OAAO,SAAS;AAAA,YACxB,QAAQ,OAAO,SAAS;AAAA,UAC1B;AAAA,QACF;AAEA,eAAO;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAEA,YAAM,IAAI,qBAAqB,iCAAiC;AAAA,QAC9D;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,qBAAqB;AAC3B,SAAK,QAAQ;AAAA,MACX;AAAA,MACA,MAAM;AACJ,aAAK,QAAQ,UAAU,EAAE,KAAK,CAAC,UAAU;AACvC,eAAK,SAAS,MAAM;AAEpB,eAAK,KAAK,gBAAgB;AAAA,YACxB,OAAO,MAAM;AAAA,UACf,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,uBAAuB;AAC7B,SAAK,QAAQ,kBAAkB,uBAAuB,CAAC,YAAY;AACjE,WAAK,gBAAgB,QAAQ,OAAO;AAEpC,aAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEQ,kBAAkB,OAAe;AACvC,SAAK,QAAQ,kBAAkB,wBAAwB,YAAY;AACjE,aAAO;AAAA,QACL,OAAO,MAAM,IAAI,CAAC,SAAS;AACzB,iBAAO;AAAA,YACL,MAAM,KAAK;AAAA,YACX,aAAa,KAAK;AAAA,YAClB,aAAa,KAAK,aACd,gBAAgB,KAAK,UAAU,IAC/B;AAAA,UACN;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,kBAAkB,uBAAuB,OAAO,YAAY;AACvE,YAAM,OAAO,MAAM,KAAK,CAACC,UAASA,MAAK,SAAS,QAAQ,OAAO,IAAI;AAEnE,UAAI,CAAC,MAAM;AACT,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,iBAAiB,QAAQ,OAAO,IAAI;AAAA,QACtC;AAAA,MACF;AAEA,UAAI,OAAY;AAEhB,UAAI,KAAK,YAAY;AACnB,cAAM,SAAS,KAAK,WAAW,UAAU,QAAQ,OAAO,SAAS;AAEjE,YAAI,CAAC,OAAO,SAAS;AACnB,gBAAM,IAAI;AAAA,YACR,UAAU;AAAA,YACV,WAAW,QAAQ,OAAO,IAAI;AAAA,UAChC;AAAA,QACF;AAEA,eAAO,OAAO;AAAA,MAChB;AAEA,YAAM,gBAAgB,QAAQ,QAAQ,OAAO;AAE7C,UAAI;AAEJ,UAAI;AACF,cAAM,iBAAiB,OAAO,aAAuB;AACnD,gBAAM,KAAK,QAAQ,aAAa;AAAA,YAC9B,QAAQ;AAAA,YACR,QAAQ;AAAA,cACN,GAAG;AAAA,cACH;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAEA,cAAM,MAAM;AAAA,UACV,OAAO,CAAC,SAAiB,YAAgC;AACvD,iBAAK,QAAQ,mBAAmB;AAAA,cAC9B,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,OAAO,CAAC,SAAiB,YAAgC;AACvD,iBAAK,QAAQ,mBAAmB;AAAA,cAC9B,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,MAAM,CAAC,SAAiB,YAAgC;AACtD,iBAAK,QAAQ,mBAAmB;AAAA,cAC9B,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,MAAM,CAAC,SAAiB,YAAgC;AACtD,iBAAK,QAAQ,mBAAmB;AAAA,cAC9B,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,oBAAoB,MAAM,KAAK,QAAQ,MAAM;AAAA,UACjD;AAAA,UACA;AAAA,QACF,CAAC;AAED,YAAI,OAAO,sBAAsB,UAAU;AACzC,mBAAS,uBAAuB,MAAM;AAAA,YACpC,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,kBAAkB,CAAC;AAAA,UACrD,CAAC;AAAA,QACH,WAAW,UAAU,mBAAmB;AACtC,mBAAS,uBAAuB,MAAM;AAAA,YACpC,SAAS,CAAC,iBAAiB;AAAA,UAC7B,CAAC;AAAA,QACH,OAAO;AACL,mBAAS,uBAAuB,MAAM,iBAAiB;AAAA,QACzD;AAAA,MACF,SAAS,OAAO;AACd,YAAI,iBAAiB,WAAW;AAC9B,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,MAAM,QAAQ,CAAC;AAAA,YAC/C,SAAS;AAAA,UACX;AAAA,QACF;AAEA,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,KAAK,GAAG,CAAC;AAAA,UACnD,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEQ,sBAAsB,WAAuB;AACnD,SAAK,QAAQ,kBAAkB,4BAA4B,YAAY;AACrE,aAAO;AAAA,QACL,WAAW,UAAU,IAAI,CAAC,aAAa;AACrC,iBAAO;AAAA,YACL,KAAK,SAAS;AAAA,YACd,MAAM,SAAS;AAAA,YACf,UAAU,SAAS;AAAA,UACrB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,SAAK,QAAQ;AAAA,MACX;AAAA,MACA,OAAO,YAAY;AACjB,YAAI,SAAS,QAAQ,QAAQ;AAC3B,gBAAM,WAAW,UAAU;AAAA,YACzB,CAACD,cACC,SAASA,aAAYA,UAAS,QAAQ,QAAQ,OAAO;AAAA,UACzD;AAEA,cAAI,CAAC,UAAU;AACb,uBAAW,oBAAoB,KAAK,oBAAoB;AACtD,oBAAM,cAAc;AAAA,gBAClB,iBAAiB;AAAA,cACnB;AAEA,oBAAM,QAAQ,YAAY,QAAQ,QAAQ,OAAO,GAAG;AAEpD,kBAAI,CAAC,OAAO;AACV;AAAA,cACF;AAEA,oBAAM,MAAM,YAAY,KAAK,KAAK;AAElC,oBAAM,SAAS,MAAM,iBAAiB,KAAK,KAAK;AAEhD,qBAAO;AAAA,gBACL,UAAU;AAAA,kBACR;AAAA,oBACE;AAAA,oBACA,UAAU,iBAAiB;AAAA,oBAC3B,MAAM,iBAAiB;AAAA,oBACvB,GAAG;AAAA,kBACL;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAEA,kBAAM,IAAI;AAAA,cACR,UAAU;AAAA,cACV,qBAAqB,QAAQ,OAAO,GAAG;AAAA,YACzC;AAAA,UACF;AAEA,cAAI,EAAE,SAAS,WAAW;AACxB,kBAAM,IAAI,qBAAqB,mCAAmC;AAAA,UACpE;AAEA,cAAI;AAEJ,cAAI;AACF,+BAAmB,MAAM,SAAS,KAAK;AAAA,UACzC,SAAS,OAAO;AACd,kBAAM,IAAI;AAAA,cACR,UAAU;AAAA,cACV,2BAA2B,KAAK;AAAA,cAChC;AAAA,gBACE,KAAK,SAAS;AAAA,cAChB;AAAA,YACF;AAAA,UACF;AAEA,cAAI,MAAM,QAAQ,gBAAgB,GAAG;AACnC,mBAAO;AAAA,cACL,UAAU,iBAAiB,IAAI,CAAC,YAAY;AAAA,gBAC1C,KAAK,SAAS;AAAA,gBACd,UAAU,SAAS;AAAA,gBACnB,MAAM,SAAS;AAAA,gBACf,GAAG;AAAA,cACL,EAAE;AAAA,YACJ;AAAA,UACF,OAAO;AACL,mBAAO;AAAA,cACL,UAAU;AAAA,gBACR;AAAA,kBACE,KAAK,SAAS;AAAA,kBACd,UAAU,SAAS;AAAA,kBACnB,MAAM,SAAS;AAAA,kBACf,GAAG;AAAA,gBACL;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,cAAM,IAAI,qBAAqB,4BAA4B;AAAA,UACzD;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,8BAA8B,mBAAuC;AAC3E,SAAK,QAAQ;AAAA,MACX;AAAA,MACA,YAAY;AACV,eAAO;AAAA,UACL,mBAAmB,kBAAkB,IAAI,CAAC,qBAAqB;AAC7D,mBAAO;AAAA,cACL,MAAM,iBAAiB;AAAA,cACvB,aAAa,iBAAiB;AAAA,YAChC;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAAoB,SAAmB;AAC7C,SAAK,QAAQ,kBAAkB,0BAA0B,YAAY;AACnE,aAAO;AAAA,QACL,SAAS,QAAQ,IAAI,CAAC,WAAW;AAC/B,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,aAAa,OAAO;AAAA,YACpB,WAAW,OAAO;AAAA,YAClB,UAAU,OAAO;AAAA,UACnB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,kBAAkB,wBAAwB,OAAO,YAAY;AACxE,YAAM,SAAS,QAAQ;AAAA,QACrB,CAACD,YAAWA,QAAO,SAAS,QAAQ,OAAO;AAAA,MAC7C;AAEA,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,mBAAmB,QAAQ,OAAO,IAAI;AAAA,QACxC;AAAA,MACF;AAEA,YAAM,OAAO,QAAQ,OAAO;AAE5B,iBAAW,OAAO,OAAO,aAAa,CAAC,GAAG;AACxC,YAAI,IAAI,YAAY,EAAE,QAAQ,IAAI,QAAQ,OAAO;AAC/C,gBAAM,IAAI;AAAA,YACR,UAAU;AAAA,YACV,8BAA8B,IAAI,IAAI;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AAEJ,UAAI;AACF,iBAAS,MAAM,OAAO,KAAK,IAA0C;AAAA,MACvE,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,yBAAyB,KAAK;AAAA,QAChC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,aAAa,OAAO;AAAA,QACpB,UAAU;AAAA,UACR;AAAA,YACE,MAAM;AAAA,YACN,SAAS,EAAE,MAAM,QAAQ,MAAM,OAAO;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,IAAM,0BAEF;AAEJ,IAAM,sBAAN,cAAkC,wBAAwB;AAAC;AAEpD,IAAM,UAAN,cAAsB,oBAAoB;AAAA,EAS/C,YAAmB,SAAwB;AACzC,UAAM;AADW;AAGjB,SAAK,WAAW;AAAA,EAClB;AAAA,EAZA;AAAA,EACA,WAA0B,CAAC;AAAA,EAC3B,aAAyB,CAAC;AAAA,EAC1B,sBAA+C,CAAC;AAAA,EAChD,YAA8B,CAAC;AAAA,EAC/B,aAA+B;AAAA,EAC/B,SAAiB,CAAC;AAAA,EAQlB,IAAW,WAA6B;AACtC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,QAAuC,MAAoB;AAChE,SAAK,OAAO,KAAK,IAAuB;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKO,YAAY,UAAoB;AACrC,SAAK,WAAW,KAAK,QAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKO,oBAEL,UAAuC;AACvC,SAAK,oBAAoB,KAAK,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKO,UACL,QACA;AACA,SAAK,SAAS,KAAK,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,MACX,UAKQ;AAAA,IACN,eAAe;AAAA,EACjB,GACA;AACA,QAAI,QAAQ,kBAAkB,SAAS;AACrC,YAAM,YAAY,IAAI,qBAAqB;AAE3C,YAAM,UAAU,IAAI,eAAe;AAAA,QACjC,MAAM,KAAK,SAAS;AAAA,QACpB,SAAS,KAAK,SAAS;AAAA,QACvB,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,oBAAoB,KAAK;AAAA,QACzB,SAAS,KAAK;AAAA,MAChB,CAAC;AAED,YAAM,QAAQ,QAAQ,SAAS;AAE/B,WAAK,UAAU,KAAK,OAAO;AAE3B,WAAK,KAAK,WAAW;AAAA,QACnB;AAAA,MACF,CAAC;AAAA,IAEH,WAAW,QAAQ,kBAAkB,OAAO;AAC1C,WAAK,aAAa,MAAM,eAA+B;AAAA,QACrD,UAAU,QAAQ,IAAI;AAAA,QACtB,MAAM,QAAQ,IAAI;AAAA,QAClB,cAAc,YAAY;AACxB,iBAAO,IAAI,eAAe;AAAA,YACxB,MAAM,KAAK,SAAS;AAAA,YACpB,SAAS,KAAK,SAAS;AAAA,YACvB,OAAO,KAAK;AAAA,YACZ,WAAW,KAAK;AAAA,YAChB,oBAAoB,KAAK;AAAA,YACzB,SAAS,KAAK;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,QACA,SAAS,CAAC,YAAY;AACpB,eAAK,KAAK,cAAc;AAAA,YACtB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,QACA,WAAW,OAAO,YAAY;AAC5B,eAAK,UAAU,KAAK,OAAO;AAE3B,eAAK,KAAK,WAAW;AAAA,YACnB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAED,cAAQ;AAAA,QACN,gDAAgD,QAAQ,IAAI,IAAI,GAAG,QAAQ,IAAI,QAAQ;AAAA,MACzF;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,OAAO;AAClB,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,MAAM;AAAA,IACxB;AAAA,EACF;AACF;","names":["prompt","resource","tool"]}
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glama/fastmcp",
3
- "version": "1.19.1",
3
+ "version": "1.19.3",
4
4
  "exports": "./src/FastMCP.ts",
5
5
  "include": ["src/FastMCP.ts", "src/bin/fastmcp.ts"]
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastmcp",
3
- "version": "1.19.1",
3
+ "version": "1.19.3",
4
4
  "main": "dist/FastMCP.js",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -25,7 +25,7 @@
25
25
  "execa": "^9.5.2",
26
26
  "file-type": "^20.3.0",
27
27
  "fuse.js": "^7.1.0",
28
- "mcp-proxy": "^2.5.0",
28
+ "mcp-proxy": "^2.5.2",
29
29
  "strict-event-emitter-types": "^2.0.0",
30
30
  "uri-templates": "^0.2.0",
31
31
  "yargs": "^17.7.2",
@@ -55,6 +55,7 @@
55
55
  "@types/yargs": "^17.0.33",
56
56
  "eslint": "^9.21.0",
57
57
  "eslint-plugin-perfectionist": "^4.9.0",
58
+ "eventsource-client": "^1.1.3",
58
59
  "get-port-please": "^3.1.2",
59
60
  "jsr": "^0.13.3",
60
61
  "prettier": "^3.5.2",
@@ -14,6 +14,7 @@ import {
14
14
  PingRequestSchema,
15
15
  Root,
16
16
  } from "@modelcontextprotocol/sdk/types.js";
17
+ import { createEventSource, EventSourceClient } from 'eventsource-client';
17
18
 
18
19
  const runWithTestServer = async ({
19
20
  run,
@@ -1369,3 +1370,170 @@ test("server remains usable after InvalidParams error", async () => {
1369
1370
  },
1370
1371
  });
1371
1372
  });
1373
+
1374
+ test("allows new clients to connect after a client disconnects", async () => {
1375
+ const port = await getRandomPort();
1376
+
1377
+ const server = new FastMCP({
1378
+ name: "Test",
1379
+ version: "1.0.0",
1380
+ });
1381
+
1382
+ server.addTool({
1383
+ name: "add",
1384
+ description: "Add two numbers",
1385
+ parameters: z.object({
1386
+ a: z.number(),
1387
+ b: z.number(),
1388
+ }),
1389
+ execute: async (args) => {
1390
+ return String(args.a + args.b);
1391
+ },
1392
+ });
1393
+
1394
+ await server.start({
1395
+ transportType: "sse",
1396
+ sse: {
1397
+ endpoint: "/sse",
1398
+ port,
1399
+ },
1400
+ });
1401
+
1402
+ const client1 = new Client(
1403
+ {
1404
+ name: "example-client",
1405
+ version: "1.0.0",
1406
+ },
1407
+ {
1408
+ capabilities: {},
1409
+ },
1410
+ );
1411
+
1412
+ const transport1 = new SSEClientTransport(
1413
+ new URL(`http://localhost:${port}/sse`),
1414
+ );
1415
+
1416
+ await client1.connect(transport1);
1417
+
1418
+ expect(
1419
+ await client1.callTool({
1420
+ name: "add",
1421
+ arguments: {
1422
+ a: 1,
1423
+ b: 2,
1424
+ },
1425
+ }),
1426
+ ).toEqual({
1427
+ content: [{ type: "text", text: "3" }],
1428
+ });
1429
+
1430
+ await client1.close();
1431
+
1432
+ const client2 = new Client(
1433
+ {
1434
+ name: "example-client",
1435
+ version: "1.0.0",
1436
+ },
1437
+ {
1438
+ capabilities: {},
1439
+ },
1440
+ );
1441
+
1442
+ const transport2 = new SSEClientTransport(
1443
+ new URL(`http://localhost:${port}/sse`),
1444
+ );
1445
+
1446
+ await client2.connect(transport2);
1447
+
1448
+ expect(
1449
+ await client2.callTool({
1450
+ name: "add",
1451
+ arguments: {
1452
+ a: 1,
1453
+ b: 2,
1454
+ },
1455
+ }),
1456
+ ).toEqual({
1457
+ content: [{ type: "text", text: "3" }],
1458
+ });
1459
+
1460
+ await client2.close();
1461
+
1462
+ await server.stop();
1463
+ });
1464
+
1465
+ test("able to close server immediately after starting it", async () => {
1466
+ const port = await getRandomPort();
1467
+
1468
+ const server = new FastMCP({
1469
+ name: "Test",
1470
+ version: "1.0.0",
1471
+ });
1472
+
1473
+ await server.start({
1474
+ transportType: "sse",
1475
+ sse: {
1476
+ endpoint: "/sse",
1477
+ port,
1478
+ },
1479
+ });
1480
+
1481
+ // We were previously not waiting for the server to start.
1482
+ // Therefore, this would have caused error 'Server is not running.'.
1483
+ await server.stop();
1484
+ });
1485
+
1486
+ test("closing event source does not produce error", async () => {
1487
+ const port = await getRandomPort();
1488
+
1489
+ const server = new FastMCP({
1490
+ name: "Test",
1491
+ version: "1.0.0",
1492
+ });
1493
+
1494
+ server.addTool({
1495
+ name: "add",
1496
+ description: "Add two numbers",
1497
+ parameters: z.object({
1498
+ a: z.number(),
1499
+ b: z.number(),
1500
+ }),
1501
+ execute: async (args) => {
1502
+ return String(args.a + args.b);
1503
+ },
1504
+ });
1505
+
1506
+ await server.start({
1507
+ transportType: "sse",
1508
+ sse: {
1509
+ endpoint: "/sse",
1510
+ port,
1511
+ },
1512
+ });
1513
+
1514
+ const eventSource = await new Promise<EventSourceClient>((onMessage) => {
1515
+ const eventSource = createEventSource({
1516
+ onConnect: () => {
1517
+ console.info('connected');
1518
+ },
1519
+ onDisconnect: () => {
1520
+ console.info('disconnected');
1521
+ },
1522
+ onMessage: () => {
1523
+ onMessage(eventSource);
1524
+ },
1525
+ url: `http://127.0.0.1:${port}/sse`,
1526
+ });
1527
+ });
1528
+
1529
+ expect(eventSource.readyState).toBe('open');
1530
+
1531
+ eventSource.close();
1532
+
1533
+ // We were getting unhandled error 'Not connected'
1534
+ // https://github.com/punkpeye/mcp-proxy/commit/62cf27d5e3dfcbc353e8d03c7714a62c37177b52
1535
+ await delay(1000);
1536
+
1537
+ await server.stop();
1538
+ });
1539
+
package/src/FastMCP.ts CHANGED
@@ -1117,7 +1117,7 @@ export class FastMCP extends FastMCPEventEmitter {
1117
1117
  },
1118
1118
  });
1119
1119
 
1120
- console.error(
1120
+ console.info(
1121
1121
  `server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,
1122
1122
  );
1123
1123
  } else {