fastmcp 4.23.7 → 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 (39) hide show
  1. package/dist/FastMCP.cjs +4 -4
  2. package/dist/FastMCP.d.cts +1 -1
  3. package/dist/FastMCP.d.ts +1 -1
  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-YZ5QEHBX.js → chunk-F76U45MT.js} +11 -3
  14. package/dist/chunk-F76U45MT.js.map +1 -0
  15. package/dist/{chunk-7WNI6AGD.js → chunk-PLUAEIWE.js} +42 -19
  16. package/dist/chunk-PLUAEIWE.js.map +1 -0
  17. package/dist/{chunk-MPFPOZ2H.cjs → chunk-T2F3RYH2.cjs} +12 -4
  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-TBMRFQ6M.cjs → chunk-XEP3OP7Q.cjs} +99 -76
  22. package/dist/chunk-XEP3OP7Q.cjs.map +1 -0
  23. package/dist/edge/index.cjs +8 -4
  24. package/dist/edge/index.cjs.map +1 -1
  25. package/dist/edge/index.js +6 -2
  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-7WNI6AGD.js.map +0 -1
  35. package/dist/chunk-C7TBI7A5.cjs.map +0 -1
  36. package/dist/chunk-CA2EPNZF.js.map +0 -1
  37. package/dist/chunk-MPFPOZ2H.cjs.map +0 -1
  38. package/dist/chunk-TBMRFQ6M.cjs.map +0 -1
  39. package/dist/chunk-YZ5QEHBX.js.map +0 -1
@@ -1,10 +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
6
 
7
- var _chunkMPFPOZ2Hcjs = require('./chunk-MPFPOZ2H.cjs');
7
+
8
+ var _chunkT2F3RYH2cjs = require('./chunk-T2F3RYH2.cjs');
8
9
 
9
10
  // src/FastMCP.ts
10
11
  var _indexjs = require('@modelcontextprotocol/sdk/server/index.js');
@@ -140,7 +141,7 @@ var DiscoveryDocumentCache = class {
140
141
  throw error;
141
142
  }
142
143
  if (!res.ok) {
143
- await _chunkC7TBI7A5cjs.cancelResponseBody.call(void 0, res);
144
+ await _chunkAJRXMUZRcjs.cancelResponseBody.call(void 0, res);
144
145
  throw new Error(
145
146
  `Failed to fetch discovery document from ${url}: ${res.status} ${res.statusText}`
146
147
  );
@@ -186,9 +187,11 @@ function jsonSchemaAdapter(schema) {
186
187
  };
187
188
  }
188
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";
189
192
  let ajvModule;
190
193
  try {
191
- 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")));
192
195
  } catch (e2) {
193
196
  throw new Error(
194
197
  'The "ajv" package is required to validate JSON Schema tool parameters. Install it with: npm install ajv'
@@ -204,14 +207,14 @@ async function compileSchema(schema) {
204
207
  addFormats(ajv);
205
208
  } catch (e3) {
206
209
  }
207
- return ajv.compile(schema);
210
+ return ajv.compile(isDraft2020 ? { ...schema, $schema: dialect } : schema);
208
211
  }
209
212
  function toIssue(error) {
210
213
  const path = error.instancePath.split("/").slice(1).map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~")).map((segment) => {
211
214
  const index = Number(segment);
212
215
  return /^(?:0|[1-9]\d*)$/.test(segment) && Number.isSafeInteger(index) ? index : segment;
213
216
  });
214
- 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]);
215
218
  if (error.keyword === "required" && typeof missingProperty === "string") {
216
219
  path.push(missingProperty);
217
220
  }
@@ -246,7 +249,7 @@ var imageContent = async (input) => {
246
249
  signal: AbortSignal.timeout(timeoutMs)
247
250
  });
248
251
  if (!response.ok) {
249
- await _chunkC7TBI7A5cjs.cancelResponseBody.call(void 0, response);
252
+ await _chunkAJRXMUZRcjs.cancelResponseBody.call(void 0, response);
250
253
  throw new Error(
251
254
  `Server responded with status: ${response.status} - ${response.statusText}`
252
255
  );
@@ -279,7 +282,7 @@ var imageContent = async (input) => {
279
282
  }
280
283
  const { fileTypeFromBuffer } = await Promise.resolve().then(() => _interopRequireWildcard(require("file-type")));
281
284
  const fileType = await fileTypeFromBuffer(rawData);
282
- 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]);
283
286
  if (!mimeType || !mimeType.startsWith("image/")) {
284
287
  console.warn(
285
288
  `Warning: Content may not be a valid image. Detected MIME: ${mimeType || "unknown"}`
@@ -308,11 +311,11 @@ var AUDIO_CONTAINER_TYPES = /* @__PURE__ */ new Map([
308
311
  ["video/webm", "audio/webm"]
309
312
  ]);
310
313
  var resolveAudioMimeType = (detected, declared) => {
311
- if (_optionalChain([detected, 'optionalAccess', _5 => _5.startsWith, 'call', _6 => _6("audio/")])) {
314
+ if (_optionalChain([detected, 'optionalAccess', _10 => _10.startsWith, 'call', _11 => _11("audio/")])) {
312
315
  return detected;
313
316
  }
314
- 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()]);
315
- 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/")])) {
316
319
  return declaredMime;
317
320
  }
318
321
  return _nullishCoalesce((detected && AUDIO_CONTAINER_TYPES.get(detected)), () => ( detected));
@@ -328,7 +331,7 @@ var audioContent = async (input) => {
328
331
  signal: AbortSignal.timeout(timeoutMs)
329
332
  });
330
333
  if (!response.ok) {
331
- await _chunkC7TBI7A5cjs.cancelResponseBody.call(void 0, response);
334
+ await _chunkAJRXMUZRcjs.cancelResponseBody.call(void 0, response);
332
335
  throw new Error(
333
336
  `Server responded with status: ${response.status} - ${response.statusText}`
334
337
  );
@@ -362,7 +365,7 @@ var audioContent = async (input) => {
362
365
  }
363
366
  const { fileTypeFromBuffer } = await Promise.resolve().then(() => _interopRequireWildcard(require("file-type")));
364
367
  const detected = await fileTypeFromBuffer(rawData);
365
- const mimeType = resolveAudioMimeType(_optionalChain([detected, 'optionalAccess', _16 => _16.mime]), declaredMimeType);
368
+ const mimeType = resolveAudioMimeType(_optionalChain([detected, 'optionalAccess', _21 => _21.mime]), declaredMimeType);
366
369
  if (!mimeType || !mimeType.startsWith("audio/")) {
367
370
  console.warn(
368
371
  `Warning: Content may not be a valid audio file. Detected MIME: ${mimeType || "unknown"}`
@@ -402,7 +405,7 @@ var UserError = class extends UnexpectedStateError {
402
405
  };
403
406
  function assertStandardSchema(toolName, schemaName, schema) {
404
407
  const standard = schema["~standard"];
405
- if (typeof _optionalChain([standard, 'optionalAccess', _17 => _17.validate]) === "function") {
408
+ if (typeof _optionalChain([standard, 'optionalAccess', _22 => _22.validate]) === "function") {
406
409
  return;
407
410
  }
408
411
  throw new UserError(
@@ -519,7 +522,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
519
522
  */
520
523
  get sessionId() {
521
524
  if (this.#sessionId === void 0) {
522
- 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]);
523
526
  if (typeof transportSessionId === "string") {
524
527
  this.#sessionId = transportSessionId;
525
528
  }
@@ -910,7 +913,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
910
913
  },
911
914
  elicit: this.#createElicit(requestId),
912
915
  log: this.#createLog(sendNotification),
913
- 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,
914
917
  session: this.#auth,
915
918
  sessionId: this.sessionId
916
919
  };
@@ -932,8 +935,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
932
935
  };
933
936
  }
934
937
  #formatSchemaIssues(issues) {
935
- return _optionalChain([this, 'access', _22 => _22.#utils, 'optionalAccess', _23 => _23.formatInvalidParamsErrorMessage]) ? this.#utils.formatInvalidParamsErrorMessage(issues) : issues.map((issue) => {
936
- 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";
937
940
  return `${path}: ${issue.message}`;
938
941
  }).join(", ");
939
942
  }
@@ -955,7 +958,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
955
958
  * is bounded and retried, and the result is announced with `rootsChanged`.
956
959
  */
957
960
  async #loadRoots(streamableHttp) {
958
- 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") {
959
962
  return;
960
963
  }
961
964
  const maxAttempts = streamableHttp ? 5 : 1;
@@ -965,7 +968,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
965
968
  void 0,
966
969
  streamableHttp ? { timeout: 1e3 } : void 0
967
970
  );
968
- this.#roots = _optionalChain([roots, 'optionalAccess', _32 => _32.roots]) || [];
971
+ this.#roots = _optionalChain([roots, 'optionalAccess', _37 => _37.roots]) || [];
969
972
  if (streamableHttp) {
970
973
  this.emit("rootsChanged", { roots: this.#roots });
971
974
  }
@@ -1103,7 +1106,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1103
1106
  */
1104
1107
  #startStreamKeepalive(extra, toolName) {
1105
1108
  const config = this.#streamKeepaliveConfig;
1106
- if (!_optionalChain([config, 'optionalAccess', _33 => _33.enabled])) {
1109
+ if (!_optionalChain([config, 'optionalAccess', _38 => _38.enabled])) {
1107
1110
  return () => {
1108
1111
  };
1109
1112
  }
@@ -1123,9 +1126,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1123
1126
  );
1124
1127
  });
1125
1128
  }, intervalMs);
1126
- _optionalChain([timer, 'access', _34 => _34.unref, 'optionalCall', _35 => _35()]);
1129
+ _optionalChain([timer, 'access', _39 => _39.unref, 'optionalCall', _40 => _40()]);
1127
1130
  const stop = () => clearInterval(timer);
1128
- _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 })]);
1129
1132
  return stop;
1130
1133
  }
1131
1134
  async #validateStructuredContent(tool, value, toolName) {
@@ -1345,7 +1348,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1345
1348
  _nullishCoalesce(args, () => ( {})),
1346
1349
  this.#auth,
1347
1350
  this.#createLoadContext(
1348
- _optionalChain([request, 'access', _39 => _39.params, 'optionalAccess', _40 => _40._meta]),
1351
+ _optionalChain([request, 'access', _44 => _44.params, 'optionalAccess', _45 => _45._meta]),
1349
1352
  extra.sendNotification,
1350
1353
  extra.requestId
1351
1354
  )
@@ -1415,7 +1418,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1415
1418
  match,
1416
1419
  this.#auth,
1417
1420
  this.#createLoadContext(
1418
- _optionalChain([request, 'access', _41 => _41.params, 'optionalAccess', _42 => _42._meta]),
1421
+ _optionalChain([request, 'access', _46 => _46.params, 'optionalAccess', _47 => _47._meta]),
1419
1422
  extra.sendNotification,
1420
1423
  extra.requestId
1421
1424
  )
@@ -1445,7 +1448,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1445
1448
  maybeArrayResult = await resource.load(
1446
1449
  this.#auth,
1447
1450
  this.#createLoadContext(
1448
- _optionalChain([request, 'access', _43 => _43.params, 'optionalAccess', _44 => _44._meta]),
1451
+ _optionalChain([request, 'access', _48 => _48.params, 'optionalAccess', _49 => _49._meta]),
1449
1452
  extra.sendNotification,
1450
1453
  extra.requestId
1451
1454
  )
@@ -1511,7 +1514,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1511
1514
  );
1512
1515
  }
1513
1516
  setupRootsHandlers() {
1514
- 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) {
1515
1518
  this.#logger.debug(
1516
1519
  "[FastMCP debug] roots capability explicitly disabled via config"
1517
1520
  );
@@ -1562,8 +1565,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1562
1565
  return {
1563
1566
  annotations: tool.annotations,
1564
1567
  description: tool.description,
1565
- inputSchema: tool.parameters ? _chunkMPFPOZ2Hcjs.strictInputSchema.call(void 0,
1566
- tool.parameters["~standard"].vendor === "zod" && "_zod" in tool.parameters ? _chunkMPFPOZ2Hcjs.zodInputSchema.call(void 0, tool.parameters, "draft-7") : 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)
1567
1570
  ) : {
1568
1571
  additionalProperties: false,
1569
1572
  properties: {},
@@ -1571,8 +1574,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1571
1574
  },
1572
1575
  name: tool.name,
1573
1576
  ...tool.outputSchema && {
1574
- outputSchema: await _xsschema.toJsonSchema.call(void 0,
1575
- tool.outputSchema
1577
+ outputSchema: _chunkT2F3RYH2cjs.objectRootSchema.call(void 0,
1578
+ await _xsschema.toJsonSchema.call(void 0, tool.outputSchema)
1576
1579
  )
1577
1580
  },
1578
1581
  // Pass through _meta for MCP ext-apps UI support (issue #229)
@@ -1608,7 +1611,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1608
1611
  }
1609
1612
  args = parsed.value;
1610
1613
  }
1611
- 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]);
1612
1615
  let result;
1613
1616
  try {
1614
1617
  const reportProgress = async (progress) => {
@@ -1676,7 +1679,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1676
1679
  elicit: this.#createElicit(extra.requestId),
1677
1680
  log,
1678
1681
  reportProgress,
1679
- 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,
1680
1683
  session: this.#auth,
1681
1684
  sessionId: this.sessionId,
1682
1685
  signal,
@@ -1745,10 +1748,22 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1745
1748
  }
1746
1749
  } catch (error) {
1747
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
+ }
1748
1763
  return {
1749
1764
  content: [{ text: error.message, type: "text" }],
1750
1765
  isError: true,
1751
- ...error.extras ? { structuredContent: error.extras } : {}
1766
+ ...structuredContent ? { structuredContent } : {}
1752
1767
  };
1753
1768
  }
1754
1769
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1818,14 +1833,14 @@ function normalizePath(path) {
1818
1833
  return path.startsWith("/") ? path : `/${path}`;
1819
1834
  }
1820
1835
  function parseBasicAuthHeader(authHeader) {
1821
- 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+(.+)$/)]);
1822
1837
  if (!basicMatch) return null;
1823
1838
  try {
1824
1839
  const credentials = Buffer.from(basicMatch[1], "base64").toString("utf-8");
1825
1840
  const credMatch = credentials.match(/^([^:]+):(.*)$/);
1826
1841
  if (!credMatch) return null;
1827
1842
  return { clientId: credMatch[1], clientSecret: credMatch[2] };
1828
- } catch (e5) {
1843
+ } catch (e6) {
1829
1844
  return null;
1830
1845
  }
1831
1846
  }
@@ -1862,7 +1877,7 @@ function protectedResourceMetadataUrl(resource) {
1862
1877
  let url;
1863
1878
  try {
1864
1879
  url = new URL(resource);
1865
- } catch (e6) {
1880
+ } catch (e7) {
1866
1881
  return `${resource}/.well-known/oauth-protected-resource`;
1867
1882
  }
1868
1883
  const path = url.pathname === "/" ? "" : url.pathname;
@@ -1964,7 +1979,9 @@ var FastMCP = class extends FastMCPEventEmitter {
1964
1979
  * Adds a resource to the server.
1965
1980
  */
1966
1981
  addResource(resource) {
1967
- 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
+ );
1968
1985
  this.#resources.push(resource);
1969
1986
  if (this.#serverState === "running" /* Running */) {
1970
1987
  this.#resourcesListChanged(this.#resources);
@@ -1974,13 +1991,12 @@ var FastMCP = class extends FastMCPEventEmitter {
1974
1991
  * Adds resources to the server.
1975
1992
  */
1976
1993
  addResources(resources) {
1977
- const newResourceNames = new Set(
1978
- resources.map((resource) => resource.name)
1979
- );
1980
- this.#resources = this.#resources.filter(
1981
- (r) => !newResourceNames.has(r.name)
1982
- );
1983
- 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
+ }
1984
2000
  if (this.#serverState === "running" /* Running */) {
1985
2001
  this.#resourcesListChanged(this.#resources);
1986
2002
  }
@@ -2028,9 +2044,12 @@ var FastMCP = class extends FastMCPEventEmitter {
2028
2044
  */
2029
2045
  addTools(tools) {
2030
2046
  tools.forEach(assertToolSchemas);
2031
- const newToolNames = new Set(tools.map((tool) => tool.name));
2032
- this.#tools = this.#tools.filter((t) => !newToolNames.has(t.name));
2033
- 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());
2034
2053
  if (this.#serverState === "running" /* Running */) {
2035
2054
  this.#toolsListChanged(this.#tools);
2036
2055
  }
@@ -2332,6 +2351,9 @@ var FastMCP = class extends FastMCPEventEmitter {
2332
2351
  this.#serverState = "running" /* Running */;
2333
2352
  }
2334
2353
  } else if (config.transportType === "httpStream") {
2354
+ if (this.#httpStreamServer) {
2355
+ throw new Error("HTTP server is already running");
2356
+ }
2335
2357
  const httpConfig = config.httpStream;
2336
2358
  const protocol = httpConfig.sslCert || httpConfig.sslKey ? "https" : "http";
2337
2359
  const streamEndpoint = joinPaths(
@@ -2461,6 +2483,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2461
2483
  );
2462
2484
  if (this.#httpStreamServer) {
2463
2485
  await this.#httpStreamServer.close();
2486
+ this.#httpStreamServer = null;
2464
2487
  }
2465
2488
  this.#serverState = "stopped" /* Stopped */;
2466
2489
  }
@@ -2474,9 +2497,9 @@ var FastMCP = class extends FastMCPEventEmitter {
2474
2497
  const originalOnClose = transport.onclose;
2475
2498
  transport.onclose = () => {
2476
2499
  closed = true;
2477
- _optionalChain([onClose, 'optionalCall', _55 => _55()]);
2500
+ _optionalChain([onClose, 'optionalCall', _60 => _60()]);
2478
2501
  this.#removeSession(session);
2479
- _optionalChain([originalOnClose, 'optionalCall', _56 => _56()]);
2502
+ _optionalChain([originalOnClose, 'optionalCall', _61 => _61()]);
2480
2503
  };
2481
2504
  await session.connect(transport);
2482
2505
  if (closed) {
@@ -2541,7 +2564,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2541
2564
  */
2542
2565
  #createUnauthorizedResponse(message) {
2543
2566
  const oauth = this.#options.oauth;
2544
- 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;
2545
2568
  const wwwAuthenticateParts = [
2546
2569
  'error="invalid_token"',
2547
2570
  `error_description="${message.replace(/"/g, '\\"')}"`
@@ -2680,7 +2703,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2680
2703
  }
2681
2704
  }
2682
2705
  const oauthConfig = this.#options.oauth;
2683
- if (_optionalChain([oauthConfig, 'optionalAccess', _60 => _60.enabled]) && req.method === "GET") {
2706
+ if (_optionalChain([oauthConfig, 'optionalAccess', _65 => _65.enabled]) && req.method === "GET") {
2684
2707
  const url2 = new URL(req.url || "", `http://${host}`);
2685
2708
  const authorizationServerMetadataPath = joinPaths(
2686
2709
  "",
@@ -2714,8 +2737,8 @@ var FastMCP = class extends FastMCPEventEmitter {
2714
2737
  }
2715
2738
  }
2716
2739
  }
2717
- const oauthProxy = _optionalChain([oauthConfig, 'optionalAccess', _61 => _61.proxy]);
2718
- 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])) {
2719
2742
  const url2 = new URL(req.url || "", `http://${host}`);
2720
2743
  const oauthPath = basePathRelativePath;
2721
2744
  try {
@@ -2768,7 +2791,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2768
2791
  const statusCode = error.statusCode || 400;
2769
2792
  res.writeHead(statusCode, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(
2770
2793
  JSON.stringify(
2771
- _optionalChain([error, 'access', _63 => _63.toJSON, 'optionalCall', _64 => _64()]) || {
2794
+ _optionalChain([error, 'access', _68 => _68.toJSON, 'optionalCall', _69 => _69()]) || {
2772
2795
  error: "invalid_request"
2773
2796
  }
2774
2797
  )
@@ -2795,7 +2818,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2795
2818
  } catch (error) {
2796
2819
  res.writeHead(400, { "Content-Type": "application/json" }).end(
2797
2820
  JSON.stringify(
2798
- _optionalChain([error, 'access', _65 => _65.toJSON, 'optionalCall', _66 => _66()]) || {
2821
+ _optionalChain([error, 'access', _70 => _70.toJSON, 'optionalCall', _71 => _71()]) || {
2799
2822
  error: "invalid_request"
2800
2823
  }
2801
2824
  )
@@ -2817,7 +2840,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2817
2840
  } catch (error) {
2818
2841
  res.writeHead(400, { "Content-Type": "application/json" }).end(
2819
2842
  JSON.stringify(
2820
- _optionalChain([error, 'access', _67 => _67.toJSON, 'optionalCall', _68 => _68()]) || {
2843
+ _optionalChain([error, 'access', _72 => _72.toJSON, 'optionalCall', _73 => _73()]) || {
2821
2844
  error: "server_error"
2822
2845
  }
2823
2846
  )
@@ -2886,7 +2909,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2886
2909
  } catch (error) {
2887
2910
  res.writeHead(400, { "Content-Type": "application/json" }).end(
2888
2911
  JSON.stringify(
2889
- _optionalChain([error, 'access', _69 => _69.toJSON, 'optionalCall', _70 => _70()]) || {
2912
+ _optionalChain([error, 'access', _74 => _74.toJSON, 'optionalCall', _75 => _75()]) || {
2890
2913
  error: "server_error"
2891
2914
  }
2892
2915
  )
@@ -2944,8 +2967,8 @@ var FastMCP = class extends FastMCPEventEmitter {
2944
2967
  const basicAuth = parseBasicAuthHeader(
2945
2968
  req.headers.authorization
2946
2969
  );
2947
- const clientId = _optionalChain([basicAuth, 'optionalAccess', _71 => _71.clientId]) || params.get("client_id") || "";
2948
- 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));
2949
2972
  let response;
2950
2973
  if (grantType === "authorization_code") {
2951
2974
  response = await oauthProxy.exchangeAuthorizationCode({
@@ -2975,7 +2998,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2975
2998
  const statusCode = error.statusCode || 400;
2976
2999
  res.writeHead(statusCode, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(
2977
3000
  JSON.stringify(
2978
- _optionalChain([error, 'access', _73 => _73.toJSON, 'optionalCall', _74 => _74()]) || {
3001
+ _optionalChain([error, 'access', _78 => _78.toJSON, 'optionalCall', _79 => _79()]) || {
2979
3002
  error: "invalid_request"
2980
3003
  }
2981
3004
  )
@@ -3001,7 +3024,7 @@ var FastMCP = class extends FastMCPEventEmitter {
3001
3024
  * regardless (RFC 7235), so no config is needed just to get the header.
3002
3025
  */
3003
3026
  #httpStreamOAuthConfig() {
3004
- 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;
3005
3028
  if (!resource) {
3006
3029
  return {};
3007
3030
  }
@@ -3109,24 +3132,24 @@ var FastMCP = class extends FastMCPEventEmitter {
3109
3132
  const envBasePath = process.env.FASTMCP_BASE_PATH;
3110
3133
  const envStateless = process.env.FASTMCP_STATELESS;
3111
3134
  const envHost = process.env.FASTMCP_HOST;
3112
- 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";
3113
3136
  if (transportType === "httpStream") {
3114
3137
  const port = parseInt(
3115
- _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"
3116
3139
  );
3117
- const host = _optionalChain([overrides, 'optionalAccess', _87 => _87.httpStream, 'optionalAccess', _88 => _88.host]) || hostArg || envHost || "localhost";
3118
- 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";
3119
3142
  const basePath = normalizeBasePath(
3120
- _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
3121
3144
  );
3122
- const enableJsonResponse = _optionalChain([overrides, 'optionalAccess', _93 => _93.httpStream, 'optionalAccess', _94 => _94.enableJsonResponse]) || false;
3123
- 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`.
3124
3147
  (statelessArg === "" ? true : parseBooleanSetting(statelessArg, "--stateless")))), () => ( parseBooleanSetting(envStateless, "FASTMCP_STATELESS"))), () => ( false));
3125
- const cors = _optionalChain([overrides, 'optionalAccess', _97 => _97.httpStream, 'optionalAccess', _98 => _98.cors]);
3126
- const eventStore = _optionalChain([overrides, 'optionalAccess', _99 => _99.httpStream, 'optionalAccess', _100 => _100.eventStore]);
3127
- const sslCa = _optionalChain([overrides, 'optionalAccess', _101 => _101.httpStream, 'optionalAccess', _102 => _102.sslCa]);
3128
- const sslCert = _optionalChain([overrides, 'optionalAccess', _103 => _103.httpStream, 'optionalAccess', _104 => _104.sslCert]);
3129
- 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]);
3130
3153
  return {
3131
3154
  httpStream: {
3132
3155
  basePath,
@@ -3218,7 +3241,7 @@ var FastMCP = class extends FastMCPEventEmitter {
3218
3241
  */
3219
3242
  #useEndpointAsResource(endpoint) {
3220
3243
  const oauth = this.#options.oauth;
3221
- if (this.#providerResourceBase === void 0 || !_optionalChain([oauth, 'optionalAccess', _107 => _107.protectedResource]))
3244
+ if (this.#providerResourceBase === void 0 || !_optionalChain([oauth, 'optionalAccess', _112 => _112.protectedResource]))
3222
3245
  return;
3223
3246
  this.#options = {
3224
3247
  ...this.#options,
@@ -3247,4 +3270,4 @@ var FastMCP = class extends FastMCPEventEmitter {
3247
3270
 
3248
3271
 
3249
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;
3250
- //# sourceMappingURL=chunk-TBMRFQ6M.cjs.map
3273
+ //# sourceMappingURL=chunk-XEP3OP7Q.cjs.map