fastmcp 3.14.4 → 3.15.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/dist/FastMCP.d.ts CHANGED
@@ -618,6 +618,7 @@ declare class FastMCP<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends
618
618
  enableJsonResponse?: boolean;
619
619
  endpoint?: `/${string}`;
620
620
  eventStore?: EventStore;
621
+ host?: string;
621
622
  port: number;
622
623
  stateless?: boolean;
623
624
  };
package/dist/FastMCP.js CHANGED
@@ -1076,7 +1076,21 @@ var FastMCP = class extends FastMCPEventEmitter {
1076
1076
  const config = this.#parseRuntimeConfig(options);
1077
1077
  if (config.transportType === "stdio") {
1078
1078
  const transport = new StdioServerTransport();
1079
+ let auth;
1080
+ if (this.#authenticate) {
1081
+ try {
1082
+ auth = await this.#authenticate(
1083
+ void 0
1084
+ );
1085
+ } catch (error) {
1086
+ this.#logger.error(
1087
+ "[FastMCP error] Authentication failed for stdio transport:",
1088
+ error instanceof Error ? error.message : String(error)
1089
+ );
1090
+ }
1091
+ }
1079
1092
  const session = new FastMCPSession({
1093
+ auth,
1080
1094
  instructions: this.#options.instructions,
1081
1095
  logger: this.#logger,
1082
1096
  name: this.#options.name,
@@ -1099,7 +1113,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1099
1113
  const httpConfig = config.httpStream;
1100
1114
  if (httpConfig.stateless) {
1101
1115
  this.#logger.info(
1102
- `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`
1116
+ `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`
1103
1117
  );
1104
1118
  this.#httpStreamServer = await startHTTPServer({
1105
1119
  createServer: async (request) => {
@@ -1111,6 +1125,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1111
1125
  },
1112
1126
  enableJsonResponse: httpConfig.enableJsonResponse,
1113
1127
  eventStore: httpConfig.eventStore,
1128
+ host: httpConfig.host,
1114
1129
  // In stateless mode, we don't track sessions
1115
1130
  onClose: async () => {
1116
1131
  },
@@ -1120,7 +1135,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1120
1135
  );
1121
1136
  },
1122
1137
  onUnhandledRequest: async (req, res) => {
1123
- await this.#handleUnhandledRequest(req, res, true);
1138
+ await this.#handleUnhandledRequest(req, res, true, httpConfig.host);
1124
1139
  },
1125
1140
  port: httpConfig.port,
1126
1141
  stateless: true,
@@ -1137,6 +1152,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1137
1152
  },
1138
1153
  enableJsonResponse: httpConfig.enableJsonResponse,
1139
1154
  eventStore: httpConfig.eventStore,
1155
+ host: httpConfig.host,
1140
1156
  onClose: async (session) => {
1141
1157
  this.emit("disconnect", {
1142
1158
  session
@@ -1150,13 +1166,18 @@ var FastMCP = class extends FastMCPEventEmitter {
1150
1166
  });
1151
1167
  },
1152
1168
  onUnhandledRequest: async (req, res) => {
1153
- await this.#handleUnhandledRequest(req, res, false);
1169
+ await this.#handleUnhandledRequest(
1170
+ req,
1171
+ res,
1172
+ false,
1173
+ httpConfig.host
1174
+ );
1154
1175
  },
1155
1176
  port: httpConfig.port,
1156
1177
  streamEndpoint: httpConfig.endpoint
1157
1178
  });
1158
1179
  this.#logger.info(
1159
- `[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`
1180
+ `[FastMCP info] server is running on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`
1160
1181
  );
1161
1182
  this.#logger.info(
1162
1183
  `[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`
@@ -1200,12 +1221,12 @@ var FastMCP = class extends FastMCPEventEmitter {
1200
1221
  /**
1201
1222
  * Handles unhandled HTTP requests with health, readiness, and OAuth endpoints
1202
1223
  */
1203
- #handleUnhandledRequest = async (req, res, isStateless = false) => {
1224
+ #handleUnhandledRequest = async (req, res, isStateless = false, host) => {
1204
1225
  const healthConfig = this.#options.health ?? {};
1205
1226
  const enabled = healthConfig.enabled === void 0 ? true : healthConfig.enabled;
1206
1227
  if (enabled) {
1207
1228
  const path = healthConfig.path ?? "/health";
1208
- const url = new URL(req.url || "", "http://localhost");
1229
+ const url = new URL(req.url || "", `http://${host}`);
1209
1230
  try {
1210
1231
  if (req.method === "GET" && url.pathname === path) {
1211
1232
  res.writeHead(healthConfig.status ?? 200, {
@@ -1247,7 +1268,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1247
1268
  }
1248
1269
  const oauthConfig = this.#options.oauth;
1249
1270
  if (oauthConfig?.enabled && req.method === "GET") {
1250
- const url = new URL(req.url || "", "http://localhost");
1271
+ const url = new URL(req.url || "", `http://${host}`);
1251
1272
  if (url.pathname === "/.well-known/oauth-authorization-server" && oauthConfig.authorizationServer) {
1252
1273
  const metadata = convertObjectToSnakeCase(
1253
1274
  oauthConfig.authorizationServer
@@ -1279,15 +1300,18 @@ var FastMCP = class extends FastMCPEventEmitter {
1279
1300
  const portArg = getArg("port");
1280
1301
  const endpointArg = getArg("endpoint");
1281
1302
  const statelessArg = getArg("stateless");
1303
+ const hostArg = getArg("host");
1282
1304
  const envTransport = process.env.FASTMCP_TRANSPORT;
1283
1305
  const envPort = process.env.FASTMCP_PORT;
1284
1306
  const envEndpoint = process.env.FASTMCP_ENDPOINT;
1285
1307
  const envStateless = process.env.FASTMCP_STATELESS;
1308
+ const envHost = process.env.FASTMCP_HOST;
1286
1309
  const transportType = overrides?.transportType || (transportArg === "http-stream" ? "httpStream" : transportArg) || envTransport || "stdio";
1287
1310
  if (transportType === "httpStream") {
1288
1311
  const port = parseInt(
1289
1312
  overrides?.httpStream?.port?.toString() || portArg || envPort || "8080"
1290
1313
  );
1314
+ const host = overrides?.httpStream?.host || hostArg || envHost || "localhost";
1291
1315
  const endpoint = overrides?.httpStream?.endpoint || endpointArg || envEndpoint || "/mcp";
1292
1316
  const enableJsonResponse = overrides?.httpStream?.enableJsonResponse || false;
1293
1317
  const stateless = overrides?.httpStream?.stateless || statelessArg === "true" || envStateless === "true" || false;
@@ -1295,6 +1319,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1295
1319
  httpStream: {
1296
1320
  enableJsonResponse,
1297
1321
  endpoint,
1322
+ host,
1298
1323
  port,
1299
1324
  stateless
1300
1325
  },
@@ -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 { EventStore } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { RequestOptions } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport {\n CallToolRequestSchema,\n ClientCapabilities,\n CompleteRequestSchema,\n CreateMessageRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n GetPromptResult,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListResourcesResult,\n ListResourceTemplatesRequestSchema,\n ListResourceTemplatesResult,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n ResourceLink,\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 { readFile } from \"fs/promises\";\nimport Fuse from \"fuse.js\";\nimport http from \"http\";\nimport { startHTTPServer } from \"mcp-proxy\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { fetch } from \"undici\";\nimport parseURITemplate from \"uri-templates\";\nimport { toJsonSchema } from \"xsschema\";\nimport { z } from \"zod\";\n\nexport interface Logger {\n debug(...args: unknown[]): void;\n error(...args: unknown[]): void;\n info(...args: unknown[]): void;\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n}\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 ready: () => 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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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 { fileTypeFromBuffer } = await import(\"file-type\");\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: ${\n mimeType?.mime || \"unknown\"\n }`,\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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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 { fileTypeFromBuffer } = await import(\"file-type\");\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: ${\n mimeType?.mime || \"unknown\"\n }`,\n );\n }\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"audio/mpeg\",\n type: \"audio\",\n } as const;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n } else {\n throw new Error(`Unexpected error processing audio: ${String(error)}`);\n }\n }\n};\n\ntype Context<T extends FastMCPSessionAuth> = {\n log: {\n debug: (message: string, data?: SerializableValue) => void;\n error: (message: string, data?: SerializableValue) => void;\n info: (message: string, data?: SerializableValue) => void;\n warn: (message: string, data?: SerializableValue) => void;\n };\n reportProgress: (progress: Progress) => Promise<void>;\n session: T | undefined;\n streamContent: (content: Content | Content[]) => Promise<void>;\n};\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\ntype Literal = boolean | null | number | string | undefined;\n\ntype Progress = {\n /**\n * The progress thus far. This should increase every time progress is made, even if the total is unknown.\n */\n progress: number;\n /**\n * Total number of items to process (or total progress required), if known.\n */\n total?: number;\n};\n\ntype SerializableValue =\n | { [key: string]: SerializableValue }\n | Literal\n | SerializableValue[];\n\ntype TextContent = {\n text: string;\n type: \"text\";\n};\n\ntype ToolParameters = StandardSchemaV1;\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class UnexpectedStateError extends FastMCPError {\n public extras?: Extras;\n\n public constructor(message: string, extras?: Extras) {\n super(message);\n this.name = new.target.name;\n this.extras = extras;\n }\n}\n\n/**\n * An error that is meant to be surfaced to the user.\n */\nexport class UserError extends UnexpectedStateError {}\n\nconst TextContentZodSchema = z\n .object({\n /**\n * The text content of the message.\n */\n text: z.string(),\n type: z.literal(\"text\"),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n data: string;\n mimeType: string;\n type: \"image\";\n};\n\nconst ImageContentZodSchema = z\n .object({\n /**\n * The base64-encoded image data.\n */\n data: z.string().base64(),\n /**\n * The MIME type of the image. Different providers may support different image types.\n */\n mimeType: z.string(),\n type: z.literal(\"image\"),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype AudioContent = {\n data: string;\n mimeType: string;\n type: \"audio\";\n};\n\nconst AudioContentZodSchema = z\n .object({\n /**\n * The base64-encoded audio data.\n */\n data: z.string().base64(),\n mimeType: z.string(),\n type: z.literal(\"audio\"),\n })\n .strict() satisfies z.ZodType<AudioContent>;\n\ntype ResourceContent = {\n resource: {\n blob?: string;\n mimeType?: string;\n text?: string;\n uri: string;\n };\n type: \"resource\";\n};\n\nconst ResourceContentZodSchema = z\n .object({\n resource: z.object({\n blob: z.string().optional(),\n mimeType: z.string().optional(),\n text: z.string().optional(),\n uri: z.string(),\n }),\n type: z.literal(\"resource\"),\n })\n .strict() satisfies z.ZodType<ResourceContent>;\n\nconst ResourceLinkZodSchema = z.object({\n description: z.string().optional(),\n mimeType: z.string().optional(),\n name: z.string(),\n title: z.string().optional(),\n type: z.literal(\"resource_link\"),\n uri: z.string(),\n}) satisfies z.ZodType<ResourceLink>;\n\ntype Content =\n | AudioContent\n | ImageContent\n | ResourceContent\n | ResourceLink\n | TextContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n AudioContentZodSchema,\n ResourceContentZodSchema,\n ResourceLinkZodSchema,\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<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n (value: string, auth?: T) => Promise<Completion>;\n\ntype InputPrompt<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n Arguments extends InputPromptArgument<T>[] = InputPromptArgument<T>[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: InputPromptArgument<T>[];\n description?: string;\n load: (args: Args, auth?: T) => Promise<PromptResult>;\n name: string;\n};\n\ntype InputPromptArgument<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n Readonly<{\n complete?: ArgumentValueCompleter<T>;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\n }>;\n\ntype InputResourceTemplate<\n T extends FastMCPSessionAuth,\n Arguments extends\n InputResourceTemplateArgument<T>[] = InputResourceTemplateArgument<T>[],\n> = {\n arguments: Arguments;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n auth?: T,\n ) => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype InputResourceTemplateArgument<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> = Readonly<{\n complete?: ArgumentValueCompleter<T>;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype LoggingLevel =\n | \"alert\"\n | \"critical\"\n | \"debug\"\n | \"emergency\"\n | \"error\"\n | \"info\"\n | \"notice\"\n | \"warning\";\n\ntype Prompt<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n Arguments extends PromptArgument<T>[] = PromptArgument<T>[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: PromptArgument<T>[];\n complete?: (name: string, value: string, auth?: T) => Promise<Completion>;\n description?: string;\n load: (args: Args, auth?: T) => Promise<PromptResult>;\n name: string;\n};\n\ntype PromptArgument<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n Readonly<{\n complete?: ArgumentValueCompleter<T>;\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 PromptResult = Pick<GetPromptResult, \"messages\"> | string;\n\ntype Resource<T extends FastMCPSessionAuth> = {\n complete?: (name: string, value: string, auth?: T) => Promise<Completion>;\n description?: string;\n load: (auth?: T) => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uri: string;\n};\n\ntype ResourceResult =\n | {\n blob: string;\n mimeType?: string;\n uri?: string;\n }\n | {\n mimeType?: string;\n text: string;\n uri?: string;\n };\n\ntype ResourceTemplate<\n T extends FastMCPSessionAuth,\n Arguments extends\n ResourceTemplateArgument<T>[] = ResourceTemplateArgument<T>[],\n> = {\n arguments: Arguments;\n complete?: (name: string, value: string, auth?: T) => Promise<Completion>;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n auth?: T,\n ) => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype ResourceTemplateArgument<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> = Readonly<{\n complete?: ArgumentValueCompleter<T>;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {\n [K in T[number][\"name\"]]: string;\n};\n\ntype SamplingResponse = {\n content: AudioContent | ImageContent | TextContent;\n model: string;\n role: \"assistant\" | \"user\";\n stopReason?: \"endTurn\" | \"maxTokens\" | \"stopSequence\" | string;\n};\n\ntype ServerOptions<T extends FastMCPSessionAuth> = {\n authenticate?: Authenticate<T>;\n /**\n * Configuration for the health-check endpoint that can be exposed when the\n * server is running using the HTTP Stream transport. When enabled, the\n * server will respond to an HTTP GET request with the configured path (by\n * default \"/health\") rendering a plain-text response (by default \"ok\") and\n * the configured status code (by default 200).\n *\n * The endpoint is only added when the server is started with\n * `transportType: \"httpStream\"` – it is ignored for the stdio transport.\n */\n health?: {\n /**\n * When set to `false` the health-check endpoint is disabled.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Plain-text body returned by the endpoint.\n * @default \"ok\"\n */\n message?: string;\n\n /**\n * HTTP path that should be handled.\n * @default \"/health\"\n */\n path?: string;\n\n /**\n * HTTP response status that will be returned.\n * @default 200\n */\n status?: number;\n };\n instructions?: string;\n /**\n * Custom logger instance. If not provided, defaults to console.\n * Use this to integrate with your own logging system.\n */\n logger?: Logger;\n name: string;\n\n /**\n * Configuration for OAuth well-known discovery endpoints that can be exposed\n * when the server is running using HTTP-based transports (SSE or HTTP Stream).\n * When enabled, the server will respond to requests for OAuth discovery endpoints\n * with the configured metadata.\n *\n * The endpoints are only added when the server is started with\n * `transportType: \"httpStream\"` – they are ignored for the stdio transport.\n * Both SSE and HTTP Stream transports support OAuth endpoints.\n */\n oauth?: {\n /**\n * OAuth Authorization Server metadata for /.well-known/oauth-authorization-server\n *\n * This endpoint follows RFC 8414 (OAuth 2.0 Authorization Server Metadata)\n * and provides metadata about the OAuth 2.0 authorization server.\n *\n * Required by MCP Specification 2025-03-26\n */\n authorizationServer?: {\n authorizationEndpoint: string;\n codeChallengeMethodsSupported?: string[];\n // DPoP support\n dpopSigningAlgValuesSupported?: string[];\n grantTypesSupported?: string[];\n\n introspectionEndpoint?: string;\n // Required\n issuer: string;\n // Common optional\n jwksUri?: string;\n opPolicyUri?: string;\n opTosUri?: string;\n registrationEndpoint?: string;\n responseModesSupported?: string[];\n responseTypesSupported: string[];\n revocationEndpoint?: string;\n scopesSupported?: string[];\n serviceDocumentation?: string;\n tokenEndpoint: string;\n tokenEndpointAuthMethodsSupported?: string[];\n tokenEndpointAuthSigningAlgValuesSupported?: string[];\n\n uiLocalesSupported?: string[];\n };\n\n /**\n * Whether OAuth discovery endpoints should be enabled.\n */\n enabled: boolean;\n\n /**\n * OAuth Protected Resource metadata for `/.well-known/oauth-protected-resource`\n *\n * This endpoint follows {@link https://www.rfc-editor.org/rfc/rfc9728.html | RFC 9728}\n * and provides metadata describing how an OAuth 2.0 protected resource (in this case,\n * an MCP server) expects to be accessed.\n *\n * When configured, FastMCP will automatically serve this metadata at the\n * `/.well-known/oauth-protected-resource` endpoint. The `authorizationServers` and `resource`\n * fields are required. All others are optional and will be omitted from the published\n * metadata if not specified.\n *\n * This satisfies the requirements of the MCP Authorization specification's\n * {@link https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-server-location | Authorization Server Location section}.\n *\n * Clients consuming this metadata MUST validate that any presented values comply with\n * RFC 9728, including strict validation of the `resource` identifier and intended audience\n * when access tokens are issued and presented (per RFC 8707 §2).\n *\n * @remarks Required by MCP Specification version 2025-06-18\n */\n protectedResource?: {\n /**\n * Allows for additional metadata fields beyond those defined in RFC 9728.\n *\n * @remarks This supports vendor-specific or experimental extensions.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2.3 | RFC 9728 §2.3}\n */\n [key: string]: unknown;\n\n /**\n * Supported values for the `authorization_details` parameter (RFC 9396).\n *\n * @remarks Used when fine-grained access control is in play.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.23 | RFC 9728 §2.2.23}\n */\n authorizationDetailsTypesSupported?: string[];\n\n /**\n * List of OAuth 2.0 authorization server issuer identifiers.\n *\n * These correspond to ASes that can issue access tokens for this protected resource.\n * MCP clients use these values to locate the relevant `/.well-known/oauth-authorization-server`\n * metadata for initiating the OAuth flow.\n *\n * @remarks Required by the MCP spec. MCP servers MUST provide at least one issuer.\n * Clients are responsible for choosing among them (see RFC 9728 §7.6).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.3 | RFC 9728 §2.2.3}\n */\n authorizationServers: string[];\n\n /**\n * List of supported methods for presenting OAuth 2.0 bearer tokens.\n *\n * @remarks Valid values are `header`, `body`, and `query`.\n * If omitted, clients MAY assume only `header` is supported, per RFC 6750.\n * This is a client-side interpretation and not a serialization default.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.9 | RFC 9728 §2.2.9}\n */\n bearerMethodsSupported?: string[];\n\n /**\n * Whether this resource requires all access tokens to be DPoP-bound.\n *\n * @remarks If omitted, clients SHOULD assume this is `false`.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.27 | RFC 9728 §2.2.27}\n */\n dpopBoundAccessTokensRequired?: boolean;\n\n /**\n * Supported algorithms for verifying DPoP proofs (RFC 9449).\n *\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.25 | RFC 9728 §2.2.25}\n */\n dpopSigningAlgValuesSupported?: string[];\n\n /**\n * JWKS URI of this resource. Used to validate access tokens or sign responses.\n *\n * @remarks When present, this MUST be an `https:` URI pointing to a valid JWK Set (RFC 7517).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.5 | RFC 9728 §2.2.5}\n */\n jwksUri?: string;\n\n /**\n * Canonical OAuth resource identifier for this protected resource (the MCP server).\n *\n * @remarks Typically the base URL of the MCP server. Clients MUST use this as the\n * `resource` parameter in authorization and token requests (per RFC 8707).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.1 | RFC 9728 §2.2.1}\n */\n resource: string;\n\n /**\n * URL to developer-accessible documentation for this resource.\n *\n * @remarks This field MAY be localized.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.15 | RFC 9728 §2.2.15}\n */\n resourceDocumentation?: string;\n\n /**\n * Human-readable name for display purposes (e.g., in UIs).\n *\n * @remarks This field MAY be localized using language tags (`resource_name#en`, etc.).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.13 | RFC 9728 §2.2.13}\n */\n resourceName?: string;\n\n /**\n * URL to a human-readable policy page describing acceptable use.\n *\n * @remarks This field MAY be localized.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.17 | RFC 9728 §2.2.17}\n */\n resourcePolicyUri?: string;\n\n /**\n * Supported JWS algorithms for signed responses from this resource (e.g., response signing).\n *\n * @remarks MUST NOT include `none`.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.11 | RFC 9728 §2.2.11}\n */\n resourceSigningAlgValuesSupported?: string[];\n\n /**\n * URL to the protected resource’s Terms of Service.\n *\n * @remarks This field MAY be localized.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.19 | RFC 9728 §2.2.19}\n */\n resourceTosUri?: string;\n\n /**\n * Supported OAuth scopes for requesting access to this resource.\n *\n * @remarks Useful for discovery, but clients SHOULD still request the minimal scope required.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.7 | RFC 9728 §2.2.7}\n */\n scopesSupported?: string[];\n\n /**\n * Developer-accessible documentation for how to use the service (not end-user docs).\n *\n * @remarks Semantically equivalent to `resourceDocumentation`, but included under its\n * alternate name for compatibility with tools or schemas expecting either.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.15 | RFC 9728 §2.2.15}\n */\n serviceDocumentation?: string;\n\n /**\n * Whether mutual-TLS-bound access tokens are required.\n *\n * @remarks If omitted, clients SHOULD assume this is `false` (client-side behavior).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.21 | RFC 9728 §2.2.21}\n */\n tlsClientCertificateBoundAccessTokens?: boolean;\n };\n };\n\n ping?: {\n /**\n * Whether ping should be enabled by default.\n * - true for SSE or HTTP Stream\n * - false for stdio\n */\n enabled?: boolean;\n /**\n * Interval\n * @default 5000 (5s)\n */\n intervalMs?: number;\n /**\n * Logging level for ping-related messages.\n * @default 'debug'\n */\n logLevel?: LoggingLevel;\n };\n /**\n * Configuration for roots capability\n */\n roots?: {\n /**\n * Whether roots capability should be enabled\n * Set to false to completely disable roots support\n * @default true\n */\n enabled?: boolean;\n };\n /**\n * General utilities\n */\n utils?: {\n formatInvalidParamsErrorMessage?: (\n issues: readonly StandardSchemaV1.Issue[],\n ) => string;\n };\n version: `${number}.${number}.${number}`;\n};\n\ntype Tool<\n T extends FastMCPSessionAuth,\n Params extends ToolParameters = ToolParameters,\n> = {\n annotations?: {\n /**\n * When true, the tool leverages incremental content streaming\n * Return void for tools that handle all their output via streaming\n */\n streamingHint?: boolean;\n } & ToolAnnotations;\n canAccess?: (auth: T) => boolean;\n description?: string;\n\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n | AudioContent\n | ContentResult\n | ImageContent\n | ResourceContent\n | ResourceLink\n | string\n | TextContent\n | void\n >;\n name: string;\n parameters?: Params;\n timeoutMs?: number;\n};\n\n/**\n * Tool annotations as defined in MCP Specification (2025-03-26)\n * These provide hints about a tool's behavior.\n */\ntype ToolAnnotations = {\n /**\n * If true, the tool may perform destructive updates\n * Only meaningful when readOnlyHint is false\n * @default true\n */\n destructiveHint?: boolean;\n\n /**\n * If true, calling the tool repeatedly with the same arguments has no additional effect\n * Only meaningful when readOnlyHint is false\n * @default false\n */\n idempotentHint?: boolean;\n\n /**\n * If true, the tool may interact with an \"open world\" of external entities\n * @default true\n */\n openWorldHint?: boolean;\n\n /**\n * If true, indicates the tool does not modify its environment\n * @default false\n */\n readOnlyHint?: boolean;\n\n /**\n * A human-readable title for the tool, useful for UI display\n */\n title?: string;\n};\n\nconst FastMCPSessionEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;\n} = EventEmitter;\n\ntype Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;\n\ntype FastMCPSessionAuth = Record<string, unknown> | undefined;\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 isReady(): boolean {\n return this.#connectionState === \"ready\";\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 #connectionState: \"closed\" | \"connecting\" | \"error\" | \"ready\" = \"connecting\";\n #logger: Logger;\n #loggingLevel: LoggingLevel = \"info\";\n #needsEventLoopFlush: boolean = false;\n #pingConfig?: ServerOptions<T>[\"ping\"];\n\n #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Prompt<T>[] = [];\n\n #resources: Resource<T>[] = [];\n\n #resourceTemplates: ResourceTemplate<T>[] = [];\n\n #roots: Root[] = [];\n\n #rootsConfig?: ServerOptions<T>[\"roots\"];\n\n #server: Server;\n\n #utils?: ServerOptions<T>[\"utils\"];\n\n constructor({\n auth,\n instructions,\n logger,\n name,\n ping,\n prompts,\n resources,\n resourcesTemplates,\n roots,\n tools,\n transportType,\n utils,\n version,\n }: {\n auth?: T;\n instructions?: string;\n logger: Logger;\n name: string;\n ping?: ServerOptions<T>[\"ping\"];\n prompts: Prompt<T>[];\n resources: Resource<T>[];\n resourcesTemplates: InputResourceTemplate<T>[];\n roots?: ServerOptions<T>[\"roots\"];\n tools: Tool<T>[];\n transportType?: \"httpStream\" | \"stdio\";\n utils?: ServerOptions<T>[\"utils\"];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\n this.#logger = logger;\n this.#pingConfig = ping;\n this.#rootsConfig = roots;\n this.#needsEventLoopFlush = transportType === \"httpStream\";\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.#utils = utils;\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 this.#connectionState = \"closed\";\n\n if (this.#pingInterval) {\n clearInterval(this.#pingInterval);\n }\n\n try {\n await this.#server.close();\n } catch (error) {\n this.#logger.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 this.#connectionState = \"connecting\";\n\n try {\n await this.#server.connect(transport);\n\n let attempt = 0;\n const maxAttempts = 10;\n const retryDelay = 100;\n\n while (attempt++ < maxAttempts) {\n const capabilities = this.#server.getClientCapabilities();\n\n if (capabilities) {\n this.#clientCapabilities = capabilities;\n break;\n }\n\n await delay(retryDelay);\n }\n\n if (!this.#clientCapabilities) {\n this.#logger.warn(\n `[FastMCP warning] could not infer client capabilities after ${maxAttempts} attempts. Connection may be unstable.`,\n );\n }\n\n if (\n this.#clientCapabilities?.roots?.listChanged &&\n typeof this.#server.listRoots === \"function\"\n ) {\n try {\n const roots = await this.#server.listRoots();\n this.#roots = roots?.roots || [];\n } catch (e) {\n if (e instanceof McpError && e.code === ErrorCode.MethodNotFound) {\n this.#logger.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n this.#logger.error(\n `[FastMCP error] received error listing roots.\\n\\n${\n e instanceof Error ? e.stack : JSON.stringify(e)\n }`,\n );\n }\n }\n }\n\n if (this.#clientCapabilities) {\n const pingConfig = this.#getPingConfig(transport);\n\n if (pingConfig.enabled) {\n this.#pingInterval = setInterval(async () => {\n try {\n await this.#server.ping();\n } catch {\n // The reason we are not emitting an error here is because some clients\n // seem to not respond to the ping request, and we don't want to crash the server,\n // e.g., https://github.com/punkpeye/fastmcp/issues/38.\n const logLevel = pingConfig.logLevel;\n\n if (logLevel === \"debug\") {\n this.#logger.debug(\"[FastMCP debug] server ping failed\");\n } else if (logLevel === \"warning\") {\n this.#logger.warn(\n \"[FastMCP warning] server is not responding to ping\",\n );\n } else if (logLevel === \"error\") {\n this.#logger.error(\n \"[FastMCP error] server is not responding to ping\",\n );\n } else {\n this.#logger.info(\"[FastMCP info] server ping failed\");\n }\n }\n }, pingConfig.intervalMs);\n }\n }\n\n // Mark connection as ready and emit event\n this.#connectionState = \"ready\";\n this.emit(\"ready\");\n } catch (error) {\n this.#connectionState = \"error\";\n const errorEvent = {\n error: error instanceof Error ? error : new Error(String(error)),\n };\n this.emit(\"error\", errorEvent);\n throw error;\n }\n }\n\n public async requestSampling(\n message: z.infer<typeof CreateMessageRequestSchema>[\"params\"],\n options?: RequestOptions,\n ): Promise<SamplingResponse> {\n return this.#server.createMessage(message, options);\n }\n\n public waitForReady(): Promise<void> {\n if (this.isReady) {\n return Promise.resolve();\n }\n\n if (\n this.#connectionState === \"error\" ||\n this.#connectionState === \"closed\"\n ) {\n return Promise.reject(\n new Error(`Connection is in ${this.#connectionState} state`),\n );\n }\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n \"Connection timeout: Session failed to become ready within 5 seconds\",\n ),\n );\n }, 5000);\n\n this.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve();\n });\n\n this.once(\"error\", (event) => {\n clearTimeout(timeout);\n reject(event.error);\n });\n });\n }\n\n #getPingConfig(transport: Transport): {\n enabled: boolean;\n intervalMs: number;\n logLevel: LoggingLevel;\n } {\n const pingConfig = this.#pingConfig || {};\n\n let defaultEnabled = false;\n\n if (\"type\" in transport) {\n // Enable by default for SSE and HTTP streaming\n if (transport.type === \"httpStream\") {\n defaultEnabled = true;\n }\n }\n\n return {\n enabled:\n pingConfig.enabled !== undefined ? pingConfig.enabled : defaultEnabled,\n intervalMs: pingConfig.intervalMs || 5000,\n logLevel: pingConfig.logLevel || \"debug\",\n };\n }\n\n private addPrompt(inputPrompt: InputPrompt<T>) {\n const completers: Record<string, ArgumentValueCompleter<T>> = {};\n const enums: Record<string, string[]> = {};\n const fuseInstances: Record<string, Fuse<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 fuseInstances[argument.name] = new Fuse(argument.enum, {\n includeScore: true,\n threshold: 0.3, // More flexible matching!\n });\n }\n }\n\n const prompt = {\n ...inputPrompt,\n complete: async (name: string, value: string, auth?: T) => {\n if (completers[name]) {\n return await completers[name](value, auth);\n }\n\n if (fuseInstances[name]) {\n const result = fuseInstances[name].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<T>) {\n this.#resources.push(inputResource);\n }\n\n private addResourceTemplate(inputResourceTemplate: InputResourceTemplate<T>) {\n const completers: Record<string, ArgumentValueCompleter<T>> = {};\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, auth?: T) => {\n if (completers[name]) {\n return await completers[name](value, auth);\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 this.#auth,\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 this.#auth,\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 this.#logger.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<T>[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n arguments: prompt.arguments,\n complete: prompt.complete,\n description: prompt.description,\n name: prompt.name,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = prompts.find(\n (prompt) => prompt.name === request.params.name,\n );\n\n if (!prompt) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown prompt: ${request.params.name}`,\n );\n }\n\n const args = request.params.arguments;\n\n for (const arg of prompt.arguments ?? []) {\n if (arg.required && !(args && arg.name in args)) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Prompt '${request.params.name}' requires argument '${arg.name}': ${\n arg.description || \"No description provided\"\n }`,\n );\n }\n }\n\n let result: Awaited<ReturnType<Prompt<T>[\"load\"]>>;\n\n try {\n result = await prompt.load(\n args as Record<string, string | undefined>,\n this.#auth,\n );\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new McpError(\n ErrorCode.InternalError,\n `Failed to load prompt '${request.params.name}': ${errorMessage}`,\n );\n }\n\n if (typeof result === \"string\") {\n return {\n description: prompt.description,\n messages: [\n {\n content: { text: result, type: \"text\" },\n role: \"user\",\n },\n ],\n };\n } else {\n return {\n description: prompt.description,\n messages: result.messages,\n };\n }\n });\n }\n\n private setupResourceHandlers(resources: Resource<T>[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => ({\n description: resource.description,\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\n })),\n } satisfies ListResourcesResult;\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, this.#auth);\n\n const resources = Array.isArray(result) ? result : [result];\n return {\n contents: resources.map((resource) => ({\n ...resource,\n description: resourceTemplate.description,\n mimeType: resource.mimeType ?? resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uri: resource.uri ?? uri,\n })),\n };\n }\n\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Resource not found: '${request.params.uri}'. Available resources: ${\n resources.map((r) => r.uri).join(\", \") || \"none\"\n }`,\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<T>[\"load\"]>>;\n\n try {\n maybeArrayResult = await resource.load(this.#auth);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new McpError(\n ErrorCode.InternalError,\n `Failed to load resource '${resource.name}' (${resource.uri}): ${errorMessage}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n const resourceResults = Array.isArray(maybeArrayResult)\n ? maybeArrayResult\n : [maybeArrayResult];\n\n return {\n contents: resourceResults.map((result) => ({\n ...result,\n mimeType: result.mimeType ?? resource.mimeType,\n name: resource.name,\n uri: result.uri ?? resource.uri,\n })),\n };\n }\n\n throw new UnexpectedStateError(\"Unknown resource request\", {\n request,\n });\n },\n );\n }\n\n private setupResourceTemplateHandlers(\n resourceTemplates: ResourceTemplate<T>[],\n ) {\n this.#server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async () => {\n return {\n resourceTemplates: resourceTemplates.map((resourceTemplate) => ({\n description: resourceTemplate.description,\n mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uriTemplate: resourceTemplate.uriTemplate,\n })),\n } satisfies ListResourceTemplatesResult;\n },\n );\n }\n\n private setupRootsHandlers() {\n if (this.#rootsConfig?.enabled === false) {\n this.#logger.debug(\n \"[FastMCP debug] roots capability explicitly disabled via config\",\n );\n return;\n }\n\n // Only set up roots notification handling if the server supports it\n if (typeof this.#server.listRoots === \"function\") {\n this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server\n .listRoots()\n .then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n })\n .catch((error) => {\n if (\n error instanceof McpError &&\n error.code === ErrorCode.MethodNotFound\n ) {\n this.#logger.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n this.#logger.error(\n `[FastMCP error] received error listing roots.\\n\\n${\n error instanceof Error ? error.stack : JSON.stringify(error)\n }`,\n );\n }\n });\n },\n );\n } else {\n this.#logger.debug(\n \"[FastMCP debug] roots capability not available, not setting up notification handler\",\n );\n }\n }\n\n private setupToolHandlers(tools: Tool<T>[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: await Promise.all(\n tools.map(async (tool) => {\n return {\n annotations: tool.annotations,\n description: tool.description,\n inputSchema: tool.parameters\n ? await toJsonSchema(tool.parameters)\n : {\n additionalProperties: false,\n properties: {},\n type: \"object\",\n }, // More complete schema for Cursor compatibility\n name: tool.name,\n };\n }),\n ),\n };\n });\n\n this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = tools.find((tool) => tool.name === request.params.name);\n\n if (!tool) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n let args: unknown = undefined;\n\n if (tool.parameters) {\n const parsed = await tool.parameters[\"~standard\"].validate(\n request.params.arguments,\n );\n\n if (parsed.issues) {\n const friendlyErrors = this.#utils?.formatInvalidParamsErrorMessage\n ? this.#utils.formatInvalidParamsErrorMessage(parsed.issues)\n : parsed.issues\n .map((issue) => {\n const path = issue.path?.join(\".\") || \"root\";\n return `${path}: ${issue.message}`;\n })\n .join(\", \");\n\n throw new McpError(\n ErrorCode.InvalidParams,\n `Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}. Please check the parameter types and values according to the tool's schema.`,\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 try {\n await this.#server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n\n if (this.#needsEventLoopFlush) {\n await new Promise((resolve) => setImmediate(resolve));\n }\n } catch (progressError) {\n this.#logger.warn(\n `[FastMCP warning] Failed to report progress for tool '${request.params.name}':`,\n progressError instanceof Error\n ? progressError.message\n : String(progressError),\n );\n }\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"debug\",\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"error\",\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"info\",\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"warning\",\n });\n },\n };\n\n // Create a promise for tool execution\n // Streams partial results while a tool is still executing\n // Enables progressive rendering and real-time feedback\n const streamContent = async (content: Content | Content[]) => {\n const contentArray = Array.isArray(content) ? content : [content];\n\n try {\n await this.#server.notification({\n method: \"notifications/tool/streamContent\",\n params: {\n content: contentArray,\n toolName: request.params.name,\n },\n });\n\n if (this.#needsEventLoopFlush) {\n await new Promise((resolve) => setImmediate(resolve));\n }\n } catch (streamError) {\n this.#logger.warn(\n `[FastMCP warning] Failed to stream content for tool '${request.params.name}':`,\n streamError instanceof Error\n ? streamError.message\n : String(streamError),\n );\n }\n };\n\n const executeToolPromise = tool.execute(args, {\n log,\n reportProgress,\n session: this.#auth,\n streamContent,\n });\n\n // Handle timeout if specified\n const maybeStringResult = (await (tool.timeoutMs\n ? Promise.race([\n executeToolPromise,\n new Promise<never>((_, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new UserError(\n `Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`,\n ),\n );\n }, tool.timeoutMs);\n\n // If promise resolves first\n executeToolPromise.finally(() => clearTimeout(timeoutId));\n }),\n ])\n : executeToolPromise)) as\n | AudioContent\n | ContentResult\n | ImageContent\n | null\n | ResourceContent\n | ResourceLink\n | string\n | TextContent\n | undefined;\n\n // Without this test, we are running into situations where the last progress update is not reported.\n // See the 'reports multiple progress updates without buffering' test in FastMCP.test.ts before refactoring.\n await delay(1);\n\n if (maybeStringResult === undefined || maybeStringResult === null) {\n result = ContentResultZodSchema.parse({\n content: [],\n });\n } else if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ text: maybeStringResult, type: \"text\" }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ text: error.message, type: \"text\" }],\n isError: true,\n };\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,\n type: \"text\",\n },\n ],\n isError: true,\n };\n }\n\n return result;\n });\n }\n}\n\n/**\n * Converts camelCase to snake_case for OAuth endpoint responses\n */\nfunction camelToSnakeCase(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Converts an object with camelCase keys to snake_case keys\n */\nfunction convertObjectToSnakeCase(\n obj: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnakeCase(key);\n result[snakeKey] = value;\n }\n\n return result;\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents<FastMCPSessionAuth>>;\n} = EventEmitter;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\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 #logger: Logger;\n #options: ServerOptions<T>;\n #prompts: InputPrompt<T>[] = [];\n #resources: Resource<T>[] = [];\n #resourcesTemplates: InputResourceTemplate<T>[] = [];\n #sessions: FastMCPSession<T>[] = [];\n\n #tools: Tool<T>[] = [];\n\n constructor(public options: ServerOptions<T>) {\n super();\n\n this.#options = options;\n this.#authenticate = options.authenticate;\n this.#logger = options.logger || console;\n }\n\n /**\n * Adds a prompt to the server.\n */\n public addPrompt<const Args extends InputPromptArgument<T>[]>(\n prompt: InputPrompt<T, Args>,\n ) {\n this.#prompts.push(prompt);\n }\n\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource<T>) {\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<T, Args>) {\n this.#resourcesTemplates.push(resource);\n }\n\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {\n this.#tools.push(tool as unknown as Tool<T>);\n }\n\n /**\n * Embeds a resource by URI, making it easy to include resources in tool responses.\n *\n * @param uri - The URI of the resource to embed\n * @returns Promise<ResourceContent> - The embedded resource content\n */\n public async embedded(uri: string): Promise<ResourceContent[\"resource\"]> {\n // First, try to find a direct resource match\n const directResource = this.#resources.find(\n (resource) => resource.uri === uri,\n );\n\n if (directResource) {\n const result = await directResource.load();\n const results = Array.isArray(result) ? result : [result];\n const firstResult = results[0];\n\n const resourceData: ResourceContent[\"resource\"] = {\n mimeType: directResource.mimeType,\n uri,\n };\n\n if (\"text\" in firstResult) {\n resourceData.text = firstResult.text;\n }\n\n if (\"blob\" in firstResult) {\n resourceData.blob = firstResult.blob;\n }\n\n return resourceData;\n }\n\n // Try to match against resource templates\n for (const template of this.#resourcesTemplates) {\n // Check if the URI starts with the template base\n const templateBase = template.uriTemplate.split(\"{\")[0];\n\n if (uri.startsWith(templateBase)) {\n const params: Record<string, string> = {};\n const templateParts = template.uriTemplate.split(\"/\");\n const uriParts = uri.split(\"/\");\n\n for (let i = 0; i < templateParts.length; i++) {\n const templatePart = templateParts[i];\n\n if (templatePart?.startsWith(\"{\") && templatePart.endsWith(\"}\")) {\n const paramName = templatePart.slice(1, -1);\n const paramValue = uriParts[i];\n\n if (paramValue) {\n params[paramName] = paramValue;\n }\n }\n }\n\n const result = await template.load(\n params as ResourceTemplateArgumentsToObject<\n typeof template.arguments\n >,\n );\n\n const resourceData: ResourceContent[\"resource\"] = {\n mimeType: template.mimeType,\n uri,\n };\n\n if (\"text\" in result) {\n resourceData.text = result.text;\n }\n\n if (\"blob\" in result) {\n resourceData.blob = result.blob;\n }\n\n return resourceData; // The resource we're looking for\n }\n }\n\n throw new UnexpectedStateError(`Resource not found: ${uri}`, { uri });\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options?: Partial<{\n httpStream: {\n enableJsonResponse?: boolean;\n endpoint?: `/${string}`;\n eventStore?: EventStore;\n port: number;\n stateless?: boolean;\n };\n transportType: \"httpStream\" | \"stdio\";\n }>,\n ) {\n const config = this.#parseRuntimeConfig(options);\n\n if (config.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n const session = new FastMCPSession<T>({\n instructions: this.#options.instructions,\n logger: this.#logger,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n transportType: \"stdio\",\n utils: this.#options.utils,\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: session as FastMCPSession<FastMCPSessionAuth>,\n });\n } else if (config.transportType === \"httpStream\") {\n const httpConfig = config.httpStream;\n\n if (httpConfig.stateless) {\n // Stateless mode - create new server instance for each request\n this.#logger.info(\n `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,\n );\n\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n // In stateless mode, create a new session for each request\n // without persisting it in the sessions array\n return this.#createSession(auth);\n },\n enableJsonResponse: httpConfig.enableJsonResponse,\n eventStore: httpConfig.eventStore,\n // In stateless mode, we don't track sessions\n onClose: async () => {\n // No session tracking in stateless mode\n },\n onConnect: async () => {\n // No persistent session tracking in stateless mode\n this.#logger.debug(\n `[FastMCP debug] Stateless HTTP Stream request handled`,\n );\n },\n onUnhandledRequest: async (req, res) => {\n await this.#handleUnhandledRequest(req, res, true);\n },\n port: httpConfig.port,\n stateless: true,\n streamEndpoint: httpConfig.endpoint,\n });\n } else {\n // Regular mode with session management\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n return this.#createSession(auth);\n },\n enableJsonResponse: httpConfig.enableJsonResponse,\n eventStore: httpConfig.eventStore,\n onClose: async (session) => {\n this.emit(\"disconnect\", {\n session: session as FastMCPSession<FastMCPSessionAuth>,\n });\n },\n onConnect: async (session) => {\n this.#sessions.push(session);\n\n this.#logger.info(`[FastMCP info] HTTP Stream session established`);\n\n this.emit(\"connect\", {\n session: session as FastMCPSession<FastMCPSessionAuth>,\n });\n },\n\n onUnhandledRequest: async (req, res) => {\n await this.#handleUnhandledRequest(req, res, false);\n },\n port: httpConfig.port,\n streamEndpoint: httpConfig.endpoint,\n });\n\n this.#logger.info(\n `[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,\n );\n this.#logger.info(\n `[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`,\n );\n }\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#httpStreamServer) {\n await this.#httpStreamServer.close();\n }\n }\n\n /**\n * Creates a new FastMCPSession instance with the current configuration.\n * Used both for regular sessions and stateless requests.\n */\n #createSession(auth?: T): FastMCPSession<T> {\n const allowedTools = auth\n ? this.#tools.filter((tool) =>\n tool.canAccess ? tool.canAccess(auth) : true,\n )\n : this.#tools;\n return new FastMCPSession<T>({\n auth,\n logger: this.#logger,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: allowedTools,\n transportType: \"httpStream\",\n utils: this.#options.utils,\n version: this.#options.version,\n });\n }\n\n /**\n * Handles unhandled HTTP requests with health, readiness, and OAuth endpoints\n */\n #handleUnhandledRequest = async (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n isStateless = false,\n ) => {\n const healthConfig = this.#options.health ?? {};\n\n const enabled =\n healthConfig.enabled === undefined ? true : healthConfig.enabled;\n\n if (enabled) {\n const path = healthConfig.path ?? \"/health\";\n const url = new URL(req.url || \"\", \"http://localhost\");\n\n try {\n if (req.method === \"GET\" && url.pathname === path) {\n res\n .writeHead(healthConfig.status ?? 200, {\n \"Content-Type\": \"text/plain\",\n })\n .end(healthConfig.message ?? \"✓ Ok\");\n\n return;\n }\n\n // Enhanced readiness check endpoint\n if (req.method === \"GET\" && url.pathname === \"/ready\") {\n if (isStateless) {\n // In stateless mode, we're always ready if the server is running\n const response = {\n mode: \"stateless\",\n ready: 1,\n status: \"ready\",\n total: 1,\n };\n\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(response));\n } else {\n const readySessions = this.#sessions.filter(\n (s) => s.isReady,\n ).length;\n const totalSessions = this.#sessions.length;\n const allReady =\n readySessions === totalSessions && totalSessions > 0;\n\n const response = {\n ready: readySessions,\n status: allReady\n ? \"ready\"\n : totalSessions === 0\n ? \"no_sessions\"\n : \"initializing\",\n total: totalSessions,\n };\n\n res\n .writeHead(allReady ? 200 : 503, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(response));\n }\n\n return;\n }\n } catch (error) {\n this.#logger.error(\"[FastMCP error] health endpoint error\", error);\n }\n }\n\n // Handle OAuth well-known endpoints\n const oauthConfig = this.#options.oauth;\n if (oauthConfig?.enabled && req.method === \"GET\") {\n const url = new URL(req.url || \"\", \"http://localhost\");\n\n if (\n url.pathname === \"/.well-known/oauth-authorization-server\" &&\n oauthConfig.authorizationServer\n ) {\n const metadata = convertObjectToSnakeCase(\n oauthConfig.authorizationServer,\n );\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(metadata));\n return;\n }\n\n if (\n url.pathname === \"/.well-known/oauth-protected-resource\" &&\n oauthConfig.protectedResource\n ) {\n const metadata = convertObjectToSnakeCase(\n oauthConfig.protectedResource,\n );\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(metadata));\n return;\n }\n }\n\n // If the request was not handled above, return 404\n res.writeHead(404).end();\n };\n #parseRuntimeConfig(\n overrides?: Partial<{\n httpStream: {\n enableJsonResponse?: boolean;\n endpoint?: `/${string}`;\n port: number;\n stateless?: boolean;\n };\n transportType: \"httpStream\" | \"stdio\";\n }>,\n ):\n | {\n httpStream: {\n enableJsonResponse?: boolean;\n endpoint: `/${string}`;\n eventStore?: EventStore;\n port: number;\n stateless?: boolean;\n };\n transportType: \"httpStream\";\n }\n | { transportType: \"stdio\" } {\n const args = process.argv.slice(2);\n const getArg = (name: string) => {\n const index = args.findIndex((arg) => arg === `--${name}`);\n\n return index !== -1 && index + 1 < args.length\n ? args[index + 1]\n : undefined;\n };\n\n const transportArg = getArg(\"transport\");\n const portArg = getArg(\"port\");\n const endpointArg = getArg(\"endpoint\");\n const statelessArg = getArg(\"stateless\");\n\n const envTransport = process.env.FASTMCP_TRANSPORT;\n const envPort = process.env.FASTMCP_PORT;\n const envEndpoint = process.env.FASTMCP_ENDPOINT;\n const envStateless = process.env.FASTMCP_STATELESS;\n\n // Overrides > CLI > env > defaults\n const transportType =\n overrides?.transportType ||\n (transportArg === \"http-stream\" ? \"httpStream\" : transportArg) ||\n envTransport ||\n \"stdio\";\n\n if (transportType === \"httpStream\") {\n const port = parseInt(\n overrides?.httpStream?.port?.toString() || portArg || envPort || \"8080\",\n );\n const endpoint =\n overrides?.httpStream?.endpoint || endpointArg || envEndpoint || \"/mcp\";\n const enableJsonResponse =\n overrides?.httpStream?.enableJsonResponse || false;\n const stateless =\n overrides?.httpStream?.stateless ||\n statelessArg === \"true\" ||\n envStateless === \"true\" ||\n false;\n\n return {\n httpStream: {\n enableJsonResponse,\n endpoint: endpoint as `/${string}`,\n port,\n stateless,\n },\n transportType: \"httpStream\" as const,\n };\n }\n\n return { transportType: \"stdio\" as const };\n }\n}\n\nexport type {\n AudioContent,\n Content,\n ContentResult,\n Context,\n FastMCPEvents,\n FastMCPSessionEvents,\n ImageContent,\n InputPrompt,\n InputPromptArgument,\n LoggingLevel,\n Progress,\n Prompt,\n PromptArgument,\n Resource,\n ResourceContent,\n ResourceLink,\n ResourceResult,\n ResourceTemplate,\n ResourceTemplateArgument,\n SerializableValue,\n ServerOptions,\n TextContent,\n Tool,\n ToolParameters,\n};\n"],"mappings":"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","names":["prompt","resource","resources","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 { EventStore } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { RequestOptions } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport {\n CallToolRequestSchema,\n ClientCapabilities,\n CompleteRequestSchema,\n CreateMessageRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n GetPromptResult,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListResourcesResult,\n ListResourceTemplatesRequestSchema,\n ListResourceTemplatesResult,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n ResourceLink,\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 { readFile } from \"fs/promises\";\nimport Fuse from \"fuse.js\";\nimport http from \"http\";\nimport { startHTTPServer } from \"mcp-proxy\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { fetch } from \"undici\";\nimport parseURITemplate from \"uri-templates\";\nimport { toJsonSchema } from \"xsschema\";\nimport { z } from \"zod\";\n\nexport interface Logger {\n debug(...args: unknown[]): void;\n error(...args: unknown[]): void;\n info(...args: unknown[]): void;\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n}\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 ready: () => 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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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 { fileTypeFromBuffer } = await import(\"file-type\");\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: ${\n mimeType?.mime || \"unknown\"\n }`,\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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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}): ${\n error instanceof Error ? error.message : String(error)\n }`,\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 { fileTypeFromBuffer } = await import(\"file-type\");\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: ${\n mimeType?.mime || \"unknown\"\n }`,\n );\n }\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n data: base64Data,\n mimeType: mimeType?.mime ?? \"audio/mpeg\",\n type: \"audio\",\n } as const;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n } else {\n throw new Error(`Unexpected error processing audio: ${String(error)}`);\n }\n }\n};\n\ntype Context<T extends FastMCPSessionAuth> = {\n log: {\n debug: (message: string, data?: SerializableValue) => void;\n error: (message: string, data?: SerializableValue) => void;\n info: (message: string, data?: SerializableValue) => void;\n warn: (message: string, data?: SerializableValue) => void;\n };\n reportProgress: (progress: Progress) => Promise<void>;\n session: T | undefined;\n streamContent: (content: Content | Content[]) => Promise<void>;\n};\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\ntype Literal = boolean | null | number | string | undefined;\n\ntype Progress = {\n /**\n * The progress thus far. This should increase every time progress is made, even if the total is unknown.\n */\n progress: number;\n /**\n * Total number of items to process (or total progress required), if known.\n */\n total?: number;\n};\n\ntype SerializableValue =\n | { [key: string]: SerializableValue }\n | Literal\n | SerializableValue[];\n\ntype TextContent = {\n text: string;\n type: \"text\";\n};\n\ntype ToolParameters = StandardSchemaV1;\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class UnexpectedStateError extends FastMCPError {\n public extras?: Extras;\n\n public constructor(message: string, extras?: Extras) {\n super(message);\n this.name = new.target.name;\n this.extras = extras;\n }\n}\n\n/**\n * An error that is meant to be surfaced to the user.\n */\nexport class UserError extends UnexpectedStateError {}\n\nconst TextContentZodSchema = z\n .object({\n /**\n * The text content of the message.\n */\n text: z.string(),\n type: z.literal(\"text\"),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n data: string;\n mimeType: string;\n type: \"image\";\n};\n\nconst ImageContentZodSchema = z\n .object({\n /**\n * The base64-encoded image data.\n */\n data: z.string().base64(),\n /**\n * The MIME type of the image. Different providers may support different image types.\n */\n mimeType: z.string(),\n type: z.literal(\"image\"),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype AudioContent = {\n data: string;\n mimeType: string;\n type: \"audio\";\n};\n\nconst AudioContentZodSchema = z\n .object({\n /**\n * The base64-encoded audio data.\n */\n data: z.string().base64(),\n mimeType: z.string(),\n type: z.literal(\"audio\"),\n })\n .strict() satisfies z.ZodType<AudioContent>;\n\ntype ResourceContent = {\n resource: {\n blob?: string;\n mimeType?: string;\n text?: string;\n uri: string;\n };\n type: \"resource\";\n};\n\nconst ResourceContentZodSchema = z\n .object({\n resource: z.object({\n blob: z.string().optional(),\n mimeType: z.string().optional(),\n text: z.string().optional(),\n uri: z.string(),\n }),\n type: z.literal(\"resource\"),\n })\n .strict() satisfies z.ZodType<ResourceContent>;\n\nconst ResourceLinkZodSchema = z.object({\n description: z.string().optional(),\n mimeType: z.string().optional(),\n name: z.string(),\n title: z.string().optional(),\n type: z.literal(\"resource_link\"),\n uri: z.string(),\n}) satisfies z.ZodType<ResourceLink>;\n\ntype Content =\n | AudioContent\n | ImageContent\n | ResourceContent\n | ResourceLink\n | TextContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n AudioContentZodSchema,\n ResourceContentZodSchema,\n ResourceLinkZodSchema,\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<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n (value: string, auth?: T) => Promise<Completion>;\n\ntype InputPrompt<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n Arguments extends InputPromptArgument<T>[] = InputPromptArgument<T>[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: InputPromptArgument<T>[];\n description?: string;\n load: (args: Args, auth?: T) => Promise<PromptResult>;\n name: string;\n};\n\ntype InputPromptArgument<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n Readonly<{\n complete?: ArgumentValueCompleter<T>;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\n }>;\n\ntype InputResourceTemplate<\n T extends FastMCPSessionAuth,\n Arguments extends\n InputResourceTemplateArgument<T>[] = InputResourceTemplateArgument<T>[],\n> = {\n arguments: Arguments;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n auth?: T,\n ) => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype InputResourceTemplateArgument<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> = Readonly<{\n complete?: ArgumentValueCompleter<T>;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype LoggingLevel =\n | \"alert\"\n | \"critical\"\n | \"debug\"\n | \"emergency\"\n | \"error\"\n | \"info\"\n | \"notice\"\n | \"warning\";\n\ntype Prompt<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n Arguments extends PromptArgument<T>[] = PromptArgument<T>[],\n Args = PromptArgumentsToObject<Arguments>,\n> = {\n arguments?: PromptArgument<T>[];\n complete?: (name: string, value: string, auth?: T) => Promise<Completion>;\n description?: string;\n load: (args: Args, auth?: T) => Promise<PromptResult>;\n name: string;\n};\n\ntype PromptArgument<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n Readonly<{\n complete?: ArgumentValueCompleter<T>;\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 PromptResult = Pick<GetPromptResult, \"messages\"> | string;\n\ntype Resource<T extends FastMCPSessionAuth> = {\n complete?: (name: string, value: string, auth?: T) => Promise<Completion>;\n description?: string;\n load: (auth?: T) => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uri: string;\n};\n\ntype ResourceResult =\n | {\n blob: string;\n mimeType?: string;\n uri?: string;\n }\n | {\n mimeType?: string;\n text: string;\n uri?: string;\n };\n\ntype ResourceTemplate<\n T extends FastMCPSessionAuth,\n Arguments extends\n ResourceTemplateArgument<T>[] = ResourceTemplateArgument<T>[],\n> = {\n arguments: Arguments;\n complete?: (name: string, value: string, auth?: T) => Promise<Completion>;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject<Arguments>,\n auth?: T,\n ) => Promise<ResourceResult | ResourceResult[]>;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype ResourceTemplateArgument<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> = Readonly<{\n complete?: ArgumentValueCompleter<T>;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {\n [K in T[number][\"name\"]]: string;\n};\n\ntype SamplingResponse = {\n content: AudioContent | ImageContent | TextContent;\n model: string;\n role: \"assistant\" | \"user\";\n stopReason?: \"endTurn\" | \"maxTokens\" | \"stopSequence\" | string;\n};\n\ntype ServerOptions<T extends FastMCPSessionAuth> = {\n authenticate?: Authenticate<T>;\n /**\n * Configuration for the health-check endpoint that can be exposed when the\n * server is running using the HTTP Stream transport. When enabled, the\n * server will respond to an HTTP GET request with the configured path (by\n * default \"/health\") rendering a plain-text response (by default \"ok\") and\n * the configured status code (by default 200).\n *\n * The endpoint is only added when the server is started with\n * `transportType: \"httpStream\"` – it is ignored for the stdio transport.\n */\n health?: {\n /**\n * When set to `false` the health-check endpoint is disabled.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Plain-text body returned by the endpoint.\n * @default \"ok\"\n */\n message?: string;\n\n /**\n * HTTP path that should be handled.\n * @default \"/health\"\n */\n path?: string;\n\n /**\n * HTTP response status that will be returned.\n * @default 200\n */\n status?: number;\n };\n instructions?: string;\n /**\n * Custom logger instance. If not provided, defaults to console.\n * Use this to integrate with your own logging system.\n */\n logger?: Logger;\n name: string;\n\n /**\n * Configuration for OAuth well-known discovery endpoints that can be exposed\n * when the server is running using HTTP-based transports (SSE or HTTP Stream).\n * When enabled, the server will respond to requests for OAuth discovery endpoints\n * with the configured metadata.\n *\n * The endpoints are only added when the server is started with\n * `transportType: \"httpStream\"` – they are ignored for the stdio transport.\n * Both SSE and HTTP Stream transports support OAuth endpoints.\n */\n oauth?: {\n /**\n * OAuth Authorization Server metadata for /.well-known/oauth-authorization-server\n *\n * This endpoint follows RFC 8414 (OAuth 2.0 Authorization Server Metadata)\n * and provides metadata about the OAuth 2.0 authorization server.\n *\n * Required by MCP Specification 2025-03-26\n */\n authorizationServer?: {\n authorizationEndpoint: string;\n codeChallengeMethodsSupported?: string[];\n // DPoP support\n dpopSigningAlgValuesSupported?: string[];\n grantTypesSupported?: string[];\n\n introspectionEndpoint?: string;\n // Required\n issuer: string;\n // Common optional\n jwksUri?: string;\n opPolicyUri?: string;\n opTosUri?: string;\n registrationEndpoint?: string;\n responseModesSupported?: string[];\n responseTypesSupported: string[];\n revocationEndpoint?: string;\n scopesSupported?: string[];\n serviceDocumentation?: string;\n tokenEndpoint: string;\n tokenEndpointAuthMethodsSupported?: string[];\n tokenEndpointAuthSigningAlgValuesSupported?: string[];\n\n uiLocalesSupported?: string[];\n };\n\n /**\n * Whether OAuth discovery endpoints should be enabled.\n */\n enabled: boolean;\n\n /**\n * OAuth Protected Resource metadata for `/.well-known/oauth-protected-resource`\n *\n * This endpoint follows {@link https://www.rfc-editor.org/rfc/rfc9728.html | RFC 9728}\n * and provides metadata describing how an OAuth 2.0 protected resource (in this case,\n * an MCP server) expects to be accessed.\n *\n * When configured, FastMCP will automatically serve this metadata at the\n * `/.well-known/oauth-protected-resource` endpoint. The `authorizationServers` and `resource`\n * fields are required. All others are optional and will be omitted from the published\n * metadata if not specified.\n *\n * This satisfies the requirements of the MCP Authorization specification's\n * {@link https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-server-location | Authorization Server Location section}.\n *\n * Clients consuming this metadata MUST validate that any presented values comply with\n * RFC 9728, including strict validation of the `resource` identifier and intended audience\n * when access tokens are issued and presented (per RFC 8707 §2).\n *\n * @remarks Required by MCP Specification version 2025-06-18\n */\n protectedResource?: {\n /**\n * Allows for additional metadata fields beyond those defined in RFC 9728.\n *\n * @remarks This supports vendor-specific or experimental extensions.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2.3 | RFC 9728 §2.3}\n */\n [key: string]: unknown;\n\n /**\n * Supported values for the `authorization_details` parameter (RFC 9396).\n *\n * @remarks Used when fine-grained access control is in play.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.23 | RFC 9728 §2.2.23}\n */\n authorizationDetailsTypesSupported?: string[];\n\n /**\n * List of OAuth 2.0 authorization server issuer identifiers.\n *\n * These correspond to ASes that can issue access tokens for this protected resource.\n * MCP clients use these values to locate the relevant `/.well-known/oauth-authorization-server`\n * metadata for initiating the OAuth flow.\n *\n * @remarks Required by the MCP spec. MCP servers MUST provide at least one issuer.\n * Clients are responsible for choosing among them (see RFC 9728 §7.6).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.3 | RFC 9728 §2.2.3}\n */\n authorizationServers: string[];\n\n /**\n * List of supported methods for presenting OAuth 2.0 bearer tokens.\n *\n * @remarks Valid values are `header`, `body`, and `query`.\n * If omitted, clients MAY assume only `header` is supported, per RFC 6750.\n * This is a client-side interpretation and not a serialization default.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.9 | RFC 9728 §2.2.9}\n */\n bearerMethodsSupported?: string[];\n\n /**\n * Whether this resource requires all access tokens to be DPoP-bound.\n *\n * @remarks If omitted, clients SHOULD assume this is `false`.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.27 | RFC 9728 §2.2.27}\n */\n dpopBoundAccessTokensRequired?: boolean;\n\n /**\n * Supported algorithms for verifying DPoP proofs (RFC 9449).\n *\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.25 | RFC 9728 §2.2.25}\n */\n dpopSigningAlgValuesSupported?: string[];\n\n /**\n * JWKS URI of this resource. Used to validate access tokens or sign responses.\n *\n * @remarks When present, this MUST be an `https:` URI pointing to a valid JWK Set (RFC 7517).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.5 | RFC 9728 §2.2.5}\n */\n jwksUri?: string;\n\n /**\n * Canonical OAuth resource identifier for this protected resource (the MCP server).\n *\n * @remarks Typically the base URL of the MCP server. Clients MUST use this as the\n * `resource` parameter in authorization and token requests (per RFC 8707).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.1 | RFC 9728 §2.2.1}\n */\n resource: string;\n\n /**\n * URL to developer-accessible documentation for this resource.\n *\n * @remarks This field MAY be localized.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.15 | RFC 9728 §2.2.15}\n */\n resourceDocumentation?: string;\n\n /**\n * Human-readable name for display purposes (e.g., in UIs).\n *\n * @remarks This field MAY be localized using language tags (`resource_name#en`, etc.).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.13 | RFC 9728 §2.2.13}\n */\n resourceName?: string;\n\n /**\n * URL to a human-readable policy page describing acceptable use.\n *\n * @remarks This field MAY be localized.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.17 | RFC 9728 §2.2.17}\n */\n resourcePolicyUri?: string;\n\n /**\n * Supported JWS algorithms for signed responses from this resource (e.g., response signing).\n *\n * @remarks MUST NOT include `none`.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.11 | RFC 9728 §2.2.11}\n */\n resourceSigningAlgValuesSupported?: string[];\n\n /**\n * URL to the protected resource’s Terms of Service.\n *\n * @remarks This field MAY be localized.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.19 | RFC 9728 §2.2.19}\n */\n resourceTosUri?: string;\n\n /**\n * Supported OAuth scopes for requesting access to this resource.\n *\n * @remarks Useful for discovery, but clients SHOULD still request the minimal scope required.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.7 | RFC 9728 §2.2.7}\n */\n scopesSupported?: string[];\n\n /**\n * Developer-accessible documentation for how to use the service (not end-user docs).\n *\n * @remarks Semantically equivalent to `resourceDocumentation`, but included under its\n * alternate name for compatibility with tools or schemas expecting either.\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.15 | RFC 9728 §2.2.15}\n */\n serviceDocumentation?: string;\n\n /**\n * Whether mutual-TLS-bound access tokens are required.\n *\n * @remarks If omitted, clients SHOULD assume this is `false` (client-side behavior).\n * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.21 | RFC 9728 §2.2.21}\n */\n tlsClientCertificateBoundAccessTokens?: boolean;\n };\n };\n\n ping?: {\n /**\n * Whether ping should be enabled by default.\n * - true for SSE or HTTP Stream\n * - false for stdio\n */\n enabled?: boolean;\n /**\n * Interval\n * @default 5000 (5s)\n */\n intervalMs?: number;\n /**\n * Logging level for ping-related messages.\n * @default 'debug'\n */\n logLevel?: LoggingLevel;\n };\n /**\n * Configuration for roots capability\n */\n roots?: {\n /**\n * Whether roots capability should be enabled\n * Set to false to completely disable roots support\n * @default true\n */\n enabled?: boolean;\n };\n /**\n * General utilities\n */\n utils?: {\n formatInvalidParamsErrorMessage?: (\n issues: readonly StandardSchemaV1.Issue[],\n ) => string;\n };\n version: `${number}.${number}.${number}`;\n};\n\ntype Tool<\n T extends FastMCPSessionAuth,\n Params extends ToolParameters = ToolParameters,\n> = {\n annotations?: {\n /**\n * When true, the tool leverages incremental content streaming\n * Return void for tools that handle all their output via streaming\n */\n streamingHint?: boolean;\n } & ToolAnnotations;\n canAccess?: (auth: T) => boolean;\n description?: string;\n\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n | AudioContent\n | ContentResult\n | ImageContent\n | ResourceContent\n | ResourceLink\n | string\n | TextContent\n | void\n >;\n name: string;\n parameters?: Params;\n timeoutMs?: number;\n};\n\n/**\n * Tool annotations as defined in MCP Specification (2025-03-26)\n * These provide hints about a tool's behavior.\n */\ntype ToolAnnotations = {\n /**\n * If true, the tool may perform destructive updates\n * Only meaningful when readOnlyHint is false\n * @default true\n */\n destructiveHint?: boolean;\n\n /**\n * If true, calling the tool repeatedly with the same arguments has no additional effect\n * Only meaningful when readOnlyHint is false\n * @default false\n */\n idempotentHint?: boolean;\n\n /**\n * If true, the tool may interact with an \"open world\" of external entities\n * @default true\n */\n openWorldHint?: boolean;\n\n /**\n * If true, indicates the tool does not modify its environment\n * @default false\n */\n readOnlyHint?: boolean;\n\n /**\n * A human-readable title for the tool, useful for UI display\n */\n title?: string;\n};\n\nconst FastMCPSessionEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;\n} = EventEmitter;\n\ntype Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;\n\ntype FastMCPSessionAuth = Record<string, unknown> | undefined;\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 isReady(): boolean {\n return this.#connectionState === \"ready\";\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 #connectionState: \"closed\" | \"connecting\" | \"error\" | \"ready\" = \"connecting\";\n #logger: Logger;\n #loggingLevel: LoggingLevel = \"info\";\n #needsEventLoopFlush: boolean = false;\n #pingConfig?: ServerOptions<T>[\"ping\"];\n\n #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Prompt<T>[] = [];\n\n #resources: Resource<T>[] = [];\n\n #resourceTemplates: ResourceTemplate<T>[] = [];\n\n #roots: Root[] = [];\n\n #rootsConfig?: ServerOptions<T>[\"roots\"];\n\n #server: Server;\n\n #utils?: ServerOptions<T>[\"utils\"];\n\n constructor({\n auth,\n instructions,\n logger,\n name,\n ping,\n prompts,\n resources,\n resourcesTemplates,\n roots,\n tools,\n transportType,\n utils,\n version,\n }: {\n auth?: T;\n instructions?: string;\n logger: Logger;\n name: string;\n ping?: ServerOptions<T>[\"ping\"];\n prompts: Prompt<T>[];\n resources: Resource<T>[];\n resourcesTemplates: InputResourceTemplate<T>[];\n roots?: ServerOptions<T>[\"roots\"];\n tools: Tool<T>[];\n transportType?: \"httpStream\" | \"stdio\";\n utils?: ServerOptions<T>[\"utils\"];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\n this.#logger = logger;\n this.#pingConfig = ping;\n this.#rootsConfig = roots;\n this.#needsEventLoopFlush = transportType === \"httpStream\";\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.#utils = utils;\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 this.#connectionState = \"closed\";\n\n if (this.#pingInterval) {\n clearInterval(this.#pingInterval);\n }\n\n try {\n await this.#server.close();\n } catch (error) {\n this.#logger.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 this.#connectionState = \"connecting\";\n\n try {\n await this.#server.connect(transport);\n\n let attempt = 0;\n const maxAttempts = 10;\n const retryDelay = 100;\n\n while (attempt++ < maxAttempts) {\n const capabilities = this.#server.getClientCapabilities();\n\n if (capabilities) {\n this.#clientCapabilities = capabilities;\n break;\n }\n\n await delay(retryDelay);\n }\n\n if (!this.#clientCapabilities) {\n this.#logger.warn(\n `[FastMCP warning] could not infer client capabilities after ${maxAttempts} attempts. Connection may be unstable.`,\n );\n }\n\n if (\n this.#clientCapabilities?.roots?.listChanged &&\n typeof this.#server.listRoots === \"function\"\n ) {\n try {\n const roots = await this.#server.listRoots();\n this.#roots = roots?.roots || [];\n } catch (e) {\n if (e instanceof McpError && e.code === ErrorCode.MethodNotFound) {\n this.#logger.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n this.#logger.error(\n `[FastMCP error] received error listing roots.\\n\\n${\n e instanceof Error ? e.stack : JSON.stringify(e)\n }`,\n );\n }\n }\n }\n\n if (this.#clientCapabilities) {\n const pingConfig = this.#getPingConfig(transport);\n\n if (pingConfig.enabled) {\n this.#pingInterval = setInterval(async () => {\n try {\n await this.#server.ping();\n } catch {\n // The reason we are not emitting an error here is because some clients\n // seem to not respond to the ping request, and we don't want to crash the server,\n // e.g., https://github.com/punkpeye/fastmcp/issues/38.\n const logLevel = pingConfig.logLevel;\n\n if (logLevel === \"debug\") {\n this.#logger.debug(\"[FastMCP debug] server ping failed\");\n } else if (logLevel === \"warning\") {\n this.#logger.warn(\n \"[FastMCP warning] server is not responding to ping\",\n );\n } else if (logLevel === \"error\") {\n this.#logger.error(\n \"[FastMCP error] server is not responding to ping\",\n );\n } else {\n this.#logger.info(\"[FastMCP info] server ping failed\");\n }\n }\n }, pingConfig.intervalMs);\n }\n }\n\n // Mark connection as ready and emit event\n this.#connectionState = \"ready\";\n this.emit(\"ready\");\n } catch (error) {\n this.#connectionState = \"error\";\n const errorEvent = {\n error: error instanceof Error ? error : new Error(String(error)),\n };\n this.emit(\"error\", errorEvent);\n throw error;\n }\n }\n\n public async requestSampling(\n message: z.infer<typeof CreateMessageRequestSchema>[\"params\"],\n options?: RequestOptions,\n ): Promise<SamplingResponse> {\n return this.#server.createMessage(message, options);\n }\n\n public waitForReady(): Promise<void> {\n if (this.isReady) {\n return Promise.resolve();\n }\n\n if (\n this.#connectionState === \"error\" ||\n this.#connectionState === \"closed\"\n ) {\n return Promise.reject(\n new Error(`Connection is in ${this.#connectionState} state`),\n );\n }\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n \"Connection timeout: Session failed to become ready within 5 seconds\",\n ),\n );\n }, 5000);\n\n this.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve();\n });\n\n this.once(\"error\", (event) => {\n clearTimeout(timeout);\n reject(event.error);\n });\n });\n }\n\n #getPingConfig(transport: Transport): {\n enabled: boolean;\n intervalMs: number;\n logLevel: LoggingLevel;\n } {\n const pingConfig = this.#pingConfig || {};\n\n let defaultEnabled = false;\n\n if (\"type\" in transport) {\n // Enable by default for SSE and HTTP streaming\n if (transport.type === \"httpStream\") {\n defaultEnabled = true;\n }\n }\n\n return {\n enabled:\n pingConfig.enabled !== undefined ? pingConfig.enabled : defaultEnabled,\n intervalMs: pingConfig.intervalMs || 5000,\n logLevel: pingConfig.logLevel || \"debug\",\n };\n }\n\n private addPrompt(inputPrompt: InputPrompt<T>) {\n const completers: Record<string, ArgumentValueCompleter<T>> = {};\n const enums: Record<string, string[]> = {};\n const fuseInstances: Record<string, Fuse<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 fuseInstances[argument.name] = new Fuse(argument.enum, {\n includeScore: true,\n threshold: 0.3, // More flexible matching!\n });\n }\n }\n\n const prompt = {\n ...inputPrompt,\n complete: async (name: string, value: string, auth?: T) => {\n if (completers[name]) {\n return await completers[name](value, auth);\n }\n\n if (fuseInstances[name]) {\n const result = fuseInstances[name].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<T>) {\n this.#resources.push(inputResource);\n }\n\n private addResourceTemplate(inputResourceTemplate: InputResourceTemplate<T>) {\n const completers: Record<string, ArgumentValueCompleter<T>> = {};\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, auth?: T) => {\n if (completers[name]) {\n return await completers[name](value, auth);\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 this.#auth,\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 this.#auth,\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 this.#logger.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<T>[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n arguments: prompt.arguments,\n complete: prompt.complete,\n description: prompt.description,\n name: prompt.name,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = prompts.find(\n (prompt) => prompt.name === request.params.name,\n );\n\n if (!prompt) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown prompt: ${request.params.name}`,\n );\n }\n\n const args = request.params.arguments;\n\n for (const arg of prompt.arguments ?? []) {\n if (arg.required && !(args && arg.name in args)) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Prompt '${request.params.name}' requires argument '${arg.name}': ${\n arg.description || \"No description provided\"\n }`,\n );\n }\n }\n\n let result: Awaited<ReturnType<Prompt<T>[\"load\"]>>;\n\n try {\n result = await prompt.load(\n args as Record<string, string | undefined>,\n this.#auth,\n );\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new McpError(\n ErrorCode.InternalError,\n `Failed to load prompt '${request.params.name}': ${errorMessage}`,\n );\n }\n\n if (typeof result === \"string\") {\n return {\n description: prompt.description,\n messages: [\n {\n content: { text: result, type: \"text\" },\n role: \"user\",\n },\n ],\n };\n } else {\n return {\n description: prompt.description,\n messages: result.messages,\n };\n }\n });\n }\n\n private setupResourceHandlers(resources: Resource<T>[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => ({\n description: resource.description,\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\n })),\n } satisfies ListResourcesResult;\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, this.#auth);\n\n const resources = Array.isArray(result) ? result : [result];\n return {\n contents: resources.map((resource) => ({\n ...resource,\n description: resourceTemplate.description,\n mimeType: resource.mimeType ?? resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uri: resource.uri ?? uri,\n })),\n };\n }\n\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Resource not found: '${request.params.uri}'. Available resources: ${\n resources.map((r) => r.uri).join(\", \") || \"none\"\n }`,\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<T>[\"load\"]>>;\n\n try {\n maybeArrayResult = await resource.load(this.#auth);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new McpError(\n ErrorCode.InternalError,\n `Failed to load resource '${resource.name}' (${resource.uri}): ${errorMessage}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n const resourceResults = Array.isArray(maybeArrayResult)\n ? maybeArrayResult\n : [maybeArrayResult];\n\n return {\n contents: resourceResults.map((result) => ({\n ...result,\n mimeType: result.mimeType ?? resource.mimeType,\n name: resource.name,\n uri: result.uri ?? resource.uri,\n })),\n };\n }\n\n throw new UnexpectedStateError(\"Unknown resource request\", {\n request,\n });\n },\n );\n }\n\n private setupResourceTemplateHandlers(\n resourceTemplates: ResourceTemplate<T>[],\n ) {\n this.#server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async () => {\n return {\n resourceTemplates: resourceTemplates.map((resourceTemplate) => ({\n description: resourceTemplate.description,\n mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uriTemplate: resourceTemplate.uriTemplate,\n })),\n } satisfies ListResourceTemplatesResult;\n },\n );\n }\n\n private setupRootsHandlers() {\n if (this.#rootsConfig?.enabled === false) {\n this.#logger.debug(\n \"[FastMCP debug] roots capability explicitly disabled via config\",\n );\n return;\n }\n\n // Only set up roots notification handling if the server supports it\n if (typeof this.#server.listRoots === \"function\") {\n this.#server.setNotificationHandler(\n RootsListChangedNotificationSchema,\n () => {\n this.#server\n .listRoots()\n .then((roots) => {\n this.#roots = roots.roots;\n\n this.emit(\"rootsChanged\", {\n roots: roots.roots,\n });\n })\n .catch((error) => {\n if (\n error instanceof McpError &&\n error.code === ErrorCode.MethodNotFound\n ) {\n this.#logger.debug(\n \"[FastMCP debug] listRoots method not supported by client\",\n );\n } else {\n this.#logger.error(\n `[FastMCP error] received error listing roots.\\n\\n${\n error instanceof Error ? error.stack : JSON.stringify(error)\n }`,\n );\n }\n });\n },\n );\n } else {\n this.#logger.debug(\n \"[FastMCP debug] roots capability not available, not setting up notification handler\",\n );\n }\n }\n\n private setupToolHandlers(tools: Tool<T>[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: await Promise.all(\n tools.map(async (tool) => {\n return {\n annotations: tool.annotations,\n description: tool.description,\n inputSchema: tool.parameters\n ? await toJsonSchema(tool.parameters)\n : {\n additionalProperties: false,\n properties: {},\n type: \"object\",\n }, // More complete schema for Cursor compatibility\n name: tool.name,\n };\n }),\n ),\n };\n });\n\n this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = tools.find((tool) => tool.name === request.params.name);\n\n if (!tool) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n let args: unknown = undefined;\n\n if (tool.parameters) {\n const parsed = await tool.parameters[\"~standard\"].validate(\n request.params.arguments,\n );\n\n if (parsed.issues) {\n const friendlyErrors = this.#utils?.formatInvalidParamsErrorMessage\n ? this.#utils.formatInvalidParamsErrorMessage(parsed.issues)\n : parsed.issues\n .map((issue) => {\n const path = issue.path?.join(\".\") || \"root\";\n return `${path}: ${issue.message}`;\n })\n .join(\", \");\n\n throw new McpError(\n ErrorCode.InvalidParams,\n `Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}. Please check the parameter types and values according to the tool's schema.`,\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 try {\n await this.#server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n\n if (this.#needsEventLoopFlush) {\n await new Promise((resolve) => setImmediate(resolve));\n }\n } catch (progressError) {\n this.#logger.warn(\n `[FastMCP warning] Failed to report progress for tool '${request.params.name}':`,\n progressError instanceof Error\n ? progressError.message\n : String(progressError),\n );\n }\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"debug\",\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"error\",\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"info\",\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"warning\",\n });\n },\n };\n\n // Create a promise for tool execution\n // Streams partial results while a tool is still executing\n // Enables progressive rendering and real-time feedback\n const streamContent = async (content: Content | Content[]) => {\n const contentArray = Array.isArray(content) ? content : [content];\n\n try {\n await this.#server.notification({\n method: \"notifications/tool/streamContent\",\n params: {\n content: contentArray,\n toolName: request.params.name,\n },\n });\n\n if (this.#needsEventLoopFlush) {\n await new Promise((resolve) => setImmediate(resolve));\n }\n } catch (streamError) {\n this.#logger.warn(\n `[FastMCP warning] Failed to stream content for tool '${request.params.name}':`,\n streamError instanceof Error\n ? streamError.message\n : String(streamError),\n );\n }\n };\n\n const executeToolPromise = tool.execute(args, {\n log,\n reportProgress,\n session: this.#auth,\n streamContent,\n });\n\n // Handle timeout if specified\n const maybeStringResult = (await (tool.timeoutMs\n ? Promise.race([\n executeToolPromise,\n new Promise<never>((_, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new UserError(\n `Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`,\n ),\n );\n }, tool.timeoutMs);\n\n // If promise resolves first\n executeToolPromise.finally(() => clearTimeout(timeoutId));\n }),\n ])\n : executeToolPromise)) as\n | AudioContent\n | ContentResult\n | ImageContent\n | null\n | ResourceContent\n | ResourceLink\n | string\n | TextContent\n | undefined;\n\n // Without this test, we are running into situations where the last progress update is not reported.\n // See the 'reports multiple progress updates without buffering' test in FastMCP.test.ts before refactoring.\n await delay(1);\n\n if (maybeStringResult === undefined || maybeStringResult === null) {\n result = ContentResultZodSchema.parse({\n content: [],\n });\n } else if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ text: maybeStringResult, type: \"text\" }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ text: error.message, type: \"text\" }],\n isError: true,\n };\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,\n type: \"text\",\n },\n ],\n isError: true,\n };\n }\n\n return result;\n });\n }\n}\n\n/**\n * Converts camelCase to snake_case for OAuth endpoint responses\n */\nfunction camelToSnakeCase(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Converts an object with camelCase keys to snake_case keys\n */\nfunction convertObjectToSnakeCase(\n obj: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnakeCase(key);\n result[snakeKey] = value;\n }\n\n return result;\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents<FastMCPSessionAuth>>;\n} = EventEmitter;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\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 #logger: Logger;\n #options: ServerOptions<T>;\n #prompts: InputPrompt<T>[] = [];\n #resources: Resource<T>[] = [];\n #resourcesTemplates: InputResourceTemplate<T>[] = [];\n #sessions: FastMCPSession<T>[] = [];\n\n #tools: Tool<T>[] = [];\n\n constructor(public options: ServerOptions<T>) {\n super();\n\n this.#options = options;\n this.#authenticate = options.authenticate;\n this.#logger = options.logger || console;\n }\n\n /**\n * Adds a prompt to the server.\n */\n public addPrompt<const Args extends InputPromptArgument<T>[]>(\n prompt: InputPrompt<T, Args>,\n ) {\n this.#prompts.push(prompt);\n }\n\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource<T>) {\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<T, Args>) {\n this.#resourcesTemplates.push(resource);\n }\n\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {\n this.#tools.push(tool as unknown as Tool<T>);\n }\n\n /**\n * Embeds a resource by URI, making it easy to include resources in tool responses.\n *\n * @param uri - The URI of the resource to embed\n * @returns Promise<ResourceContent> - The embedded resource content\n */\n public async embedded(uri: string): Promise<ResourceContent[\"resource\"]> {\n // First, try to find a direct resource match\n const directResource = this.#resources.find(\n (resource) => resource.uri === uri,\n );\n\n if (directResource) {\n const result = await directResource.load();\n const results = Array.isArray(result) ? result : [result];\n const firstResult = results[0];\n\n const resourceData: ResourceContent[\"resource\"] = {\n mimeType: directResource.mimeType,\n uri,\n };\n\n if (\"text\" in firstResult) {\n resourceData.text = firstResult.text;\n }\n\n if (\"blob\" in firstResult) {\n resourceData.blob = firstResult.blob;\n }\n\n return resourceData;\n }\n\n // Try to match against resource templates\n for (const template of this.#resourcesTemplates) {\n // Check if the URI starts with the template base\n const templateBase = template.uriTemplate.split(\"{\")[0];\n\n if (uri.startsWith(templateBase)) {\n const params: Record<string, string> = {};\n const templateParts = template.uriTemplate.split(\"/\");\n const uriParts = uri.split(\"/\");\n\n for (let i = 0; i < templateParts.length; i++) {\n const templatePart = templateParts[i];\n\n if (templatePart?.startsWith(\"{\") && templatePart.endsWith(\"}\")) {\n const paramName = templatePart.slice(1, -1);\n const paramValue = uriParts[i];\n\n if (paramValue) {\n params[paramName] = paramValue;\n }\n }\n }\n\n const result = await template.load(\n params as ResourceTemplateArgumentsToObject<\n typeof template.arguments\n >,\n );\n\n const resourceData: ResourceContent[\"resource\"] = {\n mimeType: template.mimeType,\n uri,\n };\n\n if (\"text\" in result) {\n resourceData.text = result.text;\n }\n\n if (\"blob\" in result) {\n resourceData.blob = result.blob;\n }\n\n return resourceData; // The resource we're looking for\n }\n }\n\n throw new UnexpectedStateError(`Resource not found: ${uri}`, { uri });\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options?: Partial<{\n httpStream: {\n enableJsonResponse?: boolean;\n endpoint?: `/${string}`;\n eventStore?: EventStore;\n host?: string;\n port: number;\n stateless?: boolean;\n };\n transportType: \"httpStream\" | \"stdio\";\n }>,\n ) {\n const config = this.#parseRuntimeConfig(options);\n\n if (config.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n // For stdio transport, if authenticate function is provided, call it\n // with undefined request (since stdio doesn't have HTTP request context)\n let auth: T | undefined;\n\n if (this.#authenticate) {\n try {\n auth = await this.#authenticate(\n undefined as unknown as http.IncomingMessage,\n );\n } catch (error) {\n this.#logger.error(\n \"[FastMCP error] Authentication failed for stdio transport:\",\n error instanceof Error ? error.message : String(error),\n );\n // Continue without auth if authentication fails\n }\n }\n\n const session = new FastMCPSession<T>({\n auth,\n instructions: this.#options.instructions,\n logger: this.#logger,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n transportType: \"stdio\",\n utils: this.#options.utils,\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: session as FastMCPSession<FastMCPSessionAuth>,\n });\n } else if (config.transportType === \"httpStream\") {\n const httpConfig = config.httpStream;\n\n if (httpConfig.stateless) {\n // Stateless mode - create new server instance for each request\n this.#logger.info(\n `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,\n );\n\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n // In stateless mode, create a new session for each request\n // without persisting it in the sessions array\n return this.#createSession(auth);\n },\n enableJsonResponse: httpConfig.enableJsonResponse,\n eventStore: httpConfig.eventStore,\n host: httpConfig.host,\n // In stateless mode, we don't track sessions\n onClose: async () => {\n // No session tracking in stateless mode\n },\n onConnect: async () => {\n // No persistent session tracking in stateless mode\n this.#logger.debug(\n `[FastMCP debug] Stateless HTTP Stream request handled`,\n );\n },\n onUnhandledRequest: async (req, res) => {\n await this.#handleUnhandledRequest(req, res, true, httpConfig.host);\n },\n port: httpConfig.port,\n stateless: true,\n streamEndpoint: httpConfig.endpoint,\n });\n } else {\n // Regular mode with session management\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n return this.#createSession(auth);\n },\n enableJsonResponse: httpConfig.enableJsonResponse,\n eventStore: httpConfig.eventStore,\n host: httpConfig.host,\n onClose: async (session) => {\n this.emit(\"disconnect\", {\n session: session as FastMCPSession<FastMCPSessionAuth>,\n });\n },\n onConnect: async (session) => {\n this.#sessions.push(session);\n\n this.#logger.info(`[FastMCP info] HTTP Stream session established`);\n\n this.emit(\"connect\", {\n session: session as FastMCPSession<FastMCPSessionAuth>,\n });\n },\n\n onUnhandledRequest: async (req, res) => {\n await this.#handleUnhandledRequest(\n req,\n res,\n false,\n httpConfig.host,\n );\n },\n port: httpConfig.port,\n streamEndpoint: httpConfig.endpoint,\n });\n\n this.#logger.info(\n `[FastMCP info] server is running on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,\n );\n this.#logger.info(\n `[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`,\n );\n }\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#httpStreamServer) {\n await this.#httpStreamServer.close();\n }\n }\n\n /**\n * Creates a new FastMCPSession instance with the current configuration.\n * Used both for regular sessions and stateless requests.\n */\n #createSession(auth?: T): FastMCPSession<T> {\n const allowedTools = auth\n ? this.#tools.filter((tool) =>\n tool.canAccess ? tool.canAccess(auth) : true,\n )\n : this.#tools;\n return new FastMCPSession<T>({\n auth,\n logger: this.#logger,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: allowedTools,\n transportType: \"httpStream\",\n utils: this.#options.utils,\n version: this.#options.version,\n });\n }\n\n /**\n * Handles unhandled HTTP requests with health, readiness, and OAuth endpoints\n */\n #handleUnhandledRequest = async (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n isStateless = false,\n host: string,\n ) => {\n const healthConfig = this.#options.health ?? {};\n\n const enabled =\n healthConfig.enabled === undefined ? true : healthConfig.enabled;\n\n if (enabled) {\n const path = healthConfig.path ?? \"/health\";\n const url = new URL(req.url || \"\", `http://${host}`);\n\n try {\n if (req.method === \"GET\" && url.pathname === path) {\n res\n .writeHead(healthConfig.status ?? 200, {\n \"Content-Type\": \"text/plain\",\n })\n .end(healthConfig.message ?? \"✓ Ok\");\n\n return;\n }\n\n // Enhanced readiness check endpoint\n if (req.method === \"GET\" && url.pathname === \"/ready\") {\n if (isStateless) {\n // In stateless mode, we're always ready if the server is running\n const response = {\n mode: \"stateless\",\n ready: 1,\n status: \"ready\",\n total: 1,\n };\n\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(response));\n } else {\n const readySessions = this.#sessions.filter(\n (s) => s.isReady,\n ).length;\n const totalSessions = this.#sessions.length;\n const allReady =\n readySessions === totalSessions && totalSessions > 0;\n\n const response = {\n ready: readySessions,\n status: allReady\n ? \"ready\"\n : totalSessions === 0\n ? \"no_sessions\"\n : \"initializing\",\n total: totalSessions,\n };\n\n res\n .writeHead(allReady ? 200 : 503, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(response));\n }\n\n return;\n }\n } catch (error) {\n this.#logger.error(\"[FastMCP error] health endpoint error\", error);\n }\n }\n\n // Handle OAuth well-known endpoints\n const oauthConfig = this.#options.oauth;\n if (oauthConfig?.enabled && req.method === \"GET\") {\n const url = new URL(req.url || \"\", `http://${host}`);\n\n if (\n url.pathname === \"/.well-known/oauth-authorization-server\" &&\n oauthConfig.authorizationServer\n ) {\n const metadata = convertObjectToSnakeCase(\n oauthConfig.authorizationServer,\n );\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(metadata));\n return;\n }\n\n if (\n url.pathname === \"/.well-known/oauth-protected-resource\" &&\n oauthConfig.protectedResource\n ) {\n const metadata = convertObjectToSnakeCase(\n oauthConfig.protectedResource,\n );\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(metadata));\n return;\n }\n }\n\n // If the request was not handled above, return 404\n res.writeHead(404).end();\n };\n #parseRuntimeConfig(\n overrides?: Partial<{\n httpStream: {\n enableJsonResponse?: boolean;\n endpoint?: `/${string}`;\n host?: string;\n port: number;\n stateless?: boolean;\n };\n transportType: \"httpStream\" | \"stdio\";\n }>,\n ):\n | {\n httpStream: {\n enableJsonResponse?: boolean;\n endpoint: `/${string}`;\n eventStore?: EventStore;\n host: string;\n port: number;\n stateless?: boolean;\n };\n transportType: \"httpStream\";\n }\n | { transportType: \"stdio\" } {\n const args = process.argv.slice(2);\n const getArg = (name: string) => {\n const index = args.findIndex((arg) => arg === `--${name}`);\n\n return index !== -1 && index + 1 < args.length\n ? args[index + 1]\n : undefined;\n };\n\n const transportArg = getArg(\"transport\");\n const portArg = getArg(\"port\");\n const endpointArg = getArg(\"endpoint\");\n const statelessArg = getArg(\"stateless\");\n const hostArg = getArg(\"host\");\n\n const envTransport = process.env.FASTMCP_TRANSPORT;\n const envPort = process.env.FASTMCP_PORT;\n const envEndpoint = process.env.FASTMCP_ENDPOINT;\n const envStateless = process.env.FASTMCP_STATELESS;\n const envHost = process.env.FASTMCP_HOST;\n // Overrides > CLI > env > defaults\n const transportType =\n overrides?.transportType ||\n (transportArg === \"http-stream\" ? \"httpStream\" : transportArg) ||\n envTransport ||\n \"stdio\";\n\n if (transportType === \"httpStream\") {\n const port = parseInt(\n overrides?.httpStream?.port?.toString() || portArg || envPort || \"8080\",\n );\n const host =\n overrides?.httpStream?.host || hostArg || envHost || \"localhost\";\n const endpoint =\n overrides?.httpStream?.endpoint || endpointArg || envEndpoint || \"/mcp\";\n const enableJsonResponse =\n overrides?.httpStream?.enableJsonResponse || false;\n const stateless =\n overrides?.httpStream?.stateless ||\n statelessArg === \"true\" ||\n envStateless === \"true\" ||\n false;\n\n return {\n httpStream: {\n enableJsonResponse,\n endpoint: endpoint as `/${string}`,\n host,\n port,\n stateless,\n },\n transportType: \"httpStream\" as const,\n };\n }\n\n return { transportType: \"stdio\" as const };\n }\n}\n\nexport type {\n AudioContent,\n Content,\n ContentResult,\n Context,\n FastMCPEvents,\n FastMCPSessionEvents,\n ImageContent,\n InputPrompt,\n InputPromptArgument,\n LoggingLevel,\n Progress,\n Prompt,\n PromptArgument,\n Resource,\n ResourceContent,\n ResourceLink,\n ResourceResult,\n ResourceTemplate,\n ResourceTemplateArgument,\n SerializableValue,\n ServerOptions,\n TextContent,\n Tool,\n ToolParameters,\n};\n"],"mappings":"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","names":["prompt","resource","resources","tool"]}
package/jsr.json CHANGED
@@ -3,5 +3,5 @@
3
3
  "include": ["src/FastMCP.ts", "src/bin/fastmcp.ts"],
4
4
  "license": "MIT",
5
5
  "name": "@punkpeye/fastmcp",
6
- "version": "3.14.4"
6
+ "version": "3.15.0"
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastmcp",
3
- "version": "3.14.4",
3
+ "version": "3.15.0",
4
4
  "main": "dist/FastMCP.js",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { z } from "zod";
3
+
4
+ import { FastMCP } from "./FastMCP.js";
5
+
6
+ interface TestAuth {
7
+ [key: string]: unknown; // Required for FastMCPSessionAuth compatibility
8
+ role: "admin" | "user";
9
+ userId: string;
10
+ }
11
+
12
+ describe("FastMCP Session Context", () => {
13
+ describe("stdio transport", () => {
14
+ it("should pass session context to tool execution when authenticate is provided", async () => {
15
+ const mockAuth: TestAuth = { role: "admin", userId: "test-user" };
16
+ const server = new FastMCP<TestAuth>({
17
+ authenticate: async (request) => {
18
+ if (!request) return mockAuth;
19
+
20
+ throw new Error("Unexpected request in test");
21
+ },
22
+ name: "test-server",
23
+ version: "1.0.0",
24
+ });
25
+
26
+ server.addTool({
27
+ description: "Test tool to verify session context",
28
+ execute: async (_args, context) => {
29
+ return `Session received: ${context.session ? "yes" : "no"}`;
30
+ },
31
+ name: "test-session-context",
32
+ parameters: z.object({
33
+ message: z.string(),
34
+ }),
35
+ });
36
+
37
+ await server.start({ transportType: "stdio" });
38
+
39
+ expect(server).toBeDefined();
40
+ });
41
+
42
+ it("should handle authentication errors gracefully in stdio transport", async () => {
43
+ const mockLogger = {
44
+ debug: vi.fn(),
45
+ error: vi.fn(),
46
+ info: vi.fn(),
47
+ log: vi.fn(),
48
+ warn: vi.fn(),
49
+ };
50
+ const server = new FastMCP<TestAuth>({
51
+ authenticate: async () => {
52
+ throw new Error("Auth failed");
53
+ },
54
+ logger: mockLogger,
55
+ name: "test-server",
56
+ version: "1.0.0",
57
+ });
58
+
59
+ server.addTool({
60
+ description: "Test tool",
61
+ execute: async (_args, context) => {
62
+ return `Session: ${context.session ? "present" : "undefined"}`;
63
+ },
64
+ name: "test-tool",
65
+ });
66
+
67
+ await server.start({ transportType: "stdio" });
68
+
69
+ expect(mockLogger.error).toHaveBeenCalledWith(
70
+ "[FastMCP error] Authentication failed for stdio transport:",
71
+ "Auth failed",
72
+ );
73
+ });
74
+
75
+ it("should work without authenticate function", async () => {
76
+ const server = new FastMCP({
77
+ name: "test-server",
78
+ version: "1.0.0",
79
+ });
80
+
81
+ server.addTool({
82
+ description: "Test tool without auth",
83
+ execute: async (_args, context) => {
84
+ return `Session: ${context.session ? "present" : "undefined"}`;
85
+ },
86
+ name: "test-tool",
87
+ });
88
+
89
+ await server.start({ transportType: "stdio" });
90
+
91
+ expect(server).toBeDefined();
92
+ });
93
+ });
94
+
95
+ describe("environment variable based authentication", () => {
96
+ it("should support reading from environment variables in stdio mode", async () => {
97
+ const originalEnv = process.env.TEST_USER_ID;
98
+
99
+ process.env.TEST_USER_ID = "env-user-123";
100
+
101
+ try {
102
+ const server = new FastMCP<TestAuth>({
103
+ authenticate: async (request) => {
104
+ if (!request) {
105
+ return {
106
+ role: "user" as const,
107
+ userId: process.env.TEST_USER_ID || "default-user",
108
+ };
109
+ }
110
+ throw new Error("HTTP not supported in this test");
111
+ },
112
+ name: "test-server",
113
+ version: "1.0.0",
114
+ });
115
+
116
+ server.addTool({
117
+ description: "Tool using env-based auth",
118
+ execute: async (_args, context) => {
119
+ return `Environment user: ${context.session?.userId}`;
120
+ },
121
+ name: "env-test-tool",
122
+ });
123
+
124
+ await server.start({ transportType: "stdio" });
125
+
126
+ expect(server).toBeDefined();
127
+ } finally {
128
+ if (originalEnv !== undefined) {
129
+ process.env.TEST_USER_ID = originalEnv;
130
+ } else {
131
+ delete process.env.TEST_USER_ID;
132
+ }
133
+ }
134
+ });
135
+ });
136
+ });
@@ -1999,6 +1999,7 @@ test("closing event source does not produce error", async () => {
1999
1999
 
2000
2000
  await server.start({
2001
2001
  httpStream: {
2002
+ host: "127.0.0.1",
2002
2003
  port,
2003
2004
  },
2004
2005
  transportType: "httpStream",
@@ -3235,3 +3236,28 @@ test("stateless mode health check includes mode indicator", async () => {
3235
3236
  await server.stop();
3236
3237
  }
3237
3238
  });
3239
+
3240
+ test("host configuration works with 0.0.0.0", async () => {
3241
+ const port = await getRandomPort();
3242
+
3243
+ const server = new FastMCP({
3244
+ name: "Test server",
3245
+ version: "1.0.0",
3246
+ });
3247
+
3248
+ await server.start({
3249
+ httpStream: {
3250
+ host: "0.0.0.0",
3251
+ port,
3252
+ },
3253
+ transportType: "httpStream",
3254
+ });
3255
+
3256
+ try {
3257
+ const healthResponse = await fetch(`http://0.0.0.0:${port}/health`);
3258
+ expect(healthResponse.status).toBe(200);
3259
+ expect(await healthResponse.text()).toBe("✓ Ok");
3260
+ } finally {
3261
+ await server.stop();
3262
+ }
3263
+ });
package/src/FastMCP.ts CHANGED
@@ -2036,6 +2036,7 @@ export class FastMCP<
2036
2036
  enableJsonResponse?: boolean;
2037
2037
  endpoint?: `/${string}`;
2038
2038
  eventStore?: EventStore;
2039
+ host?: string;
2039
2040
  port: number;
2040
2041
  stateless?: boolean;
2041
2042
  };
@@ -2046,7 +2047,27 @@ export class FastMCP<
2046
2047
 
2047
2048
  if (config.transportType === "stdio") {
2048
2049
  const transport = new StdioServerTransport();
2050
+
2051
+ // For stdio transport, if authenticate function is provided, call it
2052
+ // with undefined request (since stdio doesn't have HTTP request context)
2053
+ let auth: T | undefined;
2054
+
2055
+ if (this.#authenticate) {
2056
+ try {
2057
+ auth = await this.#authenticate(
2058
+ undefined as unknown as http.IncomingMessage,
2059
+ );
2060
+ } catch (error) {
2061
+ this.#logger.error(
2062
+ "[FastMCP error] Authentication failed for stdio transport:",
2063
+ error instanceof Error ? error.message : String(error),
2064
+ );
2065
+ // Continue without auth if authentication fails
2066
+ }
2067
+ }
2068
+
2049
2069
  const session = new FastMCPSession<T>({
2070
+ auth,
2050
2071
  instructions: this.#options.instructions,
2051
2072
  logger: this.#logger,
2052
2073
  name: this.#options.name,
@@ -2074,7 +2095,7 @@ export class FastMCP<
2074
2095
  if (httpConfig.stateless) {
2075
2096
  // Stateless mode - create new server instance for each request
2076
2097
  this.#logger.info(
2077
- `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2098
+ `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,
2078
2099
  );
2079
2100
 
2080
2101
  this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({
@@ -2091,6 +2112,7 @@ export class FastMCP<
2091
2112
  },
2092
2113
  enableJsonResponse: httpConfig.enableJsonResponse,
2093
2114
  eventStore: httpConfig.eventStore,
2115
+ host: httpConfig.host,
2094
2116
  // In stateless mode, we don't track sessions
2095
2117
  onClose: async () => {
2096
2118
  // No session tracking in stateless mode
@@ -2102,7 +2124,7 @@ export class FastMCP<
2102
2124
  );
2103
2125
  },
2104
2126
  onUnhandledRequest: async (req, res) => {
2105
- await this.#handleUnhandledRequest(req, res, true);
2127
+ await this.#handleUnhandledRequest(req, res, true, httpConfig.host);
2106
2128
  },
2107
2129
  port: httpConfig.port,
2108
2130
  stateless: true,
@@ -2122,6 +2144,7 @@ export class FastMCP<
2122
2144
  },
2123
2145
  enableJsonResponse: httpConfig.enableJsonResponse,
2124
2146
  eventStore: httpConfig.eventStore,
2147
+ host: httpConfig.host,
2125
2148
  onClose: async (session) => {
2126
2149
  this.emit("disconnect", {
2127
2150
  session: session as FastMCPSession<FastMCPSessionAuth>,
@@ -2138,14 +2161,19 @@ export class FastMCP<
2138
2161
  },
2139
2162
 
2140
2163
  onUnhandledRequest: async (req, res) => {
2141
- await this.#handleUnhandledRequest(req, res, false);
2164
+ await this.#handleUnhandledRequest(
2165
+ req,
2166
+ res,
2167
+ false,
2168
+ httpConfig.host,
2169
+ );
2142
2170
  },
2143
2171
  port: httpConfig.port,
2144
2172
  streamEndpoint: httpConfig.endpoint,
2145
2173
  });
2146
2174
 
2147
2175
  this.#logger.info(
2148
- `[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2176
+ `[FastMCP info] server is running on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,
2149
2177
  );
2150
2178
  this.#logger.info(
2151
2179
  `[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`,
@@ -2198,6 +2226,7 @@ export class FastMCP<
2198
2226
  req: http.IncomingMessage,
2199
2227
  res: http.ServerResponse,
2200
2228
  isStateless = false,
2229
+ host: string,
2201
2230
  ) => {
2202
2231
  const healthConfig = this.#options.health ?? {};
2203
2232
 
@@ -2206,7 +2235,7 @@ export class FastMCP<
2206
2235
 
2207
2236
  if (enabled) {
2208
2237
  const path = healthConfig.path ?? "/health";
2209
- const url = new URL(req.url || "", "http://localhost");
2238
+ const url = new URL(req.url || "", `http://${host}`);
2210
2239
 
2211
2240
  try {
2212
2241
  if (req.method === "GET" && url.pathname === path) {
@@ -2270,7 +2299,7 @@ export class FastMCP<
2270
2299
  // Handle OAuth well-known endpoints
2271
2300
  const oauthConfig = this.#options.oauth;
2272
2301
  if (oauthConfig?.enabled && req.method === "GET") {
2273
- const url = new URL(req.url || "", "http://localhost");
2302
+ const url = new URL(req.url || "", `http://${host}`);
2274
2303
 
2275
2304
  if (
2276
2305
  url.pathname === "/.well-known/oauth-authorization-server" &&
@@ -2311,6 +2340,7 @@ export class FastMCP<
2311
2340
  httpStream: {
2312
2341
  enableJsonResponse?: boolean;
2313
2342
  endpoint?: `/${string}`;
2343
+ host?: string;
2314
2344
  port: number;
2315
2345
  stateless?: boolean;
2316
2346
  };
@@ -2322,6 +2352,7 @@ export class FastMCP<
2322
2352
  enableJsonResponse?: boolean;
2323
2353
  endpoint: `/${string}`;
2324
2354
  eventStore?: EventStore;
2355
+ host: string;
2325
2356
  port: number;
2326
2357
  stateless?: boolean;
2327
2358
  };
@@ -2341,12 +2372,13 @@ export class FastMCP<
2341
2372
  const portArg = getArg("port");
2342
2373
  const endpointArg = getArg("endpoint");
2343
2374
  const statelessArg = getArg("stateless");
2375
+ const hostArg = getArg("host");
2344
2376
 
2345
2377
  const envTransport = process.env.FASTMCP_TRANSPORT;
2346
2378
  const envPort = process.env.FASTMCP_PORT;
2347
2379
  const envEndpoint = process.env.FASTMCP_ENDPOINT;
2348
2380
  const envStateless = process.env.FASTMCP_STATELESS;
2349
-
2381
+ const envHost = process.env.FASTMCP_HOST;
2350
2382
  // Overrides > CLI > env > defaults
2351
2383
  const transportType =
2352
2384
  overrides?.transportType ||
@@ -2358,6 +2390,8 @@ export class FastMCP<
2358
2390
  const port = parseInt(
2359
2391
  overrides?.httpStream?.port?.toString() || portArg || envPort || "8080",
2360
2392
  );
2393
+ const host =
2394
+ overrides?.httpStream?.host || hostArg || envHost || "localhost";
2361
2395
  const endpoint =
2362
2396
  overrides?.httpStream?.endpoint || endpointArg || envEndpoint || "/mcp";
2363
2397
  const enableJsonResponse =
@@ -2372,6 +2406,7 @@ export class FastMCP<
2372
2406
  httpStream: {
2373
2407
  enableJsonResponse,
2374
2408
  endpoint: endpoint as `/${string}`,
2409
+ host,
2375
2410
  port,
2376
2411
  stateless,
2377
2412
  },
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Example demonstrating session context support in FastMCP stdio transport
3
+ *
4
+ * This example demonstrates the fix for issue #144:
5
+ * Session context is now properly passed to tool execution handlers
6
+ * when using stdio transport with an authenticate function.
7
+ *
8
+ * To run this example:
9
+ * npx fastmcp dev src/examples/session-context.ts
10
+ */
11
+
12
+ import { z } from "zod";
13
+
14
+ import { FastMCP } from "../FastMCP.js";
15
+
16
+ interface UserSession {
17
+ [key: string]: unknown;
18
+ permissions: string[];
19
+ role: "admin" | "guest" | "user";
20
+ userId: string;
21
+ username: string;
22
+ }
23
+
24
+ const server = new FastMCP<UserSession>({
25
+ authenticate: async (request) => {
26
+ if (!request) {
27
+ console.log(
28
+ "[Auth] Authenticating stdio transport using environment variables",
29
+ );
30
+
31
+ const userId = process.env.USER_ID || "default-user";
32
+ const username = process.env.USERNAME || "Anonymous";
33
+ const role =
34
+ (process.env.USER_ROLE as "admin" | "guest" | "user") || "guest";
35
+ // Mock permissions based on role
36
+ const permissions =
37
+ role === "admin"
38
+ ? ["read", "write", "delete", "admin"]
39
+ : role === "user"
40
+ ? ["read", "write"]
41
+ : ["read"];
42
+ const session: UserSession = {
43
+ authenticatedAt: new Date().toISOString(),
44
+ permissions,
45
+ role,
46
+ userId,
47
+ username,
48
+ };
49
+
50
+ console.log(`[Auth] Authenticated user: ${username} (${role})`);
51
+
52
+ return session;
53
+ }
54
+
55
+ // For HTTP transport (request contains headers)
56
+ console.log("[Auth] Authenticating HTTP transport using headers");
57
+
58
+ const authHeader = request.headers["authorization"] as string;
59
+
60
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
61
+ throw new Response("Missing or invalid authorization header", {
62
+ status: 401,
63
+ });
64
+ }
65
+
66
+ const token = authHeader.substring(7);
67
+
68
+ // Mock token validation (in real implementation, validate against your auth service)
69
+ if (token === "admin-token") {
70
+ return {
71
+ authenticatedAt: new Date().toISOString(),
72
+ permissions: ["read", "write", "delete", "admin"],
73
+ role: "admin" as const,
74
+ userId: "admin-001",
75
+ username: "Administrator",
76
+ };
77
+ } else if (token === "user-token") {
78
+ return {
79
+ authenticatedAt: new Date().toISOString(),
80
+ permissions: ["read", "write"],
81
+ role: "user" as const,
82
+ userId: "user-001",
83
+ username: "Regular User",
84
+ };
85
+ }
86
+
87
+ throw new Response("Invalid token", { status: 401 });
88
+ },
89
+ name: "Session Context Demo",
90
+ version: "1.0.0",
91
+ });
92
+
93
+ // Tool that demonstrates session context access
94
+ server.addTool({
95
+ description: "Get information about the current authenticated user",
96
+ execute: async (_args, context) => {
97
+ if (!context.session)
98
+ return "No session context available (this shouldn't happen after the fix!)";
99
+
100
+ const { session } = context;
101
+
102
+ return `✓ Session Context Available!
103
+
104
+ User Info:
105
+ - User ID: ${session.userId}
106
+ - Username: ${session.username}
107
+ - Role: ${session.role}
108
+ - Permissions: ${session.permissions.join(", ")}
109
+ - Authenticated At: ${session.authenticatedAt}`;
110
+ },
111
+ name: "whoami",
112
+ });
113
+
114
+ // Tool that demonstrates role-based access
115
+ server.addTool({
116
+ description: "Perform an admin-only operation (requires admin role)",
117
+ execute: async (args, context) => {
118
+ if (!context.session)
119
+ return "No session context - cannot verify permissions";
120
+ if (context.session.role !== "admin")
121
+ return `Access denied. Current role: ${context.session.role}, required: admin`;
122
+ if (!context.session.permissions.includes("admin"))
123
+ return "Insufficient permissions for admin operations";
124
+
125
+ return `✓ Admin operation "${args.action}" executed successfully by ${context.session.username}`;
126
+ },
127
+ name: "admin-operation",
128
+ parameters: z.object({
129
+ action: z.string().describe("The admin action to perform"),
130
+ }),
131
+ });
132
+
133
+ // Tool that demonstrates permission checks
134
+ server.addTool({
135
+ description: "Check what permissions the current user has",
136
+ execute: async (args, context) => {
137
+ if (!context.session) return "No session context available";
138
+
139
+ const hasPermission = context.session.permissions.includes(args.operation);
140
+
141
+ return `Permission Check for "${args.operation}":
142
+ ${hasPermission ? "✓ ALLOWED" : "! DENIED"}
143
+
144
+ Your permissions: ${context.session.permissions.join(", ")}
145
+ Your role: ${context.session.role}`;
146
+ },
147
+ name: "check-permissions",
148
+ parameters: z.object({
149
+ operation: z.string().describe("Operation to check permission for"),
150
+ }),
151
+ });
152
+
153
+ // Resource that uses session context
154
+ server.addResource({
155
+ description: "Get detailed information about the current authenticated user",
156
+ load: async (auth) => {
157
+ if (!auth) {
158
+ return {
159
+ text: JSON.stringify(
160
+ {
161
+ authenticated: false,
162
+ error: "No authentication context available",
163
+ },
164
+
165
+ null,
166
+ 2,
167
+ ),
168
+ };
169
+ }
170
+
171
+ return {
172
+ text: JSON.stringify(
173
+ {
174
+ authenticated: true,
175
+ user: {
176
+ authenticatedAt: auth.authenticatedAt,
177
+ id: auth.userId,
178
+ permissions: auth.permissions,
179
+ role: auth.role,
180
+ username: auth.username,
181
+ },
182
+ },
183
+
184
+ null,
185
+ 2,
186
+ ),
187
+ };
188
+ },
189
+ mimeType: "application/json",
190
+ name: "Current User Information",
191
+ uri: "session://current-user",
192
+ });
193
+
194
+ // Prompt that uses session context
195
+ server.addPrompt({
196
+ arguments: [
197
+ {
198
+ description: "Greeting style (formal, casual, friendly)",
199
+ name: "style",
200
+ required: false,
201
+ },
202
+ ],
203
+ description: "Generate a personalized greeting based on the current user",
204
+ load: async (args, auth) => {
205
+ const style = args.style || "friendly";
206
+
207
+ if (!auth) {
208
+ return "Hello! I don't have access to your session information.";
209
+ }
210
+
211
+ const greetings = {
212
+ casual: `Hey ${auth.username}! Nice to see you again.`,
213
+ formal: `Good day, ${auth.username}. You are logged in with ${auth.role} privileges.`,
214
+ friendly: `Hello ${auth.username}! 😊 You're logged in as a ${auth.role}. How can I help you today?`,
215
+ };
216
+
217
+ return greetings[style as keyof typeof greetings] || greetings.friendly;
218
+ },
219
+ name: "personalized-greeting",
220
+ });
221
+
222
+ // Start the server
223
+ if (process.argv.includes("--http-stream")) {
224
+ const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
225
+
226
+ server.start({
227
+ httpStream: { port: PORT },
228
+ transportType: "httpStream",
229
+ });
230
+
231
+ console.log(`
232
+ 🚀 Session Context Demo server running on HTTP Stream!
233
+
234
+ Try these endpoints:
235
+ - MCP: http://localhost:${PORT}/mcp
236
+ - Health: http://localhost:${PORT}/health
237
+
238
+ Test with curl:
239
+ curl -H "Authorization: Bearer admin-token" \\
240
+ -H "Content-Type: application/json" \\
241
+ -d '{"method":"tools/call","params":{"name":"whoami","arguments":{}}}' \\
242
+ http://localhost:${PORT}/mcp
243
+ `);
244
+ } else {
245
+ server.start({ transportType: "stdio" });
246
+
247
+ console.log(`
248
+ 🚀 Session Context Demo server started with stdio transport!
249
+
250
+ Environment variables for authentication:
251
+ - USER_ID=${process.env.USER_ID || "(not set - will use 'default-user')"}
252
+ - USERNAME=${process.env.USERNAME || "(not set - will use 'Anonymous')"}
253
+ - USER_ROLE=${process.env.USER_ROLE || "(not set - will use 'guest')"}
254
+
255
+ To test with different user roles:
256
+ USER_ID=admin001 USERNAME="John Admin" USER_ROLE=admin npx fastmcp dev src/examples/session-context.ts
257
+
258
+ Available tools:
259
+ - whoami: Get current user info
260
+ - admin-operation: Test admin permissions
261
+ - check-permissions: Check specific permissions
262
+
263
+ Available resources:
264
+ - session://current-user: Current user JSON data
265
+
266
+ Available prompts:
267
+ - personalized-greeting: Get a personalized greeting
268
+ `);
269
+ }