@prefecthq/fastmcp-ts 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1172,7 +1172,7 @@ var init_version = __esm({
1172
1172
  async run({ args }) {
1173
1173
  if (args.json) setJsonMode(true);
1174
1174
  const data = {
1175
- fastmcp: "1.3.0",
1175
+ fastmcp: "1.4.0",
1176
1176
  "mcp-sdk": "2.0.0",
1177
1177
  node: process.version,
1178
1178
  platform: `${process.platform} ${process.arch}`
@@ -33404,7 +33404,7 @@ var init_inspect = __esm({
33404
33404
  // only case Python's inspect supports); over --url/--command the
33405
33405
  // generation is unknowable from the wire.
33406
33406
  generation: mode.kind === "inprocess" ? 2 : null,
33407
- fastmcpVersion: "1.3.0",
33407
+ fastmcpVersion: "1.4.0",
33408
33408
  mcpVersion: "2.0.0",
33409
33409
  tools: tools2,
33410
33410
  prompts: prompts2,
@@ -46908,7 +46908,7 @@ init_format();
46908
46908
  var main = defineCommand({
46909
46909
  meta: {
46910
46910
  name: "fastmcp",
46911
- version: "1.3.0",
46911
+ version: "1.4.0",
46912
46912
  description: "FastMCP CLI \u2014 build, run, and manage MCP servers"
46913
46913
  },
46914
46914
  args: {
package/dist/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _modelcontextprotocol_server from '@modelcontextprotocol/server';
2
2
  import { InputResponses, Server, CacheHint, ServerContext, ServerEventBus, Transport, McpHandlerRequestOptions, CallToolResult, OAuthClientInformationFull, AuthInfo } from '@modelcontextprotocol/server';
3
- export { InputRequest, InputRequests, InputRequiredResult, InputRequiredSpec, InputResponse, InputResponseView, InputResponses, ServerEventBus, acceptedContent, inputRequired, inputResponse, isInputRequiredResult } from '@modelcontextprotocol/server';
3
+ export { AuthInfo, InputRequest, InputRequests, InputRequiredResult, InputRequiredSpec, InputResponse, InputResponseView, InputResponses, McpHandlerRequestOptions, ServerEventBus, acceptedContent, inputRequired, inputResponse, isInputRequiredResult } from '@modelcontextprotocol/server';
4
4
  import { OAuthServerProvider, AuthorizationParams } from '@modelcontextprotocol/server-legacy/auth';
5
5
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
6
  import { Readable, Writable } from 'node:stream';
@@ -871,11 +871,14 @@ interface FastMCPOptions {
871
871
  */
872
872
  eventBus?: ServerEventBus;
873
873
  /**
874
- * DNS-rebinding protection for the HTTP transport: validates the `Host` and
875
- * `Origin` request headers (port-agnostic, by hostname) and rejects mismatches
876
- * with `403`. Defends localhost servers against a malicious web page whose DNS
877
- * rebinds to `127.0.0.1` (MCP transport security best practice). Only affects the
878
- * HTTP transport — stdio is unaffected.
874
+ * DNS-rebinding protection for the HTTP listener started by `run()`: validates
875
+ * the `Host` and `Origin` request headers (port-agnostic, by hostname) and rejects
876
+ * mismatches with `403`. Defends localhost servers against a malicious web page
877
+ * whose DNS rebinds to `127.0.0.1` (MCP transport security best practice).
878
+ *
879
+ * This option does not apply to `fetch()`, which has no bind address from which
880
+ * to infer a trusted host. A framework embedding `fetch()` owns Host/Origin
881
+ * validation at its HTTP boundary. stdio is unaffected.
879
882
  *
880
883
  * Default posture (option omitted): protection auto-enables when, and only when,
881
884
  * `run()` binds the HTTP server to a loopback host (`127.0.0.1`, `::1`,
@@ -1249,6 +1252,19 @@ declare class FastMCP {
1249
1252
  */
1250
1253
  get isRunning(): boolean;
1251
1254
  connect(transport: Transport): Promise<void>;
1255
+ /**
1256
+ * Serve an MCP request through a web-standard, fetch-native HTTP entrypoint.
1257
+ *
1258
+ * This entrypoint is always stateless and does not require `run()`: legacy
1259
+ * (2025-era) requests use a fresh server instance per request, while modern
1260
+ * (2026-07-28) requests share the instance's modern handler and event bus.
1261
+ * Authentication is deliberately external — `options.authInfo` is trusted and
1262
+ * passed unchanged into the protocol handler, where it is exposed as `ctx.auth`.
1263
+ * The embedding framework also owns Host/Origin validation and should abort its
1264
+ * carrying requests during shutdown; stateless legacy response streams follow
1265
+ * that request lifecycle, while `close()` terminates modern exchanges and streams.
1266
+ */
1267
+ fetch(request: Request, options?: McpHandlerRequestOptions): Promise<Response>;
1252
1268
  /**
1253
1269
  * Modern-era (2026-07-28) in-process fetch entrypoint — the `McpServerLike`
1254
1270
  * duck-type hook `fastmcp-ts/client`'s `Client` looks for when a caller pins
@@ -1265,9 +1281,9 @@ declare class FastMCP {
1265
1281
  /** Lazily builds the modern (2026-07-28) HTTP handler. One per FastMCP instance;
1266
1282
  * builds a fresh Server (via _makeServer) per request, matching createMcpHandler's
1267
1283
  * per-request-factory model. Modern-only (legacy: 'reject') — legacy (2025-era)
1268
- * traffic is routed to the existing sessionful transport by _dispatchHttp instead
1269
- * of createMcpHandler's own stateless legacy fallback, so session state and the
1270
- * legacy server-initiated-request shim keep working for 2025-era clients. */
1284
+ * traffic is routed separately: to the existing sessionful transport by
1285
+ * _dispatchHttp, or to the stateless fallback by fetch(). This preserves the
1286
+ * session state and server-initiated-request shim for run()'s default HTTP path. */
1271
1287
  private _getModernHandler;
1272
1288
  /** Lazily builds the stateless legacy (2025-era) HTTP handler. One per FastMCP
1273
1289
  * instance, mirroring _getModernHandler's per-instance, per-request-factory model.
@@ -1276,8 +1292,9 @@ declare class FastMCP {
1276
1292
  * built with `sessionIdGenerator: undefined`, and answers GET and DELETE with 405
1277
1293
  * because both are session operations that mean nothing per request.
1278
1294
  *
1279
- * Only reachable when `_stateless` is on. The sessionful transport in
1280
- * _dispatchLegacyHttp is untouched and still serves every other deployment. */
1295
+ * Used unconditionally by fetch(), and by run() only when `_stateless` is on.
1296
+ * The sessionful transport in _dispatchLegacyHttp is untouched and remains the
1297
+ * default for listener-based HTTP deployments. */
1281
1298
  private _getStatelessLegacyHandler;
1282
1299
  /**
1283
1300
  * Dual-era HTTP dispatch shared by the OAuth and non-OAuth serve paths. Assumes CORS
package/dist/server.js CHANGED
@@ -2111,6 +2111,29 @@ var FastMCP = class {
2111
2111
  this._primaryServer = this._makeServer();
2112
2112
  await this._primaryServer.connect(transport);
2113
2113
  }
2114
+ /**
2115
+ * Serve an MCP request through a web-standard, fetch-native HTTP entrypoint.
2116
+ *
2117
+ * This entrypoint is always stateless and does not require `run()`: legacy
2118
+ * (2025-era) requests use a fresh server instance per request, while modern
2119
+ * (2026-07-28) requests share the instance's modern handler and event bus.
2120
+ * Authentication is deliberately external — `options.authInfo` is trusted and
2121
+ * passed unchanged into the protocol handler, where it is exposed as `ctx.auth`.
2122
+ * The embedding framework also owns Host/Origin validation and should abort its
2123
+ * carrying requests during shutdown; stateless legacy response streams follow
2124
+ * that request lifecycle, while `close()` terminates modern exchanges and streams.
2125
+ */
2126
+ async fetch(request, options) {
2127
+ if (request.method.toUpperCase() === "POST" && !isJsonContentType(request.headers.get("content-type"))) {
2128
+ return new Response(
2129
+ JSON.stringify({ error: "Unsupported Media Type: expected application/json" }),
2130
+ { status: 415, headers: { "Content-Type": "application/json" } }
2131
+ );
2132
+ }
2133
+ const legacy = await isLegacyRequest(request, options?.parsedBody);
2134
+ if (legacy) return this._getStatelessLegacyHandler()(request, options);
2135
+ return this._getModernHandler().fetch(request, options);
2136
+ }
2114
2137
  /**
2115
2138
  * Modern-era (2026-07-28) in-process fetch entrypoint — the `McpServerLike`
2116
2139
  * duck-type hook `fastmcp-ts/client`'s `Client` looks for when a caller pins
@@ -2157,9 +2180,9 @@ var FastMCP = class {
2157
2180
  /** Lazily builds the modern (2026-07-28) HTTP handler. One per FastMCP instance;
2158
2181
  * builds a fresh Server (via _makeServer) per request, matching createMcpHandler's
2159
2182
  * per-request-factory model. Modern-only (legacy: 'reject') — legacy (2025-era)
2160
- * traffic is routed to the existing sessionful transport by _dispatchHttp instead
2161
- * of createMcpHandler's own stateless legacy fallback, so session state and the
2162
- * legacy server-initiated-request shim keep working for 2025-era clients. */
2183
+ * traffic is routed separately: to the existing sessionful transport by
2184
+ * _dispatchHttp, or to the stateless fallback by fetch(). This preserves the
2185
+ * session state and server-initiated-request shim for run()'s default HTTP path. */
2163
2186
  _getModernHandler() {
2164
2187
  if (!this._modernHandler) {
2165
2188
  this._modernHandler = createMcpHandler(() => this._makeServer(/* @__PURE__ */ new Map(), { modern: true }), {
@@ -2176,8 +2199,9 @@ var FastMCP = class {
2176
2199
  * built with `sessionIdGenerator: undefined`, and answers GET and DELETE with 405
2177
2200
  * because both are session operations that mean nothing per request.
2178
2201
  *
2179
- * Only reachable when `_stateless` is on. The sessionful transport in
2180
- * _dispatchLegacyHttp is untouched and still serves every other deployment. */
2202
+ * Used unconditionally by fetch(), and by run() only when `_stateless` is on.
2203
+ * The sessionful transport in _dispatchLegacyHttp is untouched and remains the
2204
+ * default for listener-based HTTP deployments. */
2181
2205
  _getStatelessLegacyHandler() {
2182
2206
  if (!this._statelessLegacyHandler) {
2183
2207
  this._statelessLegacyHandler = legacyStatelessFallback(