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
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkC7TBI7A5cjs = require('./chunk-C7TBI7A5.cjs');
3
+ var _chunkAJRXMUZRcjs = require('./chunk-AJRXMUZR.cjs');
4
4
 
5
5
 
6
- var _chunkO22SYZMCcjs = require('./chunk-O22SYZMC.cjs');
6
+
7
+
8
+ var _chunkT2F3RYH2cjs = require('./chunk-T2F3RYH2.cjs');
7
9
 
8
10
  // src/FastMCP.ts
9
11
  var _indexjs = require('@modelcontextprotocol/sdk/server/index.js');
@@ -139,7 +141,7 @@ var DiscoveryDocumentCache = class {
139
141
  throw error;
140
142
  }
141
143
  if (!res.ok) {
142
- await _chunkC7TBI7A5cjs.cancelResponseBody.call(void 0, res);
144
+ await _chunkAJRXMUZRcjs.cancelResponseBody.call(void 0, res);
143
145
  throw new Error(
144
146
  `Failed to fetch discovery document from ${url}: ${res.status} ${res.statusText}`
145
147
  );
@@ -185,9 +187,11 @@ function jsonSchemaAdapter(schema) {
185
187
  };
186
188
  }
187
189
  async function compileSchema(schema) {
190
+ const dialect = _optionalChain([schema, 'access', _2 => _2.$schema, 'optionalAccess', _3 => _3.replace, 'call', _4 => _4(/^http:\/\//, "https://"), 'access', _5 => _5.replace, 'call', _6 => _6(/#$/, "")]);
191
+ const isDraft2020 = dialect === "https://json-schema.org/draft/2020-12/schema";
188
192
  let ajvModule;
189
193
  try {
190
- ajvModule = await Promise.resolve().then(() => _interopRequireWildcard(require("ajv")));
194
+ ajvModule = isDraft2020 ? await Promise.resolve().then(() => _interopRequireWildcard(require("ajv/dist/2020.js"))) : await Promise.resolve().then(() => _interopRequireWildcard(require("ajv")));
191
195
  } catch (e2) {
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,14 +207,14 @@ async function compileSchema(schema) {
203
207
  addFormats(ajv);
204
208
  } catch (e3) {
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) => {
210
214
  const index = Number(segment);
211
215
  return /^(?:0|[1-9]\d*)$/.test(segment) && Number.isSafeInteger(index) ? index : segment;
212
216
  });
213
- const missingProperty = _optionalChain([error, 'access', _2 => _2.params, 'optionalAccess', _3 => _3.missingProperty]);
217
+ const missingProperty = _optionalChain([error, 'access', _7 => _7.params, 'optionalAccess', _8 => _8.missingProperty]);
214
218
  if (error.keyword === "required" && typeof missingProperty === "string") {
215
219
  path.push(missingProperty);
216
220
  }
@@ -245,7 +249,7 @@ var imageContent = async (input) => {
245
249
  signal: AbortSignal.timeout(timeoutMs)
246
250
  });
247
251
  if (!response.ok) {
248
- await _chunkC7TBI7A5cjs.cancelResponseBody.call(void 0, response);
252
+ await _chunkAJRXMUZRcjs.cancelResponseBody.call(void 0, response);
249
253
  throw new Error(
250
254
  `Server responded with status: ${response.status} - ${response.statusText}`
251
255
  );
@@ -278,7 +282,7 @@ var imageContent = async (input) => {
278
282
  }
279
283
  const { fileTypeFromBuffer } = await Promise.resolve().then(() => _interopRequireWildcard(require("file-type")));
280
284
  const fileType = await fileTypeFromBuffer(rawData);
281
- const mimeType = (!fileType || fileType.mime === "application/xml") && isSvg(rawData) ? "image/svg+xml" : _optionalChain([fileType, 'optionalAccess', _4 => _4.mime]);
285
+ const mimeType = (!fileType || fileType.mime === "application/xml") && isSvg(rawData) ? "image/svg+xml" : _optionalChain([fileType, 'optionalAccess', _9 => _9.mime]);
282
286
  if (!mimeType || !mimeType.startsWith("image/")) {
283
287
  console.warn(
284
288
  `Warning: Content may not be a valid image. Detected MIME: ${mimeType || "unknown"}`
@@ -307,11 +311,11 @@ var AUDIO_CONTAINER_TYPES = /* @__PURE__ */ new Map([
307
311
  ["video/webm", "audio/webm"]
308
312
  ]);
309
313
  var resolveAudioMimeType = (detected, declared) => {
310
- if (_optionalChain([detected, 'optionalAccess', _5 => _5.startsWith, 'call', _6 => _6("audio/")])) {
314
+ if (_optionalChain([detected, 'optionalAccess', _10 => _10.startsWith, 'call', _11 => _11("audio/")])) {
311
315
  return detected;
312
316
  }
313
- const declaredMime = _optionalChain([declared, 'optionalAccess', _7 => _7.split, 'call', _8 => _8(";", 1), 'access', _9 => _9[0], 'access', _10 => _10.trim, 'call', _11 => _11(), 'access', _12 => _12.toLowerCase, 'call', _13 => _13()]);
314
- if (_optionalChain([declaredMime, 'optionalAccess', _14 => _14.startsWith, 'call', _15 => _15("audio/")])) {
317
+ const declaredMime = _optionalChain([declared, 'optionalAccess', _12 => _12.split, 'call', _13 => _13(";", 1), 'access', _14 => _14[0], 'access', _15 => _15.trim, 'call', _16 => _16(), 'access', _17 => _17.toLowerCase, 'call', _18 => _18()]);
318
+ if (_optionalChain([declaredMime, 'optionalAccess', _19 => _19.startsWith, 'call', _20 => _20("audio/")])) {
315
319
  return declaredMime;
316
320
  }
317
321
  return _nullishCoalesce((detected && AUDIO_CONTAINER_TYPES.get(detected)), () => ( detected));
@@ -327,7 +331,7 @@ var audioContent = async (input) => {
327
331
  signal: AbortSignal.timeout(timeoutMs)
328
332
  });
329
333
  if (!response.ok) {
330
- await _chunkC7TBI7A5cjs.cancelResponseBody.call(void 0, response);
334
+ await _chunkAJRXMUZRcjs.cancelResponseBody.call(void 0, response);
331
335
  throw new Error(
332
336
  `Server responded with status: ${response.status} - ${response.statusText}`
333
337
  );
@@ -361,7 +365,7 @@ var audioContent = async (input) => {
361
365
  }
362
366
  const { fileTypeFromBuffer } = await Promise.resolve().then(() => _interopRequireWildcard(require("file-type")));
363
367
  const detected = await fileTypeFromBuffer(rawData);
364
- const mimeType = resolveAudioMimeType(_optionalChain([detected, 'optionalAccess', _16 => _16.mime]), declaredMimeType);
368
+ const mimeType = resolveAudioMimeType(_optionalChain([detected, 'optionalAccess', _21 => _21.mime]), declaredMimeType);
365
369
  if (!mimeType || !mimeType.startsWith("audio/")) {
366
370
  console.warn(
367
371
  `Warning: Content may not be a valid audio file. Detected MIME: ${mimeType || "unknown"}`
@@ -401,7 +405,7 @@ var UserError = class extends UnexpectedStateError {
401
405
  };
402
406
  function assertStandardSchema(toolName, schemaName, schema) {
403
407
  const standard = schema["~standard"];
404
- if (typeof _optionalChain([standard, 'optionalAccess', _17 => _17.validate]) === "function") {
408
+ if (typeof _optionalChain([standard, 'optionalAccess', _22 => _22.validate]) === "function") {
405
409
  return;
406
410
  }
407
411
  throw new UserError(
@@ -518,7 +522,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
518
522
  */
519
523
  get sessionId() {
520
524
  if (this.#sessionId === void 0) {
521
- const transportSessionId = _optionalChain([this, 'access', _18 => _18.#server, 'access', _19 => _19.transport, 'optionalAccess', _20 => _20.sessionId]);
525
+ const transportSessionId = _optionalChain([this, 'access', _23 => _23.#server, 'access', _24 => _24.transport, 'optionalAccess', _25 => _25.sessionId]);
522
526
  if (typeof transportSessionId === "string") {
523
527
  this.#sessionId = transportSessionId;
524
528
  }
@@ -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,14 +906,14 @@ ${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
- requestId: typeof _optionalChain([meta, 'optionalAccess', _21 => _21.requestId]) === "string" ? meta.requestId : void 0,
916
+ requestId: typeof _optionalChain([meta, 'optionalAccess', _26 => _26.requestId]) === "string" ? meta.requestId : void 0,
896
917
  session: this.#auth,
897
918
  sessionId: this.sessionId
898
919
  };
@@ -914,8 +935,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
914
935
  };
915
936
  }
916
937
  #formatSchemaIssues(issues) {
917
- return _optionalChain([this, 'access', _22 => _22.#utils, 'optionalAccess', _23 => _23.formatInvalidParamsErrorMessage]) ? this.#utils.formatInvalidParamsErrorMessage(issues) : issues.map((issue) => {
918
- const path = _optionalChain([issue, 'access', _24 => _24.path, 'optionalAccess', _25 => _25.join, 'call', _26 => _26(".")]) || "root";
938
+ return _optionalChain([this, 'access', _27 => _27.#utils, 'optionalAccess', _28 => _28.formatInvalidParamsErrorMessage]) ? this.#utils.formatInvalidParamsErrorMessage(issues) : issues.map((issue) => {
939
+ const path = _optionalChain([issue, 'access', _29 => _29.path, 'optionalAccess', _30 => _30.join, 'call', _31 => _31(".")]) || "root";
919
940
  return `${path}: ${issue.message}`;
920
941
  }).join(", ");
921
942
  }
@@ -937,7 +958,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
937
958
  * is bounded and retried, and the result is announced with `rootsChanged`.
938
959
  */
939
960
  async #loadRoots(streamableHttp) {
940
- if (_optionalChain([this, 'access', _27 => _27.#rootsConfig, 'optionalAccess', _28 => _28.enabled]) === false || !_optionalChain([this, 'access', _29 => _29.#clientCapabilities, 'optionalAccess', _30 => _30.roots, 'optionalAccess', _31 => _31.listChanged]) || typeof this.#server.listRoots !== "function") {
961
+ if (_optionalChain([this, 'access', _32 => _32.#rootsConfig, 'optionalAccess', _33 => _33.enabled]) === false || !_optionalChain([this, 'access', _34 => _34.#clientCapabilities, 'optionalAccess', _35 => _35.roots, 'optionalAccess', _36 => _36.listChanged]) || typeof this.#server.listRoots !== "function") {
941
962
  return;
942
963
  }
943
964
  const maxAttempts = streamableHttp ? 5 : 1;
@@ -947,7 +968,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
947
968
  void 0,
948
969
  streamableHttp ? { timeout: 1e3 } : void 0
949
970
  );
950
- this.#roots = _optionalChain([roots, 'optionalAccess', _32 => _32.roots]) || [];
971
+ this.#roots = _optionalChain([roots, 'optionalAccess', _37 => _37.roots]) || [];
951
972
  if (streamableHttp) {
952
973
  this.emit("rootsChanged", { roots: this.#roots });
953
974
  }
@@ -1085,7 +1106,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1085
1106
  */
1086
1107
  #startStreamKeepalive(extra, toolName) {
1087
1108
  const config = this.#streamKeepaliveConfig;
1088
- if (!_optionalChain([config, 'optionalAccess', _33 => _33.enabled])) {
1109
+ if (!_optionalChain([config, 'optionalAccess', _38 => _38.enabled])) {
1089
1110
  return () => {
1090
1111
  };
1091
1112
  }
@@ -1105,9 +1126,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1105
1126
  );
1106
1127
  });
1107
1128
  }, intervalMs);
1108
- _optionalChain([timer, 'access', _34 => _34.unref, 'optionalCall', _35 => _35()]);
1129
+ _optionalChain([timer, 'access', _39 => _39.unref, 'optionalCall', _40 => _40()]);
1109
1130
  const stop = () => clearInterval(timer);
1110
- _optionalChain([extra, 'access', _36 => _36.signal, 'optionalAccess', _37 => _37.addEventListener, 'call', _38 => _38("abort", stop, { once: true })]);
1131
+ _optionalChain([extra, 'access', _41 => _41.signal, 'optionalAccess', _42 => _42.addEventListener, 'call', _43 => _43("abort", stop, { once: true })]);
1111
1132
  return stop;
1112
1133
  }
1113
1134
  async #validateStructuredContent(tool, value, toolName) {
@@ -1327,8 +1348,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1327
1348
  _nullishCoalesce(args, () => ( {})),
1328
1349
  this.#auth,
1329
1350
  this.#createLoadContext(
1330
- _optionalChain([request, 'access', _39 => _39.params, 'optionalAccess', _40 => _40._meta]),
1331
- extra.sendNotification
1351
+ _optionalChain([request, 'access', _44 => _44.params, 'optionalAccess', _45 => _45._meta]),
1352
+ extra.sendNotification,
1353
+ extra.requestId
1332
1354
  )
1333
1355
  );
1334
1356
  } catch (error) {
@@ -1396,8 +1418,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1396
1418
  match,
1397
1419
  this.#auth,
1398
1420
  this.#createLoadContext(
1399
- _optionalChain([request, 'access', _41 => _41.params, 'optionalAccess', _42 => _42._meta]),
1400
- extra.sendNotification
1421
+ _optionalChain([request, 'access', _46 => _46.params, 'optionalAccess', _47 => _47._meta]),
1422
+ extra.sendNotification,
1423
+ extra.requestId
1401
1424
  )
1402
1425
  );
1403
1426
  const resources = Array.isArray(result) ? result : [result];
@@ -1425,8 +1448,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1425
1448
  maybeArrayResult = await resource.load(
1426
1449
  this.#auth,
1427
1450
  this.#createLoadContext(
1428
- _optionalChain([request, 'access', _43 => _43.params, 'optionalAccess', _44 => _44._meta]),
1429
- extra.sendNotification
1451
+ _optionalChain([request, 'access', _48 => _48.params, 'optionalAccess', _49 => _49._meta]),
1452
+ extra.sendNotification,
1453
+ extra.requestId
1430
1454
  )
1431
1455
  );
1432
1456
  } catch (error) {
@@ -1490,7 +1514,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1490
1514
  );
1491
1515
  }
1492
1516
  setupRootsHandlers() {
1493
- if (_optionalChain([this, 'access', _45 => _45.#rootsConfig, 'optionalAccess', _46 => _46.enabled]) === false) {
1517
+ if (_optionalChain([this, 'access', _50 => _50.#rootsConfig, 'optionalAccess', _51 => _51.enabled]) === false) {
1494
1518
  this.#logger.debug(
1495
1519
  "[FastMCP debug] roots capability explicitly disabled via config"
1496
1520
  );
@@ -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 ? _chunkO22SYZMCcjs.strictInputSchema.call(void 0, await _xsschema.toJsonSchema.call(void 0, tool.parameters)) : {
1568
+ inputSchema: tool.parameters ? _chunkT2F3RYH2cjs.strictInputSchema.call(void 0,
1569
+ tool.parameters["~standard"].vendor === "zod" && "_zod" in tool.parameters ? _chunkT2F3RYH2cjs.zodInputSchema.call(void 0, tool.parameters, "draft-7") : await _xsschema.toJsonSchema.call(void 0, 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 _xsschema.toJsonSchema.call(void 0,
1552
- tool.outputSchema
1577
+ outputSchema: _chunkT2F3RYH2cjs.objectRootSchema.call(void 0,
1578
+ await _xsschema.toJsonSchema.call(void 0, tool.outputSchema)
1553
1579
  )
1554
1580
  },
1555
1581
  // Pass through _meta for MCP ext-apps UI support (issue #229)
@@ -1585,7 +1611,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1585
1611
  }
1586
1612
  args = parsed.value;
1587
1613
  }
1588
- const progressToken = _optionalChain([request, 'access', _47 => _47.params, 'optionalAccess', _48 => _48._meta, 'optionalAccess', _49 => _49.progressToken]);
1614
+ const progressToken = _optionalChain([request, 'access', _52 => _52.params, 'optionalAccess', _53 => _53._meta, 'optionalAccess', _54 => _54.progressToken]);
1589
1615
  let result;
1590
1616
  try {
1591
1617
  const reportProgress = async (progress) => {
@@ -1650,10 +1676,10 @@ ${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
- requestId: typeof _optionalChain([request, 'access', _50 => _50.params, 'optionalAccess', _51 => _51._meta, 'optionalAccess', _52 => _52.requestId]) === "string" ? request.params._meta.requestId : void 0,
1682
+ requestId: typeof _optionalChain([request, 'access', _55 => _55.params, 'optionalAccess', _56 => _56._meta, 'optionalAccess', _57 => _57.requestId]) === "string" ? request.params._meta.requestId : void 0,
1657
1683
  session: this.#auth,
1658
1684
  sessionId: this.sessionId,
1659
1685
  signal,
@@ -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 (e5) {
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);
@@ -1795,14 +1833,14 @@ function normalizePath(path) {
1795
1833
  return path.startsWith("/") ? path : `/${path}`;
1796
1834
  }
1797
1835
  function parseBasicAuthHeader(authHeader) {
1798
- const basicMatch = _optionalChain([authHeader, 'optionalAccess', _53 => _53.match, 'call', _54 => _54(/^Basic\s+(.+)$/)]);
1836
+ const basicMatch = _optionalChain([authHeader, 'optionalAccess', _58 => _58.match, 'call', _59 => _59(/^Basic\s+(.+)$/)]);
1799
1837
  if (!basicMatch) return null;
1800
1838
  try {
1801
1839
  const credentials = Buffer.from(basicMatch[1], "base64").toString("utf-8");
1802
1840
  const credMatch = credentials.match(/^([^:]+):(.*)$/);
1803
1841
  if (!credMatch) return null;
1804
1842
  return { clientId: credMatch[1], clientSecret: credMatch[2] };
1805
- } catch (e5) {
1843
+ } catch (e6) {
1806
1844
  return null;
1807
1845
  }
1808
1846
  }
@@ -1839,7 +1877,7 @@ function protectedResourceMetadataUrl(resource) {
1839
1877
  let url;
1840
1878
  try {
1841
1879
  url = new URL(resource);
1842
- } catch (e6) {
1880
+ } catch (e7) {
1843
1881
  return `${resource}/.well-known/oauth-protected-resource`;
1844
1882
  }
1845
1883
  const path = url.pathname === "/" ? "" : url.pathname;
@@ -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
  }
@@ -2441,9 +2497,9 @@ var FastMCP = class extends FastMCPEventEmitter {
2441
2497
  const originalOnClose = transport.onclose;
2442
2498
  transport.onclose = () => {
2443
2499
  closed = true;
2444
- _optionalChain([onClose, 'optionalCall', _55 => _55()]);
2500
+ _optionalChain([onClose, 'optionalCall', _60 => _60()]);
2445
2501
  this.#removeSession(session);
2446
- _optionalChain([originalOnClose, 'optionalCall', _56 => _56()]);
2502
+ _optionalChain([originalOnClose, 'optionalCall', _61 => _61()]);
2447
2503
  };
2448
2504
  await session.connect(transport);
2449
2505
  if (closed) {
@@ -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,
@@ -2507,7 +2564,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2507
2564
  */
2508
2565
  #createUnauthorizedResponse(message) {
2509
2566
  const oauth = this.#options.oauth;
2510
- const resource = _optionalChain([oauth, 'optionalAccess', _57 => _57.enabled]) ? _optionalChain([oauth, 'access', _58 => _58.protectedResource, 'optionalAccess', _59 => _59.resource]) : void 0;
2567
+ const resource = _optionalChain([oauth, 'optionalAccess', _62 => _62.enabled]) ? _optionalChain([oauth, 'access', _63 => _63.protectedResource, 'optionalAccess', _64 => _64.resource]) : void 0;
2511
2568
  const wwwAuthenticateParts = [
2512
2569
  'error="invalid_token"',
2513
2570
  `error_description="${message.replace(/"/g, '\\"')}"`
@@ -2646,7 +2703,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2646
2703
  }
2647
2704
  }
2648
2705
  const oauthConfig = this.#options.oauth;
2649
- if (_optionalChain([oauthConfig, 'optionalAccess', _60 => _60.enabled]) && req.method === "GET") {
2706
+ if (_optionalChain([oauthConfig, 'optionalAccess', _65 => _65.enabled]) && req.method === "GET") {
2650
2707
  const url2 = new URL(req.url || "", `http://${host}`);
2651
2708
  const authorizationServerMetadataPath = joinPaths(
2652
2709
  "",
@@ -2680,8 +2737,8 @@ var FastMCP = class extends FastMCPEventEmitter {
2680
2737
  }
2681
2738
  }
2682
2739
  }
2683
- const oauthProxy = _optionalChain([oauthConfig, 'optionalAccess', _61 => _61.proxy]);
2684
- if (oauthProxy && _optionalChain([oauthConfig, 'optionalAccess', _62 => _62.enabled])) {
2740
+ const oauthProxy = _optionalChain([oauthConfig, 'optionalAccess', _66 => _66.proxy]);
2741
+ if (oauthProxy && _optionalChain([oauthConfig, 'optionalAccess', _67 => _67.enabled])) {
2685
2742
  const url2 = new URL(req.url || "", `http://${host}`);
2686
2743
  const oauthPath = basePathRelativePath;
2687
2744
  try {
@@ -2734,7 +2791,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2734
2791
  const statusCode = error.statusCode || 400;
2735
2792
  res.writeHead(statusCode, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(
2736
2793
  JSON.stringify(
2737
- _optionalChain([error, 'access', _63 => _63.toJSON, 'optionalCall', _64 => _64()]) || {
2794
+ _optionalChain([error, 'access', _68 => _68.toJSON, 'optionalCall', _69 => _69()]) || {
2738
2795
  error: "invalid_request"
2739
2796
  }
2740
2797
  )
@@ -2761,7 +2818,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2761
2818
  } catch (error) {
2762
2819
  res.writeHead(400, { "Content-Type": "application/json" }).end(
2763
2820
  JSON.stringify(
2764
- _optionalChain([error, 'access', _65 => _65.toJSON, 'optionalCall', _66 => _66()]) || {
2821
+ _optionalChain([error, 'access', _70 => _70.toJSON, 'optionalCall', _71 => _71()]) || {
2765
2822
  error: "invalid_request"
2766
2823
  }
2767
2824
  )
@@ -2783,7 +2840,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2783
2840
  } catch (error) {
2784
2841
  res.writeHead(400, { "Content-Type": "application/json" }).end(
2785
2842
  JSON.stringify(
2786
- _optionalChain([error, 'access', _67 => _67.toJSON, 'optionalCall', _68 => _68()]) || {
2843
+ _optionalChain([error, 'access', _72 => _72.toJSON, 'optionalCall', _73 => _73()]) || {
2787
2844
  error: "server_error"
2788
2845
  }
2789
2846
  )
@@ -2852,7 +2909,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2852
2909
  } catch (error) {
2853
2910
  res.writeHead(400, { "Content-Type": "application/json" }).end(
2854
2911
  JSON.stringify(
2855
- _optionalChain([error, 'access', _69 => _69.toJSON, 'optionalCall', _70 => _70()]) || {
2912
+ _optionalChain([error, 'access', _74 => _74.toJSON, 'optionalCall', _75 => _75()]) || {
2856
2913
  error: "server_error"
2857
2914
  }
2858
2915
  )
@@ -2910,8 +2967,8 @@ var FastMCP = class extends FastMCPEventEmitter {
2910
2967
  const basicAuth = parseBasicAuthHeader(
2911
2968
  req.headers.authorization
2912
2969
  );
2913
- const clientId = _optionalChain([basicAuth, 'optionalAccess', _71 => _71.clientId]) || params.get("client_id") || "";
2914
- const clientSecret = _nullishCoalesce(_nullishCoalesce(_optionalChain([basicAuth, 'optionalAccess', _72 => _72.clientSecret]), () => ( params.get("client_secret"))), () => ( void 0));
2970
+ const clientId = _optionalChain([basicAuth, 'optionalAccess', _76 => _76.clientId]) || params.get("client_id") || "";
2971
+ const clientSecret = _nullishCoalesce(_nullishCoalesce(_optionalChain([basicAuth, 'optionalAccess', _77 => _77.clientSecret]), () => ( params.get("client_secret"))), () => ( void 0));
2915
2972
  let response;
2916
2973
  if (grantType === "authorization_code") {
2917
2974
  response = await oauthProxy.exchangeAuthorizationCode({
@@ -2941,7 +2998,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2941
2998
  const statusCode = error.statusCode || 400;
2942
2999
  res.writeHead(statusCode, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(
2943
3000
  JSON.stringify(
2944
- _optionalChain([error, 'access', _73 => _73.toJSON, 'optionalCall', _74 => _74()]) || {
3001
+ _optionalChain([error, 'access', _78 => _78.toJSON, 'optionalCall', _79 => _79()]) || {
2945
3002
  error: "invalid_request"
2946
3003
  }
2947
3004
  )
@@ -2967,7 +3024,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2967
3024
  * regardless (RFC 7235), so no config is needed just to get the header.
2968
3025
  */
2969
3026
  #httpStreamOAuthConfig() {
2970
- const resource = _optionalChain([this, 'access', _75 => _75.#options, 'access', _76 => _76.oauth, 'optionalAccess', _77 => _77.enabled]) ? _optionalChain([this, 'access', _78 => _78.#options, 'access', _79 => _79.oauth, 'access', _80 => _80.protectedResource, 'optionalAccess', _81 => _81.resource]) : void 0;
3027
+ const resource = _optionalChain([this, 'access', _80 => _80.#options, 'access', _81 => _81.oauth, 'optionalAccess', _82 => _82.enabled]) ? _optionalChain([this, 'access', _83 => _83.#options, 'access', _84 => _84.oauth, 'access', _85 => _85.protectedResource, 'optionalAccess', _86 => _86.resource]) : void 0;
2971
3028
  if (!resource) {
2972
3029
  return {};
2973
3030
  }
@@ -3075,24 +3132,24 @@ var FastMCP = class extends FastMCPEventEmitter {
3075
3132
  const envBasePath = process.env.FASTMCP_BASE_PATH;
3076
3133
  const envStateless = process.env.FASTMCP_STATELESS;
3077
3134
  const envHost = process.env.FASTMCP_HOST;
3078
- const transportType = _optionalChain([overrides, 'optionalAccess', _82 => _82.transportType]) || parseTransportSetting(transportArg, "--transport") || parseTransportSetting(envTransport, "FASTMCP_TRANSPORT") || "stdio";
3135
+ const transportType = _optionalChain([overrides, 'optionalAccess', _87 => _87.transportType]) || parseTransportSetting(transportArg, "--transport") || parseTransportSetting(envTransport, "FASTMCP_TRANSPORT") || "stdio";
3079
3136
  if (transportType === "httpStream") {
3080
3137
  const port = parseInt(
3081
- _optionalChain([overrides, 'optionalAccess', _83 => _83.httpStream, 'optionalAccess', _84 => _84.port, 'optionalAccess', _85 => _85.toString, 'call', _86 => _86()]) || portArg || envPort || "8080"
3138
+ _optionalChain([overrides, 'optionalAccess', _88 => _88.httpStream, 'optionalAccess', _89 => _89.port, 'optionalAccess', _90 => _90.toString, 'call', _91 => _91()]) || portArg || envPort || "8080"
3082
3139
  );
3083
- const host = _optionalChain([overrides, 'optionalAccess', _87 => _87.httpStream, 'optionalAccess', _88 => _88.host]) || hostArg || envHost || "localhost";
3084
- const endpoint = _optionalChain([overrides, 'optionalAccess', _89 => _89.httpStream, 'optionalAccess', _90 => _90.endpoint]) || endpointArg || envEndpoint || "/mcp";
3140
+ const host = _optionalChain([overrides, 'optionalAccess', _92 => _92.httpStream, 'optionalAccess', _93 => _93.host]) || hostArg || envHost || "localhost";
3141
+ const endpoint = _optionalChain([overrides, 'optionalAccess', _94 => _94.httpStream, 'optionalAccess', _95 => _95.endpoint]) || endpointArg || envEndpoint || "/mcp";
3085
3142
  const basePath = normalizeBasePath(
3086
- _optionalChain([overrides, 'optionalAccess', _91 => _91.httpStream, 'optionalAccess', _92 => _92.basePath]) || basePathArg || envBasePath
3143
+ _optionalChain([overrides, 'optionalAccess', _96 => _96.httpStream, 'optionalAccess', _97 => _97.basePath]) || basePathArg || envBasePath
3087
3144
  );
3088
- const enableJsonResponse = _optionalChain([overrides, 'optionalAccess', _93 => _93.httpStream, 'optionalAccess', _94 => _94.enableJsonResponse]) || false;
3089
- const stateless = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _95 => _95.httpStream, 'optionalAccess', _96 => _96.stateless]), () => ( // A bare `--stateless` means `--stateless true`.
3145
+ const enableJsonResponse = _optionalChain([overrides, 'optionalAccess', _98 => _98.httpStream, 'optionalAccess', _99 => _99.enableJsonResponse]) || false;
3146
+ const stateless = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _100 => _100.httpStream, 'optionalAccess', _101 => _101.stateless]), () => ( // A bare `--stateless` means `--stateless true`.
3090
3147
  (statelessArg === "" ? true : parseBooleanSetting(statelessArg, "--stateless")))), () => ( parseBooleanSetting(envStateless, "FASTMCP_STATELESS"))), () => ( false));
3091
- const cors = _optionalChain([overrides, 'optionalAccess', _97 => _97.httpStream, 'optionalAccess', _98 => _98.cors]);
3092
- const eventStore = _optionalChain([overrides, 'optionalAccess', _99 => _99.httpStream, 'optionalAccess', _100 => _100.eventStore]);
3093
- const sslCa = _optionalChain([overrides, 'optionalAccess', _101 => _101.httpStream, 'optionalAccess', _102 => _102.sslCa]);
3094
- const sslCert = _optionalChain([overrides, 'optionalAccess', _103 => _103.httpStream, 'optionalAccess', _104 => _104.sslCert]);
3095
- const sslKey = _optionalChain([overrides, 'optionalAccess', _105 => _105.httpStream, 'optionalAccess', _106 => _106.sslKey]);
3148
+ const cors = _optionalChain([overrides, 'optionalAccess', _102 => _102.httpStream, 'optionalAccess', _103 => _103.cors]);
3149
+ const eventStore = _optionalChain([overrides, 'optionalAccess', _104 => _104.httpStream, 'optionalAccess', _105 => _105.eventStore]);
3150
+ const sslCa = _optionalChain([overrides, 'optionalAccess', _106 => _106.httpStream, 'optionalAccess', _107 => _107.sslCa]);
3151
+ const sslCert = _optionalChain([overrides, 'optionalAccess', _108 => _108.httpStream, 'optionalAccess', _109 => _109.sslCert]);
3152
+ const sslKey = _optionalChain([overrides, 'optionalAccess', _110 => _110.httpStream, 'optionalAccess', _111 => _111.sslKey]);
3096
3153
  return {
3097
3154
  httpStream: {
3098
3155
  basePath,
@@ -3184,7 +3241,7 @@ var FastMCP = class extends FastMCPEventEmitter {
3184
3241
  */
3185
3242
  #useEndpointAsResource(endpoint) {
3186
3243
  const oauth = this.#options.oauth;
3187
- if (this.#providerResourceBase === void 0 || !_optionalChain([oauth, 'optionalAccess', _107 => _107.protectedResource]))
3244
+ if (this.#providerResourceBase === void 0 || !_optionalChain([oauth, 'optionalAccess', _112 => _112.protectedResource]))
3188
3245
  return;
3189
3246
  this.#options = {
3190
3247
  ...this.#options,
@@ -3213,4 +3270,4 @@ var FastMCP = class extends FastMCPEventEmitter {
3213
3270
 
3214
3271
 
3215
3272
  exports.DiscoveryDocumentCache = DiscoveryDocumentCache; exports.jsonSchemaAdapter = jsonSchemaAdapter; exports.MEDIA_FETCH_TIMEOUT_MS = MEDIA_FETCH_TIMEOUT_MS; exports.imageContent = imageContent; exports.audioContent = audioContent; exports.FastMCPError = FastMCPError; exports.SessionError = SessionError; exports.UnexpectedStateError = UnexpectedStateError; exports.UserError = UserError; exports.ServerState = ServerState; exports.FastMCPSession = FastMCPSession; exports.FastMCP = FastMCP;
3216
- //# sourceMappingURL=chunk-2PXF6JQB.cjs.map
3273
+ //# sourceMappingURL=chunk-XEP3OP7Q.cjs.map