fastmcp 1.22.4 → 1.23.1
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 +51 -8
- package/dist/FastMCP.d.ts +165 -130
- package/dist/FastMCP.js +281 -274
- 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 +435 -424
- package/src/FastMCP.ts +517 -460
- package/src/bin/fastmcp.ts +7 -7
- package/src/examples/addition.ts +33 -15
- package/eslint.config.js +0 -3
package/dist/FastMCP.js
CHANGED
|
@@ -15,18 +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";
|
|
23
|
+
import { setTimeout as delay } from "timers/promises";
|
|
24
|
+
import { fetch } from "undici";
|
|
26
25
|
import parseURITemplate from "uri-templates";
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
} from "undici";
|
|
26
|
+
import { toJsonSchema } from "xsschema";
|
|
27
|
+
import { z } from "zod";
|
|
30
28
|
var imageContent = async (input) => {
|
|
31
29
|
let rawData;
|
|
32
30
|
if ("url" in input) {
|
|
@@ -47,9 +45,9 @@ var imageContent = async (input) => {
|
|
|
47
45
|
const mimeType = await fileTypeFromBuffer(rawData);
|
|
48
46
|
const base64Data = rawData.toString("base64");
|
|
49
47
|
return {
|
|
50
|
-
type: "image",
|
|
51
48
|
data: base64Data,
|
|
52
|
-
mimeType: mimeType?.mime ?? "image/png"
|
|
49
|
+
mimeType: mimeType?.mime ?? "image/png",
|
|
50
|
+
type: "image"
|
|
53
51
|
};
|
|
54
52
|
};
|
|
55
53
|
var audioContent = async (input) => {
|
|
@@ -65,14 +63,16 @@ var audioContent = async (input) => {
|
|
|
65
63
|
} else if ("buffer" in input) {
|
|
66
64
|
rawData = input.buffer;
|
|
67
65
|
} else {
|
|
68
|
-
throw new Error(
|
|
66
|
+
throw new Error(
|
|
67
|
+
"Invalid input: Provide a valid 'url', 'path', or 'buffer'"
|
|
68
|
+
);
|
|
69
69
|
}
|
|
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,39 +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,
|
|
162
|
+
instructions,
|
|
149
163
|
name,
|
|
150
|
-
|
|
151
|
-
tools,
|
|
164
|
+
prompts,
|
|
152
165
|
resources,
|
|
153
166
|
resourcesTemplates,
|
|
154
|
-
|
|
167
|
+
tools,
|
|
168
|
+
version
|
|
155
169
|
}) {
|
|
156
170
|
super();
|
|
157
171
|
this.#auth = auth;
|
|
@@ -170,7 +184,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
170
184
|
this.#capabilities.logging = {};
|
|
171
185
|
this.#server = new Server(
|
|
172
186
|
{ name, version },
|
|
173
|
-
{ capabilities: this.#capabilities }
|
|
187
|
+
{ capabilities: this.#capabilities, instructions }
|
|
174
188
|
);
|
|
175
189
|
this.setupErrorHandling();
|
|
176
190
|
this.setupLoggingHandlers();
|
|
@@ -195,72 +209,15 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
195
209
|
this.setupPromptHandlers(prompts);
|
|
196
210
|
}
|
|
197
211
|
}
|
|
198
|
-
|
|
199
|
-
this.#
|
|
200
|
-
|
|
201
|
-
addResourceTemplate(inputResourceTemplate) {
|
|
202
|
-
const completers = {};
|
|
203
|
-
for (const argument of inputResourceTemplate.arguments ?? []) {
|
|
204
|
-
if (argument.complete) {
|
|
205
|
-
completers[argument.name] = argument.complete;
|
|
206
|
-
}
|
|
212
|
+
async close() {
|
|
213
|
+
if (this.#pingInterval) {
|
|
214
|
+
clearInterval(this.#pingInterval);
|
|
207
215
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return await completers[name](value);
|
|
213
|
-
}
|
|
214
|
-
return {
|
|
215
|
-
values: []
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
this.#resourceTemplates.push(resourceTemplate);
|
|
220
|
-
}
|
|
221
|
-
addPrompt(inputPrompt) {
|
|
222
|
-
const completers = {};
|
|
223
|
-
const enums = {};
|
|
224
|
-
for (const argument of inputPrompt.arguments ?? []) {
|
|
225
|
-
if (argument.complete) {
|
|
226
|
-
completers[argument.name] = argument.complete;
|
|
227
|
-
}
|
|
228
|
-
if (argument.enum) {
|
|
229
|
-
enums[argument.name] = argument.enum;
|
|
230
|
-
}
|
|
216
|
+
try {
|
|
217
|
+
await this.#server.close();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error("[FastMCP error]", "could not close server", error);
|
|
231
220
|
}
|
|
232
|
-
const prompt = {
|
|
233
|
-
...inputPrompt,
|
|
234
|
-
complete: async (name, value) => {
|
|
235
|
-
if (completers[name]) {
|
|
236
|
-
return await completers[name](value);
|
|
237
|
-
}
|
|
238
|
-
if (enums[name]) {
|
|
239
|
-
const fuse = new Fuse(enums[name], {
|
|
240
|
-
keys: ["value"]
|
|
241
|
-
});
|
|
242
|
-
const result = fuse.search(value);
|
|
243
|
-
return {
|
|
244
|
-
values: result.map((item) => item.item),
|
|
245
|
-
total: result.length
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
return {
|
|
249
|
-
values: []
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
this.#prompts.push(prompt);
|
|
254
|
-
}
|
|
255
|
-
get clientCapabilities() {
|
|
256
|
-
return this.#clientCapabilities ?? null;
|
|
257
|
-
}
|
|
258
|
-
get server() {
|
|
259
|
-
return this.#server;
|
|
260
|
-
}
|
|
261
|
-
#pingInterval = null;
|
|
262
|
-
async requestSampling(message) {
|
|
263
|
-
return this.#server.createMessage(message);
|
|
264
221
|
}
|
|
265
222
|
async connect(transport) {
|
|
266
223
|
if (this.#server.transport) {
|
|
@@ -284,9 +241,11 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
284
241
|
const roots = await this.#server.listRoots();
|
|
285
242
|
this.#roots = roots.roots;
|
|
286
243
|
} catch (e) {
|
|
287
|
-
console.error(
|
|
244
|
+
console.error(
|
|
245
|
+
`[FastMCP error] received error listing roots.
|
|
288
246
|
|
|
289
|
-
${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
247
|
+
${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
248
|
+
);
|
|
290
249
|
}
|
|
291
250
|
}
|
|
292
251
|
if (this.#clientCapabilities) {
|
|
@@ -299,26 +258,65 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
299
258
|
}, 1e3);
|
|
300
259
|
}
|
|
301
260
|
}
|
|
302
|
-
|
|
303
|
-
return this.#
|
|
261
|
+
async requestSampling(message) {
|
|
262
|
+
return this.#server.createMessage(message);
|
|
304
263
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
+
}
|
|
313
274
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
+
}
|
|
318
295
|
};
|
|
296
|
+
this.#prompts.push(prompt);
|
|
319
297
|
}
|
|
320
|
-
|
|
321
|
-
|
|
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);
|
|
322
320
|
}
|
|
323
321
|
setupCompleteHandlers() {
|
|
324
322
|
this.#server.setRequestHandler(CompleteRequestSchema, async (request) => {
|
|
@@ -381,18 +379,10 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
381
379
|
});
|
|
382
380
|
});
|
|
383
381
|
}
|
|
384
|
-
|
|
385
|
-
this.#server.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
this.#server.listRoots().then((roots) => {
|
|
389
|
-
this.#roots = roots.roots;
|
|
390
|
-
this.emit("rootsChanged", {
|
|
391
|
-
roots: roots.roots
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
);
|
|
382
|
+
setupErrorHandling() {
|
|
383
|
+
this.#server.onerror = (error) => {
|
|
384
|
+
console.error("[FastMCP error]", error);
|
|
385
|
+
};
|
|
396
386
|
}
|
|
397
387
|
setupLoggingHandlers() {
|
|
398
388
|
this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {
|
|
@@ -400,118 +390,56 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
400
390
|
return {};
|
|
401
391
|
});
|
|
402
392
|
}
|
|
403
|
-
|
|
404
|
-
this.#server.setRequestHandler(
|
|
393
|
+
setupPromptHandlers(prompts) {
|
|
394
|
+
this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
405
395
|
return {
|
|
406
|
-
|
|
396
|
+
prompts: prompts.map((prompt) => {
|
|
407
397
|
return {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
398
|
+
arguments: prompt.arguments,
|
|
399
|
+
complete: prompt.complete,
|
|
400
|
+
description: prompt.description,
|
|
401
|
+
name: prompt.name
|
|
411
402
|
};
|
|
412
|
-
})
|
|
403
|
+
})
|
|
413
404
|
};
|
|
414
405
|
});
|
|
415
|
-
this.#server.setRequestHandler(
|
|
416
|
-
const
|
|
417
|
-
|
|
406
|
+
this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
407
|
+
const prompt = prompts.find(
|
|
408
|
+
(prompt2) => prompt2.name === request.params.name
|
|
409
|
+
);
|
|
410
|
+
if (!prompt) {
|
|
418
411
|
throw new McpError(
|
|
419
412
|
ErrorCode.MethodNotFound,
|
|
420
|
-
`Unknown
|
|
413
|
+
`Unknown prompt: ${request.params.name}`
|
|
421
414
|
);
|
|
422
415
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
request.params.arguments
|
|
427
|
-
);
|
|
428
|
-
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)) {
|
|
429
419
|
throw new McpError(
|
|
430
|
-
ErrorCode.
|
|
431
|
-
`
|
|
420
|
+
ErrorCode.InvalidRequest,
|
|
421
|
+
`Missing required argument: ${arg.name}`
|
|
432
422
|
);
|
|
433
423
|
}
|
|
434
|
-
args = parsed.value;
|
|
435
424
|
}
|
|
436
|
-
const progressToken = request.params?._meta?.progressToken;
|
|
437
425
|
let result;
|
|
438
426
|
try {
|
|
439
|
-
|
|
440
|
-
await this.#server.notification({
|
|
441
|
-
method: "notifications/progress",
|
|
442
|
-
params: {
|
|
443
|
-
...progress,
|
|
444
|
-
progressToken
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
};
|
|
448
|
-
const log = {
|
|
449
|
-
debug: (message, context) => {
|
|
450
|
-
this.#server.sendLoggingMessage({
|
|
451
|
-
level: "debug",
|
|
452
|
-
data: {
|
|
453
|
-
message,
|
|
454
|
-
context
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
},
|
|
458
|
-
error: (message, context) => {
|
|
459
|
-
this.#server.sendLoggingMessage({
|
|
460
|
-
level: "error",
|
|
461
|
-
data: {
|
|
462
|
-
message,
|
|
463
|
-
context
|
|
464
|
-
}
|
|
465
|
-
});
|
|
466
|
-
},
|
|
467
|
-
info: (message, context) => {
|
|
468
|
-
this.#server.sendLoggingMessage({
|
|
469
|
-
level: "info",
|
|
470
|
-
data: {
|
|
471
|
-
message,
|
|
472
|
-
context
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
},
|
|
476
|
-
warn: (message, context) => {
|
|
477
|
-
this.#server.sendLoggingMessage({
|
|
478
|
-
level: "warning",
|
|
479
|
-
data: {
|
|
480
|
-
message,
|
|
481
|
-
context
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
const maybeStringResult = await tool.execute(args, {
|
|
487
|
-
reportProgress,
|
|
488
|
-
log,
|
|
489
|
-
session: this.#auth
|
|
490
|
-
});
|
|
491
|
-
if (typeof maybeStringResult === "string") {
|
|
492
|
-
result = ContentResultZodSchema.parse({
|
|
493
|
-
content: [{ type: "text", text: maybeStringResult }]
|
|
494
|
-
});
|
|
495
|
-
} else if ("type" in maybeStringResult) {
|
|
496
|
-
result = ContentResultZodSchema.parse({
|
|
497
|
-
content: [maybeStringResult]
|
|
498
|
-
});
|
|
499
|
-
} else {
|
|
500
|
-
result = ContentResultZodSchema.parse(maybeStringResult);
|
|
501
|
-
}
|
|
427
|
+
result = await prompt.load(args);
|
|
502
428
|
} catch (error) {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
return {
|
|
510
|
-
content: [{ type: "text", text: `Error: ${error}` }],
|
|
511
|
-
isError: true
|
|
512
|
-
};
|
|
429
|
+
throw new McpError(
|
|
430
|
+
ErrorCode.InternalError,
|
|
431
|
+
`Error loading prompt: ${error}`
|
|
432
|
+
);
|
|
513
433
|
}
|
|
514
|
-
return
|
|
434
|
+
return {
|
|
435
|
+
description: prompt.description,
|
|
436
|
+
messages: [
|
|
437
|
+
{
|
|
438
|
+
content: { text: result, type: "text" },
|
|
439
|
+
role: "user"
|
|
440
|
+
}
|
|
441
|
+
]
|
|
442
|
+
};
|
|
515
443
|
});
|
|
516
444
|
}
|
|
517
445
|
setupResourceHandlers(resources) {
|
|
@@ -519,9 +447,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
519
447
|
return {
|
|
520
448
|
resources: resources.map((resource) => {
|
|
521
449
|
return {
|
|
522
|
-
|
|
450
|
+
mimeType: resource.mimeType,
|
|
523
451
|
name: resource.name,
|
|
524
|
-
|
|
452
|
+
uri: resource.uri
|
|
525
453
|
};
|
|
526
454
|
})
|
|
527
455
|
};
|
|
@@ -547,9 +475,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
547
475
|
return {
|
|
548
476
|
contents: [
|
|
549
477
|
{
|
|
550
|
-
uri,
|
|
551
478
|
mimeType: resourceTemplate.mimeType,
|
|
552
479
|
name: resourceTemplate.name,
|
|
480
|
+
uri,
|
|
553
481
|
...result
|
|
554
482
|
}
|
|
555
483
|
]
|
|
@@ -578,9 +506,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
578
506
|
if (Array.isArray(maybeArrayResult)) {
|
|
579
507
|
return {
|
|
580
508
|
contents: maybeArrayResult.map((result) => ({
|
|
581
|
-
uri: resource.uri,
|
|
582
509
|
mimeType: resource.mimeType,
|
|
583
510
|
name: resource.name,
|
|
511
|
+
uri: resource.uri,
|
|
584
512
|
...result
|
|
585
513
|
}))
|
|
586
514
|
};
|
|
@@ -588,9 +516,9 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
588
516
|
return {
|
|
589
517
|
contents: [
|
|
590
518
|
{
|
|
591
|
-
uri: resource.uri,
|
|
592
519
|
mimeType: resource.mimeType,
|
|
593
520
|
name: resource.name,
|
|
521
|
+
uri: resource.uri,
|
|
594
522
|
...maybeArrayResult
|
|
595
523
|
}
|
|
596
524
|
]
|
|
@@ -618,56 +546,134 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
|
|
|
618
546
|
}
|
|
619
547
|
);
|
|
620
548
|
}
|
|
621
|
-
|
|
622
|
-
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 () => {
|
|
623
564
|
return {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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
|
+
)
|
|
632
575
|
};
|
|
633
576
|
});
|
|
634
|
-
this.#server.setRequestHandler(
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
);
|
|
638
|
-
if (!prompt) {
|
|
577
|
+
this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
578
|
+
const tool = tools.find((tool2) => tool2.name === request.params.name);
|
|
579
|
+
if (!tool) {
|
|
639
580
|
throw new McpError(
|
|
640
581
|
ErrorCode.MethodNotFound,
|
|
641
|
-
`Unknown
|
|
582
|
+
`Unknown tool: ${request.params.name}`
|
|
642
583
|
);
|
|
643
584
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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) {
|
|
647
591
|
throw new McpError(
|
|
648
|
-
ErrorCode.
|
|
649
|
-
`
|
|
592
|
+
ErrorCode.InvalidParams,
|
|
593
|
+
`Invalid ${request.params.name} parameters`
|
|
650
594
|
);
|
|
651
595
|
}
|
|
596
|
+
args = parsed.value;
|
|
652
597
|
}
|
|
598
|
+
const progressToken = request.params?._meta?.progressToken;
|
|
653
599
|
let result;
|
|
654
600
|
try {
|
|
655
|
-
|
|
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
|
+
}
|
|
656
664
|
} catch (error) {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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
|
+
};
|
|
661
675
|
}
|
|
662
|
-
return
|
|
663
|
-
description: prompt.description,
|
|
664
|
-
messages: [
|
|
665
|
-
{
|
|
666
|
-
role: "user",
|
|
667
|
-
content: { type: "text", text: result }
|
|
668
|
-
}
|
|
669
|
-
]
|
|
670
|
-
};
|
|
676
|
+
return result;
|
|
671
677
|
});
|
|
672
678
|
}
|
|
673
679
|
};
|
|
@@ -681,6 +687,10 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
681
687
|
this.#options = options;
|
|
682
688
|
this.#authenticate = options.authenticate;
|
|
683
689
|
}
|
|
690
|
+
get sessions() {
|
|
691
|
+
return this.#sessions;
|
|
692
|
+
}
|
|
693
|
+
#authenticate;
|
|
684
694
|
#options;
|
|
685
695
|
#prompts = [];
|
|
686
696
|
#resources = [];
|
|
@@ -688,15 +698,11 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
688
698
|
#sessions = [];
|
|
689
699
|
#sseServer = null;
|
|
690
700
|
#tools = [];
|
|
691
|
-
#authenticate;
|
|
692
|
-
get sessions() {
|
|
693
|
-
return this.#sessions;
|
|
694
|
-
}
|
|
695
701
|
/**
|
|
696
|
-
* Adds a
|
|
702
|
+
* Adds a prompt to the server.
|
|
697
703
|
*/
|
|
698
|
-
|
|
699
|
-
this.#
|
|
704
|
+
addPrompt(prompt) {
|
|
705
|
+
this.#prompts.push(prompt);
|
|
700
706
|
}
|
|
701
707
|
/**
|
|
702
708
|
* Adds a resource to the server.
|
|
@@ -711,10 +717,10 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
711
717
|
this.#resourcesTemplates.push(resource);
|
|
712
718
|
}
|
|
713
719
|
/**
|
|
714
|
-
* Adds a
|
|
720
|
+
* Adds a tool to the server.
|
|
715
721
|
*/
|
|
716
|
-
|
|
717
|
-
this.#
|
|
722
|
+
addTool(tool) {
|
|
723
|
+
this.#tools.push(tool);
|
|
718
724
|
}
|
|
719
725
|
/**
|
|
720
726
|
* Starts the server.
|
|
@@ -725,12 +731,13 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
725
731
|
if (options.transportType === "stdio") {
|
|
726
732
|
const transport = new StdioServerTransport();
|
|
727
733
|
const session = new FastMCPSession({
|
|
734
|
+
instructions: this.#options.instructions,
|
|
728
735
|
name: this.#options.name,
|
|
729
|
-
|
|
730
|
-
tools: this.#tools,
|
|
736
|
+
prompts: this.#prompts,
|
|
731
737
|
resources: this.#resources,
|
|
732
738
|
resourcesTemplates: this.#resourcesTemplates,
|
|
733
|
-
|
|
739
|
+
tools: this.#tools,
|
|
740
|
+
version: this.#options.version
|
|
734
741
|
});
|
|
735
742
|
await session.connect(transport);
|
|
736
743
|
this.#sessions.push(session);
|
|
@@ -739,8 +746,6 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
739
746
|
});
|
|
740
747
|
} else if (options.transportType === "sse") {
|
|
741
748
|
this.#sseServer = await startSSEServer({
|
|
742
|
-
endpoint: options.sse.endpoint,
|
|
743
|
-
port: options.sse.port,
|
|
744
749
|
createServer: async (request) => {
|
|
745
750
|
let auth;
|
|
746
751
|
if (this.#authenticate) {
|
|
@@ -749,13 +754,14 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
749
754
|
return new FastMCPSession({
|
|
750
755
|
auth,
|
|
751
756
|
name: this.#options.name,
|
|
752
|
-
|
|
753
|
-
tools: this.#tools,
|
|
757
|
+
prompts: this.#prompts,
|
|
754
758
|
resources: this.#resources,
|
|
755
759
|
resourcesTemplates: this.#resourcesTemplates,
|
|
756
|
-
|
|
760
|
+
tools: this.#tools,
|
|
761
|
+
version: this.#options.version
|
|
757
762
|
});
|
|
758
763
|
},
|
|
764
|
+
endpoint: options.sse.endpoint,
|
|
759
765
|
onClose: (session) => {
|
|
760
766
|
this.emit("disconnect", {
|
|
761
767
|
session
|
|
@@ -766,7 +772,8 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
766
772
|
this.emit("connect", {
|
|
767
773
|
session
|
|
768
774
|
});
|
|
769
|
-
}
|
|
775
|
+
},
|
|
776
|
+
port: options.sse.port
|
|
770
777
|
});
|
|
771
778
|
console.info(
|
|
772
779
|
`[FastMCP info] server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`
|