{"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/chunk-EXZZ3NKL.cjs","../src/FastMCP.ts","../src/DiscoveryDocumentCache.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fastmcp/fastmcp/dist/chunk-EXZZ3NKL.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<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};\n\nconst ContentResultZodSchema = z\n  .object({\n    content: ContentZodSchema.array(),\n    isError: z.boolean().optional(),\n  })\n  .strict() satisfies z.ZodType<ContentResult>;\n\ntype Completion = {\n  hasMore?: boolean;\n  total?: number;\n  values: string[];\n};\n\n/**\n * https://github.com/modelcontextprotocol/typescript-sdk/blob/3164da64d085ec4e022ae881329eee7b72f208d4/src/types.ts#L983-L1003\n */\nconst CompletionZodSchema = z.object({\n  /**\n   * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.\n   */\n  hasMore: z.optional(z.boolean()),\n  /**\n   * The total number of completion options available. This can exceed the number of values actually sent in the response.\n   */\n  total: z.optional(z.number().int()),\n  /**\n   * An array of completion values. Must not exceed 100 items.\n   */\n  values: z.array(z.string()).max(100),\n}) satisfies z.ZodType<Completion>;\n\ntype ArgumentValueCompleter<T extends FastMCPSessionAuth = FastMCPSessionAuth> =\n  (value: string, auth?: T) => Promise<Completion>;\n\ntype InputPrompt<\n  T extends FastMCPSessionAuth = FastMCPSessionAuth,\n  Arguments extends InputPromptArgument<T>[] = InputPromptArgument<T>[],\n  Args = PromptArgumentsToObject<Arguments>,\n> = {\n  arguments?: InputPromptArgument<T>[];\n  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    | 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  #getPingConfig(transport: Transport): {\n    enabled: boolean;\n    intervalMs: number;\n    logLevel: LoggingLevel;\n  } {\n    const pingConfig = this.#pingConfig || {};\n\n    let defaultEnabled = false;\n\n    if (\"type\" in transport) {\n      // Enable by default for SSE and HTTP streaming\n      if (transport.type === \"httpStream\") {\n        defaultEnabled = true;\n      }\n    }\n\n    return {\n      enabled:\n        pingConfig.enabled !== undefined ? pingConfig.enabled : defaultEnabled,\n      intervalMs: pingConfig.intervalMs || 5000,\n      logLevel: pingConfig.logLevel || \"debug\",\n    };\n  }\n\n  private addPrompt(inputPrompt: InputPrompt<T>) {\n    const completers: Record<string, ArgumentValueCompleter<T>> = {};\n    const enums: Record<string, string[]> = {};\n    const fuseInstances: Record<string, Fuse<string>> = {};\n\n    for (const argument of inputPrompt.arguments ?? []) {\n      if (argument.complete) {\n        completers[argument.name] = argument.complete;\n      }\n\n      if (argument.enum) {\n        enums[argument.name] = argument.enum;\n        fuseInstances[argument.name] = new Fuse(argument.enum, {\n          includeScore: true,\n          threshold: 0.3, // More flexible matching!\n        });\n      }\n    }\n\n    const prompt = {\n      ...inputPrompt,\n      complete: async (name: string, value: string, auth?: T) => {\n        if (completers[name]) {\n          return await completers[name](value, auth);\n        }\n\n        if (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\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<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  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  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<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              ? 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        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          | 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<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\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<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        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\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<FastMCPSession<T>>({\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<FastMCPSession<T>>({\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<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              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<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  ) => {\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<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\n      try {\n        // DCR endpoint - POST /oauth/register\n        if (req.method === \"POST\" && url.pathname === \"/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\" && 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          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}/oauth/consent`,\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\" && url.pathname === \"/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        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<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  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"]}