fastmcp 4.23.8 → 4.23.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FastMCP.cjs +4 -4
- package/dist/FastMCP.d.cts +2 -1
- package/dist/FastMCP.d.ts +2 -1
- package/dist/FastMCP.js +3 -3
- package/dist/auth/index.cjs +2 -2
- package/dist/auth/index.js +1 -1
- package/dist/{chunk-AJRXMUZR.cjs → chunk-4OWHPJEL.cjs} +9 -2
- package/dist/chunk-4OWHPJEL.cjs.map +1 -0
- package/dist/{chunk-T2F3RYH2.cjs → chunk-6TDYSPLC.cjs} +3 -3
- package/dist/chunk-6TDYSPLC.cjs.map +1 -0
- package/dist/{chunk-XEP3OP7Q.cjs → chunk-B77E3EDN.cjs} +164 -93
- package/dist/chunk-B77E3EDN.cjs.map +1 -0
- package/dist/{chunk-PLUAEIWE.js → chunk-EHTAPWBU.js} +118 -47
- package/dist/chunk-EHTAPWBU.js.map +1 -0
- package/dist/{chunk-UY253ACS.js → chunk-G44SPVP7.js} +9 -2
- package/dist/chunk-G44SPVP7.js.map +1 -0
- package/dist/{chunk-F76U45MT.js → chunk-OKKFL2M4.js} +3 -3
- package/dist/chunk-OKKFL2M4.js.map +1 -0
- package/dist/edge/index.cjs +8 -4
- package/dist/edge/index.cjs.map +1 -1
- package/dist/edge/index.js +6 -2
- package/dist/edge/index.js.map +1 -1
- package/dist/examples/custom-routes.cjs +4 -4
- package/dist/examples/custom-routes.js +3 -3
- package/dist/openapi/index.cjs +8 -8
- package/dist/openapi/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-AJRXMUZR.cjs.map +0 -1
- package/dist/chunk-F76U45MT.js.map +0 -1
- package/dist/chunk-PLUAEIWE.js.map +0 -1
- package/dist/chunk-T2F3RYH2.cjs.map +0 -1
- package/dist/chunk-UY253ACS.js.map +0 -1
- package/dist/chunk-XEP3OP7Q.cjs.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cancelResponseBody
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-G44SPVP7.js";
|
|
4
4
|
import {
|
|
5
5
|
objectRootSchema,
|
|
6
6
|
strictInputSchema,
|
|
7
7
|
zodInputSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OKKFL2M4.js";
|
|
9
9
|
|
|
10
10
|
// src/FastMCP.ts
|
|
11
11
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -189,9 +189,16 @@ function jsonSchemaAdapter(schema) {
|
|
|
189
189
|
async function compileSchema(schema) {
|
|
190
190
|
const dialect = schema.$schema?.replace(/^http:\/\//, "https://").replace(/#$/, "");
|
|
191
191
|
const isDraft2020 = dialect === "https://json-schema.org/draft/2020-12/schema";
|
|
192
|
+
const isDraft2019 = dialect === "https://json-schema.org/draft/2019-09/schema";
|
|
192
193
|
let ajvModule;
|
|
193
194
|
try {
|
|
194
|
-
|
|
195
|
+
if (isDraft2020) {
|
|
196
|
+
ajvModule = await import("ajv/dist/2020.js");
|
|
197
|
+
} else if (isDraft2019) {
|
|
198
|
+
ajvModule = await import("ajv/dist/2019.js");
|
|
199
|
+
} else {
|
|
200
|
+
ajvModule = await import("ajv");
|
|
201
|
+
}
|
|
195
202
|
} catch {
|
|
196
203
|
throw new Error(
|
|
197
204
|
'The "ajv" package is required to validate JSON Schema tool parameters. Install it with: npm install ajv'
|
|
@@ -207,7 +214,9 @@ async function compileSchema(schema) {
|
|
|
207
214
|
addFormats(ajv);
|
|
208
215
|
} catch {
|
|
209
216
|
}
|
|
210
|
-
return ajv.compile(
|
|
217
|
+
return ajv.compile(
|
|
218
|
+
isDraft2020 || isDraft2019 ? { ...schema, $schema: dialect } : schema
|
|
219
|
+
);
|
|
211
220
|
}
|
|
212
221
|
function toIssue(error) {
|
|
213
222
|
const path = error.instancePath.split("/").slice(1).map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~")).map((segment) => {
|
|
@@ -490,6 +499,28 @@ var ServerState = /* @__PURE__ */ ((ServerState2) => {
|
|
|
490
499
|
})(ServerState || {});
|
|
491
500
|
var FastMCPSessionEventEmitter = class extends FastMCPSessionEventEmitterBase {
|
|
492
501
|
};
|
|
502
|
+
var lazyRequestBody = (req) => {
|
|
503
|
+
let iterator;
|
|
504
|
+
return new ReadableStream(
|
|
505
|
+
{
|
|
506
|
+
async cancel(reason) {
|
|
507
|
+
await iterator?.return?.(reason);
|
|
508
|
+
},
|
|
509
|
+
async pull(controller) {
|
|
510
|
+
iterator ??= req[Symbol.asyncIterator]();
|
|
511
|
+
const { done, value } = await iterator.next();
|
|
512
|
+
if (done) {
|
|
513
|
+
controller.close();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
controller.enqueue(
|
|
517
|
+
typeof value === "string" ? Buffer.from(value) : new Uint8Array(value)
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
{ highWaterMark: 0 }
|
|
522
|
+
);
|
|
523
|
+
};
|
|
493
524
|
var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
494
525
|
get clientCapabilities() {
|
|
495
526
|
return this.#clientCapabilities ?? null;
|
|
@@ -936,7 +967,11 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
936
967
|
}
|
|
937
968
|
#formatSchemaIssues(issues) {
|
|
938
969
|
return this.#utils?.formatInvalidParamsErrorMessage ? this.#utils.formatInvalidParamsErrorMessage(issues) : issues.map((issue) => {
|
|
939
|
-
const path = issue.path?.
|
|
970
|
+
const path = issue.path?.map(
|
|
971
|
+
(segment) => String(
|
|
972
|
+
typeof segment === "object" && segment !== null ? segment.key : segment
|
|
973
|
+
)
|
|
974
|
+
).join(".") || "root";
|
|
940
975
|
return `${path}: ${issue.message}`;
|
|
941
976
|
}).join(", ");
|
|
942
977
|
}
|
|
@@ -950,7 +985,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
950
985
|
};
|
|
951
986
|
}
|
|
952
987
|
/**
|
|
953
|
-
* Fetches the client's roots if it advertised `roots.
|
|
988
|
+
* Fetches the client's roots if it advertised the `roots` capability.
|
|
954
989
|
*
|
|
955
990
|
* Over Streamable HTTP a server-initiated request travels on the client's
|
|
956
991
|
* standalone GET stream, which the client opens only after initialization,
|
|
@@ -958,7 +993,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
958
993
|
* is bounded and retried, and the result is announced with `rootsChanged`.
|
|
959
994
|
*/
|
|
960
995
|
async #loadRoots(streamableHttp) {
|
|
961
|
-
if (this.#rootsConfig?.enabled === false || !this.#clientCapabilities?.roots
|
|
996
|
+
if (this.#rootsConfig?.enabled === false || !this.#clientCapabilities?.roots || typeof this.#server.listRoots !== "function") {
|
|
962
997
|
return;
|
|
963
998
|
}
|
|
964
999
|
const maxAttempts = streamableHttp ? 5 : 1;
|
|
@@ -1106,7 +1141,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1106
1141
|
*/
|
|
1107
1142
|
#startStreamKeepalive(extra, toolName) {
|
|
1108
1143
|
const config = this.#streamKeepaliveConfig;
|
|
1109
|
-
if (!config?.enabled) {
|
|
1144
|
+
if (!config?.enabled || extra.signal?.aborted) {
|
|
1110
1145
|
return () => {
|
|
1111
1146
|
};
|
|
1112
1147
|
}
|
|
@@ -1127,7 +1162,10 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1127
1162
|
});
|
|
1128
1163
|
}, intervalMs);
|
|
1129
1164
|
timer.unref?.();
|
|
1130
|
-
const stop = () =>
|
|
1165
|
+
const stop = () => {
|
|
1166
|
+
clearInterval(timer);
|
|
1167
|
+
extra.signal?.removeEventListener("abort", stop);
|
|
1168
|
+
};
|
|
1131
1169
|
extra.signal?.addEventListener("abort", stop, { once: true });
|
|
1132
1170
|
return stop;
|
|
1133
1171
|
}
|
|
@@ -1613,13 +1651,33 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1613
1651
|
}
|
|
1614
1652
|
const progressToken = request.params?._meta?.progressToken;
|
|
1615
1653
|
let result;
|
|
1654
|
+
const timeoutAbort = new AbortController();
|
|
1655
|
+
const signal = AbortSignal.any([
|
|
1656
|
+
timeoutAbort.signal,
|
|
1657
|
+
this.#abortController.signal,
|
|
1658
|
+
// Only ever aborted for an explicit `notifications/cancelled`; the
|
|
1659
|
+
// session signal above is what covers a client that simply left.
|
|
1660
|
+
...extra.signal ? [extra.signal] : []
|
|
1661
|
+
]);
|
|
1662
|
+
const sendNotification = async (notification) => {
|
|
1663
|
+
if (signal.aborted) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
try {
|
|
1667
|
+
await extra.sendNotification(notification);
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
if (!signal.aborted) {
|
|
1670
|
+
throw error;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1616
1674
|
try {
|
|
1617
1675
|
const reportProgress = async (progress) => {
|
|
1618
1676
|
if (progressToken === void 0) {
|
|
1619
1677
|
return;
|
|
1620
1678
|
}
|
|
1621
1679
|
try {
|
|
1622
|
-
await
|
|
1680
|
+
await sendNotification({
|
|
1623
1681
|
method: "notifications/progress",
|
|
1624
1682
|
params: {
|
|
1625
1683
|
...progress,
|
|
@@ -1636,11 +1694,11 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1636
1694
|
);
|
|
1637
1695
|
}
|
|
1638
1696
|
};
|
|
1639
|
-
const log = this.#createLog(
|
|
1697
|
+
const log = this.#createLog(sendNotification);
|
|
1640
1698
|
const streamContent = async (content) => {
|
|
1641
1699
|
const contentArray = Array.isArray(content) ? content : [content];
|
|
1642
1700
|
try {
|
|
1643
|
-
await
|
|
1701
|
+
await sendNotification({
|
|
1644
1702
|
method: "notifications/tool/streamContent",
|
|
1645
1703
|
params: {
|
|
1646
1704
|
content: contentArray,
|
|
@@ -1663,14 +1721,6 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1663
1721
|
toolName: request.params.name
|
|
1664
1722
|
});
|
|
1665
1723
|
}
|
|
1666
|
-
const timeoutAbort = new AbortController();
|
|
1667
|
-
const signal = AbortSignal.any([
|
|
1668
|
-
timeoutAbort.signal,
|
|
1669
|
-
this.#abortController.signal,
|
|
1670
|
-
// Only ever aborted for an explicit `notifications/cancelled`; the
|
|
1671
|
-
// session signal above is what covers a client that simply left.
|
|
1672
|
-
...extra.signal ? [extra.signal] : []
|
|
1673
|
-
]);
|
|
1674
1724
|
const executeToolPromise = Promise.resolve(
|
|
1675
1725
|
tool.execute(args, {
|
|
1676
1726
|
client: {
|
|
@@ -1687,25 +1737,37 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1687
1737
|
})
|
|
1688
1738
|
);
|
|
1689
1739
|
const stopStreamKeepalive = this.#startStreamKeepalive(
|
|
1690
|
-
|
|
1740
|
+
{ sendNotification, signal },
|
|
1691
1741
|
request.params.name
|
|
1692
1742
|
);
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1743
|
+
let timeoutId;
|
|
1744
|
+
let stopWaitingForAbort = () => {
|
|
1745
|
+
};
|
|
1746
|
+
const aborted = new Promise((_, reject) => {
|
|
1747
|
+
const onAbort = () => reject(signal.reason);
|
|
1748
|
+
stopWaitingForAbort = () => signal.removeEventListener("abort", onAbort);
|
|
1749
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1750
|
+
if (signal.aborted) {
|
|
1751
|
+
onAbort();
|
|
1752
|
+
}
|
|
1753
|
+
});
|
|
1754
|
+
if (tool.timeoutMs && !signal.aborted) {
|
|
1755
|
+
timeoutId = setTimeout(() => {
|
|
1756
|
+
timeoutAbort.abort(
|
|
1757
|
+
new UserError(
|
|
1698
1758
|
`Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`
|
|
1699
|
-
)
|
|
1700
|
-
timeoutAbort.abort(timedOut);
|
|
1701
|
-
reject(timedOut);
|
|
1702
|
-
}, tool.timeoutMs);
|
|
1703
|
-
executeToolPromise.then(
|
|
1704
|
-
() => clearTimeout(timeoutId),
|
|
1705
|
-
() => clearTimeout(timeoutId)
|
|
1759
|
+
)
|
|
1706
1760
|
);
|
|
1707
|
-
})
|
|
1708
|
-
|
|
1761
|
+
}, tool.timeoutMs);
|
|
1762
|
+
}
|
|
1763
|
+
const maybeStringResult = await Promise.race([
|
|
1764
|
+
executeToolPromise,
|
|
1765
|
+
aborted
|
|
1766
|
+
]).finally(() => {
|
|
1767
|
+
clearTimeout(timeoutId);
|
|
1768
|
+
stopWaitingForAbort();
|
|
1769
|
+
stopStreamKeepalive();
|
|
1770
|
+
});
|
|
1709
1771
|
await delay(1);
|
|
1710
1772
|
if (maybeStringResult === void 0 || maybeStringResult === null) {
|
|
1711
1773
|
result = ContentResultZodSchema.parse({
|
|
@@ -1746,6 +1808,11 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1746
1808
|
} else {
|
|
1747
1809
|
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
1748
1810
|
}
|
|
1811
|
+
if (tool.outputSchema && result.structuredContent === void 0 && !result.isError) {
|
|
1812
|
+
throw new UserError(
|
|
1813
|
+
`Tool '${request.params.name}' returned no structured content. Please return a value that matches the tool's outputSchema.`
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1749
1816
|
} catch (error) {
|
|
1750
1817
|
if (error instanceof UserError) {
|
|
1751
1818
|
let structuredContent = error.extras;
|
|
@@ -2017,13 +2084,12 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
2017
2084
|
* Adds resource templates to the server.
|
|
2018
2085
|
*/
|
|
2019
2086
|
addResourceTemplates(resources) {
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
this.#resourcesTemplates.push(...resources);
|
|
2087
|
+
for (const resource of resources) {
|
|
2088
|
+
this.#resourcesTemplates = this.#resourcesTemplates.filter(
|
|
2089
|
+
(template) => template.name !== resource.name
|
|
2090
|
+
);
|
|
2091
|
+
this.#resourcesTemplates.push(resource);
|
|
2092
|
+
}
|
|
2027
2093
|
if (this.#serverState === "running" /* Running */) {
|
|
2028
2094
|
this.#resourceTemplatesListChanged(this.#resourcesTemplates);
|
|
2029
2095
|
}
|
|
@@ -2280,6 +2346,13 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
2280
2346
|
async start(options) {
|
|
2281
2347
|
const config = this.#parseRuntimeConfig(options);
|
|
2282
2348
|
if (config.transportType === "stdio") {
|
|
2349
|
+
const logger = this.#options.logger ?? {
|
|
2350
|
+
debug: (...args) => console.error(...args),
|
|
2351
|
+
error: (...args) => console.error(...args),
|
|
2352
|
+
info: (...args) => console.error(...args),
|
|
2353
|
+
log: (...args) => console.error(...args),
|
|
2354
|
+
warn: (...args) => console.warn(...args)
|
|
2355
|
+
};
|
|
2283
2356
|
const transport = new StdioServerTransport();
|
|
2284
2357
|
let auth;
|
|
2285
2358
|
const authRequired = this.#authenticate !== void 0;
|
|
@@ -2306,7 +2379,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
2306
2379
|
hasTools: this.#tools.length > 0,
|
|
2307
2380
|
icons: this.#options.icons,
|
|
2308
2381
|
instructions: this.#options.instructions,
|
|
2309
|
-
logger
|
|
2382
|
+
logger,
|
|
2310
2383
|
name: this.#options.name,
|
|
2311
2384
|
onToolCall: this.#options.onToolCall,
|
|
2312
2385
|
ping: this.#options.ping,
|
|
@@ -3090,9 +3163,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
3090
3163
|
const hasBody = method !== "GET" && method !== "HEAD";
|
|
3091
3164
|
if (hasBody) {
|
|
3092
3165
|
return new Request(url.toString(), {
|
|
3093
|
-
|
|
3094
|
-
body: req,
|
|
3095
|
-
// Node.js IncomingMessage is readable stream
|
|
3166
|
+
body: lazyRequestBody(req),
|
|
3096
3167
|
duplex: "half",
|
|
3097
3168
|
// Required for streaming bodies
|
|
3098
3169
|
headers,
|
|
@@ -3270,4 +3341,4 @@ export {
|
|
|
3270
3341
|
FastMCPSession,
|
|
3271
3342
|
FastMCP
|
|
3272
3343
|
};
|
|
3273
|
-
//# sourceMappingURL=chunk-
|
|
3344
|
+
//# sourceMappingURL=chunk-EHTAPWBU.js.map
|