{"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/chunk-XH5LGNWH.cjs","../src/FastMCP.ts","../src/DiscoveryDocumentCache.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fastmcp/fastmcp/dist/chunk-XH5LGNWH.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 { startHTTPServer } from \"mcp-proxy\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { setTimeout as delay } from \"timers/promises\";\nimport { fetch } from \"undici\";\nimport parseURITemplate from \"uri-templates\";\nimport { toJsonSchema } from \"xsschema\";\nimport { z } from \"zod\";\n\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;\n};\n\ntype FastMCPEvents = {\n connect: (event: { session: FastMCPSession }) => void;\n disconnect: (event: { session: FastMCPSession }) => 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 => {\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 => {\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 = {\n client: {\n version: ReturnType;\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;\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;\n};\n\ntype Extra = unknown;\n\ntype Extras = Record;\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;\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;\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;\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;\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;\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;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType;\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;\n\ntype ArgumentValueCompleter =\n (value: string, auth?: T) => Promise;\n\ntype InputPrompt<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n Arguments extends InputPromptArgument[] = InputPromptArgument[],\n Args = PromptArgumentsToObject,\n> = {\n arguments?: InputPromptArgument[];\n complete?: (name: string, value: string, auth?: T) => Promise;\n description?: string;\n load: (args: Args, auth?: T) => Promise;\n name: string;\n};\n\ntype InputPromptArgument =\n Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\n }>;\n\ntype InputResourceTemplate<\n T extends FastMCPSessionAuth,\n Arguments extends InputResourceTemplateArgument[] =\n InputResourceTemplateArgument[],\n> = {\n arguments: Arguments;\n complete?: (name: string, value: string, auth?: T) => Promise;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject,\n auth?: T,\n ) => Promise;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype InputResourceTemplateArgument<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype LoggingLevel =\n | \"alert\"\n | \"critical\"\n | \"debug\"\n | \"emergency\"\n | \"error\"\n | \"info\"\n | \"notice\"\n | \"warning\";\n\ntype Prompt<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n Arguments extends PromptArgument[] = PromptArgument[],\n Args = PromptArgumentsToObject,\n> = {\n arguments?: PromptArgument[];\n complete?: (name: string, value: string, auth?: T) => Promise;\n description?: string;\n load: (args: Args, auth?: T) => Promise;\n name: string;\n};\n\ntype PromptArgument =\n Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n enum?: string[];\n name: string;\n required?: boolean;\n }>;\n\ntype PromptArgumentsToObject =\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 | string;\n\ntype Resource = {\n complete?: (name: string, value: string, auth?: T) => Promise;\n description?: string;\n load: (auth?: T) => Promise;\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[] =\n ResourceTemplateArgument[],\n> = {\n arguments: Arguments;\n complete?: (name: string, value: string, auth?: T) => Promise;\n description?: string;\n load: (\n args: ResourceTemplateArgumentsToObject,\n auth?: T,\n ) => Promise;\n mimeType?: string;\n name: string;\n uriTemplate: string;\n};\n\ntype ResourceTemplateArgument<\n T extends FastMCPSessionAuth = FastMCPSessionAuth,\n> = Readonly<{\n complete?: ArgumentValueCompleter;\n description?: string;\n name: string;\n required?: boolean;\n}>;\n\ntype ResourceTemplateArgumentsToObject = {\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 = {\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;\n authenticate?: Authenticate;\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 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,\n context: Context,\n ) => Promise<\n | AudioContent\n | ContentResult\n | ImageContent\n | ResourceContent\n | ResourceLink\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;\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;\n method: string;\n params: Record;\n query: Record;\n text(): Promise;\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 = (\n req: FastMCPRequest,\n res: FastMCPResponse,\n) => Promise | 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 = (request: http.IncomingMessage) => Promise;\n\ntype FastMCPSessionAuth = Record | 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 #pingConfig?: ServerOptions[\"ping\"];\n\n #pingInterval: null | ReturnType = null;\n\n #prompts: Map> = new Map();\n\n #resources: Map> = new Map();\n\n #resourceTemplates: Map> = new Map();\n\n #roots: Root[] = [];\n\n #rootsConfig?: ServerOptions[\"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[\"utils\"];\n\n constructor({\n auth,\n instructions,\n logger,\n name,\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 ping?: ServerOptions[\"ping\"];\n prompts: Prompt[];\n resources: Resource[];\n resourcesTemplates: InputResourceTemplate[];\n roots?: ServerOptions[\"roots\"];\n sessionId?: string;\n tools: Tool[];\n transportType?: \"httpStream\" | \"stdio\";\n utils?: ServerOptions[\"utils\"];\n version: string;\n }) {\n super();\n\n this.#auth = auth;\n this.#logger = logger;\n this.#pingConfig = ping;\n this.#rootsConfig = roots;\n this.#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[]) {\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[\"params\"],\n options?: RequestOptions,\n ): Promise {\n return this.#server.createMessage(message, options);\n }\n\n resourcesListChanged(resources: Resource[]) {\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[]) {\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[]) {\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 {\n if (this.isReady) {\n return Promise.resolve();\n }\n\n if (\n this.#connectionState === \"error\" ||\n this.#connectionState === \"closed\"\n ) {\n return Promise.reject(\n new Error(`Connection is in ${this.#connectionState} state`),\n );\n }\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n \"Connection timeout: Session failed to become ready within 5 seconds\",\n ),\n );\n }, 5000);\n\n this.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve();\n });\n\n this.once(\"error\", (event) => {\n clearTimeout(timeout);\n reject(event.error);\n });\n });\n }\n\n #getPingConfig(transport: Transport): {\n enabled: boolean;\n intervalMs: number;\n logLevel: LoggingLevel;\n } {\n const pingConfig = this.#pingConfig || {};\n\n let defaultEnabled = false;\n\n if (\"type\" in transport) {\n // Enable by default for SSE and HTTP streaming\n if (transport.type === \"httpStream\") {\n defaultEnabled = true;\n }\n }\n\n return {\n enabled:\n pingConfig.enabled !== undefined ? pingConfig.enabled : defaultEnabled,\n intervalMs: pingConfig.intervalMs || 5000,\n logLevel: pingConfig.logLevel || \"debug\",\n };\n }\n\n private addPrompt(inputPrompt: InputPrompt) {\n const completers: Record> = {};\n const enums: Record = {};\n const fuseInstances: Record> = {};\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) {\n this.#resources.set(inputResource.uri, inputResource);\n }\n\n private addResourceTemplate(inputResourceTemplate: InputResourceTemplate) {\n const completers: Record> = {};\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\n private setupErrorHandling() {\n this.#server.onerror = (error) => {\n this.#logger.error(\"[FastMCP error]\", error);\n };\n }\n\n private setupLoggingHandlers() {\n this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {\n this.#loggingLevel = request.params.level;\n\n return {};\n });\n }\n 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[\"load\"]>>;\n\n try {\n result = await prompt.load(\n args as Record,\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 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[\"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 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 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 private setupToolHandlers(tools: Tool[]) {\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 ? 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: (await toJsonSchema(\n 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.#utils?.formatInvalidParamsErrorMessage\n ? this.#utils.formatInvalidParamsErrorMessage(parsed.issues)\n : parsed.issues\n .map((issue) => {\n const path = issue.path?.join(\".\") || \"root\";\n return `${path}: ${issue.message}`;\n })\n .join(\", \");\n\n throw new McpError(\n ErrorCode.InvalidParams,\n `Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}. Please check the parameter types and values according to the tool's schema.`,\n );\n }\n\n args = parsed.value;\n }\n\n const progressToken = request.params?._meta?.progressToken;\n\n let result: ContentResult;\n\n try {\n const reportProgress = async (progress: Progress) => {\n try {\n await this.#server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n\n if (this.#needsEventLoopFlush) {\n await new Promise((resolve) => setImmediate(resolve));\n }\n } catch (progressError) {\n this.#logger.warn(\n `[FastMCP warning] Failed to report progress for tool '${request.params.name}':`,\n progressError instanceof Error\n ? progressError.message\n : String(progressError),\n );\n }\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"debug\",\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"error\",\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"info\",\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n data: {\n context,\n message,\n },\n level: \"warning\",\n });\n },\n };\n\n // Create a promise for tool execution\n // Streams partial results while a tool is still executing\n // Enables progressive rendering and real-time feedback\n const streamContent = async (content: Content | Content[]) => {\n const contentArray = Array.isArray(content) ? content : [content];\n\n try {\n await this.#server.notification({\n method: \"notifications/tool/streamContent\",\n params: {\n content: contentArray,\n toolName: request.params.name,\n },\n });\n\n if (this.#needsEventLoopFlush) {\n await new Promise((resolve) => setImmediate(resolve));\n }\n } catch (streamError) {\n this.#logger.warn(\n `[FastMCP warning] Failed to stream content for tool '${request.params.name}':`,\n streamError instanceof Error\n ? streamError.message\n : String(streamError),\n );\n }\n };\n\n const executeToolPromise = tool.execute(args, {\n 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((_, 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 | ResourceContent\n | ResourceLink\n | string\n | TextContent\n | undefined;\n\n // Without this test, we are running into situations where the last progress update is not reported.\n // See the 'reports multiple progress updates without buffering' test in FastMCP.test.ts before refactoring.\n await delay(1);\n\n if (maybeStringResult === undefined || maybeStringResult === null) {\n result = ContentResultZodSchema.parse({\n content: [],\n });\n } else if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ text: maybeStringResult, type: \"text\" }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ text: error.message, type: \"text\" }],\n isError: true,\n ...(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,\n): Record {\n const result: Record = {};\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\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\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter>;\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[] {\n return this.#sessions;\n }\n #authenticate: Authenticate | undefined;\n #honoApp = new Hono();\n #httpStreamServer: null | SSEServer = null;\n #logger: Logger;\n #options: ServerOptions;\n #prompts: InputPrompt[] = [];\n #resources: Resource[] = [];\n #resourcesTemplates: InputResourceTemplate[] = [];\n #serverState: ServerState = ServerState.Stopped;\n #sessions: FastMCPSession[] = [];\n\n #tools: Tool[] = [];\n\n constructor(public options: ServerOptions) {\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;\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[]>(\n prompt: InputPrompt,\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[]>(\n prompts: InputPrompt[],\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) {\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[]) {\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) {\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[]) {\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(tool: Tool) {\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);\n if (this.#serverState === ServerState.Running) {\n this.#toolsListChanged(this.#tools);\n }\n }\n /**\n * Adds tools to the server.\n */\n public addTools(tools: Tool[]) {\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[]));\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 - The embedded resource content\n */\n public async embedded(uri: string): Promise {\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,\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 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({\n auth,\n instructions: this.#options.instructions,\n logger: this.#logger,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n tools: this.#tools,\n transportType: \"stdio\",\n utils: this.#options.utils,\n version: this.#options.version,\n });\n\n await session.connect(transport);\n\n this.#sessions.push(session);\n\n 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,\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\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}${httpConfig.endpoint}`,\n );\n\n this.#httpStreamServer = await startHTTPServer>({\n ...(this.#authenticate ? { authenticate: this.#authenticate } : {}),\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 httpConfig.endpoint,\n );\n },\n port: httpConfig.port,\n sslCa: httpConfig.sslCa,\n sslCert: httpConfig.sslCert,\n sslKey: httpConfig.sslKey,\n stateless: true,\n streamEndpoint: httpConfig.endpoint,\n });\n } else {\n // Regular mode with session management\n this.#httpStreamServer = await startHTTPServer>({\n ...(this.#authenticate ? { authenticate: this.#authenticate } : {}),\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,\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,\n });\n },\n\n onUnhandledRequest: async (req, res) => {\n await this.#handleUnhandledRequest(\n req,\n res,\n false,\n httpConfig.host,\n httpConfig.endpoint,\n );\n },\n port: httpConfig.port,\n sslCa: httpConfig.sslCa,\n sslCert: httpConfig.sslCert,\n sslKey: httpConfig.sslKey,\n stateless: httpConfig.stateless,\n streamEndpoint: httpConfig.endpoint,\n });\n\n this.#logger.info(\n `[FastMCP info] server is running on HTTP Stream at ${protocol}://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`,\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 {\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({\n auth,\n instructions: this.#options.instructions,\n logger: this.#logger,\n name: this.#options.name,\n ping: this.#options.ping,\n prompts: this.#prompts,\n resources: this.#resources,\n resourcesTemplates: this.#resourcesTemplates,\n roots: this.#options.roots,\n 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 ) => {\n const url = new URL(req.url || \"\", `http://${host}`);\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 const url = new URL(req.url || \"\", `http://${host}`);\n\n try {\n if (req.method === \"GET\" && url.pathname === path) {\n res\n .writeHead(healthConfig.status ?? 200, {\n \"Content-Type\": \"text/plain\",\n })\n .end(healthConfig.message ?? \"✓ Ok\");\n\n return;\n }\n\n // Enhanced readiness check endpoint\n if (req.method === \"GET\" && url.pathname === \"/ready\") {\n if (isStateless) {\n // In stateless mode, we're always ready if the server is running\n const response = {\n mode: \"stateless\",\n ready: 1,\n status: \"ready\",\n total: 1,\n };\n\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(response));\n } else {\n const readySessions = this.#sessions.filter(\n (s) => s.isReady,\n ).length;\n const totalSessions = this.#sessions.length;\n const allReady =\n readySessions === totalSessions && totalSessions > 0;\n\n const response = {\n ready: readySessions,\n status: allReady\n ? \"ready\"\n : totalSessions === 0\n ? \"no_sessions\"\n : \"initializing\",\n total: totalSessions,\n };\n\n res\n .writeHead(allReady ? 200 : 503, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(response));\n }\n\n return;\n }\n } catch (error) {\n this.#logger.error(\"[FastMCP error] health endpoint error\", error);\n }\n }\n\n // Handle OAuth well-known endpoints\n const oauthConfig = this.#options.oauth;\n if (oauthConfig?.enabled && req.method === \"GET\") {\n const url = new URL(req.url || \"\", `http://${host}`);\n\n if (\n url.pathname === \"/.well-known/oauth-authorization-server\" &&\n oauthConfig.authorizationServer\n ) {\n const metadata = convertObjectToSnakeCase(\n oauthConfig.authorizationServer,\n );\n res\n .writeHead(200, {\n \"Content-Type\": \"application/json\",\n })\n .end(JSON.stringify(metadata));\n return;\n }\n\n // 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 (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\n try {\n // DCR endpoint - POST /oauth/register\n if (req.method === \"POST\" && url.pathname === \"/oauth/register\") {\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 });\n return;\n }\n\n // Authorization endpoint - GET /oauth/authorize\n if (req.method === \"GET\" && url.pathname === \"/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\" && url.pathname === \"/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\" && url.pathname === \"/oauth/consent\") {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const mockRequest = new Request(`http://${host}/oauth/consent`, {\n body,\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n method: \"POST\",\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 });\n return;\n }\n\n // Token endpoint - POST /oauth/token\n if (req.method === \"POST\" && url.pathname === \"/oauth/token\") {\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(req.headers.authorization);\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 });\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 // If the request was not handled above, return 404\n res.writeHead(404).end();\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 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 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 statelessArg = getArg(\"stateless\");\n const hostArg = getArg(\"host\");\n\n const envTransport = process.env.FASTMCP_TRANSPORT;\n const envPort = process.env.FASTMCP_PORT;\n const envEndpoint = process.env.FASTMCP_ENDPOINT;\n const envStateless = process.env.FASTMCP_STATELESS;\n const envHost = process.env.FASTMCP_HOST;\n // Overrides > CLI > env > defaults\n const transportType =\n overrides?.transportType ||\n (transportArg === \"http-stream\" ? \"httpStream\" : transportArg) ||\n envTransport ||\n \"stdio\";\n\n if (transportType === \"httpStream\") {\n const port = parseInt(\n overrides?.httpStream?.port?.toString() || portArg || envPort || \"8080\",\n );\n const host =\n overrides?.httpStream?.host || hostArg || envHost || \"localhost\";\n const endpoint =\n overrides?.httpStream?.endpoint || endpointArg || envEndpoint || \"/mcp\";\n const enableJsonResponse =\n overrides?.httpStream?.enableJsonResponse || false;\n const stateless =\n overrides?.httpStream?.stateless ||\n statelessArg === \"true\" ||\n envStateless === \"true\" ||\n false;\n 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 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[]) {\n for (const session of this.#sessions) {\n session.promptsListChanged(prompts);\n }\n }\n #removeSession(session: FastMCPSession): 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,\n });\n }\n }\n /**\n * Notifies all sessions that the resources list has changed.\n */\n #resourcesListChanged(resources: Resource[]) {\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[]) {\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[]) {\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 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> = 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 {\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 {\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"]}