fastmcp 1.23.0 → 1.23.2
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.d.ts +165 -165
- package/dist/FastMCP.js +275 -275
- package/dist/FastMCP.js.map +1 -1
- package/dist/bin/fastmcp.js +9 -9
- package/dist/bin/fastmcp.js.map +1 -1
- package/eslint.config.ts +14 -0
- package/jsr.json +1 -1
- package/package.json +6 -1
- package/src/FastMCP.test.ts +398 -396
- package/src/FastMCP.ts +498 -498
- package/src/bin/fastmcp.ts +7 -7
- package/src/examples/addition.ts +25 -24
- package/eslint.config.js +0 -3
package/dist/FastMCP.js
CHANGED
|
@@ -15,16 +15,16 @@ import {
|
|
|
15
15
|
RootsListChangedNotificationSchema,
|
|
16
16
|
SetLevelRequestSchema
|
|
17
17
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
18
|
-
import { toJsonSchema } from "xsschema";
|
|
19
|
-
import { z } from "zod";
|
|
20
|
-
import { setTimeout as delay } from "timers/promises";
|
|
21
|
-
import { readFile } from "fs/promises";
|
|
22
|
-
import { fileTypeFromBuffer } from "file-type";
|
|
23
18
|
import { EventEmitter } from "events";
|
|
19
|
+
import { fileTypeFromBuffer } from "file-type";
|
|
20
|
+
import { readFile } from "fs/promises";
|
|
24
21
|
import Fuse from "fuse.js";
|
|
25
22
|
import { startSSEServer } from "mcp-proxy";
|
|
26
|
-
import
|
|
23
|
+
import { setTimeout as delay } from "timers/promises";
|
|
27
24
|
import { fetch } from "undici";
|
|
25
|
+
import parseURITemplate from "uri-templates";
|
|
26
|
+
import { toJsonSchema } from "xsschema";
|
|
27
|
+
import { z } from "zod";
|
|
28
28
|
var imageContent = async (input) => {
|
|
29
29
|
let rawData;
|
|
30
30
|
if ("url" in input) {
|
|
@@ -45,9 +45,9 @@ var imageContent = async (input) => {
|
|
|
45
45
|
const mimeType = await fileTypeFromBuffer(rawData);
|
|
46
46
|
const base64Data = rawData.toString("base64");
|
|
47
47
|
return {
|
|
48
|
-
type: "image",
|
|
49
48
|
data: base64Data,
|
|
50
|
-
mimeType: mimeType?.mime ?? "image/png"
|
|
49
|
+
mimeType: mimeType?.mime ?? "image/png",
|
|
50
|
+
type: "image"
|
|
51
51
|
};
|
|
52
52
|
};
|
|
53
53
|
var audioContent = async (input) => {
|
|
@@ -70,9 +70,9 @@ var audioContent = async (input) => {
|
|
|
70
70
|
const mimeType = await fileTypeFromBuffer(rawData);
|
|
71
71
|
const base64Data = rawData.toString("base64");
|
|
72
72
|
return {
|
|
73
|
-
type: "audio",
|
|
74
73
|
data: base64Data,
|
|
75
|
-
mimeType: mimeType?.mime ?? "audio/mpeg"
|
|
74
|
+
mimeType: mimeType?.mime ?? "audio/mpeg",
|
|
75
|
+
type: "audio"
|
|
76
76
|
};
|
|
77
77
|
};
|
|
78
78
|
var FastMCPError = class extends Error {
|
|
@@ -92,14 +92,13 @@ var UnexpectedStateError = class extends FastMCPError {
|
|
|
92
92
|
var UserError = class extends UnexpectedStateError {
|
|
93
93
|
};
|
|
94
94
|
var TextContentZodSchema = z.object({
|
|
95
|
-
type: z.literal("text"),
|
|
96
95
|
/**
|
|
97
96
|
* The text content of the message.
|
|
98
97
|
*/
|
|
99
|
-
text: z.string()
|
|
98
|
+
text: z.string(),
|
|
99
|
+
type: z.literal("text")
|
|
100
100
|
}).strict();
|
|
101
101
|
var ImageContentZodSchema = z.object({
|
|
102
|
-
type: z.literal("image"),
|
|
103
102
|
/**
|
|
104
103
|
* The base64-encoded image data.
|
|
105
104
|
*/
|
|
@@ -107,7 +106,8 @@ var ImageContentZodSchema = z.object({
|
|
|
107
106
|
/**
|
|
108
107
|
* The MIME type of the image. Different providers may support different image types.
|
|
109
108
|
*/
|
|
110
|
-
mimeType: z.string()
|
|
109
|
+
mimeType: z.string(),
|
|
110
|
+
type: z.literal("image")
|
|
111
111
|
}).strict();
|
|
112
112
|
var ContentZodSchema = z.discriminatedUnion("type", [
|
|
113
113
|
TextContentZodSchema,
|
|
@@ -119,40 +119,53 @@ var ContentResultZodSchema = z.object({
|
|
|
119
119
|
}).strict();
|
|
120
120
|
var CompletionZodSchema = z.object({
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
122
|
+
* Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
|
|
123
123
|
*/
|
|
124
|
-
|
|
124
|
+
hasMore: z.optional(z.boolean()),
|
|
125
125
|
/**
|
|
126
126
|
* The total number of completion options available. This can exceed the number of values actually sent in the response.
|
|
127
127
|
*/
|
|
128
128
|
total: z.optional(z.number().int()),
|
|
129
129
|
/**
|
|
130
|
-
*
|
|
130
|
+
* An array of completion values. Must not exceed 100 items.
|
|
131
131
|
*/
|
|
132
|
-
|
|
132
|
+
values: z.array(z.string()).max(100)
|
|
133
133
|
});
|
|
134
134
|
var FastMCPSessionEventEmitterBase = EventEmitter;
|
|
135
135
|
var FastMCPSessionEventEmitter = class extends FastMCPSessionEventEmitterBase {
|
|
136
136
|
};
|
|
137
137
|
var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
138
|
+
get clientCapabilities() {
|
|
139
|
+
return this.#clientCapabilities ?? null;
|
|
140
|
+
}
|
|
141
|
+
get loggingLevel() {
|
|
142
|
+
return this.#loggingLevel;
|
|
143
|
+
}
|
|
144
|
+
get roots() {
|
|
145
|
+
return this.#roots;
|
|
146
|
+
}
|
|
147
|
+
get server() {
|
|
148
|
+
return this.#server;
|
|
149
|
+
}
|
|
150
|
+
#auth;
|
|
138
151
|
#capabilities = {};
|
|
139
152
|
#clientCapabilities;
|
|
140
153
|
#loggingLevel = "info";
|
|
154
|
+
#pingInterval = null;
|
|
141
155
|
#prompts = [];
|
|
142
156
|
#resources = [];
|
|
143
157
|
#resourceTemplates = [];
|
|
144
158
|
#roots = [];
|
|
145
159
|
#server;
|
|
146
|
-
#auth;
|
|
147
160
|
constructor({
|
|
148
161
|
auth,
|
|
149
|
-
name,
|
|
150
|
-
version,
|
|
151
162
|
instructions,
|
|
152
|
-
|
|
163
|
+
name,
|
|
164
|
+
prompts,
|
|
153
165
|
resources,
|
|
154
166
|
resourcesTemplates,
|
|
155
|
-
|
|
167
|
+
tools,
|
|
168
|
+
version
|
|
156
169
|
}) {
|
|
157
170
|
super();
|
|
158
171
|
this.#auth = auth;
|
|
@@ -196,72 +209,15 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
196
209
|
this.setupPromptHandlers(prompts);
|
|
197
210
|
}
|
|
198
211
|
}
|
|
199
|
-
|
|
200
|
-
this.#
|
|
201
|
-
|
|
202
|
-
addResourceTemplate(inputResourceTemplate) {
|
|
203
|
-
const completers = {};
|
|
204
|
-
for (const argument of inputResourceTemplate.arguments ?? []) {
|
|
205
|
-
if (argument.complete) {
|
|
206
|
-
completers[argument.name] = argument.complete;
|
|
207
|
-
}
|
|
212
|
+
async close() {
|
|
213
|
+
if (this.#pingInterval) {
|
|
214
|
+
clearInterval(this.#pingInterval);
|
|
208
215
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return await completers[name](value);
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
values: []
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
this.#resourceTemplates.push(resourceTemplate);
|
|
221
|
-
}
|
|
222
|
-
addPrompt(inputPrompt) {
|
|
223
|
-
const completers = {};
|
|
224
|
-
const enums = {};
|
|
225
|
-
for (const argument of inputPrompt.arguments ?? []) {
|
|
226
|
-
if (argument.complete) {
|
|
227
|
-
completers[argument.name] = argument.complete;
|
|
228
|
-
}
|
|
229
|
-
if (argument.enum) {
|
|
230
|
-
enums[argument.name] = argument.enum;
|
|
231
|
-
}
|
|
216
|
+
try {
|
|
217
|
+
await this.#server.close();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error("[FastMCP error]", "could not close server", error);
|
|
232
220
|
}
|
|
233
|
-
const prompt = {
|
|
234
|
-
...inputPrompt,
|
|
235
|
-
complete: async (name, value) => {
|
|
236
|
-
if (completers[name]) {
|
|
237
|
-
return await completers[name](value);
|
|
238
|
-
}
|
|
239
|
-
if (enums[name]) {
|
|
240
|
-
const fuse = new Fuse(enums[name], {
|
|
241
|
-
keys: ["value"]
|
|
242
|
-
});
|
|
243
|
-
const result = fuse.search(value);
|
|
244
|
-
return {
|
|
245
|
-
values: result.map((item) => item.item),
|
|
246
|
-
total: result.length
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
return {
|
|
250
|
-
values: []
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
this.#prompts.push(prompt);
|
|
255
|
-
}
|
|
256
|
-
get clientCapabilities() {
|
|
257
|
-
return this.#clientCapabilities ?? null;
|
|
258
|
-
}
|
|
259
|
-
get server() {
|
|
260
|
-
return this.#server;
|
|
261
|
-
}
|
|
262
|
-
#pingInterval = null;
|
|
263
|
-
async requestSampling(message) {
|
|
264
|
-
return this.#server.createMessage(message);
|
|
265
221
|
}
|
|
266
222
|
async connect(transport) {
|
|
267
223
|
if (this.#server.transport) {
|
|
@@ -302,26 +258,65 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
302
258
|
}, 1e3);
|
|
303
259
|
}
|
|
304
260
|
}
|
|
305
|
-
|
|
306
|
-
return this.#
|
|
261
|
+
async requestSampling(message) {
|
|
262
|
+
return this.#server.createMessage(message);
|
|
307
263
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
264
|
+
addPrompt(inputPrompt) {
|
|
265
|
+
const completers = {};
|
|
266
|
+
const enums = {};
|
|
267
|
+
for (const argument of inputPrompt.arguments ?? []) {
|
|
268
|
+
if (argument.complete) {
|
|
269
|
+
completers[argument.name] = argument.complete;
|
|
270
|
+
}
|
|
271
|
+
if (argument.enum) {
|
|
272
|
+
enums[argument.name] = argument.enum;
|
|
273
|
+
}
|
|
316
274
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
275
|
+
const prompt = {
|
|
276
|
+
...inputPrompt,
|
|
277
|
+
complete: async (name, value) => {
|
|
278
|
+
if (completers[name]) {
|
|
279
|
+
return await completers[name](value);
|
|
280
|
+
}
|
|
281
|
+
if (enums[name]) {
|
|
282
|
+
const fuse = new Fuse(enums[name], {
|
|
283
|
+
keys: ["value"]
|
|
284
|
+
});
|
|
285
|
+
const result = fuse.search(value);
|
|
286
|
+
return {
|
|
287
|
+
total: result.length,
|
|
288
|
+
values: result.map((item) => item.item)
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
values: []
|
|
293
|
+
};
|
|
294
|
+
}
|
|
321
295
|
};
|
|
296
|
+
this.#prompts.push(prompt);
|
|
322
297
|
}
|
|
323
|
-
|
|
324
|
-
|
|
298
|
+
addResource(inputResource) {
|
|
299
|
+
this.#resources.push(inputResource);
|
|
300
|
+
}
|
|
301
|
+
addResourceTemplate(inputResourceTemplate) {
|
|
302
|
+
const completers = {};
|
|
303
|
+
for (const argument of inputResourceTemplate.arguments ?? []) {
|
|
304
|
+
if (argument.complete) {
|
|
305
|
+
completers[argument.name] = argument.complete;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const resourceTemplate = {
|
|
309
|
+
...inputResourceTemplate,
|
|
310
|
+
complete: async (name, value) => {
|
|
311
|
+
if (completers[name]) {
|
|
312
|
+
return await completers[name](value);
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
values: []
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
this.#resourceTemplates.push(resourceTemplate);
|
|
325
320
|
}
|
|
326
321
|
setupCompleteHandlers() {
|
|
327
322
|
this.#server.setRequestHandler(CompleteRequestSchema, async (request) => {
|
|
@@ -384,18 +379,10 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
384
379
|
});
|
|
385
380
|
});
|
|
386
381
|
}
|
|
387
|
-
|
|
388
|
-
this.#server.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.#server.listRoots().then((roots) => {
|
|
392
|
-
this.#roots = roots.roots;
|
|
393
|
-
this.emit("rootsChanged", {
|
|
394
|
-
roots: roots.roots
|
|
395
|
-
});
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
);
|
|
382
|
+
setupErrorHandling() {
|
|
383
|
+
this.#server.onerror = (error) => {
|
|
384
|
+
console.error("[FastMCP error]", error);
|
|
385
|
+
};
|
|
399
386
|
}
|
|
400
387
|
setupLoggingHandlers() {
|
|
401
388
|
this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {
|
|
@@ -403,121 +390,56 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
403
390
|
return {};
|
|
404
391
|
});
|
|
405
392
|
}
|
|
406
|
-
|
|
407
|
-
this.#server.setRequestHandler(
|
|
393
|
+
setupPromptHandlers(prompts) {
|
|
394
|
+
this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
408
395
|
return {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
})
|
|
418
|
-
)
|
|
396
|
+
prompts: prompts.map((prompt) => {
|
|
397
|
+
return {
|
|
398
|
+
arguments: prompt.arguments,
|
|
399
|
+
complete: prompt.complete,
|
|
400
|
+
description: prompt.description,
|
|
401
|
+
name: prompt.name
|
|
402
|
+
};
|
|
403
|
+
})
|
|
419
404
|
};
|
|
420
405
|
});
|
|
421
|
-
this.#server.setRequestHandler(
|
|
422
|
-
const
|
|
423
|
-
|
|
406
|
+
this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
407
|
+
const prompt = prompts.find(
|
|
408
|
+
(prompt2) => prompt2.name === request.params.name
|
|
409
|
+
);
|
|
410
|
+
if (!prompt) {
|
|
424
411
|
throw new McpError(
|
|
425
412
|
ErrorCode.MethodNotFound,
|
|
426
|
-
`Unknown
|
|
413
|
+
`Unknown prompt: ${request.params.name}`
|
|
427
414
|
);
|
|
428
415
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
request.params.arguments
|
|
433
|
-
);
|
|
434
|
-
if (parsed.issues) {
|
|
416
|
+
const args = request.params.arguments;
|
|
417
|
+
for (const arg of prompt.arguments ?? []) {
|
|
418
|
+
if (arg.required && !(args && arg.name in args)) {
|
|
435
419
|
throw new McpError(
|
|
436
|
-
ErrorCode.
|
|
437
|
-
`
|
|
420
|
+
ErrorCode.InvalidRequest,
|
|
421
|
+
`Missing required argument: ${arg.name}`
|
|
438
422
|
);
|
|
439
423
|
}
|
|
440
|
-
args = parsed.value;
|
|
441
424
|
}
|
|
442
|
-
const progressToken = request.params?._meta?.progressToken;
|
|
443
425
|
let result;
|
|
444
426
|
try {
|
|
445
|
-
|
|
446
|
-
await this.#server.notification({
|
|
447
|
-
method: "notifications/progress",
|
|
448
|
-
params: {
|
|
449
|
-
...progress,
|
|
450
|
-
progressToken
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
};
|
|
454
|
-
const log = {
|
|
455
|
-
debug: (message, context) => {
|
|
456
|
-
this.#server.sendLoggingMessage({
|
|
457
|
-
level: "debug",
|
|
458
|
-
data: {
|
|
459
|
-
message,
|
|
460
|
-
context
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
},
|
|
464
|
-
error: (message, context) => {
|
|
465
|
-
this.#server.sendLoggingMessage({
|
|
466
|
-
level: "error",
|
|
467
|
-
data: {
|
|
468
|
-
message,
|
|
469
|
-
context
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
},
|
|
473
|
-
info: (message, context) => {
|
|
474
|
-
this.#server.sendLoggingMessage({
|
|
475
|
-
level: "info",
|
|
476
|
-
data: {
|
|
477
|
-
message,
|
|
478
|
-
context
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
},
|
|
482
|
-
warn: (message, context) => {
|
|
483
|
-
this.#server.sendLoggingMessage({
|
|
484
|
-
level: "warning",
|
|
485
|
-
data: {
|
|
486
|
-
message,
|
|
487
|
-
context
|
|
488
|
-
}
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
};
|
|
492
|
-
const maybeStringResult = await tool.execute(args, {
|
|
493
|
-
reportProgress,
|
|
494
|
-
log,
|
|
495
|
-
session: this.#auth
|
|
496
|
-
});
|
|
497
|
-
if (typeof maybeStringResult === "string") {
|
|
498
|
-
result = ContentResultZodSchema.parse({
|
|
499
|
-
content: [{ type: "text", text: maybeStringResult }]
|
|
500
|
-
});
|
|
501
|
-
} else if ("type" in maybeStringResult) {
|
|
502
|
-
result = ContentResultZodSchema.parse({
|
|
503
|
-
content: [maybeStringResult]
|
|
504
|
-
});
|
|
505
|
-
} else {
|
|
506
|
-
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
507
|
-
}
|
|
427
|
+
result = await prompt.load(args);
|
|
508
428
|
} catch (error) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
return {
|
|
516
|
-
content: [{ type: "text", text: `Error: ${error}` }],
|
|
517
|
-
isError: true
|
|
518
|
-
};
|
|
429
|
+
throw new McpError(
|
|
430
|
+
ErrorCode.InternalError,
|
|
431
|
+
`Error loading prompt: ${error}`
|
|
432
|
+
);
|
|
519
433
|
}
|
|
520
|
-
return
|
|
434
|
+
return {
|
|
435
|
+
description: prompt.description,
|
|
436
|
+
messages: [
|
|
437
|
+
{
|
|
438
|
+
content: { text: result, type: "text" },
|
|
439
|
+
role: "user"
|
|
440
|
+
}
|
|
441
|
+
]
|
|
442
|
+
};
|
|
521
443
|
});
|
|
522
444
|
}
|
|
523
445
|
setupResourceHandlers(resources) {
|
|
@@ -525,9 +447,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
525
447
|
return {
|
|
526
448
|
resources: resources.map((resource) => {
|
|
527
449
|
return {
|
|
528
|
-
|
|
450
|
+
mimeType: resource.mimeType,
|
|
529
451
|
name: resource.name,
|
|
530
|
-
|
|
452
|
+
uri: resource.uri
|
|
531
453
|
};
|
|
532
454
|
})
|
|
533
455
|
};
|
|
@@ -553,9 +475,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
553
475
|
return {
|
|
554
476
|
contents: [
|
|
555
477
|
{
|
|
556
|
-
uri,
|
|
557
478
|
mimeType: resourceTemplate.mimeType,
|
|
558
479
|
name: resourceTemplate.name,
|
|
480
|
+
uri,
|
|
559
481
|
...result
|
|
560
482
|
}
|
|
561
483
|
]
|
|
@@ -584,9 +506,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
584
506
|
if (Array.isArray(maybeArrayResult)) {
|
|
585
507
|
return {
|
|
586
508
|
contents: maybeArrayResult.map((result) => ({
|
|
587
|
-
uri: resource.uri,
|
|
588
509
|
mimeType: resource.mimeType,
|
|
589
510
|
name: resource.name,
|
|
511
|
+
uri: resource.uri,
|
|
590
512
|
...result
|
|
591
513
|
}))
|
|
592
514
|
};
|
|
@@ -594,9 +516,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
594
516
|
return {
|
|
595
517
|
contents: [
|
|
596
518
|
{
|
|
597
|
-
uri: resource.uri,
|
|
598
519
|
mimeType: resource.mimeType,
|
|
599
520
|
name: resource.name,
|
|
521
|
+
uri: resource.uri,
|
|
600
522
|
...maybeArrayResult
|
|
601
523
|
}
|
|
602
524
|
]
|
|
@@ -624,56 +546,134 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
624
546
|
}
|
|
625
547
|
);
|
|
626
548
|
}
|
|
627
|
-
|
|
628
|
-
this.#server.
|
|
549
|
+
setupRootsHandlers() {
|
|
550
|
+
this.#server.setNotificationHandler(
|
|
551
|
+
RootsListChangedNotificationSchema,
|
|
552
|
+
() => {
|
|
553
|
+
this.#server.listRoots().then((roots) => {
|
|
554
|
+
this.#roots = roots.roots;
|
|
555
|
+
this.emit("rootsChanged", {
|
|
556
|
+
roots: roots.roots
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
setupToolHandlers(tools) {
|
|
563
|
+
this.#server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
629
564
|
return {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
565
|
+
tools: await Promise.all(
|
|
566
|
+
tools.map(async (tool) => {
|
|
567
|
+
return {
|
|
568
|
+
annotations: tool.annotations,
|
|
569
|
+
description: tool.description,
|
|
570
|
+
inputSchema: tool.parameters ? await toJsonSchema(tool.parameters) : void 0,
|
|
571
|
+
name: tool.name
|
|
572
|
+
};
|
|
573
|
+
})
|
|
574
|
+
)
|
|
638
575
|
};
|
|
639
576
|
});
|
|
640
|
-
this.#server.setRequestHandler(
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
);
|
|
644
|
-
if (!prompt) {
|
|
577
|
+
this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
578
|
+
const tool = tools.find((tool2) => tool2.name === request.params.name);
|
|
579
|
+
if (!tool) {
|
|
645
580
|
throw new McpError(
|
|
646
581
|
ErrorCode.MethodNotFound,
|
|
647
|
-
`Unknown
|
|
582
|
+
`Unknown tool: ${request.params.name}`
|
|
648
583
|
);
|
|
649
584
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
585
|
+
let args = void 0;
|
|
586
|
+
if (tool.parameters) {
|
|
587
|
+
const parsed = await tool.parameters["~standard"].validate(
|
|
588
|
+
request.params.arguments
|
|
589
|
+
);
|
|
590
|
+
if (parsed.issues) {
|
|
653
591
|
throw new McpError(
|
|
654
|
-
ErrorCode.
|
|
655
|
-
`
|
|
592
|
+
ErrorCode.InvalidParams,
|
|
593
|
+
`Invalid ${request.params.name} parameters: ${JSON.stringify(parsed.issues)}`
|
|
656
594
|
);
|
|
657
595
|
}
|
|
596
|
+
args = parsed.value;
|
|
658
597
|
}
|
|
598
|
+
const progressToken = request.params?._meta?.progressToken;
|
|
659
599
|
let result;
|
|
660
600
|
try {
|
|
661
|
-
|
|
601
|
+
const reportProgress = async (progress) => {
|
|
602
|
+
await this.#server.notification({
|
|
603
|
+
method: "notifications/progress",
|
|
604
|
+
params: {
|
|
605
|
+
...progress,
|
|
606
|
+
progressToken
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
};
|
|
610
|
+
const log = {
|
|
611
|
+
debug: (message, context) => {
|
|
612
|
+
this.#server.sendLoggingMessage({
|
|
613
|
+
data: {
|
|
614
|
+
context,
|
|
615
|
+
message
|
|
616
|
+
},
|
|
617
|
+
level: "debug"
|
|
618
|
+
});
|
|
619
|
+
},
|
|
620
|
+
error: (message, context) => {
|
|
621
|
+
this.#server.sendLoggingMessage({
|
|
622
|
+
data: {
|
|
623
|
+
context,
|
|
624
|
+
message
|
|
625
|
+
},
|
|
626
|
+
level: "error"
|
|
627
|
+
});
|
|
628
|
+
},
|
|
629
|
+
info: (message, context) => {
|
|
630
|
+
this.#server.sendLoggingMessage({
|
|
631
|
+
data: {
|
|
632
|
+
context,
|
|
633
|
+
message
|
|
634
|
+
},
|
|
635
|
+
level: "info"
|
|
636
|
+
});
|
|
637
|
+
},
|
|
638
|
+
warn: (message, context) => {
|
|
639
|
+
this.#server.sendLoggingMessage({
|
|
640
|
+
data: {
|
|
641
|
+
context,
|
|
642
|
+
message
|
|
643
|
+
},
|
|
644
|
+
level: "warning"
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
const maybeStringResult = await tool.execute(args, {
|
|
649
|
+
log,
|
|
650
|
+
reportProgress,
|
|
651
|
+
session: this.#auth
|
|
652
|
+
});
|
|
653
|
+
if (typeof maybeStringResult === "string") {
|
|
654
|
+
result = ContentResultZodSchema.parse({
|
|
655
|
+
content: [{ text: maybeStringResult, type: "text" }]
|
|
656
|
+
});
|
|
657
|
+
} else if ("type" in maybeStringResult) {
|
|
658
|
+
result = ContentResultZodSchema.parse({
|
|
659
|
+
content: [maybeStringResult]
|
|
660
|
+
});
|
|
661
|
+
} else {
|
|
662
|
+
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
663
|
+
}
|
|
662
664
|
} catch (error) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
665
|
+
if (error instanceof UserError) {
|
|
666
|
+
return {
|
|
667
|
+
content: [{ text: error.message, type: "text" }],
|
|
668
|
+
isError: true
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
content: [{ text: `Error: ${error}`, type: "text" }],
|
|
673
|
+
isError: true
|
|
674
|
+
};
|
|
667
675
|
}
|
|
668
|
-
return
|
|
669
|
-
description: prompt.description,
|
|
670
|
-
messages: [
|
|
671
|
-
{
|
|
672
|
-
role: "user",
|
|
673
|
-
content: { type: "text", text: result }
|
|
674
|
-
}
|
|
675
|
-
]
|
|
676
|
-
};
|
|
676
|
+
return result;
|
|
677
677
|
});
|
|
678
678
|
}
|
|
679
679
|
};
|
|
@@ -687,6 +687,10 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
687
687
|
this.#options = options;
|
|
688
688
|
this.#authenticate = options.authenticate;
|
|
689
689
|
}
|
|
690
|
+
get sessions() {
|
|
691
|
+
return this.#sessions;
|
|
692
|
+
}
|
|
693
|
+
#authenticate;
|
|
690
694
|
#options;
|
|
691
695
|
#prompts = [];
|
|
692
696
|
#resources = [];
|
|
@@ -694,15 +698,11 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
694
698
|
#sessions = [];
|
|
695
699
|
#sseServer = null;
|
|
696
700
|
#tools = [];
|
|
697
|
-
#authenticate;
|
|
698
|
-
get sessions() {
|
|
699
|
-
return this.#sessions;
|
|
700
|
-
}
|
|
701
701
|
/**
|
|
702
|
-
* Adds a
|
|
702
|
+
* Adds a prompt to the server.
|
|
703
703
|
*/
|
|
704
|
-
|
|
705
|
-
this.#
|
|
704
|
+
addPrompt(prompt) {
|
|
705
|
+
this.#prompts.push(prompt);
|
|
706
706
|
}
|
|
707
707
|
/**
|
|
708
708
|
* Adds a resource to the server.
|
|
@@ -717,10 +717,10 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
717
717
|
this.#resourcesTemplates.push(resource);
|
|
718
718
|
}
|
|
719
719
|
/**
|
|
720
|
-
* Adds a
|
|
720
|
+
* Adds a tool to the server.
|
|
721
721
|
*/
|
|
722
|
-
|
|
723
|
-
this.#
|
|
722
|
+
addTool(tool) {
|
|
723
|
+
this.#tools.push(tool);
|
|
724
724
|
}
|
|
725
725
|
/**
|
|
726
726
|
* Starts the server.
|
|
@@ -731,13 +731,13 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
731
731
|
if (options.transportType === "stdio") {
|
|
732
732
|
const transport = new StdioServerTransport();
|
|
733
733
|
const session = new FastMCPSession({
|
|
734
|
-
name: this.#options.name,
|
|
735
|
-
version: this.#options.version,
|
|
736
734
|
instructions: this.#options.instructions,
|
|
737
|
-
|
|
735
|
+
name: this.#options.name,
|
|
736
|
+
prompts: this.#prompts,
|
|
738
737
|
resources: this.#resources,
|
|
739
738
|
resourcesTemplates: this.#resourcesTemplates,
|
|
740
|
-
|
|
739
|
+
tools: this.#tools,
|
|
740
|
+
version: this.#options.version
|
|
741
741
|
});
|
|
742
742
|
await session.connect(transport);
|
|
743
743
|
this.#sessions.push(session);
|
|
@@ -746,8 +746,6 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
746
746
|
});
|
|
747
747
|
} else if (options.transportType === "sse") {
|
|
748
748
|
this.#sseServer = await startSSEServer({
|
|
749
|
-
endpoint: options.sse.endpoint,
|
|
750
|
-
port: options.sse.port,
|
|
751
749
|
createServer: async (request) => {
|
|
752
750
|
let auth;
|
|
753
751
|
if (this.#authenticate) {
|
|
@@ -756,13 +754,14 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
756
754
|
return new FastMCPSession({
|
|
757
755
|
auth,
|
|
758
756
|
name: this.#options.name,
|
|
759
|
-
|
|
760
|
-
tools: this.#tools,
|
|
757
|
+
prompts: this.#prompts,
|
|
761
758
|
resources: this.#resources,
|
|
762
759
|
resourcesTemplates: this.#resourcesTemplates,
|
|
763
|
-
|
|
760
|
+
tools: this.#tools,
|
|
761
|
+
version: this.#options.version
|
|
764
762
|
});
|
|
765
763
|
},
|
|
764
|
+
endpoint: options.sse.endpoint,
|
|
766
765
|
onClose: (session) => {
|
|
767
766
|
this.emit("disconnect", {
|
|
768
767
|
session
|
|
@@ -773,7 +772,8 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
773
772
|
this.emit("connect", {
|
|
774
773
|
session
|
|
775
774
|
});
|
|
776
|
-
}
|
|
775
|
+
},
|
|
776
|
+
port: options.sse.port
|
|
777
777
|
});
|
|
778
778
|
console.info(
|
|
779
779
|
`[FastMCP info] server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`
|