fastmcp 4.3.1 → 4.4.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/chunk-3YTRRGCE.cjs","../src/FastMCP.ts","../src/DiscoveryDocumentCache.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fastmcp/fastmcp/dist/chunk-3YTRRGCE.cjs","sourcesContent":[null,"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 ListPromptsResult,\n ListResourcesRequestSchema,\n ListResourcesResult,\n ListResourceTemplatesRequestSchema,\n ListResourceTemplatesResult,\n ListToolsRequestSchema,\n ListToolsResult,\n McpError,\n ReadResourceRequestSchema,\n ResourceLink,\n Root,\n RootsListChangedNotificationSchema,\n Tool as SDKTool,\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 { Hono } from \"hono\";\nimport http from \"http\";\nimport { type CorsOptions, 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 { strictJsonSchema, toJsonSchema } from \"xsschema\";\nimport { z } from \"zod\";\n\nimport type { OAuthProxy } from \"./auth/OAuthProxy.js\";\nimport type {\n AuthProvider,\n OAuthSession,\n} from \"./auth/providers/AuthProvider.js\";\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 client: {\n version: ReturnType<Server[\"getClientVersion\"]>;\n };\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 /**\n * Request ID from the current MCP request.\n * Available for all transports when the client provides it.\n */\n requestId?: string;\n session: T | undefined;\n /**\n * Session ID from the Mcp-Session-Id header.\n * Only available for HTTP-based transports (SSE, HTTP Stream).\n * Can be used to track per-session state, implement session-specific\n * counters, or maintain user-specific data across multiple requests.\n */\n sessionId?: string;\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 structuredContent?: Record<string, unknown>;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n structuredContent: z.record(z.string(), z.unknown()).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 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 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 InputResourceTemplateArgument<T>[] =\n InputResourceTemplateArgument<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 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 ResourceTemplateArgument<T>[] =\n 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 /**\n * Authentication provider for OAuth flows.\n * When provided, automatically configures the `authenticate` function\n * and `oauth` settings.\n *\n * For custom authentication logic, use the `authenticate` option instead.\n * If both are provided, `authenticate` takes precedence.\n *\n * @example\n * ```typescript\n * import { FastMCP, GitHubProvider } from \"fastmcp\";\n *\n * const server = new FastMCP({\n * auth: new GitHubProvider({\n * baseUrl: \"http://localhost:8000\",\n * clientId: process.env.GITHUB_CLIENT_ID!,\n * clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n * }),\n * name: \"My Server\",\n * version: \"1.0.0\",\n * });\n * ```\n */\n auth?: AuthProvider<T extends OAuthSession ? T : OAuthSession>;\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 * OAuth Proxy instance for automatic OAuth flow handling.\n * When provided, FastMCP will automatically register OAuth endpoints:\n * - /oauth/register (DCR)\n * - /oauth/authorize\n * - /oauth/token\n * - /oauth/callback\n * - /oauth/consent\n */\n proxy?: OAuthProxy;\n };\n /**\n * Callback invoked when a tool is called.\n * Use this to log, audit, or track tool usage.\n */\n onToolCall?: (context: {\n arguments: Record<string, unknown>;\n toolName: string;\n }) => Promise<void> | void;\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 OutputParams extends ToolParameters = ToolParameters,\n> = {\n /**\n * MCP ext-apps metadata for linking interactive UI components.\n * This field is passed through to the tool listing response.\n * @see https://modelcontextprotocol.github.io/ext-apps/\n */\n _meta?: {\n /** Additional metadata fields */\n [key: string]: unknown;\n /** UI component configuration */\n ui?: {\n /** URI of the resource serving the UI (e.g., \"ui://my-tool/app.html\") */\n resourceUri?: string;\n };\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\n description?: string;\n execute: (\n args: StandardSchemaV1.InferOutput<Params>,\n context: Context<T>,\n ) => Promise<\n | AudioContent\n | ContentResult\n | ImageContent\n | ResourceContent\n | ResourceLink\n | StandardSchemaV1.InferOutput<OutputParams>\n | string\n | TextContent\n | void\n >;\n name: string;\n outputSchema?: OutputParams;\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\nexport enum ServerState {\n Error = \"error\",\n Running = \"running\",\n Stopped = \"stopped\",\n}\n\n/**\n * Enhanced request object for custom routes\n */\nexport interface FastMCPRequest<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> {\n auth?: T;\n body?: unknown;\n headers: http.IncomingHttpHeaders;\n json(): Promise<unknown>;\n method: string;\n params: Record<string, string>;\n query: Record<string, string | string[]>;\n text(): Promise<string>;\n url: string;\n}\n\n/**\n * Enhanced response object for custom routes\n */\nexport interface FastMCPResponse {\n end(data?: Buffer | string): void;\n json(data: unknown): void;\n send(data: Buffer | string): void;\n setHeader(name: string, value: number | string | string[]): FastMCPResponse;\n status(code: number): FastMCPResponse;\n}\n\n/**\n * HTTP method types for custom routes\n */\nexport type HTTPMethod =\n | \"DELETE\"\n | \"GET\"\n | \"OPTIONS\"\n | \"PATCH\"\n | \"POST\"\n | \"PUT\";\n\n/**\n * Route handler function type\n */\nexport type RouteHandler<T extends FastMCPSessionAuth = FastMCPSessionAuth> = (\n req: FastMCPRequest<T>,\n res: FastMCPResponse,\n) => Promise<void> | void;\n\n/**\n * Options for configuring custom routes\n */\nexport interface RouteOptions {\n /**\n * Whether this route should bypass authentication.\n * When true, the route handler will be called without authentication,\n * and req.auth will be undefined.\n * @default false\n */\n public?: boolean;\n}\n\ntype Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;\n\ntype FastMCPSessionAuth = Record<string, unknown> | undefined;\n\nclass FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}\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 public get sessionId(): string | undefined {\n return this.#sessionId;\n }\n public set sessionId(value: string | undefined) {\n this.#sessionId = value;\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 #onToolCall?: ServerOptions<T>[\"onToolCall\"];\n #pingConfig?: ServerOptions<T>[\"ping\"];\n\n #pingInterval: null | ReturnType<typeof setInterval> = null;\n\n #prompts: Map<string, Prompt<T>> = new Map();\n\n #resources: Map<string, Resource<T>> = new Map();\n\n #resourceTemplates: Map<string, ResourceTemplate<T>> = new Map();\n\n #roots: Root[] = [];\n\n #rootsConfig?: ServerOptions<T>[\"roots\"];\n\n #server: Server;\n\n /**\n * Session ID from the Mcp-Session-Id header (HTTP transports only).\n * Used to track per-session state across multiple requests.\n */\n #sessionId?: string;\n\n #utils?: ServerOptions<T>[\"utils\"];\n\n constructor({\n auth,\n instructions,\n logger,\n name,\n onToolCall,\n ping,\n prompts,\n resources,\n resourcesTemplates,\n roots,\n sessionId,\n tools,\n transportType,\n utils,\n version,\n }: {\n auth?: T;\n instructions?: string;\n logger: Logger;\n name: string;\n onToolCall?: ServerOptions<T>[\"onToolCall\"];\n ping?: ServerOptions<T>[\"ping\"];\n prompts: Prompt<T>[];\n resources: Resource<T>[];\n resourcesTemplates: InputResourceTemplate<T>[];\n roots?: ServerOptions<T>[\"roots\"];\n sessionId?: string;\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.#onToolCall = onToolCall;\n this.#pingConfig = ping;\n this.#rootsConfig = roots;\n this.#sessionId = sessionId;\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.#capabilities.completions = {};\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();\n\n if (resourcesTemplates.length) {\n for (const resourceTemplate of resourcesTemplates) {\n this.addResourceTemplate(resourceTemplate);\n }\n\n this.setupResourceTemplateHandlers();\n }\n }\n\n if (prompts.length) {\n this.setupPromptHandlers();\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 // Extract session ID from transport if available (HTTP transports only)\n if (\"sessionId\" in transport) {\n const transportWithSessionId = transport as {\n sessionId?: string;\n } & Transport;\n if (typeof transportWithSessionId.sessionId === \"string\") {\n this.#sessionId = transportWithSessionId.sessionId;\n }\n }\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.#rootsConfig?.enabled !== false &&\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 promptsListChanged(prompts: Prompt<T>[]) {\n this.#prompts.clear();\n for (const prompt of prompts) {\n this.addPrompt(prompt);\n }\n this.setupPromptHandlers();\n this.triggerListChangedNotification(\"notifications/prompts/list_changed\");\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 resourcesListChanged(resources: Resource<T>[]) {\n this.#resources.clear();\n for (const resource of resources) {\n this.addResource(resource);\n }\n this.setupResourceHandlers();\n this.triggerListChangedNotification(\"notifications/resources/list_changed\");\n }\n\n resourceTemplatesListChanged(resourceTemplates: ResourceTemplate<T>[]) {\n this.#resourceTemplates.clear();\n for (const resourceTemplate of resourceTemplates) {\n this.addResourceTemplate(resourceTemplate);\n }\n this.setupResourceTemplateHandlers();\n this.triggerListChangedNotification(\"notifications/resources/list_changed\");\n }\n\n toolsListChanged(tools: Tool<T>[]) {\n const allowedTools = tools.filter((tool) =>\n tool.canAccess ? tool.canAccess(this.#auth as T) : true,\n );\n this.setupToolHandlers(allowedTools);\n this.triggerListChangedNotification(\"notifications/tools/list_changed\");\n }\n\n async triggerListChangedNotification(method: string) {\n try {\n await this.#server.notification({\n method,\n });\n } catch (error) {\n this.#logger.error(\n `[FastMCP error] failed to send ${method} notification.\\n\\n${\n error instanceof Error ? error.stack : JSON.stringify(error)\n }`,\n );\n }\n }\n\n /**\n * Update the session's authentication context.\n * Called by mcp-proxy when a new token is validated on subsequent requests.\n */\n public updateAuth(auth: T): void {\n this.#auth = auth;\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 #formatSchemaIssues(issues: readonly StandardSchemaV1.Issue[]): string {\n return this.#utils?.formatInvalidParamsErrorMessage\n ? this.#utils.formatInvalidParamsErrorMessage(issues)\n : issues\n .map((issue) => {\n const path = issue.path?.join(\".\") || \"root\";\n return `${path}: ${issue.message}`;\n })\n .join(\", \");\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 async #validateStructuredContent(\n tool: Tool<T>,\n value: Record<string, unknown>,\n toolName: string,\n ): Promise<Record<string, unknown>> {\n if (!tool.outputSchema) {\n return value;\n }\n\n const parsed = await tool.outputSchema[\"~standard\"].validate(value);\n\n if (parsed.issues) {\n throw new UserError(\n `Tool '${toolName}' structured output validation failed: ${this.#formatSchemaIssues(parsed.issues)}. Please check the result matches the tool's outputSchema.`,\n );\n }\n\n return parsed.value as Record<string, unknown>;\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 (inputPrompt.complete) {\n return await inputPrompt.complete(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.set(prompt.name, prompt);\n }\n\n private addResource(inputResource: Resource<T>) {\n this.#resources.set(inputResource.uri, 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 if (inputResourceTemplate.complete) {\n return await inputResourceTemplate.complete(name, value, auth);\n }\n\n return {\n values: [],\n };\n },\n };\n\n this.#resourceTemplates.set(resourceTemplate.name, resourceTemplate);\n }\n\n private setupCompleteHandlers() {\n this.#server.setRequestHandler(CompleteRequestSchema, async (request) => {\n if (request.params.ref.type === \"ref/prompt\") {\n const ref = request.params.ref;\n\n const prompt = \"name\" in ref && this.#prompts.get(ref.name);\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 ref = request.params.ref;\n\n const resource =\n \"uri\" in ref &&\n Array.from(this.#resourceTemplates.values()).find(\n (resource) => resource.uriTemplate === 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 private setupErrorHandling() {\n this.#server.onerror = (error) => {\n this.#logger.error(\"[FastMCP error]\", error);\n };\n }\n private setupLoggingHandlers() {\n this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {\n this.#loggingLevel = request.params.level;\n\n return {};\n });\n }\n private setupPromptHandlers() {\n let cachedPromptsList: ListPromptsResult[\"prompts\"] | null = null;\n\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n if (cachedPromptsList) {\n return {\n prompts: cachedPromptsList,\n };\n }\n\n cachedPromptsList = Array.from(this.#prompts.values()).map((prompt) => {\n return {\n arguments: prompt.arguments,\n complete: prompt.complete,\n description: prompt.description,\n name: prompt.name,\n };\n });\n\n return {\n prompts: cachedPromptsList,\n };\n });\n\n this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = this.#prompts.get(request.params.name);\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() {\n let cachedResourcesList: ListResourcesResult[\"resources\"] | null = null;\n\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n if (cachedResourcesList) {\n return {\n resources: cachedResourcesList,\n };\n }\n\n cachedResourcesList = Array.from(this.#resources.values()).map(\n (resource) => ({\n description: resource.description,\n mimeType: resource.mimeType,\n name: resource.name,\n uri: resource.uri,\n }),\n );\n\n return {\n resources: cachedResourcesList,\n };\n });\n\n this.#server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request) => {\n if (\"uri\" in request.params) {\n const resource = this.#resources.get(request.params.uri);\n\n if (!resource) {\n for (const resourceTemplate of this.#resourceTemplates.values()) {\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 Array.from(this.#resources.values())\n .map((r) => r.uri)\n .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 let cachedResourceTemplatesList:\n | ListResourceTemplatesResult[\"resourceTemplates\"]\n | null = null;\n\n this.#server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async () => {\n if (cachedResourceTemplatesList) {\n return {\n resourceTemplates: cachedResourceTemplatesList,\n };\n }\n\n cachedResourceTemplatesList = Array.from(\n this.#resourceTemplates.values(),\n ).map((resourceTemplate) => ({\n description: resourceTemplate.description,\n mimeType: resourceTemplate.mimeType,\n name: resourceTemplate.name,\n uriTemplate: resourceTemplate.uriTemplate,\n }));\n\n return {\n resourceTemplates: cachedResourceTemplatesList,\n };\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 const toolsMap = new Map(tools.map((tool) => [tool.name, tool]));\n let cachedToolsList: ListToolsResult[\"tools\"] | null = null;\n\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n if (cachedToolsList) {\n return {\n tools: cachedToolsList,\n };\n }\n cachedToolsList = await Promise.all(\n tools.map(async (tool) => {\n return {\n annotations: tool.annotations,\n description: tool.description,\n inputSchema: (tool.parameters\n ? strictJsonSchema(await toJsonSchema(tool.parameters))\n : {\n additionalProperties: false,\n properties: {},\n type: \"object\",\n }) as SDKTool[\"inputSchema\"],\n name: tool.name,\n ...(tool.outputSchema && {\n outputSchema: strictJsonSchema(\n await toJsonSchema(tool.outputSchema),\n ) as SDKTool[\"inputSchema\"],\n }),\n // Pass through _meta for MCP ext-apps UI support (issue #229)\n ...(tool._meta && { _meta: tool._meta }),\n };\n }),\n );\n\n return {\n tools: cachedToolsList,\n };\n });\n\n this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = toolsMap.get(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.#formatSchemaIssues(parsed.issues);\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 // Progress notifications must reference the progressToken supplied by\n // the client in the initiating request. If the client did not request\n // progress, there is nothing to associate the update with, and sending\n // a notification without a token produces an invalid message.\n if (progressToken === undefined) {\n return;\n }\n\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 if (this.#onToolCall) {\n await this.#onToolCall({\n arguments: (args ?? {}) as Record<string, unknown>,\n toolName: request.params.name,\n });\n }\n\n const executeToolPromise = tool.execute(args, {\n client: {\n version: this.#server.getClientVersion(),\n },\n log,\n reportProgress,\n requestId:\n typeof request.params?._meta?.requestId === \"string\"\n ? request.params._meta.requestId\n : undefined,\n session: this.#auth,\n sessionId: this.#sessionId,\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.then(\n () => clearTimeout(timeoutId),\n () => clearTimeout(timeoutId),\n );\n }),\n ])\n : executeToolPromise)) as\n | AudioContent\n | ContentResult\n | ImageContent\n | null\n | Record<string, unknown>\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 if (\"content\" in maybeStringResult) {\n result = ContentResultZodSchema.parse(maybeStringResult);\n if (result.structuredContent !== undefined && tool.outputSchema) {\n result.structuredContent = await this.#validateStructuredContent(\n tool,\n result.structuredContent,\n request.params.name,\n );\n }\n } else if (tool.outputSchema) {\n const structuredContent = await this.#validateStructuredContent(\n tool,\n maybeStringResult,\n request.params.name,\n );\n result = ContentResultZodSchema.parse({\n content: [\n {\n text: JSON.stringify(structuredContent),\n type: \"text\",\n },\n ],\n structuredContent,\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 ...(error.extras ? { structuredContent: error.extras } : {}),\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\nfunction joinPaths(basePath: \"\" | `/${string}`, path: string): `/${string}` {\n return `${basePath}${normalizePath(path)}` as `/${string}`;\n}\n\nfunction normalizeBasePath(path: string | undefined): \"\" | `/${string}` {\n if (!path || path === \"/\") {\n return \"\";\n }\n\n const withLeadingSlash = path.startsWith(\"/\") ? path : `/${path}`;\n const withoutTrailingSlash = withLeadingSlash.replace(/\\/+$/, \"\");\n\n return withoutTrailingSlash ? (withoutTrailingSlash as `/${string}`) : \"\";\n}\n\nfunction normalizePath(path: string): `/${string}` {\n return (path.startsWith(\"/\") ? path : `/${path}`) as `/${string}`;\n}\n\n/**\n * Parses Basic auth header (RFC 6749 Section 2.3.1)\n */\nfunction parseBasicAuthHeader(\n authHeader: string | undefined,\n): { clientId: string; clientSecret: string } | null {\n const basicMatch = authHeader?.match(/^Basic\\s+(.+)$/);\n if (!basicMatch) return null;\n\n try {\n const credentials = Buffer.from(basicMatch[1], \"base64\").toString(\"utf-8\");\n const credMatch = credentials.match(/^([^:]+):(.*)$/);\n if (!credMatch) return null;\n\n return { clientId: credMatch[1], clientSecret: credMatch[2] };\n } catch {\n return null;\n }\n}\n\nfunction stripBasePath(\n path: string,\n basePath: \"\" | `/${string}`,\n): null | string {\n if (!basePath) {\n return path;\n }\n\n if (path === basePath) {\n return \"/\";\n }\n\n if (path.startsWith(`${basePath}/`)) {\n return path.slice(basePath.length);\n }\n\n return null;\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 serverState(): ServerState {\n return this.#serverState;\n }\n\n public get sessions(): FastMCPSession<T>[] {\n return this.#sessions;\n }\n #authenticate: Authenticate<T> | undefined;\n #honoApp = new Hono();\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 #serverState: ServerState = ServerState.Stopped;\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.#logger = options.logger || console;\n\n // If auth provider is specified, use it to configure authenticate and oauth\n if (options.auth) {\n // Use auth provider's authenticate if not explicitly overridden\n if (!options.authenticate) {\n this.#authenticate = ((request: http.IncomingMessage | undefined) =>\n options.auth!.authenticate(request)) as Authenticate<T>;\n } else {\n this.#authenticate = options.authenticate;\n }\n\n // Use auth provider's oauth config if not explicitly overridden\n if (!options.oauth) {\n this.#options = {\n ...options,\n oauth: options.auth.getOAuthConfig(),\n };\n }\n } else {\n this.#authenticate = options.authenticate;\n }\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 = this.#prompts.filter((p) => p.name !== prompt.name);\n this.#prompts.push(prompt);\n if (this.#serverState === ServerState.Running) {\n this.#promptsListChanged(this.#prompts);\n }\n }\n /**\n * Adds prompts to the server.\n */\n public addPrompts<const Args extends InputPromptArgument<T>[]>(\n prompts: InputPrompt<T, Args>[],\n ) {\n const newPromptNames = new Set(prompts.map((prompt) => prompt.name));\n this.#prompts = this.#prompts.filter((p) => !newPromptNames.has(p.name));\n this.#prompts.push(...prompts);\n\n if (this.#serverState === ServerState.Running) {\n this.#promptsListChanged(this.#prompts);\n }\n }\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource<T>) {\n this.#resources = this.#resources.filter((r) => r.name !== resource.name);\n\n this.#resources.push(resource);\n if (this.#serverState === ServerState.Running) {\n this.#resourcesListChanged(this.#resources);\n }\n }\n /**\n * Adds resources to the server.\n */\n public addResources(resources: Resource<T>[]) {\n const newResourceNames = new Set(\n resources.map((resource) => resource.name),\n );\n this.#resources = this.#resources.filter(\n (r) => !newResourceNames.has(r.name),\n );\n this.#resources.push(...resources);\n\n if (this.#serverState === ServerState.Running) {\n this.#resourcesListChanged(this.#resources);\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 = this.#resourcesTemplates.filter(\n (t) => t.name !== resource.name,\n );\n\n this.#resourcesTemplates.push(resource);\n if (this.#serverState === ServerState.Running) {\n this.#resourceTemplatesListChanged(this.#resourcesTemplates);\n }\n }\n /**\n * Adds resource templates to the server.\n */\n public addResourceTemplates<\n const Args extends InputResourceTemplateArgument[],\n >(resources: InputResourceTemplate<T, Args>[]) {\n const newResourceTemplateNames = new Set(\n resources.map((resource) => resource.name),\n );\n this.#resourcesTemplates = this.#resourcesTemplates.filter(\n (t) => !newResourceTemplateNames.has(t.name),\n );\n this.#resourcesTemplates.push(...resources);\n\n if (this.#serverState === ServerState.Running) {\n this.#resourceTemplatesListChanged(this.#resourcesTemplates);\n }\n }\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {\n // Remove existing tool with the same name\n this.#tools = this.#tools.filter((t) => t.name !== tool.name);\n this.#tools.push(tool as unknown as Tool<T>);\n if (this.#serverState === ServerState.Running) {\n this.#toolsListChanged(this.#tools);\n }\n }\n /**\n * Adds tools to the server.\n */\n public addTools<Params extends ToolParameters>(tools: Tool<T, Params>[]) {\n const newToolNames = new Set(tools.map((tool) => tool.name));\n this.#tools = this.#tools.filter((t) => !newToolNames.has(t.name));\n this.#tools.push(...(tools as unknown as Tool<T>[]));\n\n if (this.#serverState === ServerState.Running) {\n this.#toolsListChanged(this.#tools);\n }\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 const parsedTemplate = parseURITemplate(template.uriTemplate);\n const params = parsedTemplate.fromUri(uri);\n if (!params) {\n continue;\n }\n\n const result = await template.load(\n params as ResourceTemplateArgumentsToObject<typeof template.arguments>,\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 throw new UnexpectedStateError(`Resource not found: ${uri}`, { uri });\n }\n /**\n * Returns the underlying Hono app instance for direct access to Hono's native API.\n * This allows you to add custom routes, middleware, and handlers using Hono's standard methods.\n *\n * @returns The Hono app instance\n *\n * @example\n * ```typescript\n * const app = server.getApp();\n *\n * // Add routes using native Hono API\n * app.get('/api/users', async (c) => {\n * return c.json({ users: [] });\n * });\n *\n * app.post('/api/users/:id', async (c) => {\n * const id = c.req.param('id');\n * return c.json({ id });\n * });\n * ```\n */\n public getApp(): Hono {\n return this.#honoApp;\n }\n /**\n * Removes a prompt from the server.\n */\n public removePrompt(name: string) {\n this.#prompts = this.#prompts.filter((p) => p.name !== name);\n if (this.#serverState === ServerState.Running) {\n this.#promptsListChanged(this.#prompts);\n }\n }\n /**\n * Removes prompts from the server.\n */\n public removePrompts(names: string[]) {\n for (const name of names) {\n this.#prompts = this.#prompts.filter((p) => p.name !== name);\n }\n if (this.#serverState === ServerState.Running) {\n this.#promptsListChanged(this.#prompts);\n }\n }\n\n /**\n * Removes a resource from the server.\n */\n public removeResource(name: string) {\n this.#resources = this.#resources.filter((r) => r.name !== name);\n if (this.#serverState === ServerState.Running) {\n this.#resourcesListChanged(this.#resources);\n }\n }\n /**\n * Removes resources from the server.\n */\n public removeResources(names: string[]) {\n for (const name of names) {\n this.#resources = this.#resources.filter((r) => r.name !== name);\n }\n if (this.#serverState === ServerState.Running) {\n this.#resourcesListChanged(this.#resources);\n }\n }\n /**\n * Removes a resource template from the server.\n */\n public removeResourceTemplate(name: string) {\n this.#resourcesTemplates = this.#resourcesTemplates.filter(\n (t) => t.name !== name,\n );\n if (this.#serverState === ServerState.Running) {\n this.#resourceTemplatesListChanged(this.#resourcesTemplates);\n }\n }\n /**\n * Removes resource templates from the server.\n */\n public removeResourceTemplates(names: string[]) {\n for (const name of names) {\n this.#resourcesTemplates = this.#resourcesTemplates.filter(\n (t) => t.name !== name,\n );\n }\n if (this.#serverState === ServerState.Running) {\n this.#resourceTemplatesListChanged(this.#resourcesTemplates);\n }\n }\n\n /**\n * Removes a tool from the server.\n */\n public removeTool(name: string) {\n // Remove existing tool with the same name\n this.#tools = this.#tools.filter((t) => t.name !== name);\n if (this.#serverState === ServerState.Running) {\n this.#toolsListChanged(this.#tools);\n }\n }\n\n /**\n * Removes tools from the server.\n */\n public removeTools(names: string[]) {\n for (const name of names) {\n this.#tools = this.#tools.filter((t) => t.name !== name);\n }\n if (this.#serverState === ServerState.Running) {\n this.#toolsListChanged(this.#tools);\n }\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options?: Partial<{\n httpStream: {\n basePath?: `/${string}`;\n cors?: boolean | CorsOptions;\n enableJsonResponse?: boolean;\n endpoint?: `/${string}`;\n eventStore?: EventStore;\n host?: string;\n port: number;\n sslCa?: string;\n sslCert?: string;\n sslKey?: string;\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 onToolCall: this.#options.onToolCall,\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 session.once(\"error\", () => {\n this.#removeSession(session);\n });\n\n // Monitor the underlying transport for close events\n if (transport.onclose) {\n const originalOnClose = transport.onclose;\n\n transport.onclose = () => {\n this.#removeSession(session);\n\n if (originalOnClose) {\n originalOnClose();\n }\n };\n } else {\n transport.onclose = () => {\n this.#removeSession(session);\n };\n }\n\n this.emit(\"connect\", {\n session: session as FastMCPSession<FastMCPSessionAuth>,\n });\n this.#serverState = ServerState.Running;\n } else if (config.transportType === \"httpStream\") {\n const httpConfig = config.httpStream;\n const protocol =\n httpConfig.sslCert || httpConfig.sslKey ? \"https\" : \"http\";\n const streamEndpoint = joinPaths(\n httpConfig.basePath,\n httpConfig.endpoint,\n );\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 ${protocol}://${httpConfig.host}:${httpConfig.port}${streamEndpoint}`,\n );\n\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n ...(this.#authenticate ? { authenticate: this.#authenticate } : {}),\n cors: httpConfig.cors,\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n\n // In stateless mode, authentication is REQUIRED\n // mcp-proxy will catch this error and return 401\n if (auth === undefined || auth === null) {\n throw new Error(\"Authentication required\");\n }\n }\n\n // Extract session ID from headers\n const sessionId = Array.isArray(request.headers[\"mcp-session-id\"])\n ? request.headers[\"mcp-session-id\"][0]\n : request.headers[\"mcp-session-id\"];\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, sessionId);\n },\n enableJsonResponse: httpConfig.enableJsonResponse,\n eventStore: httpConfig.eventStore,\n host: httpConfig.host,\n ...(this.#options.oauth?.enabled &&\n this.#options.oauth.protectedResource?.resource\n ? {\n oauth: {\n protectedResource: {\n resource: this.#options.oauth.protectedResource.resource,\n },\n },\n }\n : {}),\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(\n req,\n res,\n true,\n httpConfig.host,\n streamEndpoint,\n httpConfig.basePath,\n );\n },\n port: httpConfig.port,\n sslCa: httpConfig.sslCa,\n sslCert: httpConfig.sslCert,\n sslKey: httpConfig.sslKey,\n stateless: true,\n streamEndpoint,\n });\n } else {\n // Regular mode with session management\n this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({\n ...(this.#authenticate ? { authenticate: this.#authenticate } : {}),\n cors: httpConfig.cors,\n createServer: async (request) => {\n let auth: T | undefined;\n\n if (this.#authenticate) {\n auth = await this.#authenticate(request);\n }\n\n // Extract session ID from headers\n const sessionId = Array.isArray(request.headers[\"mcp-session-id\"])\n ? request.headers[\"mcp-session-id\"][0]\n : request.headers[\"mcp-session-id\"];\n\n return this.#createSession(auth, sessionId);\n },\n enableJsonResponse: httpConfig.enableJsonResponse,\n eventStore: httpConfig.eventStore,\n host: httpConfig.host,\n ...(this.#options.oauth?.enabled &&\n this.#options.oauth.protectedResource?.resource\n ? {\n oauth: {\n protectedResource: {\n resource: this.#options.oauth.protectedResource.resource,\n },\n },\n }\n : {}),\n onClose: async (session) => {\n const sessionIndex = this.#sessions.indexOf(session);\n\n if (sessionIndex !== -1) this.#sessions.splice(sessionIndex, 1);\n\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 streamEndpoint,\n httpConfig.basePath,\n );\n },\n port: httpConfig.port,\n sslCa: httpConfig.sslCa,\n sslCert: httpConfig.sslCert,\n sslKey: httpConfig.sslKey,\n stateless: httpConfig.stateless,\n streamEndpoint,\n });\n\n this.#logger.info(\n `[FastMCP info] server is running on HTTP Stream at ${protocol}://${httpConfig.host}:${httpConfig.port}${streamEndpoint}`,\n );\n }\n this.#serverState = ServerState.Running;\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 this.#serverState = ServerState.Stopped;\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, sessionId?: string): FastMCPSession<T> {\n // Check if authentication failed\n if (\n auth &&\n typeof auth === \"object\" &&\n \"authenticated\" in auth &&\n !(auth as { authenticated: unknown }).authenticated\n ) {\n const errorMessage =\n \"error\" in auth &&\n typeof (auth as { error: unknown }).error === \"string\"\n ? (auth as { error: string }).error\n : \"Authentication failed\";\n throw new Error(errorMessage);\n }\n\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 instructions: this.#options.instructions,\n logger: this.#logger,\n name: this.#options.name,\n onToolCall: this.#options.onToolCall,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n sessionId,\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, OAuth endpoints, and custom routes\n */\n #handleUnhandledRequest = async (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n isStateless = false,\n host: string,\n streamEndpoint?: string,\n basePath: \"\" | `/${string}` = \"\",\n ) => {\n const url = new URL(req.url || \"\", `http://${host}`);\n const basePathRelativePath = stripBasePath(url.pathname, basePath);\n\n // Try Hono routes first - users may have added routes via getApp()\n try {\n // Convert Node.js IncomingMessage to Web Request\n const webRequest = this.#nodeRequestToWebRequest(req, url);\n\n // Call Hono's fetch handler\n const honoResponse = await this.#honoApp.fetch(webRequest, {\n incoming: req,\n outgoing: res,\n });\n\n // If Hono handled it (not 404), write response and return\n if (honoResponse.status !== 404) {\n // Write Hono response to Node.js response\n if (!res.headersSent) {\n res.statusCode = honoResponse.status;\n honoResponse.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n\n if (honoResponse.body) {\n const reader = honoResponse.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n }\n } finally {\n reader.releaseLock();\n }\n }\n res.end();\n }\n return;\n }\n } catch (error) {\n // If Hono throws, log and continue to other endpoints\n this.#logger.debug(\"[FastMCP debug] Hono route not matched\", error);\n }\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\n try {\n if (\n (req.method === \"GET\" || req.method === \"HEAD\") &&\n url.pathname === joinPaths(basePath, path)\n ) {\n res\n .writeHead(healthConfig.status ?? 200, {\n \"Content-Type\": \"text/plain\",\n })\n .end(\n req.method === \"HEAD\"\n ? undefined\n : (healthConfig.message ?? \"✓ Ok\"),\n );\n\n return;\n }\n\n // Enhanced readiness check endpoint\n if (\n (req.method === \"GET\" || req.method === \"HEAD\") &&\n url.pathname === joinPaths(basePath, \"/ready\")\n ) {\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(\n req.method === \"HEAD\" ? undefined : JSON.stringify(response),\n );\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(\n req.method === \"HEAD\" ? undefined : JSON.stringify(response),\n );\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 const authorizationServerMetadataPath = joinPaths(\n \"\",\n `/.well-known/oauth-authorization-server${basePath}`,\n );\n\n if (\n url.pathname === authorizationServerMetadataPath &&\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 // Handle Protected Resource Metadata with MCP 2025-11-25 compliant discovery\n // Per spec, clients should search in order:\n // 1. WWW-Authenticate header (handled by mcp-proxy)\n // 2. /.well-known/oauth-protected-resource<sub-path> (e.g., /mcp)\n // 3. /.well-known/oauth-protected-resource (root)\n if (oauthConfig.protectedResource) {\n const wellKnownBase = \"/.well-known/oauth-protected-resource\";\n let shouldServeMetadata = false;\n\n // Check for sub-path variant first (higher priority per MCP spec)\n if (\n streamEndpoint &&\n url.pathname === `${wellKnownBase}${streamEndpoint}`\n ) {\n shouldServeMetadata = true;\n }\n // Fall back to root path\n else if (url.pathname === wellKnownBase) {\n shouldServeMetadata = true;\n }\n\n if (shouldServeMetadata) {\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\n // Handle OAuth Proxy endpoints\n const oauthProxy = oauthConfig?.proxy;\n if (oauthProxy && oauthConfig?.enabled) {\n const url = new URL(req.url || \"\", `http://${host}`);\n const oauthPath = basePathRelativePath;\n\n try {\n // DCR endpoint - POST /oauth/register\n if (req.method === \"POST\" && oauthPath === \"/oauth/register\") {\n await new Promise<void>((resolve) => {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const request = JSON.parse(body);\n const response = await oauthProxy.registerClient(request);\n res\n .writeHead(201, { \"Content-Type\": \"application/json\" })\n .end(JSON.stringify(response));\n } catch (error) {\n const statusCode =\n (error as { statusCode?: number }).statusCode || 400;\n res\n .writeHead(statusCode, { \"Content-Type\": \"application/json\" })\n .end(\n JSON.stringify(\n (error as { toJSON?: () => unknown }).toJSON?.() || {\n error: \"invalid_request\",\n },\n ),\n );\n }\n resolve();\n });\n });\n return;\n }\n\n // Authorization endpoint - GET /oauth/authorize\n if (req.method === \"GET\" && oauthPath === \"/oauth/authorize\") {\n try {\n const params = Object.fromEntries(url.searchParams.entries());\n const response = await oauthProxy.authorize(\n params as {\n [key: string]: unknown;\n client_id: string;\n redirect_uri: string;\n response_type: string;\n },\n );\n\n // Response is a redirect\n const location = response.headers.get(\"Location\");\n if (location) {\n res.writeHead(response.status, { Location: location }).end();\n } else {\n // HTML consent screen\n const html = await response.text();\n res\n .writeHead(response.status, { \"Content-Type\": \"text/html\" })\n .end(html);\n }\n } catch (error) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" }).end(\n JSON.stringify(\n (error as { toJSON?: () => unknown }).toJSON?.() || {\n error: \"invalid_request\",\n },\n ),\n );\n }\n return;\n }\n\n // Callback endpoint - GET /oauth/callback\n if (req.method === \"GET\" && oauthPath === \"/oauth/callback\") {\n try {\n const mockRequest = new Request(`http://${host}${req.url}`);\n const response = await oauthProxy.handleCallback(mockRequest);\n\n const location = response.headers.get(\"Location\");\n if (location) {\n res.writeHead(response.status, { Location: location }).end();\n } else {\n const text = await response.text();\n res.writeHead(response.status).end(text);\n }\n } catch (error) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" }).end(\n JSON.stringify(\n (error as { toJSON?: () => unknown }).toJSON?.() || {\n error: \"server_error\",\n },\n ),\n );\n }\n return;\n }\n\n // Consent endpoint - POST /oauth/consent\n if (req.method === \"POST\" && oauthPath === \"/oauth/consent\") {\n await new Promise<void>((resolve) => {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const mockRequest = new Request(\n `http://${host}${url.pathname}${url.search}`,\n {\n body,\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n method: \"POST\",\n },\n );\n const response = await oauthProxy.handleConsent(mockRequest);\n\n const location = response.headers.get(\"Location\");\n if (location) {\n res.writeHead(response.status, { Location: location }).end();\n } else {\n const text = await response.text();\n res.writeHead(response.status).end(text);\n }\n } catch (error) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" }).end(\n JSON.stringify(\n (error as { toJSON?: () => unknown }).toJSON?.() || {\n error: \"server_error\",\n },\n ),\n );\n }\n resolve();\n });\n });\n return;\n }\n\n // Token endpoint - POST /oauth/token\n if (req.method === \"POST\" && oauthPath === \"/oauth/token\") {\n await new Promise<void>((resolve) => {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const params = new URLSearchParams(body);\n const grantType = params.get(\"grant_type\");\n\n // Parse Basic auth header (RFC 6749 Section 2.3.1)\n const basicAuth = parseBasicAuthHeader(\n req.headers.authorization,\n );\n\n // Use Basic auth credentials if present, otherwise fall back to POST body\n const clientId =\n basicAuth?.clientId || params.get(\"client_id\") || \"\";\n const clientSecret =\n basicAuth?.clientSecret ??\n params.get(\"client_secret\") ??\n undefined;\n\n let response;\n if (grantType === \"authorization_code\") {\n response = await oauthProxy.exchangeAuthorizationCode({\n client_id: clientId,\n client_secret: clientSecret,\n code: params.get(\"code\") || \"\",\n code_verifier: params.get(\"code_verifier\") || undefined,\n grant_type: \"authorization_code\",\n redirect_uri: params.get(\"redirect_uri\") || \"\",\n });\n } else if (grantType === \"refresh_token\") {\n response = await oauthProxy.exchangeRefreshToken({\n client_id: clientId,\n client_secret: clientSecret,\n grant_type: \"refresh_token\",\n refresh_token: params.get(\"refresh_token\") || \"\",\n scope: params.get(\"scope\") || undefined,\n });\n } else {\n throw {\n statusCode: 400,\n toJSON: () => ({ error: \"unsupported_grant_type\" }),\n };\n }\n\n res\n .writeHead(200, { \"Content-Type\": \"application/json\" })\n .end(JSON.stringify(response));\n } catch (error) {\n const statusCode =\n (error as { statusCode?: number }).statusCode || 400;\n res\n .writeHead(statusCode, { \"Content-Type\": \"application/json\" })\n .end(\n JSON.stringify(\n (error as { toJSON?: () => unknown }).toJSON?.() || {\n error: \"invalid_request\",\n },\n ),\n );\n }\n resolve();\n });\n });\n return;\n }\n } catch (error) {\n this.#logger.error(\"[FastMCP error] OAuth Proxy endpoint error\", error);\n res.writeHead(500).end();\n return;\n }\n }\n };\n\n /**\n * Converts Node.js IncomingMessage to Web Request for Hono\n */\n #nodeRequestToWebRequest(req: http.IncomingMessage, url: URL): Request {\n const method = req.method || \"GET\";\n\n // Build headers\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value) {\n if (Array.isArray(value)) {\n for (const v of value) {\n headers.append(key, v);\n }\n } else {\n headers.set(key, value);\n }\n }\n }\n\n // Create Web Request\n // For methods that can have a body, we need to pass the body\n const hasBody = method !== \"GET\" && method !== \"HEAD\";\n\n if (hasBody) {\n return new Request(url.toString(), {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n body: req as any, // Node.js IncomingMessage is readable stream\n duplex: \"half\", // Required for streaming bodies\n headers,\n method,\n } as RequestInit);\n } else {\n return new Request(url.toString(), {\n headers,\n method,\n });\n }\n }\n\n #parseRuntimeConfig(\n overrides?: Partial<{\n httpStream: {\n basePath?: `/${string}`;\n cors?: boolean | CorsOptions;\n enableJsonResponse?: boolean;\n endpoint?: `/${string}`;\n eventStore?: EventStore;\n host?: string;\n port: number;\n sslCa?: string;\n sslCert?: string;\n sslKey?: string;\n stateless?: boolean;\n };\n transportType: \"httpStream\" | \"stdio\";\n }>,\n ):\n | {\n httpStream: {\n basePath: \"\" | `/${string}`;\n cors?: boolean | CorsOptions;\n enableJsonResponse?: boolean;\n endpoint: `/${string}`;\n eventStore?: EventStore;\n host: string;\n port: number;\n sslCa?: string;\n sslCert?: string;\n sslKey?: string;\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 basePathArg = getArg(\"base-path\");\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 envBasePath = process.env.FASTMCP_BASE_PATH;\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 basePath = normalizeBasePath(\n overrides?.httpStream?.basePath || basePathArg || envBasePath,\n );\n const enableJsonResponse =\n overrides?.httpStream?.enableJsonResponse || false;\n const stateless =\n overrides?.httpStream?.stateless ||\n statelessArg === \"true\" ||\n envStateless === \"true\" ||\n false;\n const cors = overrides?.httpStream?.cors;\n const eventStore = overrides?.httpStream?.eventStore;\n const sslCa = overrides?.httpStream?.sslCa;\n const sslCert = overrides?.httpStream?.sslCert;\n const sslKey = overrides?.httpStream?.sslKey;\n\n return {\n httpStream: {\n basePath,\n cors,\n enableJsonResponse,\n endpoint: endpoint as `/${string}`,\n eventStore,\n host,\n port,\n sslCa,\n sslCert,\n sslKey,\n stateless,\n },\n transportType: \"httpStream\" as const,\n };\n }\n\n return { transportType: \"stdio\" as const };\n }\n\n /**\n * Notifies all sessions that the prompts list has changed.\n */\n #promptsListChanged(prompts: Prompt<T>[]) {\n for (const session of this.#sessions) {\n session.promptsListChanged(prompts);\n }\n }\n #removeSession(session: FastMCPSession<T>): void {\n const sessionIndex = this.#sessions.indexOf(session);\n\n if (sessionIndex !== -1) {\n this.#sessions.splice(sessionIndex, 1);\n this.emit(\"disconnect\", {\n session: session as FastMCPSession<FastMCPSessionAuth>,\n });\n }\n }\n /**\n * Notifies all sessions that the resources list has changed.\n */\n #resourcesListChanged(resources: Resource<T>[]) {\n for (const session of this.#sessions) {\n session.resourcesListChanged(resources);\n }\n }\n /**\n * Notifies all sessions that the resource templates list has changed.\n */\n #resourceTemplatesListChanged(templates: InputResourceTemplate<T>[]) {\n for (const session of this.#sessions) {\n session.resourceTemplatesListChanged(templates);\n }\n }\n /**\n * Notifies all sessions that the tools list has changed.\n */\n #toolsListChanged(tools: Tool<T>[]) {\n for (const session of this.#sessions) {\n session.toolsListChanged(tools);\n }\n }\n}\n\n// Re-export commonly used auth utilities for convenience\n// Users can also import from \"fastmcp/auth\" for the full auth module\nexport {\n // Auth providers\n AuthProvider,\n AzureProvider,\n // Auth helpers for canAccess\n getAuthSession,\n GitHubProvider,\n GoogleProvider,\n OAuthProvider,\n requireAll,\n requireAny,\n requireAuth,\n requireRole,\n requireScopes,\n} from \"./auth/index.js\";\n\nexport type {\n AuthProviderConfig,\n AzureProviderConfig,\n AzureSession,\n GenericOAuthProviderConfig,\n GitHubSession,\n GoogleSession,\n OAuthSession,\n} from \"./auth/index.js\";\n\nexport { DiscoveryDocumentCache } from \"./DiscoveryDocumentCache.js\";\n\nexport type {\n AudioContent,\n Content,\n ContentResult,\n Context,\n CorsOptions,\n FastMCPEvents,\n FastMCPSessionAuth,\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","export class DiscoveryDocumentCache {\n public get size(): number {\n return this.#cache.size;\n }\n\n #cache: Map<\n string,\n {\n data: unknown;\n expiresAt: number;\n }\n > = new Map();\n\n #inFlight: Map<string, Promise<unknown>> = new Map();\n\n #ttl: number;\n\n /**\n * @param options - configuration options\n * @param options.ttl - time-to-live in miliseconds\n */\n public constructor(options: { ttl?: number } = {}) {\n this.#ttl = options.ttl ?? 3600000; // default 1 hour\n }\n\n /**\n * @param url - optional URL to clear. if omitted, clears all cached documents.\n */\n public clear(url?: string): void {\n if (url) {\n this.#cache.delete(url);\n } else {\n this.#cache.clear();\n }\n }\n\n /**\n * fetches a discovery document from the given URL.\n * uses cached value if available and not expired.\n * coalesces concurrent requests for the same URL to prevent duplicate fetches.\n *\n * @param url - the discovery document URL (e.g., /.well-known/openid-configuration)\n * @returns the discovery document as a JSON object\n * @throws Error if the fetch fails or returns non-OK status\n */\n public async get(url: string): Promise<unknown> {\n const now = Date.now();\n const cached = this.#cache.get(url);\n\n // return cached value if still valid\n if (cached && cached.expiresAt > now) {\n return cached.data;\n }\n\n // check if there’s already an in-flight request for this URL\n const inFlight = this.#inFlight.get(url);\n\n if (inFlight) {\n return inFlight;\n }\n\n // create a new fetch promise and store it\n const fetchPromise = this.#fetchAndCache(url);\n\n this.#inFlight.set(url, fetchPromise);\n\n try {\n const data = await fetchPromise;\n return data;\n } finally {\n // clean up in-flight promise after completion\n // (success or failure)\n this.#inFlight.delete(url);\n }\n }\n\n /**\n * @param url - the URL to check\n * @returns true if the URL is cached and nott expired\n */\n public has(url: string): boolean {\n const cached = this.#cache.get(url);\n\n if (!cached) {\n return false;\n }\n\n const now = Date.now();\n\n if (cached.expiresAt <= now) {\n // expired, remove from cache\n this.#cache.delete(url);\n return false;\n }\n\n return true;\n }\n\n async #fetchAndCache(url: string): Promise<unknown> {\n // fetch fresh document\n const res = await fetch(url);\n\n if (!res.ok) {\n throw new Error(\n `Failed to fetch discovery document from ${url}: ${res.status} ${res.statusText}`,\n );\n }\n\n const data = await res.json();\n // calculate expiration time AFTER fetch completes\n const expiresAt = Date.now() + this.#ttl;\n\n // store in cache with expiration\n this.#cache.set(url, {\n data,\n expiresAt,\n });\n\n return data;\n }\n}\n"]}
@@ -1044,6 +1044,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1044
1044
  let result;
1045
1045
  try {
1046
1046
  const reportProgress = async (progress) => {
1047
+ if (progressToken === void 0) {
1048
+ return;
1049
+ }
1047
1050
  try {
1048
1051
  await this.#server.notification({
1049
1052
  method: "notifications/progress",
@@ -1227,6 +1230,20 @@ function convertObjectToSnakeCase(obj) {
1227
1230
  }
1228
1231
  return result;
1229
1232
  }
1233
+ function joinPaths(basePath, path) {
1234
+ return `${basePath}${normalizePath(path)}`;
1235
+ }
1236
+ function normalizeBasePath(path) {
1237
+ if (!path || path === "/") {
1238
+ return "";
1239
+ }
1240
+ const withLeadingSlash = path.startsWith("/") ? path : `/${path}`;
1241
+ const withoutTrailingSlash = withLeadingSlash.replace(/\/+$/, "");
1242
+ return withoutTrailingSlash ? withoutTrailingSlash : "";
1243
+ }
1244
+ function normalizePath(path) {
1245
+ return path.startsWith("/") ? path : `/${path}`;
1246
+ }
1230
1247
  function parseBasicAuthHeader(authHeader) {
1231
1248
  const basicMatch = authHeader?.match(/^Basic\s+(.+)$/);
1232
1249
  if (!basicMatch) return null;
@@ -1239,6 +1256,18 @@ function parseBasicAuthHeader(authHeader) {
1239
1256
  return null;
1240
1257
  }
1241
1258
  }
1259
+ function stripBasePath(path, basePath) {
1260
+ if (!basePath) {
1261
+ return path;
1262
+ }
1263
+ if (path === basePath) {
1264
+ return "/";
1265
+ }
1266
+ if (path.startsWith(`${basePath}/`)) {
1267
+ return path.slice(basePath.length);
1268
+ }
1269
+ return null;
1270
+ }
1242
1271
  var FastMCPEventEmitterBase = EventEmitter;
1243
1272
  var FastMCPEventEmitter = class extends FastMCPEventEmitterBase {
1244
1273
  };
@@ -1593,9 +1622,13 @@ var FastMCP = class extends FastMCPEventEmitter {
1593
1622
  } else if (config.transportType === "httpStream") {
1594
1623
  const httpConfig = config.httpStream;
1595
1624
  const protocol = httpConfig.sslCert || httpConfig.sslKey ? "https" : "http";
1625
+ const streamEndpoint = joinPaths(
1626
+ httpConfig.basePath,
1627
+ httpConfig.endpoint
1628
+ );
1596
1629
  if (httpConfig.stateless) {
1597
1630
  this.#logger.info(
1598
- `[FastMCP info] Starting server in stateless mode on HTTP Stream at ${protocol}://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`
1631
+ `[FastMCP info] Starting server in stateless mode on HTTP Stream at ${protocol}://${httpConfig.host}:${httpConfig.port}${streamEndpoint}`
1599
1632
  );
1600
1633
  this.#httpStreamServer = await startHTTPServer({
1601
1634
  ...this.#authenticate ? { authenticate: this.#authenticate } : {},
@@ -1635,7 +1668,8 @@ var FastMCP = class extends FastMCPEventEmitter {
1635
1668
  res,
1636
1669
  true,
1637
1670
  httpConfig.host,
1638
- httpConfig.endpoint
1671
+ streamEndpoint,
1672
+ httpConfig.basePath
1639
1673
  );
1640
1674
  },
1641
1675
  port: httpConfig.port,
@@ -1643,7 +1677,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1643
1677
  sslCert: httpConfig.sslCert,
1644
1678
  sslKey: httpConfig.sslKey,
1645
1679
  stateless: true,
1646
- streamEndpoint: httpConfig.endpoint
1680
+ streamEndpoint
1647
1681
  });
1648
1682
  } else {
1649
1683
  this.#httpStreamServer = await startHTTPServer({
@@ -1687,7 +1721,8 @@ var FastMCP = class extends FastMCPEventEmitter {
1687
1721
  res,
1688
1722
  false,
1689
1723
  httpConfig.host,
1690
- httpConfig.endpoint
1724
+ streamEndpoint,
1725
+ httpConfig.basePath
1691
1726
  );
1692
1727
  },
1693
1728
  port: httpConfig.port,
@@ -1695,10 +1730,10 @@ var FastMCP = class extends FastMCPEventEmitter {
1695
1730
  sslCert: httpConfig.sslCert,
1696
1731
  sslKey: httpConfig.sslKey,
1697
1732
  stateless: httpConfig.stateless,
1698
- streamEndpoint: httpConfig.endpoint
1733
+ streamEndpoint
1699
1734
  });
1700
1735
  this.#logger.info(
1701
- `[FastMCP info] server is running on HTTP Stream at ${protocol}://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`
1736
+ `[FastMCP info] server is running on HTTP Stream at ${protocol}://${httpConfig.host}:${httpConfig.port}${streamEndpoint}`
1702
1737
  );
1703
1738
  }
1704
1739
  this.#serverState = "running" /* Running */;
@@ -1748,8 +1783,9 @@ var FastMCP = class extends FastMCPEventEmitter {
1748
1783
  /**
1749
1784
  * Handles unhandled HTTP requests with health, readiness, OAuth endpoints, and custom routes
1750
1785
  */
1751
- #handleUnhandledRequest = async (req, res, isStateless = false, host, streamEndpoint) => {
1786
+ #handleUnhandledRequest = async (req, res, isStateless = false, host, streamEndpoint, basePath = "") => {
1752
1787
  const url = new URL(req.url || "", `http://${host}`);
1788
+ const basePathRelativePath = stripBasePath(url.pathname, basePath);
1753
1789
  try {
1754
1790
  const webRequest = this.#nodeRequestToWebRequest(req, url);
1755
1791
  const honoResponse = await this.#honoApp.fetch(webRequest, {
@@ -1785,9 +1821,8 @@ var FastMCP = class extends FastMCPEventEmitter {
1785
1821
  const enabled = healthConfig.enabled === void 0 ? true : healthConfig.enabled;
1786
1822
  if (enabled) {
1787
1823
  const path = healthConfig.path ?? "/health";
1788
- const url2 = new URL(req.url || "", `http://${host}`);
1789
1824
  try {
1790
- if ((req.method === "GET" || req.method === "HEAD") && url2.pathname === path) {
1825
+ if ((req.method === "GET" || req.method === "HEAD") && url.pathname === joinPaths(basePath, path)) {
1791
1826
  res.writeHead(healthConfig.status ?? 200, {
1792
1827
  "Content-Type": "text/plain"
1793
1828
  }).end(
@@ -1795,7 +1830,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1795
1830
  );
1796
1831
  return;
1797
1832
  }
1798
- if ((req.method === "GET" || req.method === "HEAD") && url2.pathname === "/ready") {
1833
+ if ((req.method === "GET" || req.method === "HEAD") && url.pathname === joinPaths(basePath, "/ready")) {
1799
1834
  if (isStateless) {
1800
1835
  const response = {
1801
1836
  mode: "stateless",
@@ -1834,7 +1869,11 @@ var FastMCP = class extends FastMCPEventEmitter {
1834
1869
  const oauthConfig = this.#options.oauth;
1835
1870
  if (oauthConfig?.enabled && req.method === "GET") {
1836
1871
  const url2 = new URL(req.url || "", `http://${host}`);
1837
- if (url2.pathname === "/.well-known/oauth-authorization-server" && oauthConfig.authorizationServer) {
1872
+ const authorizationServerMetadataPath = joinPaths(
1873
+ "",
1874
+ `/.well-known/oauth-authorization-server${basePath}`
1875
+ );
1876
+ if (url2.pathname === authorizationServerMetadataPath && oauthConfig.authorizationServer) {
1838
1877
  const metadata = convertObjectToSnakeCase(
1839
1878
  oauthConfig.authorizationServer
1840
1879
  );
@@ -1865,8 +1904,9 @@ var FastMCP = class extends FastMCPEventEmitter {
1865
1904
  const oauthProxy = oauthConfig?.proxy;
1866
1905
  if (oauthProxy && oauthConfig?.enabled) {
1867
1906
  const url2 = new URL(req.url || "", `http://${host}`);
1907
+ const oauthPath = basePathRelativePath;
1868
1908
  try {
1869
- if (req.method === "POST" && url2.pathname === "/oauth/register") {
1909
+ if (req.method === "POST" && oauthPath === "/oauth/register") {
1870
1910
  await new Promise((resolve) => {
1871
1911
  let body = "";
1872
1912
  req.on("data", (chunk) => body += chunk);
@@ -1890,7 +1930,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1890
1930
  });
1891
1931
  return;
1892
1932
  }
1893
- if (req.method === "GET" && url2.pathname === "/oauth/authorize") {
1933
+ if (req.method === "GET" && oauthPath === "/oauth/authorize") {
1894
1934
  try {
1895
1935
  const params = Object.fromEntries(url2.searchParams.entries());
1896
1936
  const response = await oauthProxy.authorize(
@@ -1914,7 +1954,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1914
1954
  }
1915
1955
  return;
1916
1956
  }
1917
- if (req.method === "GET" && url2.pathname === "/oauth/callback") {
1957
+ if (req.method === "GET" && oauthPath === "/oauth/callback") {
1918
1958
  try {
1919
1959
  const mockRequest = new Request(`http://${host}${req.url}`);
1920
1960
  const response = await oauthProxy.handleCallback(mockRequest);
@@ -1936,14 +1976,14 @@ var FastMCP = class extends FastMCPEventEmitter {
1936
1976
  }
1937
1977
  return;
1938
1978
  }
1939
- if (req.method === "POST" && url2.pathname === "/oauth/consent") {
1979
+ if (req.method === "POST" && oauthPath === "/oauth/consent") {
1940
1980
  await new Promise((resolve) => {
1941
1981
  let body = "";
1942
1982
  req.on("data", (chunk) => body += chunk);
1943
1983
  req.on("end", async () => {
1944
1984
  try {
1945
1985
  const mockRequest = new Request(
1946
- `http://${host}/oauth/consent`,
1986
+ `http://${host}${url2.pathname}${url2.search}`,
1947
1987
  {
1948
1988
  body,
1949
1989
  headers: {
@@ -1974,7 +2014,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1974
2014
  });
1975
2015
  return;
1976
2016
  }
1977
- if (req.method === "POST" && url2.pathname === "/oauth/token") {
2017
+ if (req.method === "POST" && oauthPath === "/oauth/token") {
1978
2018
  await new Promise((resolve) => {
1979
2019
  let body = "";
1980
2020
  req.on("data", (chunk) => body += chunk);
@@ -2078,11 +2118,13 @@ var FastMCP = class extends FastMCPEventEmitter {
2078
2118
  const transportArg = getArg("transport");
2079
2119
  const portArg = getArg("port");
2080
2120
  const endpointArg = getArg("endpoint");
2121
+ const basePathArg = getArg("base-path");
2081
2122
  const statelessArg = getArg("stateless");
2082
2123
  const hostArg = getArg("host");
2083
2124
  const envTransport = process.env.FASTMCP_TRANSPORT;
2084
2125
  const envPort = process.env.FASTMCP_PORT;
2085
2126
  const envEndpoint = process.env.FASTMCP_ENDPOINT;
2127
+ const envBasePath = process.env.FASTMCP_BASE_PATH;
2086
2128
  const envStateless = process.env.FASTMCP_STATELESS;
2087
2129
  const envHost = process.env.FASTMCP_HOST;
2088
2130
  const transportType = overrides?.transportType || (transportArg === "http-stream" ? "httpStream" : transportArg) || envTransport || "stdio";
@@ -2092,6 +2134,9 @@ var FastMCP = class extends FastMCPEventEmitter {
2092
2134
  );
2093
2135
  const host = overrides?.httpStream?.host || hostArg || envHost || "localhost";
2094
2136
  const endpoint = overrides?.httpStream?.endpoint || endpointArg || envEndpoint || "/mcp";
2137
+ const basePath = normalizeBasePath(
2138
+ overrides?.httpStream?.basePath || basePathArg || envBasePath
2139
+ );
2095
2140
  const enableJsonResponse = overrides?.httpStream?.enableJsonResponse || false;
2096
2141
  const stateless = overrides?.httpStream?.stateless || statelessArg === "true" || envStateless === "true" || false;
2097
2142
  const cors = overrides?.httpStream?.cors;
@@ -2101,6 +2146,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2101
2146
  const sslKey = overrides?.httpStream?.sslKey;
2102
2147
  return {
2103
2148
  httpStream: {
2149
+ basePath,
2104
2150
  cors,
2105
2151
  enableJsonResponse,
2106
2152
  endpoint,
@@ -2170,4 +2216,4 @@ export {
2170
2216
  FastMCPSession,
2171
2217
  FastMCP
2172
2218
  };
2173
- //# sourceMappingURL=chunk-KFZGSERX.js.map
2219
+ //# sourceMappingURL=chunk-MDIESGNI.js.map