fastmcp 4.23.6 → 4.23.8

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.
Files changed (41) hide show
  1. package/dist/FastMCP.cjs +4 -4
  2. package/dist/FastMCP.d.cts +3 -2
  3. package/dist/FastMCP.d.ts +3 -2
  4. package/dist/FastMCP.js +3 -3
  5. package/dist/auth/index.cjs +2 -2
  6. package/dist/auth/index.js +1 -1
  7. package/dist/bin/fastmcp.cjs +7 -1
  8. package/dist/bin/fastmcp.cjs.map +1 -1
  9. package/dist/bin/fastmcp.js +7 -1
  10. package/dist/bin/fastmcp.js.map +1 -1
  11. package/dist/{chunk-C7TBI7A5.cjs → chunk-AJRXMUZR.cjs} +8 -4
  12. package/dist/chunk-AJRXMUZR.cjs.map +1 -0
  13. package/dist/chunk-F76U45MT.js +44 -0
  14. package/dist/chunk-F76U45MT.js.map +1 -0
  15. package/dist/{chunk-5QKBH7JC.js → chunk-PLUAEIWE.js} +87 -30
  16. package/dist/chunk-PLUAEIWE.js.map +1 -0
  17. package/dist/chunk-T2F3RYH2.cjs +44 -0
  18. package/dist/chunk-T2F3RYH2.cjs.map +1 -0
  19. package/dist/{chunk-CA2EPNZF.js → chunk-UY253ACS.js} +8 -4
  20. package/dist/chunk-UY253ACS.js.map +1 -0
  21. package/dist/{chunk-2PXF6JQB.cjs → chunk-XEP3OP7Q.cjs} +141 -84
  22. package/dist/chunk-XEP3OP7Q.cjs.map +1 -0
  23. package/dist/edge/index.cjs +9 -5
  24. package/dist/edge/index.cjs.map +1 -1
  25. package/dist/edge/index.js +9 -5
  26. package/dist/edge/index.js.map +1 -1
  27. package/dist/examples/custom-routes.cjs +4 -4
  28. package/dist/examples/custom-routes.js +3 -3
  29. package/dist/openapi/index.cjs +17 -12
  30. package/dist/openapi/index.cjs.map +1 -1
  31. package/dist/openapi/index.js +12 -7
  32. package/dist/openapi/index.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/chunk-2PXF6JQB.cjs.map +0 -1
  35. package/dist/chunk-5QKBH7JC.js.map +0 -1
  36. package/dist/chunk-C7TBI7A5.cjs.map +0 -1
  37. package/dist/chunk-CA2EPNZF.js.map +0 -1
  38. package/dist/chunk-O22SYZMC.cjs +0 -22
  39. package/dist/chunk-O22SYZMC.cjs.map +0 -1
  40. package/dist/chunk-UMDUIBFW.js +0 -22
  41. package/dist/chunk-UMDUIBFW.js.map +0 -1
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  cancelResponseBody
3
- } from "./chunk-CA2EPNZF.js";
3
+ } from "./chunk-UY253ACS.js";
4
4
  import {
5
- strictInputSchema
6
- } from "./chunk-UMDUIBFW.js";
5
+ objectRootSchema,
6
+ strictInputSchema,
7
+ zodInputSchema
8
+ } from "./chunk-F76U45MT.js";
7
9
 
8
10
  // src/FastMCP.ts
9
11
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -185,9 +187,11 @@ function jsonSchemaAdapter(schema) {
185
187
  };
186
188
  }
187
189
  async function compileSchema(schema) {
190
+ const dialect = schema.$schema?.replace(/^http:\/\//, "https://").replace(/#$/, "");
191
+ const isDraft2020 = dialect === "https://json-schema.org/draft/2020-12/schema";
188
192
  let ajvModule;
189
193
  try {
190
- ajvModule = await import("ajv");
194
+ ajvModule = isDraft2020 ? await import("ajv/dist/2020.js") : await import("ajv");
191
195
  } catch {
192
196
  throw new Error(
193
197
  'The "ajv" package is required to validate JSON Schema tool parameters. Install it with: npm install ajv'
@@ -203,7 +207,7 @@ async function compileSchema(schema) {
203
207
  addFormats(ajv);
204
208
  } catch {
205
209
  }
206
- return ajv.compile(schema);
210
+ return ajv.compile(isDraft2020 ? { ...schema, $schema: dialect } : schema);
207
211
  }
208
212
  function toIssue(error) {
209
213
  const path = error.instancePath.split("/").slice(1).map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~")).map((segment) => {
@@ -542,6 +546,8 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
542
546
  #capabilities = {};
543
547
  #clientCapabilities;
544
548
  #connectionState = "connecting";
549
+ // Caller-supplied transports leave the response mode unspecified.
550
+ #enableJsonResponse;
545
551
  #logger;
546
552
  /**
547
553
  * The minimum level the client asked for with `logging/setLevel`, or
@@ -590,6 +596,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
590
596
  constructor({
591
597
  auth,
592
598
  authRequired = false,
599
+ enableJsonResponse,
593
600
  hasTools,
594
601
  icons,
595
602
  instructions,
@@ -614,6 +621,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
614
621
  super();
615
622
  this.#auth = auth;
616
623
  this.#authRequired = authRequired;
624
+ this.#enableJsonResponse = enableJsonResponse;
617
625
  this.#logger = logger;
618
626
  this.#onToolCall = onToolCall;
619
627
  this.#pingConfig = ping;
@@ -875,6 +883,19 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
875
883
  }
876
884
  return false;
877
885
  }
886
+ /**
887
+ * When `start()` streams responses, an elicitation goes out on its request's
888
+ * own SSE stream, as the SDK's `extra.sendRequest` does, so it reaches a
889
+ * client that never opened the optional standalone GET stream. A JSON
890
+ * response cannot carry it, and a transport passed to `connect()` does not
891
+ * say which mode it uses, so those keep the session's standalone stream.
892
+ */
893
+ #createElicit(requestId) {
894
+ return (params, options) => this.#server.elicitInput(
895
+ params,
896
+ this.#enableJsonResponse === false ? { ...options, relatedRequestId: requestId } : options
897
+ );
898
+ }
878
899
  /**
879
900
  * Builds the context object passed as the third argument to
880
901
  * `resource.load` / `resourceTemplate.load` / `prompt.load`.
@@ -885,12 +906,12 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
885
906
  * are tied to a tool call's progress token / streaming notification,
886
907
  * which resource and prompt reads do not have.
887
908
  */
888
- #createLoadContext(meta, sendNotification) {
909
+ #createLoadContext(meta, sendNotification, requestId) {
889
910
  return {
890
911
  client: {
891
912
  version: this.#server.getClientVersion()
892
913
  },
893
- elicit: (params, options) => this.#server.elicitInput(params, options),
914
+ elicit: this.#createElicit(requestId),
894
915
  log: this.#createLog(sendNotification),
895
916
  requestId: typeof meta?.requestId === "string" ? meta.requestId : void 0,
896
917
  session: this.#auth,
@@ -1328,7 +1349,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1328
1349
  this.#auth,
1329
1350
  this.#createLoadContext(
1330
1351
  request.params?._meta,
1331
- extra.sendNotification
1352
+ extra.sendNotification,
1353
+ extra.requestId
1332
1354
  )
1333
1355
  );
1334
1356
  } catch (error) {
@@ -1397,7 +1419,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1397
1419
  this.#auth,
1398
1420
  this.#createLoadContext(
1399
1421
  request.params?._meta,
1400
- extra.sendNotification
1422
+ extra.sendNotification,
1423
+ extra.requestId
1401
1424
  )
1402
1425
  );
1403
1426
  const resources = Array.isArray(result) ? result : [result];
@@ -1426,7 +1449,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1426
1449
  this.#auth,
1427
1450
  this.#createLoadContext(
1428
1451
  request.params?._meta,
1429
- extra.sendNotification
1452
+ extra.sendNotification,
1453
+ extra.requestId
1430
1454
  )
1431
1455
  );
1432
1456
  } catch (error) {
@@ -1541,15 +1565,17 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1541
1565
  return {
1542
1566
  annotations: tool.annotations,
1543
1567
  description: tool.description,
1544
- inputSchema: tool.parameters ? strictInputSchema(await toJsonSchema(tool.parameters)) : {
1568
+ inputSchema: tool.parameters ? strictInputSchema(
1569
+ tool.parameters["~standard"].vendor === "zod" && "_zod" in tool.parameters ? zodInputSchema(tool.parameters, "draft-7") : await toJsonSchema(tool.parameters)
1570
+ ) : {
1545
1571
  additionalProperties: false,
1546
1572
  properties: {},
1547
1573
  type: "object"
1548
1574
  },
1549
1575
  name: tool.name,
1550
1576
  ...tool.outputSchema && {
1551
- outputSchema: await toJsonSchema(
1552
- tool.outputSchema
1577
+ outputSchema: objectRootSchema(
1578
+ await toJsonSchema(tool.outputSchema)
1553
1579
  )
1554
1580
  },
1555
1581
  // Pass through _meta for MCP ext-apps UI support (issue #229)
@@ -1650,7 +1676,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1650
1676
  client: {
1651
1677
  version: this.#server.getClientVersion()
1652
1678
  },
1653
- elicit: (params, options) => this.#server.elicitInput(params, options),
1679
+ elicit: this.#createElicit(extra.requestId),
1654
1680
  log,
1655
1681
  reportProgress,
1656
1682
  requestId: typeof request.params?._meta?.requestId === "string" ? request.params._meta.requestId : void 0,
@@ -1722,10 +1748,22 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1722
1748
  }
1723
1749
  } catch (error) {
1724
1750
  if (error instanceof UserError) {
1751
+ let structuredContent = error.extras;
1752
+ if (structuredContent && tool.outputSchema) {
1753
+ try {
1754
+ structuredContent = await this.#validateStructuredContent(
1755
+ tool,
1756
+ structuredContent,
1757
+ request.params.name
1758
+ );
1759
+ } catch {
1760
+ structuredContent = void 0;
1761
+ }
1762
+ }
1725
1763
  return {
1726
1764
  content: [{ text: error.message, type: "text" }],
1727
1765
  isError: true,
1728
- ...error.extras ? { structuredContent: error.extras } : {}
1766
+ ...structuredContent ? { structuredContent } : {}
1729
1767
  };
1730
1768
  }
1731
1769
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1941,7 +1979,9 @@ var FastMCP = class extends FastMCPEventEmitter {
1941
1979
  * Adds a resource to the server.
1942
1980
  */
1943
1981
  addResource(resource) {
1944
- this.#resources = this.#resources.filter((r) => r.name !== resource.name);
1982
+ this.#resources = this.#resources.filter(
1983
+ (r) => r.name !== resource.name && r.uri !== resource.uri
1984
+ );
1945
1985
  this.#resources.push(resource);
1946
1986
  if (this.#serverState === "running" /* Running */) {
1947
1987
  this.#resourcesListChanged(this.#resources);
@@ -1951,13 +1991,12 @@ var FastMCP = class extends FastMCPEventEmitter {
1951
1991
  * Adds resources to the server.
1952
1992
  */
1953
1993
  addResources(resources) {
1954
- const newResourceNames = new Set(
1955
- resources.map((resource) => resource.name)
1956
- );
1957
- this.#resources = this.#resources.filter(
1958
- (r) => !newResourceNames.has(r.name)
1959
- );
1960
- this.#resources.push(...resources);
1994
+ for (const resource of resources) {
1995
+ this.#resources = this.#resources.filter(
1996
+ (r) => r.name !== resource.name && r.uri !== resource.uri
1997
+ );
1998
+ this.#resources.push(resource);
1999
+ }
1961
2000
  if (this.#serverState === "running" /* Running */) {
1962
2001
  this.#resourcesListChanged(this.#resources);
1963
2002
  }
@@ -2005,9 +2044,12 @@ var FastMCP = class extends FastMCPEventEmitter {
2005
2044
  */
2006
2045
  addTools(tools) {
2007
2046
  tools.forEach(assertToolSchemas);
2008
- const newToolNames = new Set(tools.map((tool) => tool.name));
2009
- this.#tools = this.#tools.filter((t) => !newToolNames.has(t.name));
2010
- this.#tools.push(...tools);
2047
+ const toolsByName = new Map(this.#tools.map((tool) => [tool.name, tool]));
2048
+ for (const tool of tools) {
2049
+ toolsByName.delete(tool.name);
2050
+ toolsByName.set(tool.name, tool);
2051
+ }
2052
+ this.#tools = Array.from(toolsByName.values());
2011
2053
  if (this.#serverState === "running" /* Running */) {
2012
2054
  this.#toolsListChanged(this.#tools);
2013
2055
  }
@@ -2309,6 +2351,9 @@ var FastMCP = class extends FastMCPEventEmitter {
2309
2351
  this.#serverState = "running" /* Running */;
2310
2352
  }
2311
2353
  } else if (config.transportType === "httpStream") {
2354
+ if (this.#httpStreamServer) {
2355
+ throw new Error("HTTP server is already running");
2356
+ }
2312
2357
  const httpConfig = config.httpStream;
2313
2358
  const protocol = httpConfig.sslCert || httpConfig.sslKey ? "https" : "http";
2314
2359
  const streamEndpoint = joinPaths(
@@ -2330,7 +2375,12 @@ var FastMCP = class extends FastMCPEventEmitter {
2330
2375
  auth = this.#requireAuthenticated(await authenticate(request));
2331
2376
  }
2332
2377
  const sessionId = Array.isArray(request.headers["mcp-session-id"]) ? request.headers["mcp-session-id"][0] : request.headers["mcp-session-id"];
2333
- return this.#createSession(auth, sessionId, true);
2378
+ return this.#createSession(
2379
+ auth,
2380
+ sessionId,
2381
+ true,
2382
+ httpConfig.enableJsonResponse
2383
+ );
2334
2384
  },
2335
2385
  enableJsonResponse: httpConfig.enableJsonResponse,
2336
2386
  eventStore: httpConfig.eventStore,
@@ -2372,7 +2422,12 @@ var FastMCP = class extends FastMCPEventEmitter {
2372
2422
  auth = this.#requireAuthenticated(await authenticate(request));
2373
2423
  }
2374
2424
  const sessionId = Array.isArray(request.headers["mcp-session-id"]) ? request.headers["mcp-session-id"][0] : request.headers["mcp-session-id"];
2375
- return this.#createSession(auth, sessionId);
2425
+ return this.#createSession(
2426
+ auth,
2427
+ sessionId,
2428
+ false,
2429
+ httpConfig.enableJsonResponse
2430
+ );
2376
2431
  },
2377
2432
  enableJsonResponse: httpConfig.enableJsonResponse,
2378
2433
  eventStore: httpConfig.eventStore,
@@ -2428,6 +2483,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2428
2483
  );
2429
2484
  if (this.#httpStreamServer) {
2430
2485
  await this.#httpStreamServer.close();
2486
+ this.#httpStreamServer = null;
2431
2487
  }
2432
2488
  this.#serverState = "stopped" /* Stopped */;
2433
2489
  }
@@ -2461,7 +2517,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2461
2517
  * Creates a new FastMCPSession instance with the current configuration.
2462
2518
  * Used both for regular sessions and stateless requests.
2463
2519
  */
2464
- #createSession(auth, sessionId, stateless = false) {
2520
+ #createSession(auth, sessionId, stateless = false, enableJsonResponse) {
2465
2521
  if (auth && typeof auth === "object" && "authenticated" in auth && !auth.authenticated) {
2466
2522
  const errorMessage = "error" in auth && typeof auth.error === "string" ? auth.error : "Authentication failed";
2467
2523
  throw this.#createUnauthorizedResponse(errorMessage);
@@ -2470,6 +2526,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2470
2526
  return new FastMCPSession({
2471
2527
  auth,
2472
2528
  authRequired,
2529
+ enableJsonResponse,
2473
2530
  hasTools: this.#tools.length > 0,
2474
2531
  icons: this.#options.icons,
2475
2532
  instructions: this.#options.instructions,
@@ -3213,4 +3270,4 @@ export {
3213
3270
  FastMCPSession,
3214
3271
  FastMCP
3215
3272
  };
3216
- //# sourceMappingURL=chunk-5QKBH7JC.js.map
3273
+ //# sourceMappingURL=chunk-PLUAEIWE.js.map