fastmcp 3.11.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/FastMCP.ts CHANGED
@@ -624,20 +624,162 @@ type ServerOptions<T extends FastMCPSessionAuth> = {
624
624
  enabled: boolean;
625
625
 
626
626
  /**
627
- * OAuth Protected Resource metadata for /.well-known/oauth-protected-resource
627
+ * OAuth Protected Resource metadata for `/.well-known/oauth-protected-resource`
628
628
  *
629
- * This endpoint follows RFC 9470 (OAuth 2.0 Protected Resource Metadata)
630
- * and provides metadata about the OAuth 2.0 protected resource.
629
+ * This endpoint follows {@link https://www.rfc-editor.org/rfc/rfc9728.html | RFC 9728}
630
+ * and provides metadata describing how an OAuth 2.0 protected resource (in this case,
631
+ * an MCP server) expects to be accessed.
631
632
  *
632
- * Required by MCP Specification 2025-06-18
633
+ * When configured, FastMCP will automatically serve this metadata at the
634
+ * `/.well-known/oauth-protected-resource` endpoint. The `authorizationServers` and `resource`
635
+ * fields are required. All others are optional and will be omitted from the published
636
+ * metadata if not specified.
637
+ *
638
+ * This satisfies the requirements of the MCP Authorization specification's
639
+ * {@link https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-server-location | Authorization Server Location section}.
640
+ *
641
+ * Clients consuming this metadata MUST validate that any presented values comply with
642
+ * RFC 9728, including strict validation of the `resource` identifier and intended audience
643
+ * when access tokens are issued and presented (per RFC 8707 §2).
644
+ *
645
+ * @remarks Required by MCP Specification version 2025-06-18
633
646
  */
634
647
  protectedResource?: {
648
+ /**
649
+ * Allows for additional metadata fields beyond those defined in RFC 9728.
650
+ *
651
+ * @remarks This supports vendor-specific or experimental extensions.
652
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2.3 | RFC 9728 §2.3}
653
+ */
654
+ [key: string]: unknown;
655
+
656
+ /**
657
+ * Supported values for the `authorization_details` parameter (RFC 9396).
658
+ *
659
+ * @remarks Used when fine-grained access control is in play.
660
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.23 | RFC 9728 §2.2.23}
661
+ */
662
+ authorizationDetailsTypesSupported?: string[];
663
+
664
+ /**
665
+ * List of OAuth 2.0 authorization server issuer identifiers.
666
+ *
667
+ * These correspond to ASes that can issue access tokens for this protected resource.
668
+ * MCP clients use these values to locate the relevant `/.well-known/oauth-authorization-server`
669
+ * metadata for initiating the OAuth flow.
670
+ *
671
+ * @remarks Required by the MCP spec. MCP servers MUST provide at least one issuer.
672
+ * Clients are responsible for choosing among them (see RFC 9728 §7.6).
673
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.3 | RFC 9728 §2.2.3}
674
+ */
635
675
  authorizationServers: string[];
676
+
677
+ /**
678
+ * List of supported methods for presenting OAuth 2.0 bearer tokens.
679
+ *
680
+ * @remarks Valid values are `header`, `body`, and `query`.
681
+ * If omitted, clients MAY assume only `header` is supported, per RFC 6750.
682
+ * This is a client-side interpretation and not a serialization default.
683
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.9 | RFC 9728 §2.2.9}
684
+ */
636
685
  bearerMethodsSupported?: string[];
686
+
687
+ /**
688
+ * Whether this resource requires all access tokens to be DPoP-bound.
689
+ *
690
+ * @remarks If omitted, clients SHOULD assume this is `false`.
691
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.27 | RFC 9728 §2.2.27}
692
+ */
693
+ dpopBoundAccessTokensRequired?: boolean;
694
+
695
+ /**
696
+ * Supported algorithms for verifying DPoP proofs (RFC 9449).
697
+ *
698
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.25 | RFC 9728 §2.2.25}
699
+ */
700
+ dpopSigningAlgValuesSupported?: string[];
701
+
702
+ /**
703
+ * JWKS URI of this resource. Used to validate access tokens or sign responses.
704
+ *
705
+ * @remarks When present, this MUST be an `https:` URI pointing to a valid JWK Set (RFC 7517).
706
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.5 | RFC 9728 §2.2.5}
707
+ */
637
708
  jwksUri?: string;
709
+
710
+ /**
711
+ * Canonical OAuth resource identifier for this protected resource (the MCP server).
712
+ *
713
+ * @remarks Typically the base URL of the MCP server. Clients MUST use this as the
714
+ * `resource` parameter in authorization and token requests (per RFC 8707).
715
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.1 | RFC 9728 §2.2.1}
716
+ */
638
717
  resource: string;
718
+
719
+ /**
720
+ * URL to developer-accessible documentation for this resource.
721
+ *
722
+ * @remarks This field MAY be localized.
723
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.15 | RFC 9728 §2.2.15}
724
+ */
639
725
  resourceDocumentation?: string;
726
+
727
+ /**
728
+ * Human-readable name for display purposes (e.g., in UIs).
729
+ *
730
+ * @remarks This field MAY be localized using language tags (`resource_name#en`, etc.).
731
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.13 | RFC 9728 §2.2.13}
732
+ */
733
+ resourceName?: string;
734
+
735
+ /**
736
+ * URL to a human-readable policy page describing acceptable use.
737
+ *
738
+ * @remarks This field MAY be localized.
739
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.17 | RFC 9728 §2.2.17}
740
+ */
640
741
  resourcePolicyUri?: string;
742
+
743
+ /**
744
+ * Supported JWS algorithms for signed responses from this resource (e.g., response signing).
745
+ *
746
+ * @remarks MUST NOT include `none`.
747
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.11 | RFC 9728 §2.2.11}
748
+ */
749
+ resourceSigningAlgValuesSupported?: string[];
750
+
751
+ /**
752
+ * URL to the protected resource’s Terms of Service.
753
+ *
754
+ * @remarks This field MAY be localized.
755
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.19 | RFC 9728 §2.2.19}
756
+ */
757
+ resourceTosUri?: string;
758
+
759
+ /**
760
+ * Supported OAuth scopes for requesting access to this resource.
761
+ *
762
+ * @remarks Useful for discovery, but clients SHOULD still request the minimal scope required.
763
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.7 | RFC 9728 §2.2.7}
764
+ */
765
+ scopesSupported?: string[];
766
+
767
+ /**
768
+ * Developer-accessible documentation for how to use the service (not end-user docs).
769
+ *
770
+ * @remarks Semantically equivalent to `resourceDocumentation`, but included under its
771
+ * alternate name for compatibility with tools or schemas expecting either.
772
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.15 | RFC 9728 §2.2.15}
773
+ */
774
+ serviceDocumentation?: string;
775
+
776
+ /**
777
+ * Whether mutual-TLS-bound access tokens are required.
778
+ *
779
+ * @remarks If omitted, clients SHOULD assume this is `false` (client-side behavior).
780
+ * @see {@link https://www.rfc-editor.org/rfc/rfc9728.html#section-2-2.21 | RFC 9728 §2.2.21}
781
+ */
782
+ tlsClientCertificateBoundAccessTokens?: boolean;
641
783
  };
642
784
  };
643
785
 
@@ -1451,7 +1593,11 @@ export class FastMCPSession<
1451
1593
  "[FastMCP debug] listRoots method not supported by client",
1452
1594
  );
1453
1595
  } else {
1454
- console.error("[FastMCP error] Error listing roots", error);
1596
+ console.error(
1597
+ `[FastMCP error] received error listing roots.\n\n${
1598
+ error instanceof Error ? error.stack : JSON.stringify(error)
1599
+ }`,
1600
+ );
1455
1601
  }
1456
1602
  });
1457
1603
  },
@@ -1872,6 +2018,7 @@ export class FastMCP<
1872
2018
  endpoint?: `/${string}`;
1873
2019
  eventStore?: EventStore;
1874
2020
  port: number;
2021
+ stateless?: boolean;
1875
2022
  };
1876
2023
  transportType: "httpStream" | "stdio";
1877
2024
  }>,
@@ -1904,151 +2051,86 @@ export class FastMCP<
1904
2051
  } else if (config.transportType === "httpStream") {
1905
2052
  const httpConfig = config.httpStream;
1906
2053
 
1907
- this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({
1908
- createServer: async (request) => {
1909
- let auth: T | undefined;
1910
-
1911
- if (this.#authenticate) {
1912
- auth = await this.#authenticate(request);
1913
- }
1914
- const allowedTools = auth
1915
- ? this.#tools.filter((tool) =>
1916
- tool.canAccess ? tool.canAccess(auth) : true,
1917
- )
1918
- : this.#tools;
1919
- return new FastMCPSession<T>({
1920
- auth,
1921
- name: this.#options.name,
1922
- ping: this.#options.ping,
1923
- prompts: this.#prompts,
1924
- resources: this.#resources,
1925
- resourcesTemplates: this.#resourcesTemplates,
1926
- roots: this.#options.roots,
1927
- tools: allowedTools,
1928
- transportType: "httpStream",
1929
- utils: this.#options.utils,
1930
- version: this.#options.version,
1931
- });
1932
- },
1933
- enableJsonResponse: httpConfig.enableJsonResponse,
1934
- eventStore: httpConfig.eventStore,
1935
- onClose: async (session) => {
1936
- this.emit("disconnect", {
1937
- session: session as FastMCPSession<FastMCPSessionAuth>,
1938
- });
1939
- },
1940
- onConnect: async (session) => {
1941
- this.#sessions.push(session);
1942
-
1943
- console.info(`[FastMCP info] HTTP Stream session established`);
1944
-
1945
- this.emit("connect", {
1946
- session: session as FastMCPSession<FastMCPSessionAuth>,
1947
- });
1948
- },
1949
-
1950
- onUnhandledRequest: async (req, res) => {
1951
- const healthConfig = this.#options.health ?? {};
2054
+ if (httpConfig.stateless) {
2055
+ // Stateless mode - create new server instance for each request
2056
+ console.info(
2057
+ `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2058
+ );
1952
2059
 
1953
- const enabled =
1954
- healthConfig.enabled === undefined ? true : healthConfig.enabled;
2060
+ this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({
2061
+ createServer: async (request) => {
2062
+ let auth: T | undefined;
1955
2063
 
1956
- if (enabled) {
1957
- const path = healthConfig.path ?? "/health";
1958
- const url = new URL(req.url || "", "http://localhost");
2064
+ if (this.#authenticate) {
2065
+ auth = await this.#authenticate(request);
2066
+ }
1959
2067
 
1960
- try {
1961
- if (req.method === "GET" && url.pathname === path) {
1962
- res
1963
- .writeHead(healthConfig.status ?? 200, {
1964
- "Content-Type": "text/plain",
1965
- })
1966
- .end(healthConfig.message ?? "✓ Ok");
1967
-
1968
- return;
1969
- }
2068
+ // In stateless mode, create a new session for each request
2069
+ // without persisting it in the sessions array
2070
+ return this.#createSession(auth);
2071
+ },
2072
+ enableJsonResponse: httpConfig.enableJsonResponse,
2073
+ eventStore: httpConfig.eventStore,
2074
+ // In stateless mode, we don't track sessions
2075
+ onClose: async () => {
2076
+ // No session tracking in stateless mode
2077
+ },
2078
+ onConnect: async () => {
2079
+ // No persistent session tracking in stateless mode
2080
+ console.debug(
2081
+ `[FastMCP debug] Stateless HTTP Stream request handled`,
2082
+ );
2083
+ },
2084
+ onUnhandledRequest: async (req, res) => {
2085
+ await this.#handleUnhandledRequest(req, res, true);
2086
+ },
2087
+ port: httpConfig.port,
2088
+ stateless: true,
2089
+ streamEndpoint: httpConfig.endpoint,
2090
+ });
2091
+ } else {
2092
+ // Regular mode with session management
2093
+ this.#httpStreamServer = await startHTTPServer<FastMCPSession<T>>({
2094
+ createServer: async (request) => {
2095
+ let auth: T | undefined;
1970
2096
 
1971
- // Enhanced readiness check endpoint
1972
- if (req.method === "GET" && url.pathname === "/ready") {
1973
- const readySessions = this.#sessions.filter(
1974
- (s) => s.isReady,
1975
- ).length;
1976
- const totalSessions = this.#sessions.length;
1977
- const allReady =
1978
- readySessions === totalSessions && totalSessions > 0;
1979
-
1980
- const response = {
1981
- ready: readySessions,
1982
- status: allReady
1983
- ? "ready"
1984
- : totalSessions === 0
1985
- ? "no_sessions"
1986
- : "initializing",
1987
- total: totalSessions,
1988
- };
1989
-
1990
- res
1991
- .writeHead(allReady ? 200 : 503, {
1992
- "Content-Type": "application/json",
1993
- })
1994
- .end(JSON.stringify(response));
1995
-
1996
- return;
1997
- }
1998
- } catch (error) {
1999
- console.error("[FastMCP error] health endpoint error", error);
2097
+ if (this.#authenticate) {
2098
+ auth = await this.#authenticate(request);
2000
2099
  }
2001
- }
2002
2100
 
2003
- // Handle OAuth well-known endpoints
2004
- const oauthConfig = this.#options.oauth;
2005
- if (oauthConfig?.enabled && req.method === "GET") {
2006
- const url = new URL(req.url || "", "http://localhost");
2007
-
2008
- if (
2009
- url.pathname === "/.well-known/oauth-authorization-server" &&
2010
- oauthConfig.authorizationServer
2011
- ) {
2012
- const metadata = convertObjectToSnakeCase(
2013
- oauthConfig.authorizationServer,
2014
- );
2015
- res
2016
- .writeHead(200, {
2017
- "Content-Type": "application/json",
2018
- })
2019
- .end(JSON.stringify(metadata));
2020
- return;
2021
- }
2101
+ return this.#createSession(auth);
2102
+ },
2103
+ enableJsonResponse: httpConfig.enableJsonResponse,
2104
+ eventStore: httpConfig.eventStore,
2105
+ onClose: async (session) => {
2106
+ this.emit("disconnect", {
2107
+ session: session as FastMCPSession<FastMCPSessionAuth>,
2108
+ });
2109
+ },
2110
+ onConnect: async (session) => {
2111
+ this.#sessions.push(session);
2022
2112
 
2023
- if (
2024
- url.pathname === "/.well-known/oauth-protected-resource" &&
2025
- oauthConfig.protectedResource
2026
- ) {
2027
- const metadata = convertObjectToSnakeCase(
2028
- oauthConfig.protectedResource,
2029
- );
2030
- res
2031
- .writeHead(200, {
2032
- "Content-Type": "application/json",
2033
- })
2034
- .end(JSON.stringify(metadata));
2035
- return;
2036
- }
2037
- }
2113
+ console.info(`[FastMCP info] HTTP Stream session established`);
2038
2114
 
2039
- // If the request was not handled above, return 404
2040
- res.writeHead(404).end();
2041
- },
2042
- port: httpConfig.port,
2043
- streamEndpoint: httpConfig.endpoint,
2044
- });
2115
+ this.emit("connect", {
2116
+ session: session as FastMCPSession<FastMCPSessionAuth>,
2117
+ });
2118
+ },
2045
2119
 
2046
- console.info(
2047
- `[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2048
- );
2049
- console.info(
2050
- `[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`,
2051
- );
2120
+ onUnhandledRequest: async (req, res) => {
2121
+ await this.#handleUnhandledRequest(req, res, false);
2122
+ },
2123
+ port: httpConfig.port,
2124
+ streamEndpoint: httpConfig.endpoint,
2125
+ });
2126
+
2127
+ console.info(
2128
+ `[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`,
2129
+ );
2130
+ console.info(
2131
+ `[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`,
2132
+ );
2133
+ }
2052
2134
  } else {
2053
2135
  throw new Error("Invalid transport type");
2054
2136
  }
@@ -2063,12 +2145,153 @@ export class FastMCP<
2063
2145
  }
2064
2146
  }
2065
2147
 
2148
+ /**
2149
+ * Creates a new FastMCPSession instance with the current configuration.
2150
+ * Used both for regular sessions and stateless requests.
2151
+ */
2152
+ #createSession(auth?: T): FastMCPSession<T> {
2153
+ const allowedTools = auth
2154
+ ? this.#tools.filter((tool) =>
2155
+ tool.canAccess ? tool.canAccess(auth) : true,
2156
+ )
2157
+ : this.#tools;
2158
+ return new FastMCPSession<T>({
2159
+ auth,
2160
+ name: this.#options.name,
2161
+ ping: this.#options.ping,
2162
+ prompts: this.#prompts,
2163
+ resources: this.#resources,
2164
+ resourcesTemplates: this.#resourcesTemplates,
2165
+ roots: this.#options.roots,
2166
+ tools: allowedTools,
2167
+ transportType: "httpStream",
2168
+ utils: this.#options.utils,
2169
+ version: this.#options.version,
2170
+ });
2171
+ }
2172
+
2173
+ /**
2174
+ * Handles unhandled HTTP requests with health, readiness, and OAuth endpoints
2175
+ */
2176
+ #handleUnhandledRequest = async (
2177
+ req: http.IncomingMessage,
2178
+ res: http.ServerResponse,
2179
+ isStateless = false,
2180
+ ) => {
2181
+ const healthConfig = this.#options.health ?? {};
2182
+
2183
+ const enabled =
2184
+ healthConfig.enabled === undefined ? true : healthConfig.enabled;
2185
+
2186
+ if (enabled) {
2187
+ const path = healthConfig.path ?? "/health";
2188
+ const url = new URL(req.url || "", "http://localhost");
2189
+
2190
+ try {
2191
+ if (req.method === "GET" && url.pathname === path) {
2192
+ res
2193
+ .writeHead(healthConfig.status ?? 200, {
2194
+ "Content-Type": "text/plain",
2195
+ })
2196
+ .end(healthConfig.message ?? "✓ Ok");
2197
+
2198
+ return;
2199
+ }
2200
+
2201
+ // Enhanced readiness check endpoint
2202
+ if (req.method === "GET" && url.pathname === "/ready") {
2203
+ if (isStateless) {
2204
+ // In stateless mode, we're always ready if the server is running
2205
+ const response = {
2206
+ mode: "stateless",
2207
+ ready: 1,
2208
+ status: "ready",
2209
+ total: 1,
2210
+ };
2211
+
2212
+ res
2213
+ .writeHead(200, {
2214
+ "Content-Type": "application/json",
2215
+ })
2216
+ .end(JSON.stringify(response));
2217
+ } else {
2218
+ const readySessions = this.#sessions.filter(
2219
+ (s) => s.isReady,
2220
+ ).length;
2221
+ const totalSessions = this.#sessions.length;
2222
+ const allReady =
2223
+ readySessions === totalSessions && totalSessions > 0;
2224
+
2225
+ const response = {
2226
+ ready: readySessions,
2227
+ status: allReady
2228
+ ? "ready"
2229
+ : totalSessions === 0
2230
+ ? "no_sessions"
2231
+ : "initializing",
2232
+ total: totalSessions,
2233
+ };
2234
+
2235
+ res
2236
+ .writeHead(allReady ? 200 : 503, {
2237
+ "Content-Type": "application/json",
2238
+ })
2239
+ .end(JSON.stringify(response));
2240
+ }
2241
+
2242
+ return;
2243
+ }
2244
+ } catch (error) {
2245
+ console.error("[FastMCP error] health endpoint error", error);
2246
+ }
2247
+ }
2248
+
2249
+ // Handle OAuth well-known endpoints
2250
+ const oauthConfig = this.#options.oauth;
2251
+ if (oauthConfig?.enabled && req.method === "GET") {
2252
+ const url = new URL(req.url || "", "http://localhost");
2253
+
2254
+ if (
2255
+ url.pathname === "/.well-known/oauth-authorization-server" &&
2256
+ oauthConfig.authorizationServer
2257
+ ) {
2258
+ const metadata = convertObjectToSnakeCase(
2259
+ oauthConfig.authorizationServer,
2260
+ );
2261
+ res
2262
+ .writeHead(200, {
2263
+ "Content-Type": "application/json",
2264
+ })
2265
+ .end(JSON.stringify(metadata));
2266
+ return;
2267
+ }
2268
+
2269
+ if (
2270
+ url.pathname === "/.well-known/oauth-protected-resource" &&
2271
+ oauthConfig.protectedResource
2272
+ ) {
2273
+ const metadata = convertObjectToSnakeCase(
2274
+ oauthConfig.protectedResource,
2275
+ );
2276
+ res
2277
+ .writeHead(200, {
2278
+ "Content-Type": "application/json",
2279
+ })
2280
+ .end(JSON.stringify(metadata));
2281
+ return;
2282
+ }
2283
+ }
2284
+
2285
+ // If the request was not handled above, return 404
2286
+ res.writeHead(404).end();
2287
+ };
2066
2288
  #parseRuntimeConfig(
2067
2289
  overrides?: Partial<{
2068
2290
  httpStream: {
2069
2291
  enableJsonResponse?: boolean;
2070
2292
  endpoint?: `/${string}`;
2071
2293
  port: number;
2294
+ stateless?: boolean;
2072
2295
  };
2073
2296
  transportType: "httpStream" | "stdio";
2074
2297
  }>,
@@ -2079,6 +2302,7 @@ export class FastMCP<
2079
2302
  endpoint: `/${string}`;
2080
2303
  eventStore?: EventStore;
2081
2304
  port: number;
2305
+ stateless?: boolean;
2082
2306
  };
2083
2307
  transportType: "httpStream";
2084
2308
  }
@@ -2095,10 +2319,12 @@ export class FastMCP<
2095
2319
  const transportArg = getArg("transport");
2096
2320
  const portArg = getArg("port");
2097
2321
  const endpointArg = getArg("endpoint");
2322
+ const statelessArg = getArg("stateless");
2098
2323
 
2099
2324
  const envTransport = process.env.FASTMCP_TRANSPORT;
2100
2325
  const envPort = process.env.FASTMCP_PORT;
2101
2326
  const envEndpoint = process.env.FASTMCP_ENDPOINT;
2327
+ const envStateless = process.env.FASTMCP_STATELESS;
2102
2328
 
2103
2329
  // Overrides > CLI > env > defaults
2104
2330
  const transportType =
@@ -2115,12 +2341,18 @@ export class FastMCP<
2115
2341
  overrides?.httpStream?.endpoint || endpointArg || envEndpoint || "/mcp";
2116
2342
  const enableJsonResponse =
2117
2343
  overrides?.httpStream?.enableJsonResponse || false;
2344
+ const stateless =
2345
+ overrides?.httpStream?.stateless ||
2346
+ statelessArg === "true" ||
2347
+ envStateless === "true" ||
2348
+ false;
2118
2349
 
2119
2350
  return {
2120
2351
  httpStream: {
2121
2352
  enableJsonResponse,
2122
2353
  endpoint: endpoint as `/${string}`,
2123
2354
  port,
2355
+ stateless,
2124
2356
  },
2125
2357
  transportType: "httpStream" as const,
2126
2358
  };
@@ -46,12 +46,24 @@ const server = new FastMCP({
46
46
  },
47
47
  enabled: true,
48
48
  protectedResource: {
49
+ authorizationDetailsTypesSupported: [
50
+ "payment_initiation",
51
+ "account_access",
52
+ ],
49
53
  authorizationServers: ["https://auth.example.com"],
50
54
  bearerMethodsSupported: ["header"],
55
+ dpopBoundAccessTokensRequired: false,
56
+ dpopSigningAlgValuesSupported: ["ES256", "RS256"],
51
57
  jwksUri: "https://oauth-example-server.example.com/.well-known/jwks.json",
52
58
  resource: "mcp://oauth-example-server",
53
59
  resourceDocumentation: "https://docs.example.com/mcp-api",
60
+ resourceName: "OAuth Example API",
54
61
  resourcePolicyUri: "https://example.com/resource-policy",
62
+ resourceSigningAlgValuesSupported: ["RS256", "ES256"],
63
+ resourceTosUri: "https://example.com/terms-of-service",
64
+ scopesSupported: ["read", "write", "admin"],
65
+ serviceDocumentation: "https://developer.example.com/api-docs",
66
+ tlsClientCertificateBoundAccessTokens: false,
55
67
  },
56
68
  },
57
69
  version: "1.0.0",