fastmcp 1.23.2 → 1.25.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
@@ -16,6 +16,7 @@ A TypeScript framework for building [MCP](https://glama.ai/mcp) servers capable
16
16
  - [Logging](#logging)
17
17
  - [Error handling](#errors)
18
18
  - [SSE](#sse)
19
+ - [HTTP Streaming](#http-streaming)
19
20
  - CORS (enabled by default)
20
21
  - [Progress notifications](#progress)
21
22
  - [Typed server events](#typed-server-events)
@@ -80,11 +81,15 @@ npx fastmcp dev src/examples/addition.ts
80
81
  npx fastmcp inspect src/examples/addition.ts
81
82
  ```
82
83
 
83
- ### SSE
84
+ ### Remote Server Options
84
85
 
85
- [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE) provide a mechanism for servers to send real-time updates to clients over an HTTPS connection. In the context of MCP, SSE is primarily used to enable remote MCP communication, allowing an MCP hosted on a remote machine to be accessed and relay updates over the network.
86
+ FastMCP supports multiple transport options for remote communication, allowing an MCP hosted on a remote machine to be accessed over the network.
86
87
 
87
- You can also run the server with SSE support:
88
+ #### SSE
89
+
90
+ [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE) provide a mechanism for servers to send real-time updates to clients over an HTTPS connection.
91
+
92
+ You can run the server with SSE support:
88
93
 
89
94
  ```ts
90
95
  server.start({
@@ -98,7 +103,27 @@ server.start({
98
103
 
99
104
  This will start the server and listen for SSE connections on `http://localhost:8080/sse`.
100
105
 
101
- You can then use `SSEClientTransport` to connect to the server:
106
+ #### HTTP Streaming
107
+
108
+ [HTTP streaming](https://www.cloudflare.com/learning/video/what-is-http-live-streaming/) provides a more efficient alternative to SSE in environments that support it, with potentially better performance for larger payloads.
109
+
110
+ You can run the server with HTTP streaming support:
111
+
112
+ ```ts
113
+ server.start({
114
+ transportType: "httpStream",
115
+ httpStream: {
116
+ endpoint: "/stream",
117
+ port: 8080,
118
+ },
119
+ });
120
+ ```
121
+
122
+ This will start the server and listen for HTTP streaming connections on `http://localhost:8080/stream`.
123
+
124
+ You can connect to these servers using the appropriate client transport.
125
+
126
+ For SSE connections:
102
127
 
103
128
  ```ts
104
129
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -118,6 +143,26 @@ const transport = new SSEClientTransport(new URL(`http://localhost:8080/sse`));
118
143
  await client.connect(transport);
119
144
  ```
120
145
 
146
+ For HTTP streaming connections:
147
+
148
+ ```ts
149
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
150
+
151
+ const client = new Client(
152
+ {
153
+ name: "example-client",
154
+ version: "1.0.0",
155
+ },
156
+ {
157
+ capabilities: {},
158
+ },
159
+ );
160
+
161
+ const transport = new StreamableHTTPClientTransport(new URL(`http://localhost:8080/stream`));
162
+
163
+ await client.connect(transport);
164
+ ```
165
+
121
166
  ## Core Concepts
122
167
 
123
168
  ### Tools
package/dist/FastMCP.d.ts CHANGED
@@ -26,9 +26,6 @@ type FastMCPSessionEvents = {
26
26
  roots: Root[];
27
27
  }) => void;
28
28
  };
29
- /**
30
- * Generates an image content object from a URL, file path, or buffer.
31
- */
32
29
  declare const imageContent: (input: {
33
30
  buffer: Buffer;
34
31
  } | {
@@ -195,6 +192,7 @@ type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolPara
195
192
  execute: (args: StandardSchemaV1.InferOutput<Params>, context: Context<T>) => Promise<AudioContent | ContentResult | ImageContent | string | TextContent>;
196
193
  name: string;
197
194
  parameters?: Params;
195
+ timeoutMs?: number;
198
196
  };
199
197
  /**
200
198
  * Tool annotations as defined in MCP Specification (2025-03-26)
@@ -302,6 +300,12 @@ declare class FastMCP<T extends Record<string, unknown> | undefined = undefined>
302
300
  * Starts the server.
303
301
  */
304
302
  start(options?: {
303
+ httpStream: {
304
+ endpoint: `/${string}`;
305
+ port: number;
306
+ };
307
+ transportType: "httpStream";
308
+ } | {
305
309
  sse: {
306
310
  endpoint: `/${string}`;
307
311
  port: number;
package/dist/FastMCP.js CHANGED
@@ -19,7 +19,7 @@ import { EventEmitter } from "events";
19
19
  import { fileTypeFromBuffer } from "file-type";
20
20
  import { readFile } from "fs/promises";
21
21
  import Fuse from "fuse.js";
22
- import { startSSEServer } from "mcp-proxy";
22
+ import { startHTTPStreamServer, startSSEServer } from "mcp-proxy";
23
23
  import { setTimeout as delay } from "timers/promises";
24
24
  import { fetch } from "undici";
25
25
  import parseURITemplate from "uri-templates";
@@ -27,53 +27,107 @@ import { toJsonSchema } from "xsschema";
27
27
  import { z } from "zod";
28
28
  var imageContent = async (input) => {
29
29
  let rawData;
30
- if ("url" in input) {
31
- const response = await fetch(input.url);
32
- if (!response.ok) {
33
- throw new Error(`Failed to fetch image from URL: ${response.statusText}`);
30
+ try {
31
+ if ("url" in input) {
32
+ try {
33
+ const response = await fetch(input.url);
34
+ if (!response.ok) {
35
+ throw new Error(
36
+ `Server responded with status: ${response.status} - ${response.statusText}`
37
+ );
38
+ }
39
+ rawData = Buffer.from(await response.arrayBuffer());
40
+ } catch (error) {
41
+ throw new Error(
42
+ `Failed to fetch image from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`
43
+ );
44
+ }
45
+ } else if ("path" in input) {
46
+ try {
47
+ rawData = await readFile(input.path);
48
+ } catch (error) {
49
+ throw new Error(
50
+ `Failed to read image from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`
51
+ );
52
+ }
53
+ } else if ("buffer" in input) {
54
+ rawData = input.buffer;
55
+ } else {
56
+ throw new Error(
57
+ "Invalid input: Provide a valid 'url', 'path', or 'buffer'"
58
+ );
59
+ }
60
+ const mimeType = await fileTypeFromBuffer(rawData);
61
+ if (!mimeType || !mimeType.mime.startsWith("image/")) {
62
+ console.warn(
63
+ `Warning: Content may not be a valid image. Detected MIME: ${mimeType?.mime || "unknown"}`
64
+ );
65
+ }
66
+ const base64Data = rawData.toString("base64");
67
+ return {
68
+ data: base64Data,
69
+ mimeType: mimeType?.mime ?? "image/png",
70
+ type: "image"
71
+ };
72
+ } catch (error) {
73
+ if (error instanceof Error) {
74
+ throw error;
75
+ } else {
76
+ throw new Error(`Unexpected error processing image: ${String(error)}`);
34
77
  }
35
- rawData = Buffer.from(await response.arrayBuffer());
36
- } else if ("path" in input) {
37
- rawData = await readFile(input.path);
38
- } else if ("buffer" in input) {
39
- rawData = input.buffer;
40
- } else {
41
- throw new Error(
42
- "Invalid input: Provide a valid 'url', 'path', or 'buffer'"
43
- );
44
78
  }
45
- const mimeType = await fileTypeFromBuffer(rawData);
46
- const base64Data = rawData.toString("base64");
47
- return {
48
- data: base64Data,
49
- mimeType: mimeType?.mime ?? "image/png",
50
- type: "image"
51
- };
52
79
  };
53
80
  var audioContent = async (input) => {
54
81
  let rawData;
55
- if ("url" in input) {
56
- const response = await fetch(input.url);
57
- if (!response.ok) {
58
- throw new Error(`Failed to fetch audio from URL: ${response.statusText}`);
82
+ try {
83
+ if ("url" in input) {
84
+ try {
85
+ const response = await fetch(input.url);
86
+ if (!response.ok) {
87
+ throw new Error(
88
+ `Server responded with status: ${response.status} - ${response.statusText}`
89
+ );
90
+ }
91
+ rawData = Buffer.from(await response.arrayBuffer());
92
+ } catch (error) {
93
+ throw new Error(
94
+ `Failed to fetch audio from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`
95
+ );
96
+ }
97
+ } else if ("path" in input) {
98
+ try {
99
+ rawData = await readFile(input.path);
100
+ } catch (error) {
101
+ throw new Error(
102
+ `Failed to read audio from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`
103
+ );
104
+ }
105
+ } else if ("buffer" in input) {
106
+ rawData = input.buffer;
107
+ } else {
108
+ throw new Error(
109
+ "Invalid input: Provide a valid 'url', 'path', or 'buffer'"
110
+ );
111
+ }
112
+ const mimeType = await fileTypeFromBuffer(rawData);
113
+ if (!mimeType || !mimeType.mime.startsWith("audio/")) {
114
+ console.warn(
115
+ `Warning: Content may not be a valid audio file. Detected MIME: ${mimeType?.mime || "unknown"}`
116
+ );
117
+ }
118
+ const base64Data = rawData.toString("base64");
119
+ return {
120
+ data: base64Data,
121
+ mimeType: mimeType?.mime ?? "audio/mpeg",
122
+ type: "audio"
123
+ };
124
+ } catch (error) {
125
+ if (error instanceof Error) {
126
+ throw error;
127
+ } else {
128
+ throw new Error(`Unexpected error processing audio: ${String(error)}`);
59
129
  }
60
- rawData = Buffer.from(await response.arrayBuffer());
61
- } else if ("path" in input) {
62
- rawData = await readFile(input.path);
63
- } else if ("buffer" in input) {
64
- rawData = input.buffer;
65
- } else {
66
- throw new Error(
67
- "Invalid input: Provide a valid 'url', 'path', or 'buffer'"
68
- );
69
130
  }
70
- const mimeType = await fileTypeFromBuffer(rawData);
71
- const base64Data = rawData.toString("base64");
72
- return {
73
- data: base64Data,
74
- mimeType: mimeType?.mime ?? "audio/mpeg",
75
- type: "audio"
76
- };
77
131
  };
78
132
  var FastMCPError = class extends Error {
79
133
  constructor(message) {
@@ -645,11 +699,23 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
645
699
  });
646
700
  }
647
701
  };
648
- const maybeStringResult = await tool.execute(args, {
702
+ const executeToolPromise = tool.execute(args, {
649
703
  log,
650
704
  reportProgress,
651
705
  session: this.#auth
652
706
  });
707
+ const maybeStringResult = await (tool.timeoutMs ? Promise.race([
708
+ executeToolPromise,
709
+ new Promise((_, reject) => {
710
+ setTimeout(() => {
711
+ reject(
712
+ new UserError(
713
+ `Tool execution timed out after ${tool.timeoutMs}ms`
714
+ )
715
+ );
716
+ }, tool.timeoutMs);
717
+ })
718
+ ]) : executeToolPromise);
653
719
  if (typeof maybeStringResult === "string") {
654
720
  result = ContentResultZodSchema.parse({
655
721
  content: [{ text: maybeStringResult, type: "text" }]
@@ -691,6 +757,7 @@ var FastMCP = class extends FastMCPEventEmitter {
691
757
  return this.#sessions;
692
758
  }
693
759
  #authenticate;
760
+ #httpStreamServer = null;
694
761
  #options;
695
762
  #prompts = [];
696
763
  #resources = [];
@@ -778,6 +845,40 @@ var FastMCP = class extends FastMCPEventEmitter {
778
845
  console.info(
779
846
  `[FastMCP info] server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`
780
847
  );
848
+ } else if (options.transportType === "httpStream") {
849
+ this.#httpStreamServer = await startHTTPStreamServer({
850
+ createServer: async (request) => {
851
+ let auth;
852
+ if (this.#authenticate) {
853
+ auth = await this.#authenticate(request);
854
+ }
855
+ return new FastMCPSession({
856
+ auth,
857
+ name: this.#options.name,
858
+ prompts: this.#prompts,
859
+ resources: this.#resources,
860
+ resourcesTemplates: this.#resourcesTemplates,
861
+ tools: this.#tools,
862
+ version: this.#options.version
863
+ });
864
+ },
865
+ endpoint: options.httpStream.endpoint,
866
+ onClose: (session) => {
867
+ this.emit("disconnect", {
868
+ session
869
+ });
870
+ },
871
+ onConnect: async (session) => {
872
+ this.#sessions.push(session);
873
+ this.emit("connect", {
874
+ session
875
+ });
876
+ },
877
+ port: options.httpStream.port
878
+ });
879
+ console.info(
880
+ `[FastMCP info] server is running on HTTP Stream at http://localhost:${options.httpStream.port}${options.httpStream.endpoint}`
881
+ );
781
882
  } else {
782
883
  throw new Error("Invalid transport type");
783
884
  }
@@ -787,7 +888,10 @@ var FastMCP = class extends FastMCPEventEmitter {
787
888
  */
788
889
  async stop() {
789
890
  if (this.#sseServer) {
790
- this.#sseServer.close();
891
+ await this.#sseServer.close();
892
+ }
893
+ if (this.#httpStreamServer) {
894
+ await this.#httpStreamServer.close();
791
895
  }
792
896
  }
793
897
  };
@@ -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 AudioContent,\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 { startSSEServer } 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\n/**\n * Generates an image content object from a URL, file path, or buffer.\n */\nexport const imageContent = async (\n input: { buffer: Buffer } | { path: string } | { url: string },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n if (\"url\" in input) {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image from URL: ${response.statusText}`);\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } else if (\"path\" in input) {\n rawData = await readFile(input.path);\n } else if (\"buffer\" in input) {\n rawData = input.buffer;\n } else {\n throw new Error(\n \"Invalid input: Provide a valid 'url', 'path', or 'buffer'\",\n );\n }\n\n const mimeType = await fileTypeFromBuffer(rawData);\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n type: \"image\",\n } as const;\n};\n\nexport const audioContent = async (\n input: { buffer: Buffer } | { path: string } | { url: string },\n): Promise<AudioContent> => {\n let rawData: Buffer;\n\n if (\"url\" in input) {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch audio from URL: ${response.statusText}`);\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } else if (\"path\" in input) {\n rawData = await readFile(input.path);\n } else if (\"buffer\" in input) {\n rawData = input.buffer;\n } else {\n throw new Error(\n \"Invalid input: Provide a valid 'url', 'path', or 'buffer'\",\n );\n }\n\n const mimeType = await fileTypeFromBuffer(rawData);\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"audio/mpeg\",\n type: \"audio\",\n } as const;\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};\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 Content = ImageContent | TextContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n]) satisfies z.ZodType<Content>;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType<ContentResult>;\n\ntype Completion = {\n 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}>;\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}>;\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 instructions?: string;\n name: string;\n version: `${number}.${number}.${number}`;\n};\n\ntype Tool<\n T extends FastMCPSessionAuth,\n Params extends ToolParameters = ToolParameters,\n> = {\n annotations?: ToolAnnotations;\n description?: string;\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n AudioContent | ContentResult | ImageContent | string | TextContent\n >;\n name: string;\n parameters?: Params;\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 #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Prompt[] = [];\n\n #resources: Resource[] = [];\n\n #resourceTemplates: ResourceTemplate[] = [];\n\n #roots: Root[] = [];\n\n #server: Server;\n\n constructor({\n auth,\n instructions,\n name,\n prompts,\n resources,\n resourcesTemplates,\n tools,\n version,\n }: {\n auth?: T;\n instructions?: string;\n name: string;\n prompts: Prompt[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n tools: Tool<T>[];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\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 (this.#clientCapabilities?.roots?.listChanged) {\n try {\n const roots = await this.#server.listRoots();\n this.#roots = roots.roots;\n } catch (e) {\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 if (this.#clientCapabilities) {\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 console.warn(\"[FastMCP warning] server is not responding to ping\");\n }\n }, 1000);\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 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 this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server.listRoots().then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n });\n },\n );\n }\n\n private 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 : undefined,\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 const maybeStringResult = await tool.execute(args, {\n log,\n reportProgress,\n session: this.#auth,\n });\n\n 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 #options: ServerOptions<T>;\n #prompts: InputPrompt[] = [];\n #resources: Resource[] = [];\n #resourcesTemplates: InputResourceTemplate[] = [];\n #sessions: FastMCPSession<T>[] = [];\n #sseServer: null | SSEServer = null;\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 sse: { endpoint: `/${string}`; port: number };\n transportType: \"sse\";\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 prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\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 === \"sse\") {\n this.#sseServer = await startSSEServer<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 prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n tools: this.#tools,\n version: this.#options.version,\n });\n },\n endpoint: options.sse.endpoint as `/${string}`,\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 port: options.sse.port,\n });\n\n console.info(\n `[FastMCP info] server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,\n );\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#sseServer) {\n this.#sseServer.close();\n }\n }\n}\n\nexport type { Context };\nexport type { Tool, ToolParameters };\nexport type { Content, 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 AudioContent,\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 { startHTTPStreamServer, startSSEServer } 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};\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 Content = ImageContent | TextContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n]) satisfies z.ZodType<Content>;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType<ContentResult>;\n\ntype Completion = {\n 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}>;\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}>;\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 instructions?: string;\n name: string;\n version: `${number}.${number}.${number}`;\n};\n\ntype Tool<\n T extends FastMCPSessionAuth,\n Params extends ToolParameters = ToolParameters,\n> = {\n annotations?: ToolAnnotations;\n description?: string;\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n AudioContent | ContentResult | ImageContent | string | TextContent\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 #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Prompt[] = [];\n\n #resources: Resource[] = [];\n\n #resourceTemplates: ResourceTemplate[] = [];\n\n #roots: Root[] = [];\n\n #server: Server;\n\n constructor({\n auth,\n instructions,\n name,\n prompts,\n resources,\n resourcesTemplates,\n tools,\n version,\n }: {\n auth?: T;\n instructions?: string;\n name: string;\n prompts: Prompt[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n tools: Tool<T>[];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\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 (this.#clientCapabilities?.roots?.listChanged) {\n try {\n const roots = await this.#server.listRoots();\n this.#roots = roots.roots;\n } catch (e) {\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 if (this.#clientCapabilities) {\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 console.warn(\"[FastMCP warning] server is not responding to ping\");\n }\n }, 1000);\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 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 this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server.listRoots().then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n });\n },\n );\n }\n\n private 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 : undefined,\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 const executeToolPromise = tool.execute(args, {\n log,\n reportProgress,\n session: this.#auth,\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);\n\n 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 #sseServer: null | SSEServer = null;\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: { endpoint: `/${string}`; port: number };\n transportType: \"httpStream\";\n }\n | {\n sse: { endpoint: `/${string}`; port: number };\n transportType: \"sse\";\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 prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\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 === \"sse\") {\n this.#sseServer = await startSSEServer<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 prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n tools: this.#tools,\n version: this.#options.version,\n });\n },\n endpoint: options.sse.endpoint as `/${string}`,\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 port: options.sse.port,\n });\n\n console.info(\n `[FastMCP info] server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,\n );\n } else if (options.transportType === \"httpStream\") {\n this.#httpStreamServer = await startHTTPStreamServer<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 prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n tools: this.#tools,\n version: this.#options.version,\n });\n },\n endpoint: options.httpStream.endpoint as `/${string}`,\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 port: options.httpStream.port,\n });\n\n console.info(\n `[FastMCP info] server is running on HTTP Stream at http://localhost:${options.httpStream.port}${options.httpStream.endpoint}`,\n );\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#sseServer) {\n await this.#sseServer.close();\n }\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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glama/fastmcp",
3
- "version": "1.23.2",
3
+ "version": "1.25.0",
4
4
  "exports": "./src/FastMCP.ts",
5
5
  "include": ["src/FastMCP.ts", "src/bin/fastmcp.ts"]
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastmcp",
3
- "version": "1.23.2",
3
+ "version": "1.25.0",
4
4
  "main": "dist/FastMCP.js",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -26,7 +26,7 @@
26
26
  "execa": "^9.5.2",
27
27
  "file-type": "^20.4.1",
28
28
  "fuse.js": "^7.1.0",
29
- "mcp-proxy": "^2.12.2",
29
+ "mcp-proxy": "^2.13.1",
30
30
  "strict-event-emitter-types": "^2.0.0",
31
31
  "undici": "^7.8.0",
32
32
  "uri-templates": "^0.2.0",
@@ -1,5 +1,6 @@
1
1
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
3
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
4
  import {
4
5
  CreateMessageRequestSchema,
5
6
  ErrorCode,
@@ -15,7 +16,14 @@ import { setTimeout as delay } from "timers/promises";
15
16
  import { expect, test, vi } from "vitest";
16
17
  import { z } from "zod";
17
18
 
18
- import { FastMCP, FastMCPSession, imageContent, UserError } from "./FastMCP.js";
19
+ import {
20
+ FastMCP,
21
+ FastMCPSession,
22
+ imageContent,
23
+ UserError,
24
+ type TextContent,
25
+ type ContentResult,
26
+ } from "./FastMCP.js";
19
27
 
20
28
  const runWithTestServer = async ({
21
29
  client: createClient,
@@ -398,6 +406,60 @@ test("sets logging levels", async () => {
398
406
  });
399
407
  });
400
408
 
409
+ test("handles tool timeout", async () => {
410
+ await runWithTestServer({
411
+ run: async ({ client }) => {
412
+ const result = await client.callTool({
413
+ arguments: {
414
+ a: 1500,
415
+ b: 2,
416
+ },
417
+ name: "add",
418
+ });
419
+
420
+ expect(result.isError).toBe(true);
421
+
422
+ const result_typed = result as ContentResult;
423
+
424
+ expect(Array.isArray(result_typed.content)).toBe(true);
425
+ expect(result_typed.content.length).toBe(1);
426
+
427
+ const firstItem = result_typed.content[0] as TextContent;
428
+
429
+ expect(firstItem.type).toBe("text");
430
+ expect(firstItem.text).toBeDefined();
431
+ expect(firstItem.text).toContain("timed out");
432
+ },
433
+ server: async () => {
434
+ const server = new FastMCP({
435
+ name: "Test",
436
+ version: "1.0.0",
437
+ });
438
+
439
+ server.addTool({
440
+ description: "Add two numbers with potential timeout",
441
+ execute: async (args) => {
442
+ console.log(`Adding ${args.a} and ${args.b}`);
443
+
444
+ if (args.a > 1000 || args.b > 1000) {
445
+ await new Promise((resolve) => setTimeout(resolve, 3000));
446
+ }
447
+
448
+ return String(args.a + args.b);
449
+ },
450
+ name: "add",
451
+ parameters: z.object({
452
+ a: z.number(),
453
+ b: z.number(),
454
+ }),
455
+ timeoutMs: 1000,
456
+ });
457
+
458
+ return server;
459
+ },
460
+ });
461
+ });
462
+
401
463
  test("sends logging messages to the client", async () => {
402
464
  await runWithTestServer({
403
465
  run: async ({ client }) => {
@@ -1292,7 +1354,7 @@ test("throws ErrorCode.InvalidParams if tool parameters do not match zod schema"
1292
1354
 
1293
1355
  // @ts-expect-error - we know that error is an McpError
1294
1356
  expect(error.message).toBe(
1295
- "MCP error -32602: MCP error -32602: Invalid add parameters: [{\"code\":\"invalid_type\",\"expected\":\"number\",\"received\":\"string\",\"path\":[\"b\"],\"message\":\"Expected number, received string\"}]",
1357
+ 'MCP error -32602: MCP error -32602: Invalid add parameters: [{"code":"invalid_type","expected":"number","received":"string","path":["b"],"message":"Expected number, received string"}]',
1296
1358
  );
1297
1359
  }
1298
1360
  },
@@ -1338,7 +1400,7 @@ test("server remains usable after InvalidParams error", async () => {
1338
1400
 
1339
1401
  // @ts-expect-error - we know that error is an McpError
1340
1402
  expect(error.message).toBe(
1341
- "MCP error -32602: MCP error -32602: Invalid add parameters: [{\"code\":\"invalid_type\",\"expected\":\"number\",\"received\":\"string\",\"path\":[\"b\"],\"message\":\"Expected number, received string\"}]",
1403
+ 'MCP error -32602: MCP error -32602: Invalid add parameters: [{"code":"invalid_type","expected":"number","received":"string","path":["b"],"message":"Expected number, received string"}]',
1342
1404
  );
1343
1405
  }
1344
1406
 
@@ -1686,3 +1748,83 @@ test("blocks unauthorized requests", async () => {
1686
1748
  await client.connect(transport);
1687
1749
  }).rejects.toThrow("SSE error: Non-200 status code (401)");
1688
1750
  });
1751
+
1752
+ // We now use a direct approach for testing HTTP Stream functionality
1753
+ // rather than a helper function
1754
+
1755
+ // Set longer timeout for HTTP Stream tests
1756
+ test("HTTP Stream: calls a tool", { timeout: 20000 }, async () => {
1757
+ console.log("Starting HTTP Stream test...");
1758
+ const port = await getRandomPort();
1759
+
1760
+ // Create server directly (don't use helper function)
1761
+ const server = new FastMCP({
1762
+ name: "Test",
1763
+ version: "1.0.0",
1764
+ });
1765
+
1766
+ server.addTool({
1767
+ description: "Add two numbers",
1768
+ execute: async (args) => {
1769
+ return String(args.a + args.b);
1770
+ },
1771
+ name: "add",
1772
+ parameters: z.object({
1773
+ a: z.number(),
1774
+ b: z.number(),
1775
+ }),
1776
+ });
1777
+
1778
+ await server.start({
1779
+ httpStream: {
1780
+ endpoint: "/httpStream",
1781
+ port,
1782
+ },
1783
+ transportType: "httpStream",
1784
+ });
1785
+
1786
+ try {
1787
+ // Create client
1788
+ const client = new Client(
1789
+ {
1790
+ name: "example-client",
1791
+ version: "1.0.0",
1792
+ },
1793
+ {
1794
+ capabilities: {},
1795
+ },
1796
+ );
1797
+
1798
+ // IMPORTANT: Don't provide sessionId manually with HTTP streaming
1799
+ // The server will generate a session ID automatically
1800
+ const transport = new StreamableHTTPClientTransport(
1801
+ new URL(`http://localhost:${port}/httpStream`),
1802
+ );
1803
+
1804
+ // Connect client to server
1805
+ await client.connect(transport);
1806
+
1807
+ // Wait a bit to ensure connection is established
1808
+ await delay(1000);
1809
+
1810
+ // Call tool
1811
+ const result = await client.callTool({
1812
+ arguments: {
1813
+ a: 1,
1814
+ b: 2,
1815
+ },
1816
+ name: "add",
1817
+ });
1818
+
1819
+ // Check result
1820
+ expect(result).toEqual({
1821
+ content: [{ text: "3", type: "text" }],
1822
+ });
1823
+
1824
+ // Clean up connection
1825
+ await transport.terminateSession();
1826
+ await client.close();
1827
+ } finally {
1828
+ await server.stop();
1829
+ }
1830
+ });
package/src/FastMCP.ts CHANGED
@@ -26,7 +26,7 @@ import { fileTypeFromBuffer } from "file-type";
26
26
  import { readFile } from "fs/promises";
27
27
  import Fuse from "fuse.js";
28
28
  import http from "http";
29
- import { startSSEServer } from "mcp-proxy";
29
+ import { startHTTPStreamServer, startSSEServer } from "mcp-proxy";
30
30
  import { StrictEventEmitter } from "strict-event-emitter-types";
31
31
  import { setTimeout as delay } from "timers/promises";
32
32
  import { fetch } from "undici";
@@ -48,41 +48,66 @@ type FastMCPSessionEvents = {
48
48
  rootsChanged: (event: { roots: Root[] }) => void;
49
49
  };
50
50
 
51
- /**
52
- * Generates an image content object from a URL, file path, or buffer.
53
- */
54
51
  export const imageContent = async (
55
52
  input: { buffer: Buffer } | { path: string } | { url: string },
56
53
  ): Promise<ImageContent> => {
57
54
  let rawData: Buffer;
58
55
 
59
- if ("url" in input) {
60
- const response = await fetch(input.url);
56
+ try {
57
+ if ("url" in input) {
58
+ try {
59
+ const response = await fetch(input.url);
60
+
61
+ if (!response.ok) {
62
+ throw new Error(
63
+ `Server responded with status: ${response.status} - ${response.statusText}`,
64
+ );
65
+ }
61
66
 
62
- if (!response.ok) {
63
- throw new Error(`Failed to fetch image from URL: ${response.statusText}`);
67
+ rawData = Buffer.from(await response.arrayBuffer());
68
+ } catch (error) {
69
+ throw new Error(
70
+ `Failed to fetch image from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`,
71
+ );
72
+ }
73
+ } else if ("path" in input) {
74
+ try {
75
+ rawData = await readFile(input.path);
76
+ } catch (error) {
77
+ throw new Error(
78
+ `Failed to read image from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`,
79
+ );
80
+ }
81
+ } else if ("buffer" in input) {
82
+ rawData = input.buffer;
83
+ } else {
84
+ throw new Error(
85
+ "Invalid input: Provide a valid 'url', 'path', or 'buffer'",
86
+ );
64
87
  }
65
88
 
66
- rawData = Buffer.from(await response.arrayBuffer());
67
- } else if ("path" in input) {
68
- rawData = await readFile(input.path);
69
- } else if ("buffer" in input) {
70
- rawData = input.buffer;
71
- } else {
72
- throw new Error(
73
- "Invalid input: Provide a valid 'url', 'path', or 'buffer'",
74
- );
75
- }
89
+ const mimeType = await fileTypeFromBuffer(rawData);
76
90
 
77
- const mimeType = await fileTypeFromBuffer(rawData);
91
+ if (!mimeType || !mimeType.mime.startsWith("image/")) {
92
+ console.warn(
93
+ `Warning: Content may not be a valid image. Detected MIME: ${mimeType?.mime || "unknown"}`,
94
+ );
95
+ }
78
96
 
79
- const base64Data = rawData.toString("base64");
97
+ const base64Data = rawData.toString("base64");
80
98
 
81
- return {
82
- data: base64Data,
83
- mimeType: mimeType?.mime ?? "image/png",
84
- type: "image",
85
- } as const;
99
+ return {
100
+ data: base64Data,
101
+ mimeType: mimeType?.mime ?? "image/png",
102
+ type: "image",
103
+ } as const;
104
+ } catch (error) {
105
+ if (error instanceof Error) {
106
+ throw error;
107
+ } else {
108
+ throw new Error(`Unexpected error processing image: ${String(error)}`);
109
+ }
110
+ }
86
111
  };
87
112
 
88
113
  export const audioContent = async (
@@ -90,33 +115,61 @@ export const audioContent = async (
90
115
  ): Promise<AudioContent> => {
91
116
  let rawData: Buffer;
92
117
 
93
- if ("url" in input) {
94
- const response = await fetch(input.url);
118
+ try {
119
+ if ("url" in input) {
120
+ try {
121
+ const response = await fetch(input.url);
122
+
123
+ if (!response.ok) {
124
+ throw new Error(
125
+ `Server responded with status: ${response.status} - ${response.statusText}`,
126
+ );
127
+ }
95
128
 
96
- if (!response.ok) {
97
- throw new Error(`Failed to fetch audio from URL: ${response.statusText}`);
129
+ rawData = Buffer.from(await response.arrayBuffer());
130
+ } catch (error) {
131
+ throw new Error(
132
+ `Failed to fetch audio from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`,
133
+ );
134
+ }
135
+ } else if ("path" in input) {
136
+ try {
137
+ rawData = await readFile(input.path);
138
+ } catch (error) {
139
+ throw new Error(
140
+ `Failed to read audio from path (${input.path}): ${error instanceof Error ? error.message : String(error)}`,
141
+ );
142
+ }
143
+ } else if ("buffer" in input) {
144
+ rawData = input.buffer;
145
+ } else {
146
+ throw new Error(
147
+ "Invalid input: Provide a valid 'url', 'path', or 'buffer'",
148
+ );
98
149
  }
99
150
 
100
- rawData = Buffer.from(await response.arrayBuffer());
101
- } else if ("path" in input) {
102
- rawData = await readFile(input.path);
103
- } else if ("buffer" in input) {
104
- rawData = input.buffer;
105
- } else {
106
- throw new Error(
107
- "Invalid input: Provide a valid 'url', 'path', or 'buffer'",
108
- );
109
- }
151
+ const mimeType = await fileTypeFromBuffer(rawData);
110
152
 
111
- const mimeType = await fileTypeFromBuffer(rawData);
153
+ if (!mimeType || !mimeType.mime.startsWith("audio/")) {
154
+ console.warn(
155
+ `Warning: Content may not be a valid audio file. Detected MIME: ${mimeType?.mime || "unknown"}`,
156
+ );
157
+ }
112
158
 
113
- const base64Data = rawData.toString("base64");
159
+ const base64Data = rawData.toString("base64");
114
160
 
115
- return {
116
- data: base64Data,
117
- mimeType: mimeType?.mime ?? "audio/mpeg",
118
- type: "audio",
119
- } as const;
161
+ return {
162
+ data: base64Data,
163
+ mimeType: mimeType?.mime ?? "audio/mpeg",
164
+ type: "audio",
165
+ } as const;
166
+ } catch (error) {
167
+ if (error instanceof Error) {
168
+ throw error;
169
+ } else {
170
+ throw new Error(`Unexpected error processing audio: ${String(error)}`);
171
+ }
172
+ }
120
173
  };
121
174
 
122
175
  type Context<T extends FastMCPSessionAuth> = {
@@ -394,6 +447,7 @@ type Tool<
394
447
  >;
395
448
  name: string;
396
449
  parameters?: Params;
450
+ timeoutMs?: number;
397
451
  };
398
452
 
399
453
  /**
@@ -1076,12 +1130,29 @@ export class FastMCPSession<
1076
1130
  },
1077
1131
  };
1078
1132
 
1079
- const maybeStringResult = await tool.execute(args, {
1133
+ // Create a promise for tool execution
1134
+ const executeToolPromise = tool.execute(args, {
1080
1135
  log,
1081
1136
  reportProgress,
1082
1137
  session: this.#auth,
1083
1138
  });
1084
1139
 
1140
+ // Handle timeout if specified
1141
+ const maybeStringResult = await (tool.timeoutMs
1142
+ ? Promise.race([
1143
+ executeToolPromise,
1144
+ new Promise<never>((_, reject) => {
1145
+ setTimeout(() => {
1146
+ reject(
1147
+ new UserError(
1148
+ `Tool execution timed out after ${tool.timeoutMs}ms`,
1149
+ ),
1150
+ );
1151
+ }, tool.timeoutMs);
1152
+ }),
1153
+ ])
1154
+ : executeToolPromise);
1155
+
1085
1156
  if (typeof maybeStringResult === "string") {
1086
1157
  result = ContentResultZodSchema.parse({
1087
1158
  content: [{ text: maybeStringResult, type: "text" }],
@@ -1127,6 +1198,7 @@ export class FastMCP<
1127
1198
  return this.#sessions;
1128
1199
  }
1129
1200
  #authenticate: Authenticate<T> | undefined;
1201
+ #httpStreamServer: null | SSEServer = null;
1130
1202
  #options: ServerOptions<T>;
1131
1203
  #prompts: InputPrompt[] = [];
1132
1204
  #resources: Resource[] = [];
@@ -1180,6 +1252,10 @@ export class FastMCP<
1180
1252
  */
1181
1253
  public async start(
1182
1254
  options:
1255
+ | {
1256
+ httpStream: { endpoint: `/${string}`; port: number };
1257
+ transportType: "httpStream";
1258
+ }
1183
1259
  | {
1184
1260
  sse: { endpoint: `/${string}`; port: number };
1185
1261
  transportType: "sse";
@@ -1246,6 +1322,44 @@ export class FastMCP<
1246
1322
  console.info(
1247
1323
  `[FastMCP info] server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,
1248
1324
  );
1325
+ } else if (options.transportType === "httpStream") {
1326
+ this.#httpStreamServer = await startHTTPStreamServer<FastMCPSession<T>>({
1327
+ createServer: async (request) => {
1328
+ let auth: T | undefined;
1329
+
1330
+ if (this.#authenticate) {
1331
+ auth = await this.#authenticate(request);
1332
+ }
1333
+
1334
+ return new FastMCPSession<T>({
1335
+ auth,
1336
+ name: this.#options.name,
1337
+ prompts: this.#prompts,
1338
+ resources: this.#resources,
1339
+ resourcesTemplates: this.#resourcesTemplates,
1340
+ tools: this.#tools,
1341
+ version: this.#options.version,
1342
+ });
1343
+ },
1344
+ endpoint: options.httpStream.endpoint as `/${string}`,
1345
+ onClose: (session) => {
1346
+ this.emit("disconnect", {
1347
+ session,
1348
+ });
1349
+ },
1350
+ onConnect: async (session) => {
1351
+ this.#sessions.push(session);
1352
+
1353
+ this.emit("connect", {
1354
+ session,
1355
+ });
1356
+ },
1357
+ port: options.httpStream.port,
1358
+ });
1359
+
1360
+ console.info(
1361
+ `[FastMCP info] server is running on HTTP Stream at http://localhost:${options.httpStream.port}${options.httpStream.endpoint}`,
1362
+ );
1249
1363
  } else {
1250
1364
  throw new Error("Invalid transport type");
1251
1365
  }
@@ -1256,7 +1370,10 @@ export class FastMCP<
1256
1370
  */
1257
1371
  public async stop() {
1258
1372
  if (this.#sseServer) {
1259
- this.#sseServer.close();
1373
+ await this.#sseServer.close();
1374
+ }
1375
+ if (this.#httpStreamServer) {
1376
+ await this.#httpStreamServer.close();
1260
1377
  }
1261
1378
  }
1262
1379
  }
@@ -1,10 +1,6 @@
1
1
  import { type } from "arktype";
2
2
  import * as v from "valibot";
3
3
  import { z } from "zod";
4
-
5
- /**
6
- * This is a complete example of an MCP server.
7
- */
8
4
  import { FastMCP } from "../FastMCP.js";
9
5
 
10
6
  const server = new FastMCP({
@@ -49,13 +45,26 @@ server.addTool({
49
45
  title: "Addition (ArkType)",
50
46
  },
51
47
  description: "Add two numbers (using ArkType schema)",
52
- execute: async (args) => {
48
+ execute: async (args, { log }) => {
53
49
  // args is typed as { a: number, b: number } based on AddParamsArkType.infer
54
50
  console.log(`[ArkType] Adding ${args.a} and ${args.b}`);
51
+
52
+ // Demonstrate long-running operation that might need a timeout
53
+ log.info("Starting calculation with potential delay...");
54
+
55
+ // Simulate a complex calculation process
56
+ if (args.a > 1000 || args.b > 1000) {
57
+ log.warn("Large numbers detected, operation might take longer");
58
+ // In a real implementation, this delay might be a slow operation
59
+ await new Promise((resolve) => setTimeout(resolve, 3000));
60
+ }
61
+
55
62
  return String(args.a + args.b);
56
63
  },
57
64
  name: "add-arktype",
58
65
  parameters: AddParamsArkType,
66
+ // Will abort execution after 2s
67
+ timeoutMs: 2000,
59
68
  });
60
69
 
61
70
  // --- Valibot Example ---
@@ -105,6 +114,51 @@ server.addPrompt({
105
114
  name: "git-commit",
106
115
  });
107
116
 
108
- server.start({
109
- transportType: "stdio",
110
- });
117
+ // Select transport type based on command line arguments
118
+ const transportType = process.argv.includes("--http-stream")
119
+ ? "httpStream"
120
+ : "stdio";
121
+
122
+ if (transportType === "httpStream") {
123
+ // Start with HTTP streaming transport
124
+ const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080;
125
+
126
+ server.start({
127
+ httpStream: {
128
+ endpoint: "/stream",
129
+ port: PORT,
130
+ },
131
+ transportType: "httpStream",
132
+ });
133
+
134
+ console.log(
135
+ `HTTP Stream MCP server is running at http://localhost:${PORT}/stream`,
136
+ );
137
+ console.log("Use StreamableHTTPClientTransport to connect to this server");
138
+ console.log("For example:");
139
+ console.log(`
140
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
141
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
142
+
143
+ const client = new Client(
144
+ {
145
+ name: "example-client",
146
+ version: "1.0.0",
147
+ },
148
+ {
149
+ capabilities: {},
150
+ },
151
+ );
152
+
153
+ const transport = new StreamableHTTPClientTransport(
154
+ new URL("http://localhost:${PORT}/stream"),
155
+ );
156
+
157
+ await client.connect(transport);
158
+ `);
159
+ } else {
160
+ // Default to stdio transport
161
+ server.start({
162
+ transportType: "stdio",
163
+ });
164
+ }