fastmcp 2.1.3 → 2.2.0

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/README.md CHANGED
@@ -13,6 +13,7 @@ A TypeScript framework for building [MCP](https://glama.ai/mcp) servers capable
13
13
  - [Sessions](#sessions)
14
14
  - [Image content](#returning-an-image)
15
15
  - [Audio content](#returning-an-audio)
16
+ - [Embedded](#embedded-resources)
16
17
  - [Logging](#logging)
17
18
  - [Error handling](#errors)
18
19
  - [HTTP Streaming](#http-streaming) (with SSE compatibility)
@@ -915,6 +916,114 @@ server.addResourceTemplate({
915
916
  });
916
917
  ```
917
918
 
919
+ ### Embedded Resources
920
+
921
+ FastMCP provides a convenient `embedded()` method that simplifies including resources in tool responses. This feature reduces code duplication and makes it easier to reference resources from within tools.
922
+
923
+ #### Basic Usage
924
+
925
+ ```js
926
+ server.addTool({
927
+ name: "get_user_data",
928
+ description: "Retrieve user information",
929
+ parameters: z.object({
930
+ userId: z.string(),
931
+ }),
932
+ execute: async (args) => {
933
+ return {
934
+ content: [
935
+ {
936
+ type: "resource",
937
+ resource: await server.embedded(`user://profile/${args.userId}`),
938
+ },
939
+ ],
940
+ };
941
+ },
942
+ });
943
+ ```
944
+
945
+ #### Working with Resource Templates
946
+
947
+ The `embedded()` method works seamlessly with resource templates:
948
+
949
+ ```js
950
+ // Define a resource template
951
+ server.addResourceTemplate({
952
+ uriTemplate: "docs://project/{section}",
953
+ name: "Project Documentation",
954
+ mimeType: "text/markdown",
955
+ arguments: [
956
+ {
957
+ name: "section",
958
+ required: true,
959
+ },
960
+ ],
961
+ async load(args) {
962
+ const docs = {
963
+ "getting-started": "# Getting Started\n\nWelcome to our project!",
964
+ "api-reference": "# API Reference\n\nAuthentication is required.",
965
+ };
966
+ return {
967
+ text: docs[args.section] || "Documentation not found",
968
+ };
969
+ },
970
+ });
971
+
972
+ // Use embedded resources in a tool
973
+ server.addTool({
974
+ name: "get_documentation",
975
+ description: "Retrieve project documentation",
976
+ parameters: z.object({
977
+ section: z.enum(["getting-started", "api-reference"]),
978
+ }),
979
+ execute: async (args) => {
980
+ return {
981
+ content: [
982
+ {
983
+ type: "resource",
984
+ resource: await server.embedded(`docs://project/${args.section}`),
985
+ },
986
+ ],
987
+ };
988
+ },
989
+ });
990
+ ```
991
+
992
+ #### Working with Direct Resources
993
+
994
+ It also works with directly defined resources:
995
+
996
+ ```js
997
+ // Define a direct resource
998
+ server.addResource({
999
+ uri: "system://status",
1000
+ name: "System Status",
1001
+ mimeType: "text/plain",
1002
+ async load() {
1003
+ return {
1004
+ text: "System operational",
1005
+ };
1006
+ },
1007
+ });
1008
+
1009
+ // Use in a tool
1010
+ server.addTool({
1011
+ name: "get_system_status",
1012
+ description: "Get current system status",
1013
+ parameters: z.object({}),
1014
+ execute: async () => {
1015
+ return {
1016
+ content: [
1017
+ {
1018
+ type: "resource",
1019
+ resource: await server.embedded("system://status"),
1020
+ },
1021
+ ],
1022
+ };
1023
+ },
1024
+ });
1025
+ ```
1026
+
918
1027
  ### Prompts
919
1028
 
920
1029
  [Prompts](https://modelcontextprotocol.io/docs/concepts/prompts) enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs. They provide a powerful way to standardize and share common LLM interactions.
@@ -1195,6 +1304,7 @@ Follow the guide https://modelcontextprotocol.io/quickstart/user and add the fol
1195
1304
  - [drumnation/unsplash-smart-mcp-server](https://github.com/drumnation/unsplash-smart-mcp-server) – enables AI agents to seamlessly search, recommend, and deliver professional stock photos from Unsplash
1196
1305
  - [ssmanji89/halopsa-workflows-mcp](https://github.com/ssmanji89/halopsa-workflows-mcp) - HaloPSA Workflows integration with AI assistants
1197
1306
  - [aiamblichus/mcp-chat-adapter](https://github.com/aiamblichus/mcp-chat-adapter) – provides a clean interface for LLMs to use chat completion
1307
+ - [eyaltoledano/claude-task-master](https://github.com/eyaltoledano/claude-task-master) – advanced AI project/task manager powered by FastMCP
1198
1308
  - [cswkim/discogs-mcp-server](https://github.com/cswkim/discogs-mcp-server) - connects to the Discogs API for interacting with your music collection
1199
1309
 
1200
1310
  ## Acknowledgements
package/dist/FastMCP.d.ts CHANGED
@@ -94,7 +94,16 @@ type AudioContent = {
94
94
  mimeType: string;
95
95
  type: "audio";
96
96
  };
97
- type Content = AudioContent | ImageContent | TextContent;
97
+ type ResourceContent = {
98
+ resource: {
99
+ blob?: string;
100
+ mimeType?: string;
101
+ text?: string;
102
+ uri: string;
103
+ };
104
+ type: "resource";
105
+ };
106
+ type Content = AudioContent | ImageContent | ResourceContent | TextContent;
98
107
  type ContentResult = {
99
108
  content: Content[];
100
109
  isError?: boolean;
@@ -264,7 +273,7 @@ type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolPara
264
273
  streamingHint?: boolean;
265
274
  } & ToolAnnotations;
266
275
  description?: string;
267
- execute: (args: StandardSchemaV1.InferOutput<Params>, context: Context<T>) => Promise<AudioContent | ContentResult | ImageContent | string | TextContent | void>;
276
+ execute: (args: StandardSchemaV1.InferOutput<Params>, context: Context<T>) => Promise<AudioContent | ContentResult | ImageContent | ResourceContent | string | TextContent | void>;
268
277
  name: string;
269
278
  parameters?: Params;
270
279
  timeoutMs?: number;
@@ -373,6 +382,13 @@ declare class FastMCP<T extends Record<string, unknown> | undefined = undefined>
373
382
  * Adds a tool to the server.
374
383
  */
375
384
  addTool<Params extends ToolParameters>(tool: Tool<T, Params>): void;
385
+ /**
386
+ * Embeds a resource by URI, making it easy to include resources in tool responses.
387
+ *
388
+ * @param uri - The URI of the resource to embed
389
+ * @returns Promise<ResourceContent> - The embedded resource content
390
+ */
391
+ embedded(uri: string): Promise<ResourceContent["resource"]>;
376
392
  /**
377
393
  * Starts the server.
378
394
  */
package/dist/FastMCP.js CHANGED
@@ -171,10 +171,20 @@ var AudioContentZodSchema = z.object({
171
171
  mimeType: z.string(),
172
172
  type: z.literal("audio")
173
173
  }).strict();
174
+ var ResourceContentZodSchema = z.object({
175
+ resource: z.object({
176
+ blob: z.string().optional(),
177
+ mimeType: z.string().optional(),
178
+ text: z.string().optional(),
179
+ uri: z.string()
180
+ }),
181
+ type: z.literal("resource")
182
+ }).strict();
174
183
  var ContentZodSchema = z.discriminatedUnion("type", [
175
184
  TextContentZodSchema,
176
185
  ImageContentZodSchema,
177
- AudioContentZodSchema
186
+ AudioContentZodSchema,
187
+ ResourceContentZodSchema
178
188
  ]);
179
189
  var ContentResultZodSchema = z.object({
180
190
  content: ContentZodSchema.array(),
@@ -521,7 +531,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
521
531
  if (arg.required && !(args && arg.name in args)) {
522
532
  throw new McpError(
523
533
  ErrorCode.InvalidRequest,
524
- `Missing required argument: ${arg.name}`
534
+ `Prompt '${request.params.name}' requires argument '${arg.name}': ${arg.description || "No description provided"}`
525
535
  );
526
536
  }
527
537
  }
@@ -529,9 +539,10 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
529
539
  try {
530
540
  result = await prompt.load(args);
531
541
  } catch (error) {
542
+ const errorMessage = error instanceof Error ? error.message : String(error);
532
543
  throw new McpError(
533
544
  ErrorCode.InternalError,
534
- `Error loading prompt: ${error}`
545
+ `Failed to load prompt '${request.params.name}': ${errorMessage}`
535
546
  );
536
547
  }
537
548
  return {
@@ -588,7 +599,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
588
599
  }
589
600
  throw new McpError(
590
601
  ErrorCode.MethodNotFound,
591
- `Unknown resource: ${request.params.uri}`
602
+ `Resource not found: '${request.params.uri}'. Available resources: ${resources.map((r) => r.uri).join(", ") || "none"}`
592
603
  );
593
604
  }
594
605
  if (!("uri" in resource)) {
@@ -598,9 +609,10 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
598
609
  try {
599
610
  maybeArrayResult = await resource.load();
600
611
  } catch (error) {
612
+ const errorMessage = error instanceof Error ? error.message : String(error);
601
613
  throw new McpError(
602
614
  ErrorCode.InternalError,
603
- `Error reading resource: ${error}`,
615
+ `Failed to load resource '${resource.name}' (${resource.uri}): ${errorMessage}`,
604
616
  {
605
617
  uri: resource.uri
606
618
  }
@@ -716,9 +728,13 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
716
728
  request.params.arguments
717
729
  );
718
730
  if (parsed.issues) {
731
+ const friendlyErrors = parsed.issues.map((issue) => {
732
+ const path = issue.path?.join(".") || "root";
733
+ return `${path}: ${issue.message}`;
734
+ }).join(", ");
719
735
  throw new McpError(
720
736
  ErrorCode.InvalidParams,
721
- `Invalid ${request.params.name} parameters: ${JSON.stringify(parsed.issues)}`
737
+ `Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}`
722
738
  );
723
739
  }
724
740
  args = parsed.value;
@@ -795,7 +811,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
795
811
  setTimeout(() => {
796
812
  reject(
797
813
  new UserError(
798
- `Tool execution timed out after ${tool.timeoutMs}ms`
814
+ `Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`
799
815
  )
800
816
  );
801
817
  }, tool.timeoutMs);
@@ -823,8 +839,14 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
823
839
  isError: true
824
840
  };
825
841
  }
842
+ const errorMessage = error instanceof Error ? error.message : String(error);
826
843
  return {
827
- content: [{ text: `Error: ${error}`, type: "text" }],
844
+ content: [
845
+ {
846
+ text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,
847
+ type: "text"
848
+ }
849
+ ],
828
850
  isError: true
829
851
  };
830
852
  }
@@ -877,6 +899,66 @@ var FastMCP = class extends FastMCPEventEmitter {
877
899
  addTool(tool) {
878
900
  this.#tools.push(tool);
879
901
  }
902
+ /**
903
+ * Embeds a resource by URI, making it easy to include resources in tool responses.
904
+ *
905
+ * @param uri - The URI of the resource to embed
906
+ * @returns Promise<ResourceContent> - The embedded resource content
907
+ */
908
+ async embedded(uri) {
909
+ const directResource = this.#resources.find(
910
+ (resource) => resource.uri === uri
911
+ );
912
+ if (directResource) {
913
+ const result = await directResource.load();
914
+ const results = Array.isArray(result) ? result : [result];
915
+ const firstResult = results[0];
916
+ const resourceData = {
917
+ mimeType: directResource.mimeType,
918
+ uri
919
+ };
920
+ if ("text" in firstResult) {
921
+ resourceData.text = firstResult.text;
922
+ }
923
+ if ("blob" in firstResult) {
924
+ resourceData.blob = firstResult.blob;
925
+ }
926
+ return resourceData;
927
+ }
928
+ for (const template of this.#resourcesTemplates) {
929
+ const templateBase = template.uriTemplate.split("{")[0];
930
+ if (uri.startsWith(templateBase)) {
931
+ const params = {};
932
+ const templateParts = template.uriTemplate.split("/");
933
+ const uriParts = uri.split("/");
934
+ for (let i = 0; i < templateParts.length; i++) {
935
+ const templatePart = templateParts[i];
936
+ if (templatePart?.startsWith("{") && templatePart.endsWith("}")) {
937
+ const paramName = templatePart.slice(1, -1);
938
+ const paramValue = uriParts[i];
939
+ if (paramValue) {
940
+ params[paramName] = paramValue;
941
+ }
942
+ }
943
+ }
944
+ const result = await template.load(
945
+ params
946
+ );
947
+ const resourceData = {
948
+ mimeType: template.mimeType,
949
+ uri
950
+ };
951
+ if ("text" in result) {
952
+ resourceData.text = result.text;
953
+ }
954
+ if ("blob" in result) {
955
+ resourceData.blob = result.blob;
956
+ }
957
+ return resourceData;
958
+ }
959
+ }
960
+ throw new UnexpectedStateError(`Resource not found: ${uri}`, { uri });
961
+ }
880
962
  /**
881
963
  * Starts the server.
882
964
  */
@@ -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 { Transport } from \"@modelcontextprotocol/sdk/shared/transport.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 { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { EventEmitter } from \"events\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { readFile } from \"fs/promises\";\nimport Fuse from \"fuse.js\";\nimport http from \"http\";\nimport { startHTTPServer } from \"mcp-proxy\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { fetch } from \"undici\";\nimport parseURITemplate from \"uri-templates\";\nimport { toJsonSchema } from \"xsschema\";\nimport { z } from \"zod\";\n\nexport type SSEServer = {\n close: () => Promise<void>;\n};\n\ntype FastMCPEvents<T extends FastMCPSessionAuth> = {\n connect: (event: { session: FastMCPSession<T> }) => void;\n disconnect: (event: { session: FastMCPSession<T> }) => void;\n};\n\ntype FastMCPSessionEvents = {\n error: (event: { error: Error }) => void;\n rootsChanged: (event: { roots: Root[] }) => void;\n};\n\nexport const imageContent = async (\n input: { buffer: Buffer } | { path: string } | { url: string },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n try {\n if (\"url\" in input) {\n try {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(\n `Server responded with status: ${response.status} - ${response.statusText}`,\n );\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } catch (error) {\n throw new Error(\n `Failed to fetch image from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n } else if (\"path\" in input) {\n try {\n rawData = await readFile(input.path);\n } catch (error) {\n throw new Error(\n `Failed to read image from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\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 if (!mimeType || !mimeType.mime.startsWith(\"image/\")) {\n console.warn(\n `Warning: Content may not be a valid image. Detected MIME: ${mimeType?.mime || \"unknown\"}`,\n );\n }\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n type: \"image\",\n } as const;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n } else {\n throw new Error(`Unexpected error processing image: ${String(error)}`);\n }\n }\n};\n\nexport const audioContent = async (\n input: { buffer: Buffer } | { path: string } | { url: string },\n): Promise<AudioContent> => {\n let rawData: Buffer;\n\n try {\n if (\"url\" in input) {\n try {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(\n `Server responded with status: ${response.status} - ${response.statusText}`,\n );\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } catch (error) {\n throw new Error(\n `Failed to fetch audio from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n } else if (\"path\" in input) {\n try {\n rawData = await readFile(input.path);\n } catch (error) {\n throw new Error(\n `Failed to read audio from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\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 if (!mimeType || !mimeType.mime.startsWith(\"audio/\")) {\n console.warn(\n `Warning: Content may not be a valid audio file. Detected MIME: ${mimeType?.mime || \"unknown\"}`,\n );\n }\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"audio/mpeg\",\n type: \"audio\",\n } as const;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n } else {\n throw new Error(`Unexpected error processing audio: ${String(error)}`);\n }\n }\n};\n\ntype Context<T extends FastMCPSessionAuth> = {\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 reportProgress: (progress: Progress) => Promise<void>;\n session: T | undefined;\n streamContent: (content: Content | Content[]) => Promise<void>;\n};\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\ntype Literal = boolean | null | number | string | undefined;\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 SerializableValue =\n | { [key: string]: SerializableValue }\n | Literal\n | SerializableValue[];\n\ntype TextContent = {\n text: string;\n type: \"text\";\n};\n\ntype ToolParameters = StandardSchemaV1;\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\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\nconst TextContentZodSchema = z\n .object({\n /**\n * The text content of the message.\n */\n text: z.string(),\n type: z.literal(\"text\"),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n data: string;\n mimeType: string;\n type: \"image\";\n};\n\nconst ImageContentZodSchema = z\n .object({\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 type: z.literal(\"image\"),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype AudioContent = {\n data: string;\n mimeType: string;\n type: \"audio\";\n};\n\nconst AudioContentZodSchema = z\n .object({\n /**\n * The base64-encoded audio data.\n */\n data: z.string().base64(),\n mimeType: z.string(),\n type: z.literal(\"audio\"),\n })\n .strict() satisfies z.ZodType<AudioContent>;\n\ntype Content = AudioContent | ImageContent | TextContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n AudioContentZodSchema,\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 hasMore?: boolean;\n total?: number;\n values: string[];\n};\n\n/**\n * https://github.com/modelcontextprotocol/typescript-sdk/blob/3164da64d085ec4e022ae881329eee7b72f208d4/src/types.ts#L983-L1003\n */\nconst CompletionZodSchema = z.object({\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 /**\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 * An array of completion values. Must not exceed 100 items.\n */\n values: z.array(z.string()).max(100),\n}) satisfies z.ZodType<Completion>;\n\ntype ArgumentValueCompleter = (value: string) => Promise<Completion>;\n\ntype InputPrompt<\n Arguments extends InputPromptArgument[] = InputPromptArgument[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: InputPromptArgument[];\n description?: string;\n load: (args: Args) => Promise<string>;\n name: string;\n};\n\ntype InputPromptArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\n}>;\n\ntype InputResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n arguments: Arguments;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype InputResourceTemplateArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype LoggingLevel =\n | \"alert\"\n | \"critical\"\n | \"debug\"\n | \"emergency\"\n | \"error\"\n | \"info\"\n | \"notice\"\n | \"warning\";\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 PromptArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\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 Resource = {\n complete?: (name: string, value: string) => Promise<Completion>;\n description?: string;\n load: () => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uri: string;\n};\n\ntype ResourceResult =\n | {\n blob: string;\n }\n | {\n text: string;\n };\n\ntype ResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n arguments: Arguments;\n complete?: (name: string, value: string) => Promise<Completion>;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype ResourceTemplateArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {\n [K in T[number][\"name\"]]: string;\n};\n\ntype ServerOptions<T extends FastMCPSessionAuth> = {\n authenticate?: Authenticate<T>;\n /**\n * Configuration for the health-check endpoint that can be exposed when the\n * server is running using the HTTP Stream transport. When enabled, the\n * server will respond to an HTTP GET request with the configured path (by\n * default \"/health\") rendering a plain-text response (by default \"ok\") and\n * the configured status code (by default 200).\n *\n * The endpoint is only added when the server is started with\n * `transportType: \"httpStream\"` – it is ignored for the stdio transport.\n */\n health?: {\n /**\n * When set to `false` the health-check endpoint is disabled.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Plain-text body returned by the endpoint.\n * @default \"ok\"\n */\n message?: string;\n\n /**\n * HTTP path that should be handled.\n * @default \"/health\"\n */\n path?: string;\n\n /**\n * HTTP response status that will be returned.\n * @default 200\n */\n status?: number;\n };\n instructions?: string;\n name: string;\n\n ping?: {\n /**\n * Whether ping should be enabled by default.\n * - true for SSE or HTTP Stream\n * - false for stdio\n */\n enabled?: boolean;\n /**\n * Interval\n * @default 5000 (5s)\n */\n intervalMs?: number;\n /**\n * Logging level for ping-related messages.\n * @default 'debug'\n */\n logLevel?: LoggingLevel;\n };\n /**\n * Configuration for roots capability\n */\n roots?: {\n /**\n * Whether roots capability should be enabled\n * Set to false to completely disable roots support\n * @default true\n */\n enabled?: boolean;\n };\n version: `${number}.${number}.${number}`;\n};\n\ntype Tool<\n T extends FastMCPSessionAuth,\n Params extends ToolParameters = ToolParameters,\n> = {\n annotations?: {\n /**\n * When true, the tool leverages incremental content streaming\n * Return void for tools that handle all their output via streaming\n */\n streamingHint?: boolean;\n } & ToolAnnotations;\n description?: string;\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n AudioContent | ContentResult | ImageContent | string | TextContent | void\n >;\n name: string;\n parameters?: Params;\n timeoutMs?: number;\n};\n\n/**\n * Tool annotations as defined in MCP Specification (2025-03-26)\n * These provide hints about a tool's behavior.\n */\ntype ToolAnnotations = {\n /**\n * If true, the tool may perform destructive updates\n * Only meaningful when readOnlyHint is false\n * @default true\n */\n destructiveHint?: boolean;\n\n /**\n * If true, calling the tool repeatedly with the same arguments has no additional effect\n * Only meaningful when readOnlyHint is false\n * @default false\n */\n idempotentHint?: boolean;\n\n /**\n * If true, the tool may interact with an \"open world\" of external entities\n * @default true\n */\n openWorldHint?: boolean;\n\n /**\n * If true, indicates the tool does not modify its environment\n * @default false\n */\n readOnlyHint?: boolean;\n\n /**\n * A human-readable title for the tool, useful for UI display\n */\n title?: string;\n};\n\nconst FastMCPSessionEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;\n} = EventEmitter;\n\ntype FastMCPSessionAuth = Record<string, unknown> | undefined;\n\ntype SamplingResponse = {\n content: AudioContent | ImageContent | TextContent;\n model: string;\n role: \"assistant\" | \"user\";\n stopReason?: \"endTurn\" | \"maxTokens\" | \"stopSequence\" | string;\n};\n\nclass FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}\n\nexport class FastMCPSession<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> extends FastMCPSessionEventEmitter {\n public get clientCapabilities(): ClientCapabilities | null {\n return this.#clientCapabilities ?? null;\n }\n public get loggingLevel(): LoggingLevel {\n return this.#loggingLevel;\n }\n public get roots(): Root[] {\n return this.#roots;\n }\n public get server(): Server {\n return this.#server;\n }\n #auth: T | undefined;\n #capabilities: ServerCapabilities = {};\n #clientCapabilities?: ClientCapabilities;\n #loggingLevel: LoggingLevel = \"info\";\n #pingConfig?: ServerOptions<T>[\"ping\"];\n #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Prompt[] = [];\n\n #resources: Resource[] = [];\n\n #resourceTemplates: ResourceTemplate[] = [];\n\n #roots: Root[] = [];\n\n #rootsConfig?: ServerOptions<T>[\"roots\"];\n\n #server: Server;\n\n constructor({\n auth,\n instructions,\n name,\n ping,\n prompts,\n resources,\n resourcesTemplates,\n roots,\n tools,\n version,\n }: {\n auth?: T;\n instructions?: string;\n name: string;\n ping?: ServerOptions<T>[\"ping\"];\n prompts: Prompt[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n roots?: ServerOptions<T>[\"roots\"];\n tools: Tool<T>[];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\n this.#pingConfig = ping;\n this.#rootsConfig = roots;\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, instructions: instructions },\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 public async close() {\n if (this.#pingInterval) {\n clearInterval(this.#pingInterval);\n }\n\n try {\n await this.#server.close();\n } catch (error) {\n console.error(\"[FastMCP error]\", \"could not close server\", error);\n }\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(\"[FastMCP warning] could not infer client capabilities\");\n }\n\n if (\n this.#clientCapabilities?.roots?.listChanged &&\n typeof this.#server.listRoots === \"function\"\n ) {\n try {\n const roots = await this.#server.listRoots();\n this.#roots = roots.roots;\n } catch (e) {\n if (e instanceof McpError && e.code === ErrorCode.MethodNotFound) {\n console.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n console.error(\n `[FastMCP error] received error listing roots.\\n\\n${e instanceof Error ? e.stack : JSON.stringify(e)}`,\n );\n }\n }\n }\n\n if (this.#clientCapabilities) {\n const pingConfig = this.#getPingConfig(transport);\n\n if (pingConfig.enabled) {\n this.#pingInterval = setInterval(async () => {\n try {\n await this.#server.ping();\n } catch {\n // The reason we are not emitting an error here is because some clients\n // seem to not respond to the ping request, and we don't want to crash the server,\n // e.g., https://github.com/punkpeye/fastmcp/issues/38.\n const logLevel = pingConfig.logLevel;\n if (logLevel === \"debug\") {\n console.debug(\"[FastMCP debug] server ping failed\");\n } else if (logLevel === \"warning\") {\n console.warn(\n \"[FastMCP warning] server is not responding to ping\",\n );\n } else if (logLevel === \"error\") {\n console.error(\"[FastMCP error] server is not responding to ping\");\n } else {\n console.info(\"[FastMCP info] server ping failed\");\n }\n }\n }, pingConfig.intervalMs);\n }\n }\n }\n\n public async requestSampling(\n message: z.infer<typeof CreateMessageRequestSchema>[\"params\"],\n ): Promise<SamplingResponse> {\n return this.#server.createMessage(message);\n }\n\n #getPingConfig(transport: Transport): {\n enabled: boolean;\n intervalMs: number;\n logLevel: LoggingLevel;\n } {\n const pingConfig = this.#pingConfig || {};\n\n let defaultEnabled = false;\n\n if (\"type\" in transport) {\n // Enable by default for SSE and HTTP streaming\n if (transport.type === \"httpStream\") {\n defaultEnabled = true;\n }\n }\n\n return {\n enabled:\n pingConfig.enabled !== undefined ? pingConfig.enabled : defaultEnabled,\n intervalMs: pingConfig.intervalMs || 5000,\n logLevel: pingConfig.logLevel || \"debug\",\n };\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 total: result.length,\n values: result.map((item) => item.item),\n };\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#prompts.push(prompt);\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 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 setupErrorHandling() {\n this.#server.onerror = (error) => {\n console.error(\"[FastMCP error]\", error);\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 setupPromptHandlers(prompts: Prompt[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n arguments: prompt.arguments,\n complete: prompt.complete,\n description: prompt.description,\n name: prompt.name,\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 content: { text: result, type: \"text\" },\n role: \"user\",\n },\n ],\n };\n });\n }\n\n private setupResourceHandlers(resources: Resource[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => {\n return {\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\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 mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uri: uri,\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 mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\n ...result,\n })),\n };\n } else {\n return {\n contents: [\n {\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\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 setupRootsHandlers() {\n if (this.#rootsConfig?.enabled === false) {\n console.debug(\n \"[FastMCP debug] roots capability explicitly disabled via config\",\n );\n return;\n }\n\n // Only set up roots notification handling if the server supports it\n if (typeof this.#server.listRoots === \"function\") {\n this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server\n .listRoots()\n .then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n })\n .catch((error) => {\n if (\n error instanceof McpError &&\n error.code === ErrorCode.MethodNotFound\n ) {\n console.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n console.error(\"[FastMCP error] Error listing roots\", error);\n }\n });\n },\n );\n } else {\n console.debug(\n \"[FastMCP debug] roots capability not available, not setting up notification handler\",\n );\n }\n }\n\n private setupToolHandlers(tools: Tool<T>[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: await Promise.all(\n tools.map(async (tool) => {\n return {\n annotations: tool.annotations,\n description: tool.description,\n inputSchema: tool.parameters\n ? await toJsonSchema(tool.parameters)\n : {\n additionalProperties: false,\n properties: {},\n type: \"object\",\n }, // More complete schema for Cursor compatibility\n name: tool.name,\n };\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: unknown = undefined;\n\n if (tool.parameters) {\n const parsed = await tool.parameters[\"~standard\"].validate(\n request.params.arguments,\n );\n\n if (parsed.issues) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `Invalid ${request.params.name} parameters: ${JSON.stringify(parsed.issues)}`,\n );\n }\n\n args = parsed.value;\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 data: {\n context,\n message,\n },\n level: \"debug\",\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"error\",\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"info\",\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"warning\",\n });\n },\n };\n\n // Create a promise for tool execution\n // Streams partial results while a tool is still executing\n // Enables progressive rendering and real-time feedback\n const streamContent = async (content: Content | Content[]) => {\n const contentArray = Array.isArray(content) ? content : [content];\n\n await this.#server.notification({\n method: \"notifications/tool/streamContent\",\n params: {\n content: contentArray,\n toolName: request.params.name,\n },\n });\n };\n\n const executeToolPromise = tool.execute(args, {\n log,\n reportProgress,\n session: this.#auth,\n streamContent,\n });\n\n // Handle timeout if specified\n const maybeStringResult = (await (tool.timeoutMs\n ? Promise.race([\n executeToolPromise,\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(\n new UserError(\n `Tool execution timed out after ${tool.timeoutMs}ms`,\n ),\n );\n }, tool.timeoutMs);\n }),\n ])\n : executeToolPromise)) as\n | AudioContent\n | ContentResult\n | ImageContent\n | null\n | string\n | TextContent\n | undefined;\n\n if (maybeStringResult === undefined || maybeStringResult === null) {\n result = ContentResultZodSchema.parse({\n content: [],\n });\n } else if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ text: maybeStringResult, type: \"text\" }],\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: [{ text: error.message, type: \"text\" }],\n isError: true,\n };\n }\n\n return {\n content: [{ text: `Error: ${error}`, type: \"text\" }],\n isError: true,\n };\n }\n\n return result;\n });\n }\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents<FastMCPSessionAuth>>;\n} = EventEmitter;\n\ntype Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP<\n T extends Record<string, unknown> | undefined = undefined,\n> extends FastMCPEventEmitter {\n public get sessions(): FastMCPSession<T>[] {\n return this.#sessions;\n }\n #authenticate: Authenticate<T> | undefined;\n #httpStreamServer: null | SSEServer = null;\n #options: ServerOptions<T>;\n #prompts: InputPrompt[] = [];\n #resources: Resource[] = [];\n #resourcesTemplates: InputResourceTemplate[] = [];\n #sessions: FastMCPSession<T>[] = [];\n\n #tools: Tool<T>[] = [];\n\n constructor(public options: ServerOptions<T>) {\n super();\n\n this.#options = options;\n this.#authenticate = options.authenticate;\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 * 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 tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {\n this.#tools.push(tool as unknown as Tool<T>);\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options:\n | {\n httpStream: { port: number };\n transportType: \"httpStream\";\n }\n | { transportType: \"stdio\" } = {\n transportType: \"stdio\",\n },\n ) {\n if (options.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n const session = new FastMCPSession<T>({\n instructions: this.#options.instructions,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n version: this.#options.version,\n });\n\n await session.connect(transport);\n\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n } else if (options.transportType === \"httpStream\") {\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n return new FastMCPSession<T>({\n auth,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n version: this.#options.version,\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 onUnhandledRequest: async (req, res) => {\n const healthConfig = this.#options.health ?? {};\n\n const enabled =\n healthConfig.enabled === undefined ? true : healthConfig.enabled;\n\n if (enabled) {\n const path = healthConfig.path ?? \"/health\";\n\n try {\n if (\n req.method === \"GET\" &&\n new URL(req.url || \"\", \"http://localhost\").pathname === path\n ) {\n res\n .writeHead(healthConfig.status ?? 200, {\n \"Content-Type\": \"text/plain\",\n })\n .end(healthConfig.message ?? \"ok\");\n\n return;\n }\n } catch (error) {\n console.error(\"[FastMCP error] health endpoint error\", error);\n }\n }\n\n // If the request was not handled above, return 404\n res.writeHead(404).end();\n },\n port: options.httpStream.port,\n });\n\n console.info(\n `[FastMCP info] server is running on HTTP Stream at http://localhost:${options.httpStream.port}/stream`,\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.#httpStreamServer) {\n await this.#httpStreamServer.close();\n }\n }\n}\n\nexport type { Context };\nexport type { Tool, ToolParameters };\nexport type { Content, ContentResult, ImageContent, TextContent };\nexport type { Progress, SerializableValue };\nexport type { Resource, ResourceResult };\nexport type { ResourceTemplate, ResourceTemplateArgument };\nexport type { Prompt, PromptArgument };\nexport type { InputPrompt, InputPromptArgument };\nexport type { LoggingLevel, ServerOptions };\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 { Transport } from \"@modelcontextprotocol/sdk/shared/transport.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 { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { EventEmitter } from \"events\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { readFile } from \"fs/promises\";\nimport Fuse from \"fuse.js\";\nimport http from \"http\";\nimport { startHTTPServer } from \"mcp-proxy\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { fetch } from \"undici\";\nimport parseURITemplate from \"uri-templates\";\nimport { toJsonSchema } from \"xsschema\";\nimport { z } from \"zod\";\n\nexport type SSEServer = {\n close: () => Promise<void>;\n};\n\ntype FastMCPEvents<T extends FastMCPSessionAuth> = {\n connect: (event: { session: FastMCPSession<T> }) => void;\n disconnect: (event: { session: FastMCPSession<T> }) => void;\n};\n\ntype FastMCPSessionEvents = {\n error: (event: { error: Error }) => void;\n rootsChanged: (event: { roots: Root[] }) => void;\n};\n\nexport const imageContent = async (\n input: { buffer: Buffer } | { path: string } | { url: string },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n try {\n if (\"url\" in input) {\n try {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(\n `Server responded with status: ${response.status} - ${response.statusText}`,\n );\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } catch (error) {\n throw new Error(\n `Failed to fetch image from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n } else if (\"path\" in input) {\n try {\n rawData = await readFile(input.path);\n } catch (error) {\n throw new Error(\n `Failed to read image from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\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 if (!mimeType || !mimeType.mime.startsWith(\"image/\")) {\n console.warn(\n `Warning: Content may not be a valid image. Detected MIME: ${mimeType?.mime || \"unknown\"}`,\n );\n }\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n type: \"image\",\n } as const;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n } else {\n throw new Error(`Unexpected error processing image: ${String(error)}`);\n }\n }\n};\n\nexport const audioContent = async (\n input: { buffer: Buffer } | { path: string } | { url: string },\n): Promise<AudioContent> => {\n let rawData: Buffer;\n\n try {\n if (\"url\" in input) {\n try {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(\n `Server responded with status: ${response.status} - ${response.statusText}`,\n );\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } catch (error) {\n throw new Error(\n `Failed to fetch audio from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n } else if (\"path\" in input) {\n try {\n rawData = await readFile(input.path);\n } catch (error) {\n throw new Error(\n `Failed to read audio from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\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 if (!mimeType || !mimeType.mime.startsWith(\"audio/\")) {\n console.warn(\n `Warning: Content may not be a valid audio file. Detected MIME: ${mimeType?.mime || \"unknown\"}`,\n );\n }\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"audio/mpeg\",\n type: \"audio\",\n } as const;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n } else {\n throw new Error(`Unexpected error processing audio: ${String(error)}`);\n }\n }\n};\n\ntype Context<T extends FastMCPSessionAuth> = {\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 reportProgress: (progress: Progress) => Promise<void>;\n session: T | undefined;\n streamContent: (content: Content | Content[]) => Promise<void>;\n};\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\ntype Literal = boolean | null | number | string | undefined;\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 SerializableValue =\n | { [key: string]: SerializableValue }\n | Literal\n | SerializableValue[];\n\ntype TextContent = {\n text: string;\n type: \"text\";\n};\n\ntype ToolParameters = StandardSchemaV1;\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\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\nconst TextContentZodSchema = z\n .object({\n /**\n * The text content of the message.\n */\n text: z.string(),\n type: z.literal(\"text\"),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n data: string;\n mimeType: string;\n type: \"image\";\n};\n\nconst ImageContentZodSchema = z\n .object({\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 type: z.literal(\"image\"),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype AudioContent = {\n data: string;\n mimeType: string;\n type: \"audio\";\n};\n\nconst AudioContentZodSchema = z\n .object({\n /**\n * The base64-encoded audio data.\n */\n data: z.string().base64(),\n mimeType: z.string(),\n type: z.literal(\"audio\"),\n })\n .strict() satisfies z.ZodType<AudioContent>;\n\ntype ResourceContent = {\n resource: {\n blob?: string;\n mimeType?: string;\n text?: string;\n uri: string;\n };\n type: \"resource\";\n};\n\nconst ResourceContentZodSchema = z\n .object({\n resource: z.object({\n blob: z.string().optional(),\n mimeType: z.string().optional(),\n text: z.string().optional(),\n uri: z.string(),\n }),\n type: z.literal(\"resource\"),\n })\n .strict() satisfies z.ZodType<ResourceContent>;\n\ntype Content = AudioContent | ImageContent | ResourceContent | TextContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n AudioContentZodSchema,\n ResourceContentZodSchema,\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 hasMore?: boolean;\n total?: number;\n values: string[];\n};\n\n/**\n * https://github.com/modelcontextprotocol/typescript-sdk/blob/3164da64d085ec4e022ae881329eee7b72f208d4/src/types.ts#L983-L1003\n */\nconst CompletionZodSchema = z.object({\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 /**\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 * An array of completion values. Must not exceed 100 items.\n */\n values: z.array(z.string()).max(100),\n}) satisfies z.ZodType<Completion>;\n\ntype ArgumentValueCompleter = (value: string) => Promise<Completion>;\n\ntype InputPrompt<\n Arguments extends InputPromptArgument[] = InputPromptArgument[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: InputPromptArgument[];\n description?: string;\n load: (args: Args) => Promise<string>;\n name: string;\n};\n\ntype InputPromptArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\n}>;\n\ntype InputResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n arguments: Arguments;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype InputResourceTemplateArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype LoggingLevel =\n | \"alert\"\n | \"critical\"\n | \"debug\"\n | \"emergency\"\n | \"error\"\n | \"info\"\n | \"notice\"\n | \"warning\";\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 PromptArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\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 Resource = {\n complete?: (name: string, value: string) => Promise<Completion>;\n description?: string;\n load: () => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uri: string;\n};\n\ntype ResourceResult =\n | {\n blob: string;\n }\n | {\n text: string;\n };\n\ntype ResourceTemplate<\n Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],\n> = {\n arguments: Arguments;\n complete?: (name: string, value: string) => Promise<Completion>;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n ) => Promise<ResourceResult>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype ResourceTemplateArgument = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {\n [K in T[number][\"name\"]]: string;\n};\n\ntype ServerOptions<T extends FastMCPSessionAuth> = {\n authenticate?: Authenticate<T>;\n /**\n * Configuration for the health-check endpoint that can be exposed when the\n * server is running using the HTTP Stream transport. When enabled, the\n * server will respond to an HTTP GET request with the configured path (by\n * default \"/health\") rendering a plain-text response (by default \"ok\") and\n * the configured status code (by default 200).\n *\n * The endpoint is only added when the server is started with\n * `transportType: \"httpStream\"` – it is ignored for the stdio transport.\n */\n health?: {\n /**\n * When set to `false` the health-check endpoint is disabled.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Plain-text body returned by the endpoint.\n * @default \"ok\"\n */\n message?: string;\n\n /**\n * HTTP path that should be handled.\n * @default \"/health\"\n */\n path?: string;\n\n /**\n * HTTP response status that will be returned.\n * @default 200\n */\n status?: number;\n };\n instructions?: string;\n name: string;\n\n ping?: {\n /**\n * Whether ping should be enabled by default.\n * - true for SSE or HTTP Stream\n * - false for stdio\n */\n enabled?: boolean;\n /**\n * Interval\n * @default 5000 (5s)\n */\n intervalMs?: number;\n /**\n * Logging level for ping-related messages.\n * @default 'debug'\n */\n logLevel?: LoggingLevel;\n };\n /**\n * Configuration for roots capability\n */\n roots?: {\n /**\n * Whether roots capability should be enabled\n * Set to false to completely disable roots support\n * @default true\n */\n enabled?: boolean;\n };\n version: `${number}.${number}.${number}`;\n};\n\ntype Tool<\n T extends FastMCPSessionAuth,\n Params extends ToolParameters = ToolParameters,\n> = {\n annotations?: {\n /**\n * When true, the tool leverages incremental content streaming\n * Return void for tools that handle all their output via streaming\n */\n streamingHint?: boolean;\n } & ToolAnnotations;\n description?: string;\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n | AudioContent\n | ContentResult\n | ImageContent\n | ResourceContent\n | string\n | TextContent\n | void\n >;\n name: string;\n parameters?: Params;\n timeoutMs?: number;\n};\n\n/**\n * Tool annotations as defined in MCP Specification (2025-03-26)\n * These provide hints about a tool's behavior.\n */\ntype ToolAnnotations = {\n /**\n * If true, the tool may perform destructive updates\n * Only meaningful when readOnlyHint is false\n * @default true\n */\n destructiveHint?: boolean;\n\n /**\n * If true, calling the tool repeatedly with the same arguments has no additional effect\n * Only meaningful when readOnlyHint is false\n * @default false\n */\n idempotentHint?: boolean;\n\n /**\n * If true, the tool may interact with an \"open world\" of external entities\n * @default true\n */\n openWorldHint?: boolean;\n\n /**\n * If true, indicates the tool does not modify its environment\n * @default false\n */\n readOnlyHint?: boolean;\n\n /**\n * A human-readable title for the tool, useful for UI display\n */\n title?: string;\n};\n\nconst FastMCPSessionEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;\n} = EventEmitter;\n\ntype FastMCPSessionAuth = Record<string, unknown> | undefined;\n\ntype SamplingResponse = {\n content: AudioContent | ImageContent | TextContent;\n model: string;\n role: \"assistant\" | \"user\";\n stopReason?: \"endTurn\" | \"maxTokens\" | \"stopSequence\" | string;\n};\n\nclass FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}\n\nexport class FastMCPSession<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> extends FastMCPSessionEventEmitter {\n public get clientCapabilities(): ClientCapabilities | null {\n return this.#clientCapabilities ?? null;\n }\n public get loggingLevel(): LoggingLevel {\n return this.#loggingLevel;\n }\n public get roots(): Root[] {\n return this.#roots;\n }\n public get server(): Server {\n return this.#server;\n }\n #auth: T | undefined;\n #capabilities: ServerCapabilities = {};\n #clientCapabilities?: ClientCapabilities;\n #loggingLevel: LoggingLevel = \"info\";\n #pingConfig?: ServerOptions<T>[\"ping\"];\n #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Prompt[] = [];\n\n #resources: Resource[] = [];\n\n #resourceTemplates: ResourceTemplate[] = [];\n\n #roots: Root[] = [];\n\n #rootsConfig?: ServerOptions<T>[\"roots\"];\n\n #server: Server;\n\n constructor({\n auth,\n instructions,\n name,\n ping,\n prompts,\n resources,\n resourcesTemplates,\n roots,\n tools,\n version,\n }: {\n auth?: T;\n instructions?: string;\n name: string;\n ping?: ServerOptions<T>[\"ping\"];\n prompts: Prompt[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n roots?: ServerOptions<T>[\"roots\"];\n tools: Tool<T>[];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\n this.#pingConfig = ping;\n this.#rootsConfig = roots;\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, instructions: instructions },\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 public async close() {\n if (this.#pingInterval) {\n clearInterval(this.#pingInterval);\n }\n\n try {\n await this.#server.close();\n } catch (error) {\n console.error(\"[FastMCP error]\", \"could not close server\", error);\n }\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(\"[FastMCP warning] could not infer client capabilities\");\n }\n\n if (\n this.#clientCapabilities?.roots?.listChanged &&\n typeof this.#server.listRoots === \"function\"\n ) {\n try {\n const roots = await this.#server.listRoots();\n this.#roots = roots.roots;\n } catch (e) {\n if (e instanceof McpError && e.code === ErrorCode.MethodNotFound) {\n console.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n console.error(\n `[FastMCP error] received error listing roots.\\n\\n${e instanceof Error ? e.stack : JSON.stringify(e)}`,\n );\n }\n }\n }\n\n if (this.#clientCapabilities) {\n const pingConfig = this.#getPingConfig(transport);\n\n if (pingConfig.enabled) {\n this.#pingInterval = setInterval(async () => {\n try {\n await this.#server.ping();\n } catch {\n // The reason we are not emitting an error here is because some clients\n // seem to not respond to the ping request, and we don't want to crash the server,\n // e.g., https://github.com/punkpeye/fastmcp/issues/38.\n const logLevel = pingConfig.logLevel;\n if (logLevel === \"debug\") {\n console.debug(\"[FastMCP debug] server ping failed\");\n } else if (logLevel === \"warning\") {\n console.warn(\n \"[FastMCP warning] server is not responding to ping\",\n );\n } else if (logLevel === \"error\") {\n console.error(\"[FastMCP error] server is not responding to ping\");\n } else {\n console.info(\"[FastMCP info] server ping failed\");\n }\n }\n }, pingConfig.intervalMs);\n }\n }\n }\n\n public async requestSampling(\n message: z.infer<typeof CreateMessageRequestSchema>[\"params\"],\n ): Promise<SamplingResponse> {\n return this.#server.createMessage(message);\n }\n\n #getPingConfig(transport: Transport): {\n enabled: boolean;\n intervalMs: number;\n logLevel: LoggingLevel;\n } {\n const pingConfig = this.#pingConfig || {};\n\n let defaultEnabled = false;\n\n if (\"type\" in transport) {\n // Enable by default for SSE and HTTP streaming\n if (transport.type === \"httpStream\") {\n defaultEnabled = true;\n }\n }\n\n return {\n enabled:\n pingConfig.enabled !== undefined ? pingConfig.enabled : defaultEnabled,\n intervalMs: pingConfig.intervalMs || 5000,\n logLevel: pingConfig.logLevel || \"debug\",\n };\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 total: result.length,\n values: result.map((item) => item.item),\n };\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#prompts.push(prompt);\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 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 setupErrorHandling() {\n this.#server.onerror = (error) => {\n console.error(\"[FastMCP error]\", error);\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 setupPromptHandlers(prompts: Prompt[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n arguments: prompt.arguments,\n complete: prompt.complete,\n description: prompt.description,\n name: prompt.name,\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 `Prompt '${request.params.name}' requires argument '${arg.name}': ${arg.description || \"No description provided\"}`,\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 const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new McpError(\n ErrorCode.InternalError,\n `Failed to load prompt '${request.params.name}': ${errorMessage}`,\n );\n }\n\n return {\n description: prompt.description,\n messages: [\n {\n content: { text: result, type: \"text\" },\n role: \"user\",\n },\n ],\n };\n });\n }\n\n private setupResourceHandlers(resources: Resource[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => {\n return {\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\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 mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uri: uri,\n ...result,\n },\n ],\n };\n }\n\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Resource not found: '${request.params.uri}'. Available resources: ${resources.map((r) => r.uri).join(\", \") || \"none\"}`,\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 const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new McpError(\n ErrorCode.InternalError,\n `Failed to load resource '${resource.name}' (${resource.uri}): ${errorMessage}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n if (Array.isArray(maybeArrayResult)) {\n return {\n contents: maybeArrayResult.map((result) => ({\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\n ...result,\n })),\n };\n } else {\n return {\n contents: [\n {\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\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 setupRootsHandlers() {\n if (this.#rootsConfig?.enabled === false) {\n console.debug(\n \"[FastMCP debug] roots capability explicitly disabled via config\",\n );\n return;\n }\n\n // Only set up roots notification handling if the server supports it\n if (typeof this.#server.listRoots === \"function\") {\n this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server\n .listRoots()\n .then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n })\n .catch((error) => {\n if (\n error instanceof McpError &&\n error.code === ErrorCode.MethodNotFound\n ) {\n console.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n console.error(\"[FastMCP error] Error listing roots\", error);\n }\n });\n },\n );\n } else {\n console.debug(\n \"[FastMCP debug] roots capability not available, not setting up notification handler\",\n );\n }\n }\n\n private setupToolHandlers(tools: Tool<T>[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: await Promise.all(\n tools.map(async (tool) => {\n return {\n annotations: tool.annotations,\n description: tool.description,\n inputSchema: tool.parameters\n ? await toJsonSchema(tool.parameters)\n : {\n additionalProperties: false,\n properties: {},\n type: \"object\",\n }, // More complete schema for Cursor compatibility\n name: tool.name,\n };\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: unknown = undefined;\n\n if (tool.parameters) {\n const parsed = await tool.parameters[\"~standard\"].validate(\n request.params.arguments,\n );\n\n if (parsed.issues) {\n const friendlyErrors = parsed.issues\n .map((issue) => {\n const path = issue.path?.join(\".\") || \"root\";\n return `${path}: ${issue.message}`;\n })\n .join(\", \");\n\n throw new McpError(\n ErrorCode.InvalidParams,\n `Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}`,\n );\n }\n\n args = parsed.value;\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 data: {\n context,\n message,\n },\n level: \"debug\",\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"error\",\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"info\",\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"warning\",\n });\n },\n };\n\n // Create a promise for tool execution\n // Streams partial results while a tool is still executing\n // Enables progressive rendering and real-time feedback\n const streamContent = async (content: Content | Content[]) => {\n const contentArray = Array.isArray(content) ? content : [content];\n\n await this.#server.notification({\n method: \"notifications/tool/streamContent\",\n params: {\n content: contentArray,\n toolName: request.params.name,\n },\n });\n };\n\n const executeToolPromise = tool.execute(args, {\n log,\n reportProgress,\n session: this.#auth,\n streamContent,\n });\n\n // Handle timeout if specified\n const maybeStringResult = (await (tool.timeoutMs\n ? Promise.race([\n executeToolPromise,\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(\n new UserError(\n `Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`,\n ),\n );\n }, tool.timeoutMs);\n }),\n ])\n : executeToolPromise)) as\n | AudioContent\n | ContentResult\n | ImageContent\n | null\n | ResourceContent\n | string\n | TextContent\n | undefined;\n\n if (maybeStringResult === undefined || maybeStringResult === null) {\n result = ContentResultZodSchema.parse({\n content: [],\n });\n } else if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ text: maybeStringResult, type: \"text\" }],\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: [{ text: error.message, type: \"text\" }],\n isError: true,\n };\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,\n type: \"text\",\n },\n ],\n isError: true,\n };\n }\n\n return result;\n });\n }\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents<FastMCPSessionAuth>>;\n} = EventEmitter;\n\ntype Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP<\n T extends Record<string, unknown> | undefined = undefined,\n> extends FastMCPEventEmitter {\n public get sessions(): FastMCPSession<T>[] {\n return this.#sessions;\n }\n #authenticate: Authenticate<T> | undefined;\n #httpStreamServer: null | SSEServer = null;\n #options: ServerOptions<T>;\n #prompts: InputPrompt[] = [];\n #resources: Resource[] = [];\n #resourcesTemplates: InputResourceTemplate[] = [];\n #sessions: FastMCPSession<T>[] = [];\n\n #tools: Tool<T>[] = [];\n\n constructor(public options: ServerOptions<T>) {\n super();\n\n this.#options = options;\n this.#authenticate = options.authenticate;\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 * 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 tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {\n this.#tools.push(tool as unknown as Tool<T>);\n }\n\n /**\n * Embeds a resource by URI, making it easy to include resources in tool responses.\n *\n * @param uri - The URI of the resource to embed\n * @returns Promise<ResourceContent> - The embedded resource content\n */\n public async embedded(uri: string): Promise<ResourceContent[\"resource\"]> {\n // First, try to find a direct resource match\n const directResource = this.#resources.find(\n (resource) => resource.uri === uri,\n );\n\n if (directResource) {\n const result = await directResource.load();\n const results = Array.isArray(result) ? result : [result];\n const firstResult = results[0];\n\n const resourceData: ResourceContent[\"resource\"] = {\n mimeType: directResource.mimeType,\n uri,\n };\n\n if (\"text\" in firstResult) {\n resourceData.text = firstResult.text;\n }\n\n if (\"blob\" in firstResult) {\n resourceData.blob = firstResult.blob;\n }\n\n return resourceData;\n }\n\n // Try to match against resource templates\n for (const template of this.#resourcesTemplates) {\n // Check if the URI starts with the template base\n const templateBase = template.uriTemplate.split(\"{\")[0];\n\n if (uri.startsWith(templateBase)) {\n const params: Record<string, string> = {};\n const templateParts = template.uriTemplate.split(\"/\");\n const uriParts = uri.split(\"/\");\n\n for (let i = 0; i < templateParts.length; i++) {\n const templatePart = templateParts[i];\n\n if (templatePart?.startsWith(\"{\") && templatePart.endsWith(\"}\")) {\n const paramName = templatePart.slice(1, -1);\n const paramValue = uriParts[i];\n\n if (paramValue) {\n params[paramName] = paramValue;\n }\n }\n }\n\n const result = await template.load(\n params as ResourceTemplateArgumentsToObject<\n typeof template.arguments\n >,\n );\n\n const resourceData: ResourceContent[\"resource\"] = {\n mimeType: template.mimeType,\n uri,\n };\n\n if (\"text\" in result) {\n resourceData.text = result.text;\n }\n\n if (\"blob\" in result) {\n resourceData.blob = result.blob;\n }\n\n return resourceData; // The resource we're looking for\n }\n }\n\n throw new UnexpectedStateError(`Resource not found: ${uri}`, { uri });\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options:\n | {\n httpStream: { port: number };\n transportType: \"httpStream\";\n }\n | { transportType: \"stdio\" } = {\n transportType: \"stdio\",\n },\n ) {\n if (options.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n const session = new FastMCPSession<T>({\n instructions: this.#options.instructions,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n version: this.#options.version,\n });\n\n await session.connect(transport);\n\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n } else if (options.transportType === \"httpStream\") {\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n return new FastMCPSession<T>({\n auth,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n version: this.#options.version,\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 onUnhandledRequest: async (req, res) => {\n const healthConfig = this.#options.health ?? {};\n\n const enabled =\n healthConfig.enabled === undefined ? true : healthConfig.enabled;\n\n if (enabled) {\n const path = healthConfig.path ?? \"/health\";\n\n try {\n if (\n req.method === \"GET\" &&\n new URL(req.url || \"\", \"http://localhost\").pathname === path\n ) {\n res\n .writeHead(healthConfig.status ?? 200, {\n \"Content-Type\": \"text/plain\",\n })\n .end(healthConfig.message ?? \"ok\");\n\n return;\n }\n } catch (error) {\n console.error(\"[FastMCP error] health endpoint error\", error);\n }\n }\n\n // If the request was not handled above, return 404\n res.writeHead(404).end();\n },\n port: options.httpStream.port,\n });\n\n console.info(\n `[FastMCP info] server is running on HTTP Stream at http://localhost:${options.httpStream.port}/stream`,\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.#httpStreamServer) {\n await this.#httpStreamServer.close();\n }\n }\n}\n\nexport type { Context };\nexport type { Tool, ToolParameters };\nexport type { Content, ContentResult, ImageContent, TextContent };\nexport type { Progress, SerializableValue };\nexport type { Resource, ResourceResult };\nexport type { ResourceTemplate, ResourceTemplateArgument };\nexport type { Prompt, PromptArgument };\nexport type { InputPrompt, InputPromptArgument };\nexport type { LoggingLevel, ServerOptions };\nexport type { FastMCPEvents, FastMCPSessionEvents };\n"],"mappings":"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","names":["prompt","resource","tool"]}
package/jsr.json CHANGED
@@ -3,5 +3,5 @@
3
3
  "include": ["src/FastMCP.ts", "src/bin/fastmcp.ts"],
4
4
  "license": "MIT",
5
5
  "name": "@punkpeye/fastmcp",
6
- "version": "2.1.3"
6
+ "version": "2.2.0"
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastmcp",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "main": "dist/FastMCP.js",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -782,6 +782,138 @@ test("clients reads a resource that returns multiple resources", async () => {
782
782
  });
783
783
  });
784
784
 
785
+ test("embedded resources work in tools", async () => {
786
+ await runWithTestServer({
787
+ run: async ({ client }) => {
788
+ expect(
789
+ await client.callTool({
790
+ arguments: {
791
+ userId: "123",
792
+ },
793
+ name: "get_user_profile",
794
+ }),
795
+ ).toEqual({
796
+ content: [
797
+ {
798
+ resource: {
799
+ mimeType: "application/json",
800
+ text: '{"id":"123","name":"User","email":"user@example.com"}',
801
+ uri: "user://profile/123",
802
+ },
803
+ type: "resource",
804
+ },
805
+ ],
806
+ });
807
+ },
808
+
809
+ server: async () => {
810
+ const server = new FastMCP({
811
+ name: "Test",
812
+ version: "1.0.0",
813
+ });
814
+
815
+ server.addResourceTemplate({
816
+ arguments: [
817
+ {
818
+ name: "userId",
819
+ required: true,
820
+ },
821
+ ],
822
+ async load(args) {
823
+ return {
824
+ text: `{"id":"${args.userId}","name":"User","email":"user@example.com"}`,
825
+ };
826
+ },
827
+ mimeType: "application/json",
828
+ name: "User Profile",
829
+ uriTemplate: "user://profile/{userId}",
830
+ });
831
+
832
+ server.addTool({
833
+ description: "Get user profile data",
834
+ execute: async (args) => {
835
+ return {
836
+ content: [
837
+ {
838
+ resource: await server.embedded(
839
+ `user://profile/${args.userId}`,
840
+ ),
841
+ type: "resource",
842
+ },
843
+ ],
844
+ };
845
+ },
846
+ name: "get_user_profile",
847
+ parameters: z.object({
848
+ userId: z.string(),
849
+ }),
850
+ });
851
+
852
+ return server;
853
+ },
854
+ });
855
+ });
856
+
857
+ test("embedded resources work with direct resources", async () => {
858
+ await runWithTestServer({
859
+ run: async ({ client }) => {
860
+ expect(
861
+ await client.callTool({
862
+ arguments: {},
863
+ name: "get_logs",
864
+ }),
865
+ ).toEqual({
866
+ content: [
867
+ {
868
+ resource: {
869
+ mimeType: "text/plain",
870
+ text: "Example log content",
871
+ uri: "file:///logs/app.log",
872
+ },
873
+ type: "resource",
874
+ },
875
+ ],
876
+ });
877
+ },
878
+
879
+ server: async () => {
880
+ const server = new FastMCP({
881
+ name: "Test",
882
+ version: "1.0.0",
883
+ });
884
+
885
+ server.addResource({
886
+ async load() {
887
+ return {
888
+ text: "Example log content",
889
+ };
890
+ },
891
+ mimeType: "text/plain",
892
+ name: "Application Logs",
893
+ uri: "file:///logs/app.log",
894
+ });
895
+
896
+ server.addTool({
897
+ description: "Get application logs",
898
+ execute: async () => {
899
+ return {
900
+ content: [
901
+ {
902
+ resource: await server.embedded("file:///logs/app.log"),
903
+ type: "resource",
904
+ },
905
+ ],
906
+ };
907
+ },
908
+ name: "get_logs",
909
+ parameters: z.object({}),
910
+ });
911
+
912
+ return server;
913
+ },
914
+ });
915
+ });
916
+
785
917
  test("adds prompts", async () => {
786
918
  await runWithTestServer({
787
919
  run: async ({ client }) => {
@@ -1484,7 +1616,7 @@ test("throws ErrorCode.InvalidParams if tool parameters do not match zod schema"
1484
1616
 
1485
1617
  // @ts-expect-error - we know that error is an McpError
1486
1618
  expect(error.message).toBe(
1487
- 'MCP error -32602: MCP error -32602: Invalid add parameters: [{"code":"invalid_type","expected":"number","received":"string","path":["b"],"message":"Expected number, received string"}]',
1619
+ "MCP error -32602: MCP error -32602: Tool 'add' parameter validation failed: b: Expected number, received string",
1488
1620
  );
1489
1621
  }
1490
1622
  },
@@ -1530,7 +1662,7 @@ test("server remains usable after InvalidParams error", async () => {
1530
1662
 
1531
1663
  // @ts-expect-error - we know that error is an McpError
1532
1664
  expect(error.message).toBe(
1533
- 'MCP error -32602: MCP error -32602: Invalid add parameters: [{"code":"invalid_type","expected":"number","received":"string","path":["b"],"message":"Expected number, received string"}]',
1665
+ "MCP error -32602: MCP error -32602: Tool 'add' parameter validation failed: b: Expected number, received string",
1534
1666
  );
1535
1667
  }
1536
1668
 
@@ -1868,7 +2000,7 @@ test("supports streaming output from tools", async () => {
1868
2000
  annotations: {
1869
2001
  streamingHint: true,
1870
2002
  },
1871
- description: "Tool yang streaming dan mengembalikan void",
2003
+ description: "A streaming tool that returns void",
1872
2004
  execute: async (_args, context) => {
1873
2005
  await context.streamContent({
1874
2006
  text: "Streaming content 1",
@@ -1891,7 +2023,7 @@ test("supports streaming output from tools", async () => {
1891
2023
  annotations: {
1892
2024
  streamingHint: true,
1893
2025
  },
1894
- description: "Tool yang streaming dan mengembalikan hasil",
2026
+ description: "A streaming tool that returns a result.",
1895
2027
  execute: async (_args, context) => {
1896
2028
  await context.streamContent({
1897
2029
  text: "Streaming content 1",
package/src/FastMCP.ts CHANGED
@@ -281,12 +281,35 @@ const AudioContentZodSchema = z
281
281
  })
282
282
  .strict() satisfies z.ZodType<AudioContent>;
283
283
 
284
- type Content = AudioContent | ImageContent | TextContent;
284
+ type ResourceContent = {
285
+ resource: {
286
+ blob?: string;
287
+ mimeType?: string;
288
+ text?: string;
289
+ uri: string;
290
+ };
291
+ type: "resource";
292
+ };
293
+
294
+ const ResourceContentZodSchema = z
295
+ .object({
296
+ resource: z.object({
297
+ blob: z.string().optional(),
298
+ mimeType: z.string().optional(),
299
+ text: z.string().optional(),
300
+ uri: z.string(),
301
+ }),
302
+ type: z.literal("resource"),
303
+ })
304
+ .strict() satisfies z.ZodType<ResourceContent>;
305
+
306
+ type Content = AudioContent | ImageContent | ResourceContent | TextContent;
285
307
 
286
308
  const ContentZodSchema = z.discriminatedUnion("type", [
287
309
  TextContentZodSchema,
288
310
  ImageContentZodSchema,
289
311
  AudioContentZodSchema,
312
+ ResourceContentZodSchema,
290
313
  ]) satisfies z.ZodType<Content>;
291
314
 
292
315
  type ContentResult = {
@@ -534,7 +557,13 @@ type Tool<
534
557
  args: StandardSchemaV1.InferOutput<Params>,
535
558
  context: Context<T>,
536
559
  ) => Promise<
537
- AudioContent | ContentResult | ImageContent | string | TextContent | void
560
+ | AudioContent
561
+ | ContentResult
562
+ | ImageContent
563
+ | ResourceContent
564
+ | string
565
+ | TextContent
566
+ | void
538
567
  >;
539
568
  name: string;
540
569
  parameters?: Params;
@@ -1016,7 +1045,7 @@ export class FastMCPSession<
1016
1045
  if (arg.required && !(args && arg.name in args)) {
1017
1046
  throw new McpError(
1018
1047
  ErrorCode.InvalidRequest,
1019
- `Missing required argument: ${arg.name}`,
1048
+ `Prompt '${request.params.name}' requires argument '${arg.name}': ${arg.description || "No description provided"}`,
1020
1049
  );
1021
1050
  }
1022
1051
  }
@@ -1026,9 +1055,11 @@ export class FastMCPSession<
1026
1055
  try {
1027
1056
  result = await prompt.load(args as Record<string, string | undefined>);
1028
1057
  } catch (error) {
1058
+ const errorMessage =
1059
+ error instanceof Error ? error.message : String(error);
1029
1060
  throw new McpError(
1030
1061
  ErrorCode.InternalError,
1031
- `Error loading prompt: ${error}`,
1062
+ `Failed to load prompt '${request.params.name}': ${errorMessage}`,
1032
1063
  );
1033
1064
  }
1034
1065
 
@@ -1096,7 +1127,7 @@ export class FastMCPSession<
1096
1127
 
1097
1128
  throw new McpError(
1098
1129
  ErrorCode.MethodNotFound,
1099
- `Unknown resource: ${request.params.uri}`,
1130
+ `Resource not found: '${request.params.uri}'. Available resources: ${resources.map((r) => r.uri).join(", ") || "none"}`,
1100
1131
  );
1101
1132
  }
1102
1133
 
@@ -1109,9 +1140,11 @@ export class FastMCPSession<
1109
1140
  try {
1110
1141
  maybeArrayResult = await resource.load();
1111
1142
  } catch (error) {
1143
+ const errorMessage =
1144
+ error instanceof Error ? error.message : String(error);
1112
1145
  throw new McpError(
1113
1146
  ErrorCode.InternalError,
1114
- `Error reading resource: ${error}`,
1147
+ `Failed to load resource '${resource.name}' (${resource.uri}): ${errorMessage}`,
1115
1148
  {
1116
1149
  uri: resource.uri,
1117
1150
  },
@@ -1247,9 +1280,16 @@ export class FastMCPSession<
1247
1280
  );
1248
1281
 
1249
1282
  if (parsed.issues) {
1283
+ const friendlyErrors = parsed.issues
1284
+ .map((issue) => {
1285
+ const path = issue.path?.join(".") || "root";
1286
+ return `${path}: ${issue.message}`;
1287
+ })
1288
+ .join(", ");
1289
+
1250
1290
  throw new McpError(
1251
1291
  ErrorCode.InvalidParams,
1252
- `Invalid ${request.params.name} parameters: ${JSON.stringify(parsed.issues)}`,
1292
+ `Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}`,
1253
1293
  );
1254
1294
  }
1255
1295
 
@@ -1340,7 +1380,7 @@ export class FastMCPSession<
1340
1380
  setTimeout(() => {
1341
1381
  reject(
1342
1382
  new UserError(
1343
- `Tool execution timed out after ${tool.timeoutMs}ms`,
1383
+ `Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`,
1344
1384
  ),
1345
1385
  );
1346
1386
  }, tool.timeoutMs);
@@ -1351,6 +1391,7 @@ export class FastMCPSession<
1351
1391
  | ContentResult
1352
1392
  | ImageContent
1353
1393
  | null
1394
+ | ResourceContent
1354
1395
  | string
1355
1396
  | TextContent
1356
1397
  | undefined;
@@ -1378,8 +1419,15 @@ export class FastMCPSession<
1378
1419
  };
1379
1420
  }
1380
1421
 
1422
+ const errorMessage =
1423
+ error instanceof Error ? error.message : String(error);
1381
1424
  return {
1382
- content: [{ text: `Error: ${error}`, type: "text" }],
1425
+ content: [
1426
+ {
1427
+ text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,
1428
+ type: "text",
1429
+ },
1430
+ ],
1383
1431
  isError: true,
1384
1432
  };
1385
1433
  }
@@ -1452,6 +1500,88 @@ export class FastMCP<
1452
1500
  this.#tools.push(tool as unknown as Tool<T>);
1453
1501
  }
1454
1502
 
1503
+ /**
1504
+ * Embeds a resource by URI, making it easy to include resources in tool responses.
1505
+ *
1506
+ * @param uri - The URI of the resource to embed
1507
+ * @returns Promise<ResourceContent> - The embedded resource content
1508
+ */
1509
+ public async embedded(uri: string): Promise<ResourceContent["resource"]> {
1510
+ // First, try to find a direct resource match
1511
+ const directResource = this.#resources.find(
1512
+ (resource) => resource.uri === uri,
1513
+ );
1514
+
1515
+ if (directResource) {
1516
+ const result = await directResource.load();
1517
+ const results = Array.isArray(result) ? result : [result];
1518
+ const firstResult = results[0];
1519
+
1520
+ const resourceData: ResourceContent["resource"] = {
1521
+ mimeType: directResource.mimeType,
1522
+ uri,
1523
+ };
1524
+
1525
+ if ("text" in firstResult) {
1526
+ resourceData.text = firstResult.text;
1527
+ }
1528
+
1529
+ if ("blob" in firstResult) {
1530
+ resourceData.blob = firstResult.blob;
1531
+ }
1532
+
1533
+ return resourceData;
1534
+ }
1535
+
1536
+ // Try to match against resource templates
1537
+ for (const template of this.#resourcesTemplates) {
1538
+ // Check if the URI starts with the template base
1539
+ const templateBase = template.uriTemplate.split("{")[0];
1540
+
1541
+ if (uri.startsWith(templateBase)) {
1542
+ const params: Record<string, string> = {};
1543
+ const templateParts = template.uriTemplate.split("/");
1544
+ const uriParts = uri.split("/");
1545
+
1546
+ for (let i = 0; i < templateParts.length; i++) {
1547
+ const templatePart = templateParts[i];
1548
+
1549
+ if (templatePart?.startsWith("{") && templatePart.endsWith("}")) {
1550
+ const paramName = templatePart.slice(1, -1);
1551
+ const paramValue = uriParts[i];
1552
+
1553
+ if (paramValue) {
1554
+ params[paramName] = paramValue;
1555
+ }
1556
+ }
1557
+ }
1558
+
1559
+ const result = await template.load(
1560
+ params as ResourceTemplateArgumentsToObject<
1561
+ typeof template.arguments
1562
+ >,
1563
+ );
1564
+
1565
+ const resourceData: ResourceContent["resource"] = {
1566
+ mimeType: template.mimeType,
1567
+ uri,
1568
+ };
1569
+
1570
+ if ("text" in result) {
1571
+ resourceData.text = result.text;
1572
+ }
1573
+
1574
+ if ("blob" in result) {
1575
+ resourceData.blob = result.blob;
1576
+ }
1577
+
1578
+ return resourceData; // The resource we're looking for
1579
+ }
1580
+ }
1581
+
1582
+ throw new UnexpectedStateError(`Resource not found: ${uri}`, { uri });
1583
+ }
1584
+
1455
1585
  /**
1456
1586
  * Starts the server.
1457
1587
  */
@@ -170,6 +170,62 @@ server.addPrompt({
170
170
  name: "git-commit",
171
171
  });
172
172
 
173
+ server.addResourceTemplate({
174
+ arguments: [
175
+ {
176
+ description: "Documentation section to retrieve",
177
+ name: "section",
178
+ required: true,
179
+ },
180
+ ],
181
+ description: "Get project documentation",
182
+ load: async (args) => {
183
+ const docs = {
184
+ "api-reference":
185
+ "# API Reference\n\n## Authentication\nAll API requests require a valid API key in the Authorization header.\n\n## Endpoints\n- GET /users - List all users\n- POST /users - Create new user",
186
+ deployment:
187
+ "# Deployment Guide\n\nTo deploy this application:\n\n1. Build the project: `npm run build`\n2. Set environment variables\n3. Deploy to your hosting platform",
188
+ "getting-started":
189
+ "# Getting Started\n\nWelcome to our project! Follow these steps to set up your development environment:\n\n1. Clone the repository\n2. Install dependencies with `npm install`\n3. Run `npm start` to begin",
190
+ };
191
+
192
+ return {
193
+ text:
194
+ docs[args.section as keyof typeof docs] ||
195
+ "Documentation section not found",
196
+ };
197
+ },
198
+ mimeType: "text/markdown",
199
+ name: "Project Documentation",
200
+ uriTemplate: "docs://project/{section}",
201
+ });
202
+
203
+ server.addTool({
204
+ annotations: {
205
+ openWorldHint: false,
206
+ readOnlyHint: true,
207
+ title: "Get Documentation (Embedded)",
208
+ },
209
+ description:
210
+ "Retrieve project documentation using embedded resources - demonstrates the new embedded() feature",
211
+ execute: async (args) => {
212
+ return {
213
+ content: [
214
+ {
215
+ resource: await server.embedded(`docs://project/${args.section}`),
216
+ type: "resource",
217
+ },
218
+ ],
219
+ };
220
+ },
221
+ name: "get-documentation",
222
+ parameters: z.object({
223
+ section: z
224
+ .enum(["getting-started", "api-reference", "deployment"])
225
+ .describe("Documentation section to retrieve"),
226
+ }),
227
+ });
228
+
173
229
  // Select transport type based on command line arguments
174
230
  const transportType = process.argv.includes("--http-stream")
175
231
  ? "httpStream"