fastmcp 4.13.1 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/FastMCP.cjs +2 -2
- package/dist/FastMCP.d.cts +32 -1
- package/dist/FastMCP.d.ts +32 -1
- package/dist/FastMCP.js +1 -1
- package/dist/{chunk-3BMGHXXY.js → chunk-LMDMFMPI.js} +196 -142
- package/dist/chunk-LMDMFMPI.js.map +1 -0
- package/dist/{chunk-O72VCMGV.cjs → chunk-XK5NJ5W2.cjs} +226 -172
- package/dist/chunk-XK5NJ5W2.cjs.map +1 -0
- package/dist/examples/custom-routes.cjs +2 -2
- package/dist/examples/custom-routes.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3BMGHXXY.js.map +0 -1
- package/dist/chunk-O72VCMGV.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -903,6 +903,52 @@ By default, ping behavior is optimized for each transport type:
|
|
|
903
903
|
|
|
904
904
|
This configurable approach helps reduce log verbosity and optimize performance for different usage scenarios.
|
|
905
905
|
|
|
906
|
+
#### Keeping Long Tool Calls Alive (`streamKeepalive`)
|
|
907
|
+
|
|
908
|
+
Pings travel on the standalone server-to-client stream, so they never keep an
|
|
909
|
+
individual tool call's connection open — and in `stateless` mode that stream does
|
|
910
|
+
not exist at all. A tool that runs for minutes without producing output leaves
|
|
911
|
+
its response connection silent, and an idle-connection timeout in front of the
|
|
912
|
+
server (AWS ALB defaults to 60 seconds) closes it before the result is written.
|
|
913
|
+
|
|
914
|
+
This applies to **both** session modes. A stateful deployment keeps its
|
|
915
|
+
standalone stream warm with pings while the connection carrying the tool call
|
|
916
|
+
goes idle and is closed anyway; stateless has no standalone stream to begin
|
|
917
|
+
with.
|
|
918
|
+
|
|
919
|
+
`streamKeepalive` writes periodically to the in-flight tool call's own response
|
|
920
|
+
stream, which is the connection that would otherwise be closed. It is opt-in:
|
|
921
|
+
|
|
922
|
+
```ts
|
|
923
|
+
const server = new FastMCP({
|
|
924
|
+
name: "My Server",
|
|
925
|
+
version: "1.0.0",
|
|
926
|
+
streamKeepalive: {
|
|
927
|
+
// Opt in; disabled by default
|
|
928
|
+
enabled: true,
|
|
929
|
+
// Keep comfortably below the shortest idle timeout on the path
|
|
930
|
+
intervalMs: 20000,
|
|
931
|
+
},
|
|
932
|
+
});
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
Each keepalive is a `notifications/message` (level configurable via `logLevel`,
|
|
936
|
+
default `debug`) tagged with the logger `fastmcp-keepalive`, related to the tool
|
|
937
|
+
call being served. Keepalives start when a tool begins executing and stop when
|
|
938
|
+
the request stops waiting for it — on success, error, timeout, or client
|
|
939
|
+
cancellation — so idle connections stay quiet. Because the messages are related
|
|
940
|
+
to the request, this works in stateful and `stateless` mode alike, and needs no
|
|
941
|
+
client support beyond the standard logging notification.
|
|
942
|
+
|
|
943
|
+
Limits worth knowing:
|
|
944
|
+
|
|
945
|
+
- It has no effect with `httpStream.enableJsonResponse`, which buffers a single
|
|
946
|
+
JSON reply instead of streaming, so there is no open stream to write to.
|
|
947
|
+
- It only covers tool calls. Other long-running requests (`resources/read`,
|
|
948
|
+
`prompts/get`) still write nothing until they finish.
|
|
949
|
+
- On `stdio` there is no proxy to keep alive, so enabling it there only adds
|
|
950
|
+
notification traffic.
|
|
951
|
+
|
|
906
952
|
### Health-check Endpoint
|
|
907
953
|
|
|
908
954
|
When you run FastMCP with the `httpStream` transport you can optionally expose a
|
package/dist/FastMCP.cjs
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
var
|
|
14
|
+
var _chunkXK5NJ5W2cjs = require('./chunk-XK5NJ5W2.cjs');
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
@@ -49,5 +49,5 @@ var _chunk5FVNY65Mcjs = require('./chunk-5FVNY65M.cjs');
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
exports.AuthProvider = _chunk5FVNY65Mcjs.AuthProvider; exports.AzureProvider = _chunk5FVNY65Mcjs.AzureProvider; exports.DiscoveryDocumentCache =
|
|
52
|
+
exports.AuthProvider = _chunk5FVNY65Mcjs.AuthProvider; exports.AzureProvider = _chunk5FVNY65Mcjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkXK5NJ5W2cjs.DiscoveryDocumentCache; exports.FastMCP = _chunkXK5NJ5W2cjs.FastMCP; exports.FastMCPError = _chunkXK5NJ5W2cjs.FastMCPError; exports.FastMCPSession = _chunkXK5NJ5W2cjs.FastMCPSession; exports.GitHubProvider = _chunk5FVNY65Mcjs.GitHubProvider; exports.GoogleProvider = _chunk5FVNY65Mcjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunkXK5NJ5W2cjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunk5FVNY65Mcjs.OAuthProvider; exports.ServerState = _chunkXK5NJ5W2cjs.ServerState; exports.SessionError = _chunkXK5NJ5W2cjs.SessionError; exports.UnexpectedStateError = _chunkXK5NJ5W2cjs.UnexpectedStateError; exports.UserError = _chunkXK5NJ5W2cjs.UserError; exports.audioContent = _chunkXK5NJ5W2cjs.audioContent; exports.getAuthSession = _chunk5FVNY65Mcjs.getAuthSession; exports.imageContent = _chunkXK5NJ5W2cjs.imageContent; exports.jsonSchemaAdapter = _chunkXK5NJ5W2cjs.jsonSchemaAdapter; exports.requireAll = _chunk5FVNY65Mcjs.requireAll; exports.requireAny = _chunk5FVNY65Mcjs.requireAny; exports.requireAuth = _chunk5FVNY65Mcjs.requireAuth; exports.requireRole = _chunk5FVNY65Mcjs.requireRole; exports.requireScopes = _chunk5FVNY65Mcjs.requireScopes;
|
|
53
53
|
//# sourceMappingURL=FastMCP.cjs.map
|
package/dist/FastMCP.d.cts
CHANGED
|
@@ -697,6 +697,36 @@ type ServerOptions<T extends FastMCPSessionAuth> = {
|
|
|
697
697
|
*/
|
|
698
698
|
enabled?: boolean;
|
|
699
699
|
};
|
|
700
|
+
/**
|
|
701
|
+
* Writes periodically to an in-flight tool call's own response stream, so a
|
|
702
|
+
* proxy or load balancer does not close the connection as idle while a
|
|
703
|
+
* long-running tool produces no output.
|
|
704
|
+
*
|
|
705
|
+
* Unlike {@link ServerOptions.ping}, these messages are related to the
|
|
706
|
+
* request being served, so they travel on that request's stream instead of
|
|
707
|
+
* the standalone server-to-client stream. That makes them the only option
|
|
708
|
+
* that works with `httpStream.stateless`, where no standing server-to-client
|
|
709
|
+
* stream exists.
|
|
710
|
+
*/
|
|
711
|
+
streamKeepalive?: {
|
|
712
|
+
/**
|
|
713
|
+
* Whether to write keepalives. Opt-in.
|
|
714
|
+
* @default false
|
|
715
|
+
*/
|
|
716
|
+
enabled?: boolean;
|
|
717
|
+
/**
|
|
718
|
+
* Interval between keepalives. Keep it comfortably below the shortest idle
|
|
719
|
+
* timeout on the path (AWS ALB defaults to 60s). Values below 1ms fall back
|
|
720
|
+
* to the default.
|
|
721
|
+
* @default 20000 (20s)
|
|
722
|
+
*/
|
|
723
|
+
intervalMs?: number;
|
|
724
|
+
/**
|
|
725
|
+
* Level reported on the keepalive notification.
|
|
726
|
+
* @default 'debug'
|
|
727
|
+
*/
|
|
728
|
+
logLevel?: LoggingLevel;
|
|
729
|
+
};
|
|
700
730
|
/**
|
|
701
731
|
* General utilities
|
|
702
732
|
*/
|
|
@@ -840,7 +870,7 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
|
|
|
840
870
|
get server(): Server;
|
|
841
871
|
get sessionId(): string | undefined;
|
|
842
872
|
set sessionId(value: string | undefined);
|
|
843
|
-
constructor({ auth, instructions, logger, name, onToolCall, ping, prompts, resources, resourcesTemplates, roots, sessionId, stateless, tools, transportType, utils, version, }: {
|
|
873
|
+
constructor({ auth, instructions, logger, name, onToolCall, ping, prompts, resources, resourcesTemplates, roots, sessionId, stateless, streamKeepalive, tools, transportType, utils, version, }: {
|
|
844
874
|
auth?: T;
|
|
845
875
|
instructions?: string;
|
|
846
876
|
logger: Logger;
|
|
@@ -853,6 +883,7 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
|
|
|
853
883
|
roots?: ServerOptions<T>["roots"];
|
|
854
884
|
sessionId?: string;
|
|
855
885
|
stateless?: boolean;
|
|
886
|
+
streamKeepalive?: ServerOptions<T>["streamKeepalive"];
|
|
856
887
|
tools: Tool<T>[];
|
|
857
888
|
transportType?: "httpStream" | "stdio";
|
|
858
889
|
utils?: ServerOptions<T>["utils"];
|
package/dist/FastMCP.d.ts
CHANGED
|
@@ -697,6 +697,36 @@ type ServerOptions<T extends FastMCPSessionAuth> = {
|
|
|
697
697
|
*/
|
|
698
698
|
enabled?: boolean;
|
|
699
699
|
};
|
|
700
|
+
/**
|
|
701
|
+
* Writes periodically to an in-flight tool call's own response stream, so a
|
|
702
|
+
* proxy or load balancer does not close the connection as idle while a
|
|
703
|
+
* long-running tool produces no output.
|
|
704
|
+
*
|
|
705
|
+
* Unlike {@link ServerOptions.ping}, these messages are related to the
|
|
706
|
+
* request being served, so they travel on that request's stream instead of
|
|
707
|
+
* the standalone server-to-client stream. That makes them the only option
|
|
708
|
+
* that works with `httpStream.stateless`, where no standing server-to-client
|
|
709
|
+
* stream exists.
|
|
710
|
+
*/
|
|
711
|
+
streamKeepalive?: {
|
|
712
|
+
/**
|
|
713
|
+
* Whether to write keepalives. Opt-in.
|
|
714
|
+
* @default false
|
|
715
|
+
*/
|
|
716
|
+
enabled?: boolean;
|
|
717
|
+
/**
|
|
718
|
+
* Interval between keepalives. Keep it comfortably below the shortest idle
|
|
719
|
+
* timeout on the path (AWS ALB defaults to 60s). Values below 1ms fall back
|
|
720
|
+
* to the default.
|
|
721
|
+
* @default 20000 (20s)
|
|
722
|
+
*/
|
|
723
|
+
intervalMs?: number;
|
|
724
|
+
/**
|
|
725
|
+
* Level reported on the keepalive notification.
|
|
726
|
+
* @default 'debug'
|
|
727
|
+
*/
|
|
728
|
+
logLevel?: LoggingLevel;
|
|
729
|
+
};
|
|
700
730
|
/**
|
|
701
731
|
* General utilities
|
|
702
732
|
*/
|
|
@@ -840,7 +870,7 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
|
|
|
840
870
|
get server(): Server;
|
|
841
871
|
get sessionId(): string | undefined;
|
|
842
872
|
set sessionId(value: string | undefined);
|
|
843
|
-
constructor({ auth, instructions, logger, name, onToolCall, ping, prompts, resources, resourcesTemplates, roots, sessionId, stateless, tools, transportType, utils, version, }: {
|
|
873
|
+
constructor({ auth, instructions, logger, name, onToolCall, ping, prompts, resources, resourcesTemplates, roots, sessionId, stateless, streamKeepalive, tools, transportType, utils, version, }: {
|
|
844
874
|
auth?: T;
|
|
845
875
|
instructions?: string;
|
|
846
876
|
logger: Logger;
|
|
@@ -853,6 +883,7 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
|
|
|
853
883
|
roots?: ServerOptions<T>["roots"];
|
|
854
884
|
sessionId?: string;
|
|
855
885
|
stateless?: boolean;
|
|
886
|
+
streamKeepalive?: ServerOptions<T>["streamKeepalive"];
|
|
856
887
|
tools: Tool<T>[];
|
|
857
888
|
transportType?: "httpStream" | "stdio";
|
|
858
889
|
utils?: ServerOptions<T>["utils"];
|
package/dist/FastMCP.js
CHANGED
|
@@ -355,6 +355,8 @@ function assertToolSchemas(tool) {
|
|
|
355
355
|
assertStandardSchema(tool.name, "outputSchema", tool.outputSchema);
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
|
+
var STREAM_KEEPALIVE_LOGGER = "fastmcp-keepalive";
|
|
359
|
+
var STREAM_KEEPALIVE_DEFAULT_INTERVAL_MS = 2e4;
|
|
358
360
|
var TextContentZodSchema = z.object({
|
|
359
361
|
/**
|
|
360
362
|
* The text content of the message.
|
|
@@ -483,6 +485,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
483
485
|
* instance — so capabilities can never be inferred here.
|
|
484
486
|
*/
|
|
485
487
|
#stateless;
|
|
488
|
+
#streamKeepaliveConfig;
|
|
486
489
|
/**
|
|
487
490
|
* Resource URIs the connected client has subscribed to via
|
|
488
491
|
* `resources/subscribe`. Used to scope `notifications/resources/updated`
|
|
@@ -503,6 +506,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
503
506
|
roots,
|
|
504
507
|
sessionId,
|
|
505
508
|
stateless = false,
|
|
509
|
+
streamKeepalive,
|
|
506
510
|
tools,
|
|
507
511
|
transportType,
|
|
508
512
|
utils,
|
|
@@ -516,6 +520,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
516
520
|
this.#rootsConfig = roots;
|
|
517
521
|
this.#sessionId = sessionId;
|
|
518
522
|
this.#stateless = stateless;
|
|
523
|
+
this.#streamKeepaliveConfig = streamKeepalive;
|
|
519
524
|
this.#needsEventLoopFlush = transportType === "httpStream";
|
|
520
525
|
if (tools.length) {
|
|
521
526
|
this.#capabilities.tools = {};
|
|
@@ -843,6 +848,44 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
843
848
|
logLevel: pingConfig.logLevel || "debug"
|
|
844
849
|
};
|
|
845
850
|
}
|
|
851
|
+
/**
|
|
852
|
+
* Periodically writes to the response stream of an in-flight tool call, so an
|
|
853
|
+
* idle-connection timeout (proxy, load balancer) does not close it while a
|
|
854
|
+
* long-running tool produces no output of its own.
|
|
855
|
+
*
|
|
856
|
+
* The notification is related to the tool call, so it travels on that
|
|
857
|
+
* request's own stream, which is the only server-to-client route that exists
|
|
858
|
+
* when running stateless.
|
|
859
|
+
*
|
|
860
|
+
* @returns a function that stops the keepalive.
|
|
861
|
+
*/
|
|
862
|
+
#startStreamKeepalive(extra, toolName) {
|
|
863
|
+
const config = this.#streamKeepaliveConfig;
|
|
864
|
+
if (!config?.enabled) {
|
|
865
|
+
return () => {
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
const intervalMs = config.intervalMs && config.intervalMs > 0 ? config.intervalMs : STREAM_KEEPALIVE_DEFAULT_INTERVAL_MS;
|
|
869
|
+
const timer = setInterval(() => {
|
|
870
|
+
extra.sendNotification({
|
|
871
|
+
method: "notifications/message",
|
|
872
|
+
params: {
|
|
873
|
+
data: { message: `keepalive while '${toolName}' is running` },
|
|
874
|
+
level: config.logLevel ?? "debug",
|
|
875
|
+
logger: STREAM_KEEPALIVE_LOGGER
|
|
876
|
+
}
|
|
877
|
+
}).catch((error) => {
|
|
878
|
+
this.#logger.debug(
|
|
879
|
+
`[FastMCP debug] stream keepalive for '${toolName}' failed:`,
|
|
880
|
+
error instanceof Error ? error.message : String(error)
|
|
881
|
+
);
|
|
882
|
+
});
|
|
883
|
+
}, intervalMs);
|
|
884
|
+
timer.unref?.();
|
|
885
|
+
const stop = () => clearInterval(timer);
|
|
886
|
+
extra.signal?.addEventListener("abort", stop, { once: true });
|
|
887
|
+
return stop;
|
|
888
|
+
}
|
|
846
889
|
async #validateStructuredContent(tool, value, toolName) {
|
|
847
890
|
if (!tool.outputSchema) {
|
|
848
891
|
return value;
|
|
@@ -1260,169 +1303,178 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
1260
1303
|
tools: cachedToolsList
|
|
1261
1304
|
};
|
|
1262
1305
|
});
|
|
1263
|
-
this.#server.setRequestHandler(
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
`Unknown tool: ${request.params.name}`
|
|
1269
|
-
);
|
|
1270
|
-
}
|
|
1271
|
-
let args = void 0;
|
|
1272
|
-
if (tool.parameters) {
|
|
1273
|
-
const parsed = await tool.parameters["~standard"].validate(
|
|
1274
|
-
request.params.arguments
|
|
1275
|
-
);
|
|
1276
|
-
if (parsed.issues) {
|
|
1277
|
-
const friendlyErrors = this.#formatSchemaIssues(parsed.issues);
|
|
1306
|
+
this.#server.setRequestHandler(
|
|
1307
|
+
CallToolRequestSchema,
|
|
1308
|
+
async (request, extra) => {
|
|
1309
|
+
const tool = toolsMap.get(request.params.name);
|
|
1310
|
+
if (!tool) {
|
|
1278
1311
|
throw new McpError(
|
|
1279
|
-
ErrorCode.
|
|
1280
|
-
`
|
|
1312
|
+
ErrorCode.MethodNotFound,
|
|
1313
|
+
`Unknown tool: ${request.params.name}`
|
|
1281
1314
|
);
|
|
1282
1315
|
}
|
|
1283
|
-
args =
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1316
|
+
let args = void 0;
|
|
1317
|
+
if (tool.parameters) {
|
|
1318
|
+
const parsed = await tool.parameters["~standard"].validate(
|
|
1319
|
+
request.params.arguments
|
|
1320
|
+
);
|
|
1321
|
+
if (parsed.issues) {
|
|
1322
|
+
const friendlyErrors = this.#formatSchemaIssues(parsed.issues);
|
|
1323
|
+
throw new McpError(
|
|
1324
|
+
ErrorCode.InvalidParams,
|
|
1325
|
+
`Tool '${request.params.name}' parameter validation failed: ${friendlyErrors}. Please check the parameter types and values according to the tool's schema.`
|
|
1326
|
+
);
|
|
1291
1327
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1328
|
+
args = parsed.value;
|
|
1329
|
+
}
|
|
1330
|
+
const progressToken = request.params?._meta?.progressToken;
|
|
1331
|
+
let result;
|
|
1332
|
+
try {
|
|
1333
|
+
const reportProgress = async (progress) => {
|
|
1334
|
+
if (progressToken === void 0) {
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
try {
|
|
1338
|
+
await this.#server.notification({
|
|
1339
|
+
method: "notifications/progress",
|
|
1340
|
+
params: {
|
|
1341
|
+
...progress,
|
|
1342
|
+
progressToken
|
|
1343
|
+
}
|
|
1344
|
+
});
|
|
1345
|
+
if (this.#needsEventLoopFlush) {
|
|
1346
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
1298
1347
|
}
|
|
1299
|
-
})
|
|
1300
|
-
|
|
1301
|
-
|
|
1348
|
+
} catch (progressError) {
|
|
1349
|
+
this.#logger.warn(
|
|
1350
|
+
`[FastMCP warning] Failed to report progress for tool '${request.params.name}':`,
|
|
1351
|
+
progressError instanceof Error ? progressError.message : String(progressError)
|
|
1352
|
+
);
|
|
1302
1353
|
}
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
content: contentArray,
|
|
1318
|
-
toolName: request.params.name
|
|
1354
|
+
};
|
|
1355
|
+
const log = this.#createLog();
|
|
1356
|
+
const streamContent = async (content) => {
|
|
1357
|
+
const contentArray = Array.isArray(content) ? content : [content];
|
|
1358
|
+
try {
|
|
1359
|
+
await this.#server.notification({
|
|
1360
|
+
method: "notifications/tool/streamContent",
|
|
1361
|
+
params: {
|
|
1362
|
+
content: contentArray,
|
|
1363
|
+
toolName: request.params.name
|
|
1364
|
+
}
|
|
1365
|
+
});
|
|
1366
|
+
if (this.#needsEventLoopFlush) {
|
|
1367
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
1319
1368
|
}
|
|
1320
|
-
})
|
|
1321
|
-
|
|
1322
|
-
|
|
1369
|
+
} catch (streamError) {
|
|
1370
|
+
this.#logger.warn(
|
|
1371
|
+
`[FastMCP warning] Failed to stream content for tool '${request.params.name}':`,
|
|
1372
|
+
streamError instanceof Error ? streamError.message : String(streamError)
|
|
1373
|
+
);
|
|
1323
1374
|
}
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1375
|
+
};
|
|
1376
|
+
if (this.#onToolCall) {
|
|
1377
|
+
await this.#onToolCall({
|
|
1378
|
+
arguments: args ?? {},
|
|
1379
|
+
toolName: request.params.name
|
|
1380
|
+
});
|
|
1329
1381
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
)
|
|
1382
|
+
const executeToolPromise = Promise.resolve(
|
|
1383
|
+
tool.execute(args, {
|
|
1384
|
+
client: {
|
|
1385
|
+
version: this.#server.getClientVersion()
|
|
1386
|
+
},
|
|
1387
|
+
elicit: (params, options) => this.#server.elicitInput(params, options),
|
|
1388
|
+
log,
|
|
1389
|
+
reportProgress,
|
|
1390
|
+
requestId: typeof request.params?._meta?.requestId === "string" ? request.params._meta.requestId : void 0,
|
|
1391
|
+
session: this.#auth,
|
|
1392
|
+
sessionId: this.#sessionId,
|
|
1393
|
+
streamContent
|
|
1394
|
+
})
|
|
1395
|
+
);
|
|
1396
|
+
const stopStreamKeepalive = this.#startStreamKeepalive(
|
|
1397
|
+
extra,
|
|
1398
|
+
request.params.name
|
|
1399
|
+
);
|
|
1400
|
+
const maybeStringResult = await (tool.timeoutMs ? Promise.race([
|
|
1401
|
+
executeToolPromise,
|
|
1402
|
+
new Promise((_, reject) => {
|
|
1403
|
+
const timeoutId = setTimeout(() => {
|
|
1404
|
+
reject(
|
|
1405
|
+
new UserError(
|
|
1406
|
+
`Tool '${request.params.name}' timed out after ${tool.timeoutMs}ms. Consider increasing timeoutMs or optimizing the tool implementation.`
|
|
1407
|
+
)
|
|
1408
|
+
);
|
|
1409
|
+
}, tool.timeoutMs);
|
|
1410
|
+
executeToolPromise.then(
|
|
1411
|
+
() => clearTimeout(timeoutId),
|
|
1412
|
+
() => clearTimeout(timeoutId)
|
|
1357
1413
|
);
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
})
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
})
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1414
|
+
})
|
|
1415
|
+
]) : executeToolPromise).finally(stopStreamKeepalive);
|
|
1416
|
+
await delay(1);
|
|
1417
|
+
if (maybeStringResult === void 0 || maybeStringResult === null) {
|
|
1418
|
+
result = ContentResultZodSchema.parse({
|
|
1419
|
+
content: []
|
|
1420
|
+
});
|
|
1421
|
+
} else if (typeof maybeStringResult === "string") {
|
|
1422
|
+
result = ContentResultZodSchema.parse({
|
|
1423
|
+
content: [{ text: maybeStringResult, type: "text" }]
|
|
1424
|
+
});
|
|
1425
|
+
} else if ("type" in maybeStringResult) {
|
|
1426
|
+
result = ContentResultZodSchema.parse({
|
|
1427
|
+
content: [maybeStringResult]
|
|
1428
|
+
});
|
|
1429
|
+
} else if ("content" in maybeStringResult) {
|
|
1430
|
+
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
1431
|
+
if (result.structuredContent !== void 0 && tool.outputSchema) {
|
|
1432
|
+
result.structuredContent = await this.#validateStructuredContent(
|
|
1433
|
+
tool,
|
|
1434
|
+
result.structuredContent,
|
|
1435
|
+
request.params.name
|
|
1436
|
+
);
|
|
1437
|
+
}
|
|
1438
|
+
} else if (tool.outputSchema) {
|
|
1439
|
+
const structuredContent = await this.#validateStructuredContent(
|
|
1382
1440
|
tool,
|
|
1383
|
-
|
|
1441
|
+
maybeStringResult,
|
|
1384
1442
|
request.params.name
|
|
1385
1443
|
);
|
|
1444
|
+
result = ContentResultZodSchema.parse({
|
|
1445
|
+
content: [
|
|
1446
|
+
{
|
|
1447
|
+
text: JSON.stringify(structuredContent),
|
|
1448
|
+
type: "text"
|
|
1449
|
+
}
|
|
1450
|
+
],
|
|
1451
|
+
structuredContent
|
|
1452
|
+
});
|
|
1453
|
+
} else {
|
|
1454
|
+
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
1386
1455
|
}
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1456
|
+
} catch (error) {
|
|
1457
|
+
if (error instanceof UserError) {
|
|
1458
|
+
return {
|
|
1459
|
+
content: [{ text: error.message, type: "text" }],
|
|
1460
|
+
isError: true,
|
|
1461
|
+
...error.extras ? { structuredContent: error.extras } : {}
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1465
|
+
return {
|
|
1394
1466
|
content: [
|
|
1395
1467
|
{
|
|
1396
|
-
text:
|
|
1468
|
+
text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,
|
|
1397
1469
|
type: "text"
|
|
1398
1470
|
}
|
|
1399
1471
|
],
|
|
1400
|
-
|
|
1401
|
-
});
|
|
1402
|
-
} else {
|
|
1403
|
-
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
1404
|
-
}
|
|
1405
|
-
} catch (error) {
|
|
1406
|
-
if (error instanceof UserError) {
|
|
1407
|
-
return {
|
|
1408
|
-
content: [{ text: error.message, type: "text" }],
|
|
1409
|
-
isError: true,
|
|
1410
|
-
...error.extras ? { structuredContent: error.extras } : {}
|
|
1472
|
+
isError: true
|
|
1411
1473
|
};
|
|
1412
1474
|
}
|
|
1413
|
-
|
|
1414
|
-
return {
|
|
1415
|
-
content: [
|
|
1416
|
-
{
|
|
1417
|
-
text: `Tool '${request.params.name}' execution failed: ${errorMessage}`,
|
|
1418
|
-
type: "text"
|
|
1419
|
-
}
|
|
1420
|
-
],
|
|
1421
|
-
isError: true
|
|
1422
|
-
};
|
|
1475
|
+
return result;
|
|
1423
1476
|
}
|
|
1424
|
-
|
|
1425
|
-
});
|
|
1477
|
+
);
|
|
1426
1478
|
}
|
|
1427
1479
|
};
|
|
1428
1480
|
function camelToSnakeCase(str) {
|
|
@@ -1863,6 +1915,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1863
1915
|
resources: this.#resources,
|
|
1864
1916
|
resourcesTemplates: this.#resourcesTemplates,
|
|
1865
1917
|
roots: this.#options.roots,
|
|
1918
|
+
streamKeepalive: this.#options.streamKeepalive,
|
|
1866
1919
|
tools: this.#tools,
|
|
1867
1920
|
transportType: "stdio",
|
|
1868
1921
|
utils: this.#options.utils,
|
|
@@ -2062,6 +2115,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
2062
2115
|
roots: this.#options.roots,
|
|
2063
2116
|
sessionId,
|
|
2064
2117
|
stateless,
|
|
2118
|
+
streamKeepalive: this.#options.streamKeepalive,
|
|
2065
2119
|
tools: allowedTools,
|
|
2066
2120
|
transportType: "httpStream",
|
|
2067
2121
|
utils: this.#options.utils,
|
|
@@ -2676,4 +2730,4 @@ export {
|
|
|
2676
2730
|
FastMCPSession,
|
|
2677
2731
|
FastMCP
|
|
2678
2732
|
};
|
|
2679
|
-
//# sourceMappingURL=chunk-
|
|
2733
|
+
//# sourceMappingURL=chunk-LMDMFMPI.js.map
|