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/src/FastMCP.test.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { FastMCP, FastMCPSession, UserError, imageContent } from "./FastMCP.js";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { test, expect, vi } from "vitest";
|
|
4
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5
2
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
6
|
-
import { getRandomPort } from "get-port-please";
|
|
7
|
-
import { setTimeout as delay } from "timers/promises";
|
|
8
3
|
import {
|
|
9
4
|
CreateMessageRequestSchema,
|
|
10
5
|
ErrorCode,
|
|
@@ -14,14 +9,19 @@ import {
|
|
|
14
9
|
PingRequestSchema,
|
|
15
10
|
Root,
|
|
16
11
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
17
|
-
import { createEventSource, EventSourceClient } from
|
|
12
|
+
import { createEventSource, EventSourceClient } from "eventsource-client";
|
|
13
|
+
import { getRandomPort } from "get-port-please";
|
|
14
|
+
import { setTimeout as delay } from "timers/promises";
|
|
15
|
+
import { expect, test, vi } from "vitest";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
import { FastMCP, FastMCPSession, imageContent, UserError } from "./FastMCP.js";
|
|
18
19
|
|
|
19
20
|
const runWithTestServer = async ({
|
|
20
|
-
run,
|
|
21
21
|
client: createClient,
|
|
22
|
+
run,
|
|
22
23
|
server: createServer,
|
|
23
24
|
}: {
|
|
24
|
-
server?: () => Promise<FastMCP>;
|
|
25
25
|
client?: () => Promise<Client>;
|
|
26
26
|
run: ({
|
|
27
27
|
client,
|
|
@@ -31,6 +31,7 @@ const runWithTestServer = async ({
|
|
|
31
31
|
server: FastMCP;
|
|
32
32
|
session: FastMCPSession;
|
|
33
33
|
}) => Promise<void>;
|
|
34
|
+
server?: () => Promise<FastMCP>;
|
|
34
35
|
}) => {
|
|
35
36
|
const port = await getRandomPort();
|
|
36
37
|
|
|
@@ -42,11 +43,11 @@ const runWithTestServer = async ({
|
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
await server.start({
|
|
45
|
-
transportType: "sse",
|
|
46
46
|
sse: {
|
|
47
47
|
endpoint: "/sse",
|
|
48
48
|
port,
|
|
49
49
|
},
|
|
50
|
+
transportType: "sse",
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
try {
|
|
@@ -68,7 +69,6 @@ const runWithTestServer = async ({
|
|
|
68
69
|
|
|
69
70
|
const session = await new Promise<FastMCPSession>((resolve) => {
|
|
70
71
|
server.on("connect", (event) => {
|
|
71
|
-
|
|
72
72
|
resolve(event.session);
|
|
73
73
|
});
|
|
74
74
|
|
|
@@ -85,51 +85,26 @@ const runWithTestServer = async ({
|
|
|
85
85
|
|
|
86
86
|
test("adds tools", async () => {
|
|
87
87
|
await runWithTestServer({
|
|
88
|
-
server: async () => {
|
|
89
|
-
const server = new FastMCP({
|
|
90
|
-
name: "Test",
|
|
91
|
-
version: "1.0.0",
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
server.addTool({
|
|
95
|
-
name: "add",
|
|
96
|
-
description: "Add two numbers",
|
|
97
|
-
parameters: z.object({
|
|
98
|
-
a: z.number(),
|
|
99
|
-
b: z.number(),
|
|
100
|
-
}),
|
|
101
|
-
execute: async (args) => {
|
|
102
|
-
return String(args.a + args.b);
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
return server;
|
|
107
|
-
},
|
|
108
88
|
run: async ({ client }) => {
|
|
109
89
|
expect(await client.listTools()).toEqual({
|
|
110
90
|
tools: [
|
|
111
91
|
{
|
|
112
|
-
name: "add",
|
|
113
92
|
description: "Add two numbers",
|
|
114
93
|
inputSchema: {
|
|
115
|
-
additionalProperties: false,
|
|
116
94
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
117
|
-
|
|
95
|
+
additionalProperties: false,
|
|
118
96
|
properties: {
|
|
119
97
|
a: { type: "number" },
|
|
120
98
|
b: { type: "number" },
|
|
121
99
|
},
|
|
122
100
|
required: ["a", "b"],
|
|
101
|
+
type: "object",
|
|
123
102
|
},
|
|
103
|
+
name: "add",
|
|
124
104
|
},
|
|
125
105
|
],
|
|
126
106
|
});
|
|
127
107
|
},
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test("calls a tool", async () => {
|
|
132
|
-
await runWithTestServer({
|
|
133
108
|
server: async () => {
|
|
134
109
|
const server = new FastMCP({
|
|
135
110
|
name: "Test",
|
|
@@ -137,37 +112,37 @@ test("calls a tool", async () => {
|
|
|
137
112
|
});
|
|
138
113
|
|
|
139
114
|
server.addTool({
|
|
140
|
-
name: "add",
|
|
141
115
|
description: "Add two numbers",
|
|
116
|
+
execute: async (args) => {
|
|
117
|
+
return String(args.a + args.b);
|
|
118
|
+
},
|
|
119
|
+
name: "add",
|
|
142
120
|
parameters: z.object({
|
|
143
121
|
a: z.number(),
|
|
144
122
|
b: z.number(),
|
|
145
123
|
}),
|
|
146
|
-
execute: async (args) => {
|
|
147
|
-
return String(args.a + args.b);
|
|
148
|
-
},
|
|
149
124
|
});
|
|
150
125
|
|
|
151
126
|
return server;
|
|
152
127
|
},
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("calls a tool", async () => {
|
|
132
|
+
await runWithTestServer({
|
|
153
133
|
run: async ({ client }) => {
|
|
154
134
|
expect(
|
|
155
135
|
await client.callTool({
|
|
156
|
-
name: "add",
|
|
157
136
|
arguments: {
|
|
158
137
|
a: 1,
|
|
159
138
|
b: 2,
|
|
160
139
|
},
|
|
140
|
+
name: "add",
|
|
161
141
|
}),
|
|
162
142
|
).toEqual({
|
|
163
|
-
content: [{
|
|
143
|
+
content: [{ text: "3", type: "text" }],
|
|
164
144
|
});
|
|
165
145
|
},
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test("returns a list", async () => {
|
|
170
|
-
await runWithTestServer({
|
|
171
146
|
server: async () => {
|
|
172
147
|
const server = new FastMCP({
|
|
173
148
|
name: "Test",
|
|
@@ -175,45 +150,40 @@ test("returns a list", async () => {
|
|
|
175
150
|
});
|
|
176
151
|
|
|
177
152
|
server.addTool({
|
|
178
|
-
name: "add",
|
|
179
153
|
description: "Add two numbers",
|
|
154
|
+
execute: async (args) => {
|
|
155
|
+
return String(args.a + args.b);
|
|
156
|
+
},
|
|
157
|
+
name: "add",
|
|
180
158
|
parameters: z.object({
|
|
181
159
|
a: z.number(),
|
|
182
160
|
b: z.number(),
|
|
183
161
|
}),
|
|
184
|
-
execute: async () => {
|
|
185
|
-
return {
|
|
186
|
-
content: [
|
|
187
|
-
{ type: "text", text: "a" },
|
|
188
|
-
{ type: "text", text: "b" },
|
|
189
|
-
],
|
|
190
|
-
};
|
|
191
|
-
},
|
|
192
162
|
});
|
|
193
163
|
|
|
194
164
|
return server;
|
|
195
165
|
},
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("returns a list", async () => {
|
|
170
|
+
await runWithTestServer({
|
|
196
171
|
run: async ({ client }) => {
|
|
197
172
|
expect(
|
|
198
173
|
await client.callTool({
|
|
199
|
-
name: "add",
|
|
200
174
|
arguments: {
|
|
201
175
|
a: 1,
|
|
202
176
|
b: 2,
|
|
203
177
|
},
|
|
178
|
+
name: "add",
|
|
204
179
|
}),
|
|
205
180
|
).toEqual({
|
|
206
181
|
content: [
|
|
207
|
-
{
|
|
208
|
-
{
|
|
182
|
+
{ text: "a", type: "text" },
|
|
183
|
+
{ text: "b", type: "text" },
|
|
209
184
|
],
|
|
210
185
|
});
|
|
211
186
|
},
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
test("returns an image", async () => {
|
|
216
|
-
await runWithTestServer({
|
|
217
187
|
server: async () => {
|
|
218
188
|
const server = new FastMCP({
|
|
219
189
|
name: "Test",
|
|
@@ -221,48 +191,48 @@ test("returns an image", async () => {
|
|
|
221
191
|
});
|
|
222
192
|
|
|
223
193
|
server.addTool({
|
|
224
|
-
name: "add",
|
|
225
194
|
description: "Add two numbers",
|
|
195
|
+
execute: async () => {
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{ text: "a", type: "text" },
|
|
199
|
+
{ text: "b", type: "text" },
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
name: "add",
|
|
226
204
|
parameters: z.object({
|
|
227
205
|
a: z.number(),
|
|
228
206
|
b: z.number(),
|
|
229
207
|
}),
|
|
230
|
-
execute: async () => {
|
|
231
|
-
return imageContent({
|
|
232
|
-
buffer: Buffer.from(
|
|
233
|
-
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
|
|
234
|
-
"base64",
|
|
235
|
-
),
|
|
236
|
-
});
|
|
237
|
-
},
|
|
238
208
|
});
|
|
239
209
|
|
|
240
210
|
return server;
|
|
241
211
|
},
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("returns an image", async () => {
|
|
216
|
+
await runWithTestServer({
|
|
242
217
|
run: async ({ client }) => {
|
|
243
218
|
expect(
|
|
244
219
|
await client.callTool({
|
|
245
|
-
name: "add",
|
|
246
220
|
arguments: {
|
|
247
221
|
a: 1,
|
|
248
222
|
b: 2,
|
|
249
223
|
},
|
|
224
|
+
name: "add",
|
|
250
225
|
}),
|
|
251
226
|
).toEqual({
|
|
252
227
|
content: [
|
|
253
228
|
{
|
|
254
|
-
type: "image",
|
|
255
229
|
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
|
|
256
230
|
mimeType: "image/png",
|
|
231
|
+
type: "image",
|
|
257
232
|
},
|
|
258
233
|
],
|
|
259
234
|
});
|
|
260
235
|
},
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
test("handles UserError errors", async () => {
|
|
265
|
-
await runWithTestServer({
|
|
266
236
|
server: async () => {
|
|
267
237
|
const server = new FastMCP({
|
|
268
238
|
name: "Test",
|
|
@@ -270,54 +240,76 @@ test("handles UserError errors", async () => {
|
|
|
270
240
|
});
|
|
271
241
|
|
|
272
242
|
server.addTool({
|
|
273
|
-
name: "add",
|
|
274
243
|
description: "Add two numbers",
|
|
244
|
+
execute: async () => {
|
|
245
|
+
return imageContent({
|
|
246
|
+
buffer: Buffer.from(
|
|
247
|
+
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
|
|
248
|
+
"base64",
|
|
249
|
+
),
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
name: "add",
|
|
275
253
|
parameters: z.object({
|
|
276
254
|
a: z.number(),
|
|
277
255
|
b: z.number(),
|
|
278
256
|
}),
|
|
279
|
-
execute: async () => {
|
|
280
|
-
throw new UserError("Something went wrong");
|
|
281
|
-
},
|
|
282
257
|
});
|
|
283
258
|
|
|
284
259
|
return server;
|
|
285
260
|
},
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("handles UserError errors", async () => {
|
|
265
|
+
await runWithTestServer({
|
|
286
266
|
run: async ({ client }) => {
|
|
287
267
|
expect(
|
|
288
268
|
await client.callTool({
|
|
289
|
-
name: "add",
|
|
290
269
|
arguments: {
|
|
291
270
|
a: 1,
|
|
292
271
|
b: 2,
|
|
293
272
|
},
|
|
273
|
+
name: "add",
|
|
294
274
|
}),
|
|
295
275
|
).toEqual({
|
|
296
|
-
content: [{
|
|
276
|
+
content: [{ text: "Something went wrong", type: "text" }],
|
|
297
277
|
isError: true,
|
|
298
278
|
});
|
|
299
279
|
},
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
test("calling an unknown tool throws McpError with MethodNotFound code", async () => {
|
|
304
|
-
await runWithTestServer({
|
|
305
280
|
server: async () => {
|
|
306
281
|
const server = new FastMCP({
|
|
307
282
|
name: "Test",
|
|
308
283
|
version: "1.0.0",
|
|
309
284
|
});
|
|
310
285
|
|
|
286
|
+
server.addTool({
|
|
287
|
+
description: "Add two numbers",
|
|
288
|
+
execute: async () => {
|
|
289
|
+
throw new UserError("Something went wrong");
|
|
290
|
+
},
|
|
291
|
+
name: "add",
|
|
292
|
+
parameters: z.object({
|
|
293
|
+
a: z.number(),
|
|
294
|
+
b: z.number(),
|
|
295
|
+
}),
|
|
296
|
+
});
|
|
297
|
+
|
|
311
298
|
return server;
|
|
312
299
|
},
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("calling an unknown tool throws McpError with MethodNotFound code", async () => {
|
|
304
|
+
await runWithTestServer({
|
|
313
305
|
run: async ({ client }) => {
|
|
314
306
|
try {
|
|
315
307
|
await client.callTool({
|
|
316
|
-
name: "add",
|
|
317
308
|
arguments: {
|
|
318
309
|
a: 1,
|
|
319
310
|
b: 2,
|
|
320
311
|
},
|
|
312
|
+
name: "add",
|
|
321
313
|
});
|
|
322
314
|
} catch (error) {
|
|
323
315
|
expect(error).toBeInstanceOf(McpError);
|
|
@@ -326,48 +318,29 @@ test("calling an unknown tool throws McpError with MethodNotFound code", async (
|
|
|
326
318
|
expect(error.code).toBe(ErrorCode.MethodNotFound);
|
|
327
319
|
}
|
|
328
320
|
},
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
test("tracks tool progress", async () => {
|
|
333
|
-
await runWithTestServer({
|
|
334
321
|
server: async () => {
|
|
335
322
|
const server = new FastMCP({
|
|
336
323
|
name: "Test",
|
|
337
324
|
version: "1.0.0",
|
|
338
325
|
});
|
|
339
326
|
|
|
340
|
-
server.addTool({
|
|
341
|
-
name: "add",
|
|
342
|
-
description: "Add two numbers",
|
|
343
|
-
parameters: z.object({
|
|
344
|
-
a: z.number(),
|
|
345
|
-
b: z.number(),
|
|
346
|
-
}),
|
|
347
|
-
execute: async (args, { reportProgress }) => {
|
|
348
|
-
reportProgress({
|
|
349
|
-
progress: 0,
|
|
350
|
-
total: 10,
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
await delay(100);
|
|
354
|
-
|
|
355
|
-
return String(args.a + args.b);
|
|
356
|
-
},
|
|
357
|
-
});
|
|
358
|
-
|
|
359
327
|
return server;
|
|
360
328
|
},
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test("tracks tool progress", async () => {
|
|
333
|
+
await runWithTestServer({
|
|
361
334
|
run: async ({ client }) => {
|
|
362
335
|
const onProgress = vi.fn();
|
|
363
336
|
|
|
364
337
|
await client.callTool(
|
|
365
338
|
{
|
|
366
|
-
name: "add",
|
|
367
339
|
arguments: {
|
|
368
340
|
a: 1,
|
|
369
341
|
b: 2,
|
|
370
342
|
},
|
|
343
|
+
name: "add",
|
|
371
344
|
},
|
|
372
345
|
undefined,
|
|
373
346
|
{
|
|
@@ -381,6 +354,33 @@ test("tracks tool progress", async () => {
|
|
|
381
354
|
total: 10,
|
|
382
355
|
});
|
|
383
356
|
},
|
|
357
|
+
server: async () => {
|
|
358
|
+
const server = new FastMCP({
|
|
359
|
+
name: "Test",
|
|
360
|
+
version: "1.0.0",
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
server.addTool({
|
|
364
|
+
description: "Add two numbers",
|
|
365
|
+
execute: async (args, { reportProgress }) => {
|
|
366
|
+
reportProgress({
|
|
367
|
+
progress: 0,
|
|
368
|
+
total: 10,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
await delay(100);
|
|
372
|
+
|
|
373
|
+
return String(args.a + args.b);
|
|
374
|
+
},
|
|
375
|
+
name: "add",
|
|
376
|
+
parameters: z.object({
|
|
377
|
+
a: z.number(),
|
|
378
|
+
b: z.number(),
|
|
379
|
+
}),
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
return server;
|
|
383
|
+
},
|
|
384
384
|
});
|
|
385
385
|
});
|
|
386
386
|
|
|
@@ -400,33 +400,6 @@ test("sets logging levels", async () => {
|
|
|
400
400
|
|
|
401
401
|
test("sends logging messages to the client", async () => {
|
|
402
402
|
await runWithTestServer({
|
|
403
|
-
server: async () => {
|
|
404
|
-
const server = new FastMCP({
|
|
405
|
-
name: "Test",
|
|
406
|
-
version: "1.0.0",
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
server.addTool({
|
|
410
|
-
name: "add",
|
|
411
|
-
description: "Add two numbers",
|
|
412
|
-
parameters: z.object({
|
|
413
|
-
a: z.number(),
|
|
414
|
-
b: z.number(),
|
|
415
|
-
}),
|
|
416
|
-
execute: async (args, { log }) => {
|
|
417
|
-
log.debug("debug message", {
|
|
418
|
-
foo: "bar",
|
|
419
|
-
});
|
|
420
|
-
log.error("error message");
|
|
421
|
-
log.info("info message");
|
|
422
|
-
log.warn("warn message");
|
|
423
|
-
|
|
424
|
-
return String(args.a + args.b);
|
|
425
|
-
},
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
return server;
|
|
429
|
-
},
|
|
430
403
|
run: async ({ client }) => {
|
|
431
404
|
const onLog = vi.fn();
|
|
432
405
|
|
|
@@ -443,20 +416,20 @@ test("sends logging messages to the client", async () => {
|
|
|
443
416
|
);
|
|
444
417
|
|
|
445
418
|
await client.callTool({
|
|
446
|
-
name: "add",
|
|
447
419
|
arguments: {
|
|
448
420
|
a: 1,
|
|
449
421
|
b: 2,
|
|
450
422
|
},
|
|
423
|
+
name: "add",
|
|
451
424
|
});
|
|
452
425
|
|
|
453
426
|
expect(onLog).toHaveBeenCalledTimes(4);
|
|
454
427
|
expect(onLog).toHaveBeenNthCalledWith(1, {
|
|
455
|
-
level: "debug",
|
|
456
|
-
message: "debug message",
|
|
457
428
|
context: {
|
|
458
429
|
foo: "bar",
|
|
459
430
|
},
|
|
431
|
+
level: "debug",
|
|
432
|
+
message: "debug message",
|
|
460
433
|
});
|
|
461
434
|
expect(onLog).toHaveBeenNthCalledWith(2, {
|
|
462
435
|
level: "error",
|
|
@@ -471,46 +444,49 @@ test("sends logging messages to the client", async () => {
|
|
|
471
444
|
message: "warn message",
|
|
472
445
|
});
|
|
473
446
|
},
|
|
447
|
+
server: async () => {
|
|
448
|
+
const server = new FastMCP({
|
|
449
|
+
name: "Test",
|
|
450
|
+
version: "1.0.0",
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
server.addTool({
|
|
454
|
+
description: "Add two numbers",
|
|
455
|
+
execute: async (args, { log }) => {
|
|
456
|
+
log.debug("debug message", {
|
|
457
|
+
foo: "bar",
|
|
458
|
+
});
|
|
459
|
+
log.error("error message");
|
|
460
|
+
log.info("info message");
|
|
461
|
+
log.warn("warn message");
|
|
462
|
+
|
|
463
|
+
return String(args.a + args.b);
|
|
464
|
+
},
|
|
465
|
+
name: "add",
|
|
466
|
+
parameters: z.object({
|
|
467
|
+
a: z.number(),
|
|
468
|
+
b: z.number(),
|
|
469
|
+
}),
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
return server;
|
|
473
|
+
},
|
|
474
474
|
});
|
|
475
475
|
});
|
|
476
476
|
|
|
477
477
|
test("adds resources", async () => {
|
|
478
478
|
await runWithTestServer({
|
|
479
|
-
server: async () => {
|
|
480
|
-
const server = new FastMCP({
|
|
481
|
-
name: "Test",
|
|
482
|
-
version: "1.0.0",
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
server.addResource({
|
|
486
|
-
uri: "file:///logs/app.log",
|
|
487
|
-
name: "Application Logs",
|
|
488
|
-
mimeType: "text/plain",
|
|
489
|
-
async load() {
|
|
490
|
-
return {
|
|
491
|
-
text: "Example log content",
|
|
492
|
-
};
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
return server;
|
|
497
|
-
},
|
|
498
479
|
run: async ({ client }) => {
|
|
499
480
|
expect(await client.listResources()).toEqual({
|
|
500
481
|
resources: [
|
|
501
482
|
{
|
|
502
|
-
uri: "file:///logs/app.log",
|
|
503
|
-
name: "Application Logs",
|
|
504
483
|
mimeType: "text/plain",
|
|
484
|
+
name: "Application Logs",
|
|
485
|
+
uri: "file:///logs/app.log",
|
|
505
486
|
},
|
|
506
487
|
],
|
|
507
488
|
});
|
|
508
489
|
},
|
|
509
|
-
});
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
test("clients reads a resource", async () => {
|
|
513
|
-
await runWithTestServer({
|
|
514
490
|
server: async () => {
|
|
515
491
|
const server = new FastMCP({
|
|
516
492
|
name: "Test",
|
|
@@ -518,18 +494,23 @@ test("clients reads a resource", async () => {
|
|
|
518
494
|
});
|
|
519
495
|
|
|
520
496
|
server.addResource({
|
|
521
|
-
uri: "file:///logs/app.log",
|
|
522
|
-
name: "Application Logs",
|
|
523
|
-
mimeType: "text/plain",
|
|
524
497
|
async load() {
|
|
525
498
|
return {
|
|
526
499
|
text: "Example log content",
|
|
527
500
|
};
|
|
528
501
|
},
|
|
502
|
+
mimeType: "text/plain",
|
|
503
|
+
name: "Application Logs",
|
|
504
|
+
uri: "file:///logs/app.log",
|
|
529
505
|
});
|
|
530
506
|
|
|
531
507
|
return server;
|
|
532
508
|
},
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test("clients reads a resource", async () => {
|
|
513
|
+
await runWithTestServer({
|
|
533
514
|
run: async ({ client }) => {
|
|
534
515
|
expect(
|
|
535
516
|
await client.readResource({
|
|
@@ -538,19 +519,14 @@ test("clients reads a resource", async () => {
|
|
|
538
519
|
).toEqual({
|
|
539
520
|
contents: [
|
|
540
521
|
{
|
|
541
|
-
|
|
522
|
+
mimeType: "text/plain",
|
|
542
523
|
name: "Application Logs",
|
|
543
524
|
text: "Example log content",
|
|
544
|
-
|
|
525
|
+
uri: "file:///logs/app.log",
|
|
545
526
|
},
|
|
546
527
|
],
|
|
547
528
|
});
|
|
548
529
|
},
|
|
549
|
-
});
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
test("clients reads a resource that returns multiple resources", async () => {
|
|
553
|
-
await runWithTestServer({
|
|
554
530
|
server: async () => {
|
|
555
531
|
const server = new FastMCP({
|
|
556
532
|
name: "Test",
|
|
@@ -558,23 +534,23 @@ test("clients reads a resource that returns multiple resources", async () => {
|
|
|
558
534
|
});
|
|
559
535
|
|
|
560
536
|
server.addResource({
|
|
561
|
-
uri: "file:///logs/app.log",
|
|
562
|
-
name: "Application Logs",
|
|
563
|
-
mimeType: "text/plain",
|
|
564
537
|
async load() {
|
|
565
|
-
return
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
},
|
|
569
|
-
{
|
|
570
|
-
text: "b",
|
|
571
|
-
},
|
|
572
|
-
];
|
|
538
|
+
return {
|
|
539
|
+
text: "Example log content",
|
|
540
|
+
};
|
|
573
541
|
},
|
|
542
|
+
mimeType: "text/plain",
|
|
543
|
+
name: "Application Logs",
|
|
544
|
+
uri: "file:///logs/app.log",
|
|
574
545
|
});
|
|
575
546
|
|
|
576
547
|
return server;
|
|
577
548
|
},
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test("clients reads a resource that returns multiple resources", async () => {
|
|
553
|
+
await runWithTestServer({
|
|
578
554
|
run: async ({ client }) => {
|
|
579
555
|
expect(
|
|
580
556
|
await client.readResource({
|
|
@@ -583,65 +559,66 @@ test("clients reads a resource that returns multiple resources", async () => {
|
|
|
583
559
|
).toEqual({
|
|
584
560
|
contents: [
|
|
585
561
|
{
|
|
586
|
-
|
|
562
|
+
mimeType: "text/plain",
|
|
587
563
|
name: "Application Logs",
|
|
588
564
|
text: "a",
|
|
589
|
-
|
|
565
|
+
uri: "file:///logs/app.log",
|
|
590
566
|
},
|
|
591
567
|
{
|
|
592
|
-
|
|
568
|
+
mimeType: "text/plain",
|
|
593
569
|
name: "Application Logs",
|
|
594
570
|
text: "b",
|
|
595
|
-
|
|
571
|
+
uri: "file:///logs/app.log",
|
|
596
572
|
},
|
|
597
573
|
],
|
|
598
574
|
});
|
|
599
575
|
},
|
|
600
|
-
});
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
test("adds prompts", async () => {
|
|
604
|
-
await runWithTestServer({
|
|
605
576
|
server: async () => {
|
|
606
577
|
const server = new FastMCP({
|
|
607
578
|
name: "Test",
|
|
608
579
|
version: "1.0.0",
|
|
609
580
|
});
|
|
610
581
|
|
|
611
|
-
server.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
load: async (args) => {
|
|
622
|
-
return `Generate a concise but descriptive commit message for these changes:\n\n${args.changes}`;
|
|
582
|
+
server.addResource({
|
|
583
|
+
async load() {
|
|
584
|
+
return [
|
|
585
|
+
{
|
|
586
|
+
text: "a",
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
text: "b",
|
|
590
|
+
},
|
|
591
|
+
];
|
|
623
592
|
},
|
|
593
|
+
mimeType: "text/plain",
|
|
594
|
+
name: "Application Logs",
|
|
595
|
+
uri: "file:///logs/app.log",
|
|
624
596
|
});
|
|
625
597
|
|
|
626
598
|
return server;
|
|
627
599
|
},
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
test("adds prompts", async () => {
|
|
604
|
+
await runWithTestServer({
|
|
628
605
|
run: async ({ client }) => {
|
|
629
606
|
expect(
|
|
630
607
|
await client.getPrompt({
|
|
631
|
-
name: "git-commit",
|
|
632
608
|
arguments: {
|
|
633
609
|
changes: "foo",
|
|
634
610
|
},
|
|
611
|
+
name: "git-commit",
|
|
635
612
|
}),
|
|
636
613
|
).toEqual({
|
|
637
614
|
description: "Generate a Git commit message",
|
|
638
615
|
messages: [
|
|
639
616
|
{
|
|
640
|
-
role: "user",
|
|
641
617
|
content: {
|
|
642
|
-
type: "text",
|
|
643
618
|
text: "Generate a concise but descriptive commit message for these changes:\n\nfoo",
|
|
619
|
+
type: "text",
|
|
644
620
|
},
|
|
621
|
+
role: "user",
|
|
645
622
|
},
|
|
646
623
|
],
|
|
647
624
|
});
|
|
@@ -649,18 +626,41 @@ test("adds prompts", async () => {
|
|
|
649
626
|
expect(await client.listPrompts()).toEqual({
|
|
650
627
|
prompts: [
|
|
651
628
|
{
|
|
652
|
-
name: "git-commit",
|
|
653
|
-
description: "Generate a Git commit message",
|
|
654
629
|
arguments: [
|
|
655
630
|
{
|
|
656
|
-
name: "changes",
|
|
657
631
|
description: "Git diff or description of changes",
|
|
632
|
+
name: "changes",
|
|
658
633
|
required: true,
|
|
659
634
|
},
|
|
660
635
|
],
|
|
636
|
+
description: "Generate a Git commit message",
|
|
637
|
+
name: "git-commit",
|
|
638
|
+
},
|
|
639
|
+
],
|
|
640
|
+
});
|
|
641
|
+
},
|
|
642
|
+
server: async () => {
|
|
643
|
+
const server = new FastMCP({
|
|
644
|
+
name: "Test",
|
|
645
|
+
version: "1.0.0",
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
server.addPrompt({
|
|
649
|
+
arguments: [
|
|
650
|
+
{
|
|
651
|
+
description: "Git diff or description of changes",
|
|
652
|
+
name: "changes",
|
|
653
|
+
required: true,
|
|
661
654
|
},
|
|
662
655
|
],
|
|
656
|
+
description: "Generate a Git commit message",
|
|
657
|
+
load: async (args) => {
|
|
658
|
+
return `Generate a concise but descriptive commit message for these changes:\n\n${args.changes}`;
|
|
659
|
+
},
|
|
660
|
+
name: "git-commit",
|
|
663
661
|
});
|
|
662
|
+
|
|
663
|
+
return server;
|
|
664
664
|
},
|
|
665
665
|
});
|
|
666
666
|
});
|
|
@@ -680,11 +680,11 @@ test("uses events to notify server of client connect/disconnect", async () => {
|
|
|
680
680
|
server.on("disconnect", onDisconnect);
|
|
681
681
|
|
|
682
682
|
await server.start({
|
|
683
|
-
transportType: "sse",
|
|
684
683
|
sse: {
|
|
685
684
|
endpoint: "/sse",
|
|
686
685
|
port,
|
|
687
686
|
},
|
|
687
|
+
transportType: "sse",
|
|
688
688
|
});
|
|
689
689
|
|
|
690
690
|
const client = new Client(
|
|
@@ -729,11 +729,11 @@ test("handles multiple clients", async () => {
|
|
|
729
729
|
});
|
|
730
730
|
|
|
731
731
|
await server.start({
|
|
732
|
-
transportType: "sse",
|
|
733
732
|
sse: {
|
|
734
733
|
endpoint: "/sse",
|
|
735
734
|
port,
|
|
736
735
|
},
|
|
736
|
+
transportType: "sse",
|
|
737
737
|
});
|
|
738
738
|
|
|
739
739
|
const client1 = new Client(
|
|
@@ -799,8 +799,8 @@ test("session knows about client capabilities", async () => {
|
|
|
799
799
|
return {
|
|
800
800
|
roots: [
|
|
801
801
|
{
|
|
802
|
-
uri: "file:///home/user/projects/frontend",
|
|
803
802
|
name: "Frontend Repository",
|
|
803
|
+
uri: "file:///home/user/projects/frontend",
|
|
804
804
|
},
|
|
805
805
|
],
|
|
806
806
|
};
|
|
@@ -839,8 +839,8 @@ test("session knows about roots", async () => {
|
|
|
839
839
|
return {
|
|
840
840
|
roots: [
|
|
841
841
|
{
|
|
842
|
-
uri: "file:///home/user/projects/frontend",
|
|
843
842
|
name: "Frontend Repository",
|
|
843
|
+
uri: "file:///home/user/projects/frontend",
|
|
844
844
|
},
|
|
845
845
|
],
|
|
846
846
|
};
|
|
@@ -851,8 +851,8 @@ test("session knows about roots", async () => {
|
|
|
851
851
|
run: async ({ session }) => {
|
|
852
852
|
expect(session.roots).toEqual([
|
|
853
853
|
{
|
|
854
|
-
uri: "file:///home/user/projects/frontend",
|
|
855
854
|
name: "Frontend Repository",
|
|
855
|
+
uri: "file:///home/user/projects/frontend",
|
|
856
856
|
},
|
|
857
857
|
]);
|
|
858
858
|
},
|
|
@@ -860,10 +860,10 @@ test("session knows about roots", async () => {
|
|
|
860
860
|
});
|
|
861
861
|
|
|
862
862
|
test("session listens to roots changes", async () => {
|
|
863
|
-
|
|
863
|
+
const clientRoots: Root[] = [
|
|
864
864
|
{
|
|
865
|
-
uri: "file:///home/user/projects/frontend",
|
|
866
865
|
name: "Frontend Repository",
|
|
866
|
+
uri: "file:///home/user/projects/frontend",
|
|
867
867
|
},
|
|
868
868
|
];
|
|
869
869
|
|
|
@@ -891,17 +891,17 @@ test("session listens to roots changes", async () => {
|
|
|
891
891
|
|
|
892
892
|
return client;
|
|
893
893
|
},
|
|
894
|
-
run: async ({
|
|
894
|
+
run: async ({ client, session }) => {
|
|
895
895
|
expect(session.roots).toEqual([
|
|
896
896
|
{
|
|
897
|
-
uri: "file:///home/user/projects/frontend",
|
|
898
897
|
name: "Frontend Repository",
|
|
898
|
+
uri: "file:///home/user/projects/frontend",
|
|
899
899
|
},
|
|
900
900
|
]);
|
|
901
901
|
|
|
902
902
|
clientRoots.push({
|
|
903
|
-
uri: "file:///home/user/projects/backend",
|
|
904
903
|
name: "Backend Repository",
|
|
904
|
+
uri: "file:///home/user/projects/backend",
|
|
905
905
|
});
|
|
906
906
|
|
|
907
907
|
await client.sendRootsListChanged();
|
|
@@ -914,12 +914,12 @@ test("session listens to roots changes", async () => {
|
|
|
914
914
|
|
|
915
915
|
expect(session.roots).toEqual([
|
|
916
916
|
{
|
|
917
|
-
uri: "file:///home/user/projects/frontend",
|
|
918
917
|
name: "Frontend Repository",
|
|
918
|
+
uri: "file:///home/user/projects/frontend",
|
|
919
919
|
},
|
|
920
920
|
{
|
|
921
|
-
uri: "file:///home/user/projects/backend",
|
|
922
921
|
name: "Backend Repository",
|
|
922
|
+
uri: "file:///home/user/projects/backend",
|
|
923
923
|
},
|
|
924
924
|
]);
|
|
925
925
|
|
|
@@ -927,12 +927,12 @@ test("session listens to roots changes", async () => {
|
|
|
927
927
|
expect(onRootsChanged).toHaveBeenCalledWith({
|
|
928
928
|
roots: [
|
|
929
929
|
{
|
|
930
|
-
uri: "file:///home/user/projects/frontend",
|
|
931
930
|
name: "Frontend Repository",
|
|
931
|
+
uri: "file:///home/user/projects/frontend",
|
|
932
932
|
},
|
|
933
933
|
{
|
|
934
|
-
uri: "file:///home/user/projects/backend",
|
|
935
934
|
name: "Backend Repository",
|
|
935
|
+
uri: "file:///home/user/projects/backend",
|
|
936
936
|
},
|
|
937
937
|
],
|
|
938
938
|
});
|
|
@@ -956,6 +956,24 @@ test("session sends pings to the client", async () => {
|
|
|
956
956
|
|
|
957
957
|
test("completes prompt arguments", async () => {
|
|
958
958
|
await runWithTestServer({
|
|
959
|
+
run: async ({ client }) => {
|
|
960
|
+
const response = await client.complete({
|
|
961
|
+
argument: {
|
|
962
|
+
name: "name",
|
|
963
|
+
value: "Germ",
|
|
964
|
+
},
|
|
965
|
+
ref: {
|
|
966
|
+
name: "countryPoem",
|
|
967
|
+
type: "ref/prompt",
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
expect(response).toEqual({
|
|
972
|
+
completion: {
|
|
973
|
+
values: ["Germany"],
|
|
974
|
+
},
|
|
975
|
+
});
|
|
976
|
+
},
|
|
959
977
|
server: async () => {
|
|
960
978
|
const server = new FastMCP({
|
|
961
979
|
name: "Test",
|
|
@@ -963,16 +981,8 @@ test("completes prompt arguments", async () => {
|
|
|
963
981
|
});
|
|
964
982
|
|
|
965
983
|
server.addPrompt({
|
|
966
|
-
name: "countryPoem",
|
|
967
|
-
description: "Writes a poem about a country",
|
|
968
|
-
load: async ({ name }) => {
|
|
969
|
-
return `Hello, ${name}!`;
|
|
970
|
-
},
|
|
971
984
|
arguments: [
|
|
972
985
|
{
|
|
973
|
-
name: "name",
|
|
974
|
-
description: "Name of the country",
|
|
975
|
-
required: true,
|
|
976
986
|
complete: async (value) => {
|
|
977
987
|
if (value === "Germ") {
|
|
978
988
|
return {
|
|
@@ -984,35 +994,44 @@ test("completes prompt arguments", async () => {
|
|
|
984
994
|
values: [],
|
|
985
995
|
};
|
|
986
996
|
},
|
|
997
|
+
description: "Name of the country",
|
|
998
|
+
name: "name",
|
|
999
|
+
required: true,
|
|
987
1000
|
},
|
|
988
1001
|
],
|
|
1002
|
+
description: "Writes a poem about a country",
|
|
1003
|
+
load: async ({ name }) => {
|
|
1004
|
+
return `Hello, ${name}!`;
|
|
1005
|
+
},
|
|
1006
|
+
name: "countryPoem",
|
|
989
1007
|
});
|
|
990
1008
|
|
|
991
1009
|
return server;
|
|
992
1010
|
},
|
|
1011
|
+
});
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
test("adds automatic prompt argument completion when enum is provided", async () => {
|
|
1015
|
+
await runWithTestServer({
|
|
993
1016
|
run: async ({ client }) => {
|
|
994
1017
|
const response = await client.complete({
|
|
995
|
-
ref: {
|
|
996
|
-
type: "ref/prompt",
|
|
997
|
-
name: "countryPoem",
|
|
998
|
-
},
|
|
999
1018
|
argument: {
|
|
1000
1019
|
name: "name",
|
|
1001
1020
|
value: "Germ",
|
|
1002
1021
|
},
|
|
1022
|
+
ref: {
|
|
1023
|
+
name: "countryPoem",
|
|
1024
|
+
type: "ref/prompt",
|
|
1025
|
+
},
|
|
1003
1026
|
});
|
|
1004
1027
|
|
|
1005
1028
|
expect(response).toEqual({
|
|
1006
1029
|
completion: {
|
|
1030
|
+
total: 1,
|
|
1007
1031
|
values: ["Germany"],
|
|
1008
1032
|
},
|
|
1009
1033
|
});
|
|
1010
1034
|
},
|
|
1011
|
-
});
|
|
1012
|
-
});
|
|
1013
|
-
|
|
1014
|
-
test("adds automatic prompt argument completion when enum is provided", async () => {
|
|
1015
|
-
await runWithTestServer({
|
|
1016
1035
|
server: async () => {
|
|
1017
1036
|
const server = new FastMCP({
|
|
1018
1037
|
name: "Test",
|
|
@@ -1020,47 +1039,46 @@ test("adds automatic prompt argument completion when enum is provided", async ()
|
|
|
1020
1039
|
});
|
|
1021
1040
|
|
|
1022
1041
|
server.addPrompt({
|
|
1023
|
-
name: "countryPoem",
|
|
1024
|
-
description: "Writes a poem about a country",
|
|
1025
|
-
load: async ({ name }) => {
|
|
1026
|
-
return `Hello, ${name}!`;
|
|
1027
|
-
},
|
|
1028
1042
|
arguments: [
|
|
1029
1043
|
{
|
|
1030
|
-
name: "name",
|
|
1031
1044
|
description: "Name of the country",
|
|
1032
|
-
required: true,
|
|
1033
1045
|
enum: ["Germany", "France", "Italy"],
|
|
1046
|
+
name: "name",
|
|
1047
|
+
required: true,
|
|
1034
1048
|
},
|
|
1035
1049
|
],
|
|
1050
|
+
description: "Writes a poem about a country",
|
|
1051
|
+
load: async ({ name }) => {
|
|
1052
|
+
return `Hello, ${name}!`;
|
|
1053
|
+
},
|
|
1054
|
+
name: "countryPoem",
|
|
1036
1055
|
});
|
|
1037
1056
|
|
|
1038
1057
|
return server;
|
|
1039
1058
|
},
|
|
1059
|
+
});
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
test("completes template resource arguments", async () => {
|
|
1063
|
+
await runWithTestServer({
|
|
1040
1064
|
run: async ({ client }) => {
|
|
1041
1065
|
const response = await client.complete({
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1066
|
+
argument: {
|
|
1067
|
+
name: "issueId",
|
|
1068
|
+
value: "123",
|
|
1045
1069
|
},
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1070
|
+
ref: {
|
|
1071
|
+
type: "ref/resource",
|
|
1072
|
+
uri: "issue:///{issueId}",
|
|
1049
1073
|
},
|
|
1050
1074
|
});
|
|
1051
1075
|
|
|
1052
1076
|
expect(response).toEqual({
|
|
1053
1077
|
completion: {
|
|
1054
|
-
values: ["
|
|
1055
|
-
total: 1,
|
|
1078
|
+
values: ["123456"],
|
|
1056
1079
|
},
|
|
1057
1080
|
});
|
|
1058
1081
|
},
|
|
1059
|
-
});
|
|
1060
|
-
});
|
|
1061
|
-
|
|
1062
|
-
test("completes template resource arguments", async () => {
|
|
1063
|
-
await runWithTestServer({
|
|
1064
1082
|
server: async () => {
|
|
1065
1083
|
const server = new FastMCP({
|
|
1066
1084
|
name: "Test",
|
|
@@ -1068,13 +1086,8 @@ test("completes template resource arguments", async () => {
|
|
|
1068
1086
|
});
|
|
1069
1087
|
|
|
1070
1088
|
server.addResourceTemplate({
|
|
1071
|
-
uriTemplate: "issue:///{issueId}",
|
|
1072
|
-
name: "Issue",
|
|
1073
|
-
mimeType: "text/plain",
|
|
1074
1089
|
arguments: [
|
|
1075
1090
|
{
|
|
1076
|
-
name: "issueId",
|
|
1077
|
-
description: "ID of the issue",
|
|
1078
1091
|
complete: async (value) => {
|
|
1079
1092
|
if (value === "123") {
|
|
1080
1093
|
return {
|
|
@@ -1086,6 +1099,8 @@ test("completes template resource arguments", async () => {
|
|
|
1086
1099
|
values: [],
|
|
1087
1100
|
};
|
|
1088
1101
|
},
|
|
1102
|
+
description: "ID of the issue",
|
|
1103
|
+
name: "issueId",
|
|
1089
1104
|
},
|
|
1090
1105
|
],
|
|
1091
1106
|
load: async ({ issueId }) => {
|
|
@@ -1093,33 +1108,28 @@ test("completes template resource arguments", async () => {
|
|
|
1093
1108
|
text: `Issue ${issueId}`,
|
|
1094
1109
|
};
|
|
1095
1110
|
},
|
|
1111
|
+
mimeType: "text/plain",
|
|
1112
|
+
name: "Issue",
|
|
1113
|
+
uriTemplate: "issue:///{issueId}",
|
|
1096
1114
|
});
|
|
1097
1115
|
|
|
1098
1116
|
return server;
|
|
1099
1117
|
},
|
|
1100
|
-
run: async ({ client }) => {
|
|
1101
|
-
const response = await client.complete({
|
|
1102
|
-
ref: {
|
|
1103
|
-
type: "ref/resource",
|
|
1104
|
-
uri: "issue:///{issueId}",
|
|
1105
|
-
},
|
|
1106
|
-
argument: {
|
|
1107
|
-
name: "issueId",
|
|
1108
|
-
value: "123",
|
|
1109
|
-
},
|
|
1110
|
-
});
|
|
1111
|
-
|
|
1112
|
-
expect(response).toEqual({
|
|
1113
|
-
completion: {
|
|
1114
|
-
values: ["123456"],
|
|
1115
|
-
},
|
|
1116
|
-
});
|
|
1117
|
-
},
|
|
1118
1118
|
});
|
|
1119
1119
|
});
|
|
1120
1120
|
|
|
1121
1121
|
test("lists resource templates", async () => {
|
|
1122
1122
|
await runWithTestServer({
|
|
1123
|
+
run: async ({ client }) => {
|
|
1124
|
+
expect(await client.listResourceTemplates()).toEqual({
|
|
1125
|
+
resourceTemplates: [
|
|
1126
|
+
{
|
|
1127
|
+
name: "Application Logs",
|
|
1128
|
+
uriTemplate: "file:///logs/{name}.log",
|
|
1129
|
+
},
|
|
1130
|
+
],
|
|
1131
|
+
});
|
|
1132
|
+
},
|
|
1123
1133
|
server: async () => {
|
|
1124
1134
|
const server = new FastMCP({
|
|
1125
1135
|
name: "Test",
|
|
@@ -1127,13 +1137,10 @@ test("lists resource templates", async () => {
|
|
|
1127
1137
|
});
|
|
1128
1138
|
|
|
1129
1139
|
server.addResourceTemplate({
|
|
1130
|
-
uriTemplate: "file:///logs/{name}.log",
|
|
1131
|
-
name: "Application Logs",
|
|
1132
|
-
mimeType: "text/plain",
|
|
1133
1140
|
arguments: [
|
|
1134
1141
|
{
|
|
1135
|
-
name: "name",
|
|
1136
1142
|
description: "Name of the log",
|
|
1143
|
+
name: "name",
|
|
1137
1144
|
required: true,
|
|
1138
1145
|
},
|
|
1139
1146
|
],
|
|
@@ -1142,24 +1149,18 @@ test("lists resource templates", async () => {
|
|
|
1142
1149
|
text: `Example log content for ${name}`,
|
|
1143
1150
|
};
|
|
1144
1151
|
},
|
|
1152
|
+
mimeType: "text/plain",
|
|
1153
|
+
name: "Application Logs",
|
|
1154
|
+
uriTemplate: "file:///logs/{name}.log",
|
|
1145
1155
|
});
|
|
1146
1156
|
|
|
1147
1157
|
return server;
|
|
1148
1158
|
},
|
|
1149
|
-
run: async ({ client }) => {
|
|
1150
|
-
expect(await client.listResourceTemplates()).toEqual({
|
|
1151
|
-
resourceTemplates: [
|
|
1152
|
-
{
|
|
1153
|
-
name: "Application Logs",
|
|
1154
|
-
uriTemplate: "file:///logs/{name}.log",
|
|
1155
|
-
},
|
|
1156
|
-
],
|
|
1157
|
-
});
|
|
1158
|
-
},
|
|
1159
1159
|
});
|
|
1160
1160
|
});
|
|
1161
1161
|
|
|
1162
1162
|
test("clients reads a resource accessed via a resource template", async () => {
|
|
1163
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1163
1164
|
const loadSpy = vi.fn((_args) => {
|
|
1164
1165
|
return {
|
|
1165
1166
|
text: "Example log content",
|
|
@@ -1167,6 +1168,26 @@ test("clients reads a resource accessed via a resource template", async () => {
|
|
|
1167
1168
|
});
|
|
1168
1169
|
|
|
1169
1170
|
await runWithTestServer({
|
|
1171
|
+
run: async ({ client }) => {
|
|
1172
|
+
expect(
|
|
1173
|
+
await client.readResource({
|
|
1174
|
+
uri: "file:///logs/app.log",
|
|
1175
|
+
}),
|
|
1176
|
+
).toEqual({
|
|
1177
|
+
contents: [
|
|
1178
|
+
{
|
|
1179
|
+
mimeType: "text/plain",
|
|
1180
|
+
name: "Application Logs",
|
|
1181
|
+
text: "Example log content",
|
|
1182
|
+
uri: "file:///logs/app.log",
|
|
1183
|
+
},
|
|
1184
|
+
],
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
expect(loadSpy).toHaveBeenCalledWith({
|
|
1188
|
+
name: "app",
|
|
1189
|
+
});
|
|
1190
|
+
},
|
|
1170
1191
|
server: async () => {
|
|
1171
1192
|
const server = new FastMCP({
|
|
1172
1193
|
name: "Test",
|
|
@@ -1174,54 +1195,34 @@ test("clients reads a resource accessed via a resource template", async () => {
|
|
|
1174
1195
|
});
|
|
1175
1196
|
|
|
1176
1197
|
server.addResourceTemplate({
|
|
1177
|
-
uriTemplate: "file:///logs/{name}.log",
|
|
1178
|
-
name: "Application Logs",
|
|
1179
|
-
mimeType: "text/plain",
|
|
1180
1198
|
arguments: [
|
|
1181
1199
|
{
|
|
1182
|
-
name: "name",
|
|
1183
1200
|
description: "Name of the log",
|
|
1201
|
+
name: "name",
|
|
1184
1202
|
},
|
|
1185
1203
|
],
|
|
1186
1204
|
async load(args) {
|
|
1187
1205
|
return loadSpy(args);
|
|
1188
1206
|
},
|
|
1207
|
+
mimeType: "text/plain",
|
|
1208
|
+
name: "Application Logs",
|
|
1209
|
+
uriTemplate: "file:///logs/{name}.log",
|
|
1189
1210
|
});
|
|
1190
1211
|
|
|
1191
1212
|
return server;
|
|
1192
1213
|
},
|
|
1193
|
-
run: async ({ client }) => {
|
|
1194
|
-
expect(
|
|
1195
|
-
await client.readResource({
|
|
1196
|
-
uri: "file:///logs/app.log",
|
|
1197
|
-
}),
|
|
1198
|
-
).toEqual({
|
|
1199
|
-
contents: [
|
|
1200
|
-
{
|
|
1201
|
-
uri: "file:///logs/app.log",
|
|
1202
|
-
name: "Application Logs",
|
|
1203
|
-
text: "Example log content",
|
|
1204
|
-
mimeType: "text/plain",
|
|
1205
|
-
},
|
|
1206
|
-
],
|
|
1207
|
-
});
|
|
1208
|
-
|
|
1209
|
-
expect(loadSpy).toHaveBeenCalledWith({
|
|
1210
|
-
name: "app",
|
|
1211
|
-
});
|
|
1212
|
-
},
|
|
1213
1214
|
});
|
|
1214
1215
|
});
|
|
1215
1216
|
|
|
1216
1217
|
test("makes a sampling request", async () => {
|
|
1217
1218
|
const onMessageRequest = vi.fn(() => {
|
|
1218
1219
|
return {
|
|
1219
|
-
model: "gpt-3.5-turbo",
|
|
1220
|
-
role: "assistant",
|
|
1221
1220
|
content: {
|
|
1222
|
-
type: "text",
|
|
1223
1221
|
text: "The files are in the current directory.",
|
|
1222
|
+
type: "text",
|
|
1224
1223
|
},
|
|
1224
|
+
model: "gpt-3.5-turbo",
|
|
1225
|
+
role: "assistant",
|
|
1225
1226
|
};
|
|
1226
1227
|
});
|
|
1227
1228
|
|
|
@@ -1244,27 +1245,27 @@ test("makes a sampling request", async () => {
|
|
|
1244
1245
|
client.setRequestHandler(CreateMessageRequestSchema, onMessageRequest);
|
|
1245
1246
|
|
|
1246
1247
|
const response = await session.requestSampling({
|
|
1248
|
+
includeContext: "thisServer",
|
|
1249
|
+
maxTokens: 100,
|
|
1247
1250
|
messages: [
|
|
1248
1251
|
{
|
|
1249
|
-
role: "user",
|
|
1250
1252
|
content: {
|
|
1251
|
-
type: "text",
|
|
1252
1253
|
text: "What files are in the current directory?",
|
|
1254
|
+
type: "text",
|
|
1253
1255
|
},
|
|
1256
|
+
role: "user",
|
|
1254
1257
|
},
|
|
1255
1258
|
],
|
|
1256
1259
|
systemPrompt: "You are a helpful file system assistant.",
|
|
1257
|
-
includeContext: "thisServer",
|
|
1258
|
-
maxTokens: 100,
|
|
1259
1260
|
});
|
|
1260
1261
|
|
|
1261
1262
|
expect(response).toEqual({
|
|
1262
|
-
model: "gpt-3.5-turbo",
|
|
1263
|
-
role: "assistant",
|
|
1264
1263
|
content: {
|
|
1265
|
-
type: "text",
|
|
1266
1264
|
text: "The files are in the current directory.",
|
|
1265
|
+
type: "text",
|
|
1267
1266
|
},
|
|
1267
|
+
model: "gpt-3.5-turbo",
|
|
1268
|
+
role: "assistant",
|
|
1268
1269
|
});
|
|
1269
1270
|
|
|
1270
1271
|
expect(onMessageRequest).toHaveBeenCalledTimes(1);
|
|
@@ -1274,34 +1275,14 @@ test("makes a sampling request", async () => {
|
|
|
1274
1275
|
|
|
1275
1276
|
test("throws ErrorCode.InvalidParams if tool parameters do not match zod schema", async () => {
|
|
1276
1277
|
await runWithTestServer({
|
|
1277
|
-
server: async () => {
|
|
1278
|
-
const server = new FastMCP({
|
|
1279
|
-
name: "Test",
|
|
1280
|
-
version: "1.0.0",
|
|
1281
|
-
});
|
|
1282
|
-
|
|
1283
|
-
server.addTool({
|
|
1284
|
-
name: "add",
|
|
1285
|
-
description: "Add two numbers",
|
|
1286
|
-
parameters: z.object({
|
|
1287
|
-
a: z.number(),
|
|
1288
|
-
b: z.number(),
|
|
1289
|
-
}),
|
|
1290
|
-
execute: async (args) => {
|
|
1291
|
-
return String(args.a + args.b);
|
|
1292
|
-
},
|
|
1293
|
-
});
|
|
1294
|
-
|
|
1295
|
-
return server;
|
|
1296
|
-
},
|
|
1297
1278
|
run: async ({ client }) => {
|
|
1298
1279
|
try {
|
|
1299
1280
|
await client.callTool({
|
|
1300
|
-
name: "add",
|
|
1301
1281
|
arguments: {
|
|
1302
1282
|
a: 1,
|
|
1303
1283
|
b: "invalid",
|
|
1304
1284
|
},
|
|
1285
|
+
name: "add",
|
|
1305
1286
|
});
|
|
1306
1287
|
} catch (error) {
|
|
1307
1288
|
expect(error).toBeInstanceOf(McpError);
|
|
@@ -1310,14 +1291,11 @@ test("throws ErrorCode.InvalidParams if tool parameters do not match zod schema"
|
|
|
1310
1291
|
expect(error.code).toBe(ErrorCode.InvalidParams);
|
|
1311
1292
|
|
|
1312
1293
|
// @ts-expect-error - we know that error is an McpError
|
|
1313
|
-
expect(error.message).toBe(
|
|
1294
|
+
expect(error.message).toBe(
|
|
1295
|
+
"MCP error -32602: MCP error -32602: Invalid add parameters",
|
|
1296
|
+
);
|
|
1314
1297
|
}
|
|
1315
1298
|
},
|
|
1316
|
-
});
|
|
1317
|
-
});
|
|
1318
|
-
|
|
1319
|
-
test("server remains usable after InvalidParams error", async () => {
|
|
1320
|
-
await runWithTestServer({
|
|
1321
1299
|
server: async () => {
|
|
1322
1300
|
const server = new FastMCP({
|
|
1323
1301
|
name: "Test",
|
|
@@ -1325,27 +1303,32 @@ test("server remains usable after InvalidParams error", async () => {
|
|
|
1325
1303
|
});
|
|
1326
1304
|
|
|
1327
1305
|
server.addTool({
|
|
1328
|
-
name: "add",
|
|
1329
1306
|
description: "Add two numbers",
|
|
1307
|
+
execute: async (args) => {
|
|
1308
|
+
return String(args.a + args.b);
|
|
1309
|
+
},
|
|
1310
|
+
name: "add",
|
|
1330
1311
|
parameters: z.object({
|
|
1331
1312
|
a: z.number(),
|
|
1332
1313
|
b: z.number(),
|
|
1333
1314
|
}),
|
|
1334
|
-
execute: async (args) => {
|
|
1335
|
-
return String(args.a + args.b);
|
|
1336
|
-
},
|
|
1337
1315
|
});
|
|
1338
1316
|
|
|
1339
1317
|
return server;
|
|
1340
1318
|
},
|
|
1319
|
+
});
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
test("server remains usable after InvalidParams error", async () => {
|
|
1323
|
+
await runWithTestServer({
|
|
1341
1324
|
run: async ({ client }) => {
|
|
1342
1325
|
try {
|
|
1343
1326
|
await client.callTool({
|
|
1344
|
-
name: "add",
|
|
1345
1327
|
arguments: {
|
|
1346
1328
|
a: 1,
|
|
1347
1329
|
b: "invalid",
|
|
1348
1330
|
},
|
|
1331
|
+
name: "add",
|
|
1349
1332
|
});
|
|
1350
1333
|
} catch (error) {
|
|
1351
1334
|
expect(error).toBeInstanceOf(McpError);
|
|
@@ -1354,20 +1337,42 @@ test("server remains usable after InvalidParams error", async () => {
|
|
|
1354
1337
|
expect(error.code).toBe(ErrorCode.InvalidParams);
|
|
1355
1338
|
|
|
1356
1339
|
// @ts-expect-error - we know that error is an McpError
|
|
1357
|
-
expect(error.message).toBe(
|
|
1340
|
+
expect(error.message).toBe(
|
|
1341
|
+
"MCP error -32602: MCP error -32602: Invalid add parameters",
|
|
1342
|
+
);
|
|
1358
1343
|
}
|
|
1359
1344
|
|
|
1360
1345
|
expect(
|
|
1361
1346
|
await client.callTool({
|
|
1362
|
-
name: "add",
|
|
1363
1347
|
arguments: {
|
|
1364
1348
|
a: 1,
|
|
1365
1349
|
b: 2,
|
|
1366
1350
|
},
|
|
1351
|
+
name: "add",
|
|
1367
1352
|
}),
|
|
1368
1353
|
).toEqual({
|
|
1369
|
-
content: [{
|
|
1354
|
+
content: [{ text: "3", type: "text" }],
|
|
1355
|
+
});
|
|
1356
|
+
},
|
|
1357
|
+
server: async () => {
|
|
1358
|
+
const server = new FastMCP({
|
|
1359
|
+
name: "Test",
|
|
1360
|
+
version: "1.0.0",
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
server.addTool({
|
|
1364
|
+
description: "Add two numbers",
|
|
1365
|
+
execute: async (args) => {
|
|
1366
|
+
return String(args.a + args.b);
|
|
1367
|
+
},
|
|
1368
|
+
name: "add",
|
|
1369
|
+
parameters: z.object({
|
|
1370
|
+
a: z.number(),
|
|
1371
|
+
b: z.number(),
|
|
1372
|
+
}),
|
|
1370
1373
|
});
|
|
1374
|
+
|
|
1375
|
+
return server;
|
|
1371
1376
|
},
|
|
1372
1377
|
});
|
|
1373
1378
|
});
|
|
@@ -1381,23 +1386,23 @@ test("allows new clients to connect after a client disconnects", async () => {
|
|
|
1381
1386
|
});
|
|
1382
1387
|
|
|
1383
1388
|
server.addTool({
|
|
1384
|
-
name: "add",
|
|
1385
1389
|
description: "Add two numbers",
|
|
1390
|
+
execute: async (args) => {
|
|
1391
|
+
return String(args.a + args.b);
|
|
1392
|
+
},
|
|
1393
|
+
name: "add",
|
|
1386
1394
|
parameters: z.object({
|
|
1387
1395
|
a: z.number(),
|
|
1388
1396
|
b: z.number(),
|
|
1389
1397
|
}),
|
|
1390
|
-
execute: async (args) => {
|
|
1391
|
-
return String(args.a + args.b);
|
|
1392
|
-
},
|
|
1393
1398
|
});
|
|
1394
1399
|
|
|
1395
1400
|
await server.start({
|
|
1396
|
-
transportType: "sse",
|
|
1397
1401
|
sse: {
|
|
1398
1402
|
endpoint: "/sse",
|
|
1399
1403
|
port,
|
|
1400
1404
|
},
|
|
1405
|
+
transportType: "sse",
|
|
1401
1406
|
});
|
|
1402
1407
|
|
|
1403
1408
|
const client1 = new Client(
|
|
@@ -1418,14 +1423,14 @@ test("allows new clients to connect after a client disconnects", async () => {
|
|
|
1418
1423
|
|
|
1419
1424
|
expect(
|
|
1420
1425
|
await client1.callTool({
|
|
1421
|
-
name: "add",
|
|
1422
1426
|
arguments: {
|
|
1423
1427
|
a: 1,
|
|
1424
1428
|
b: 2,
|
|
1425
1429
|
},
|
|
1430
|
+
name: "add",
|
|
1426
1431
|
}),
|
|
1427
1432
|
).toEqual({
|
|
1428
|
-
content: [{
|
|
1433
|
+
content: [{ text: "3", type: "text" }],
|
|
1429
1434
|
});
|
|
1430
1435
|
|
|
1431
1436
|
await client1.close();
|
|
@@ -1448,14 +1453,14 @@ test("allows new clients to connect after a client disconnects", async () => {
|
|
|
1448
1453
|
|
|
1449
1454
|
expect(
|
|
1450
1455
|
await client2.callTool({
|
|
1451
|
-
name: "add",
|
|
1452
1456
|
arguments: {
|
|
1453
1457
|
a: 1,
|
|
1454
1458
|
b: 2,
|
|
1455
1459
|
},
|
|
1460
|
+
name: "add",
|
|
1456
1461
|
}),
|
|
1457
1462
|
).toEqual({
|
|
1458
|
-
content: [{
|
|
1463
|
+
content: [{ text: "3", type: "text" }],
|
|
1459
1464
|
});
|
|
1460
1465
|
|
|
1461
1466
|
await client2.close();
|
|
@@ -1472,11 +1477,11 @@ test("able to close server immediately after starting it", async () => {
|
|
|
1472
1477
|
});
|
|
1473
1478
|
|
|
1474
1479
|
await server.start({
|
|
1475
|
-
transportType: "sse",
|
|
1476
1480
|
sse: {
|
|
1477
1481
|
endpoint: "/sse",
|
|
1478
1482
|
port,
|
|
1479
1483
|
},
|
|
1484
|
+
transportType: "sse",
|
|
1480
1485
|
});
|
|
1481
1486
|
|
|
1482
1487
|
// We were previously not waiting for the server to start.
|
|
@@ -1493,32 +1498,32 @@ test("closing event source does not produce error", async () => {
|
|
|
1493
1498
|
});
|
|
1494
1499
|
|
|
1495
1500
|
server.addTool({
|
|
1496
|
-
name: "add",
|
|
1497
1501
|
description: "Add two numbers",
|
|
1502
|
+
execute: async (args) => {
|
|
1503
|
+
return String(args.a + args.b);
|
|
1504
|
+
},
|
|
1505
|
+
name: "add",
|
|
1498
1506
|
parameters: z.object({
|
|
1499
1507
|
a: z.number(),
|
|
1500
1508
|
b: z.number(),
|
|
1501
1509
|
}),
|
|
1502
|
-
execute: async (args) => {
|
|
1503
|
-
return String(args.a + args.b);
|
|
1504
|
-
},
|
|
1505
1510
|
});
|
|
1506
1511
|
|
|
1507
1512
|
await server.start({
|
|
1508
|
-
transportType: "sse",
|
|
1509
1513
|
sse: {
|
|
1510
1514
|
endpoint: "/sse",
|
|
1511
1515
|
port,
|
|
1512
1516
|
},
|
|
1517
|
+
transportType: "sse",
|
|
1513
1518
|
});
|
|
1514
1519
|
|
|
1515
1520
|
const eventSource = await new Promise<EventSourceClient>((onMessage) => {
|
|
1516
1521
|
const eventSource = createEventSource({
|
|
1517
1522
|
onConnect: () => {
|
|
1518
|
-
console.info(
|
|
1523
|
+
console.info("connected");
|
|
1519
1524
|
},
|
|
1520
1525
|
onDisconnect: () => {
|
|
1521
|
-
console.info(
|
|
1526
|
+
console.info("disconnected");
|
|
1522
1527
|
},
|
|
1523
1528
|
onMessage: () => {
|
|
1524
1529
|
onMessage(eventSource);
|
|
@@ -1527,7 +1532,7 @@ test("closing event source does not produce error", async () => {
|
|
|
1527
1532
|
});
|
|
1528
1533
|
});
|
|
1529
1534
|
|
|
1530
|
-
expect(eventSource.readyState).toBe(
|
|
1535
|
+
expect(eventSource.readyState).toBe("open");
|
|
1531
1536
|
|
|
1532
1537
|
eventSource.close();
|
|
1533
1538
|
|
|
@@ -1547,10 +1552,10 @@ test("provides auth to tools", async () => {
|
|
|
1547
1552
|
};
|
|
1548
1553
|
});
|
|
1549
1554
|
|
|
1550
|
-
const server = new FastMCP<{id: number}>({
|
|
1555
|
+
const server = new FastMCP<{ id: number }>({
|
|
1556
|
+
authenticate,
|
|
1551
1557
|
name: "Test",
|
|
1552
1558
|
version: "1.0.0",
|
|
1553
|
-
authenticate,
|
|
1554
1559
|
});
|
|
1555
1560
|
|
|
1556
1561
|
const execute = vi.fn(async (args) => {
|
|
@@ -1558,21 +1563,21 @@ test("provides auth to tools", async () => {
|
|
|
1558
1563
|
});
|
|
1559
1564
|
|
|
1560
1565
|
server.addTool({
|
|
1561
|
-
name: "add",
|
|
1562
1566
|
description: "Add two numbers",
|
|
1567
|
+
execute,
|
|
1568
|
+
name: "add",
|
|
1563
1569
|
parameters: z.object({
|
|
1564
1570
|
a: z.number(),
|
|
1565
1571
|
b: z.number(),
|
|
1566
1572
|
}),
|
|
1567
|
-
execute,
|
|
1568
1573
|
});
|
|
1569
1574
|
|
|
1570
1575
|
await server.start({
|
|
1571
|
-
transportType: "sse",
|
|
1572
1576
|
sse: {
|
|
1573
1577
|
endpoint: "/sse",
|
|
1574
1578
|
port,
|
|
1575
1579
|
},
|
|
1580
|
+
transportType: "sse",
|
|
1576
1581
|
});
|
|
1577
1582
|
|
|
1578
1583
|
const client = new Client(
|
|
@@ -1604,57 +1609,63 @@ test("provides auth to tools", async () => {
|
|
|
1604
1609
|
|
|
1605
1610
|
await client.connect(transport);
|
|
1606
1611
|
|
|
1607
|
-
expect(
|
|
1612
|
+
expect(
|
|
1613
|
+
authenticate,
|
|
1614
|
+
"authenticate should have been called",
|
|
1615
|
+
).toHaveBeenCalledTimes(1);
|
|
1608
1616
|
|
|
1609
1617
|
expect(
|
|
1610
1618
|
await client.callTool({
|
|
1611
|
-
name: "add",
|
|
1612
1619
|
arguments: {
|
|
1613
1620
|
a: 1,
|
|
1614
1621
|
b: 2,
|
|
1615
1622
|
},
|
|
1623
|
+
name: "add",
|
|
1616
1624
|
}),
|
|
1617
1625
|
).toEqual({
|
|
1618
|
-
content: [{
|
|
1626
|
+
content: [{ text: "3", type: "text" }],
|
|
1619
1627
|
});
|
|
1620
1628
|
|
|
1621
1629
|
expect(execute, "execute should have been called").toHaveBeenCalledTimes(1);
|
|
1622
1630
|
|
|
1623
|
-
expect(execute).toHaveBeenCalledWith(
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1631
|
+
expect(execute).toHaveBeenCalledWith(
|
|
1632
|
+
{
|
|
1633
|
+
a: 1,
|
|
1634
|
+
b: 2,
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
log: {
|
|
1638
|
+
debug: expect.any(Function),
|
|
1639
|
+
error: expect.any(Function),
|
|
1640
|
+
info: expect.any(Function),
|
|
1641
|
+
warn: expect.any(Function),
|
|
1642
|
+
},
|
|
1643
|
+
reportProgress: expect.any(Function),
|
|
1644
|
+
session: { id: 1 },
|
|
1645
|
+
},
|
|
1646
|
+
);
|
|
1636
1647
|
});
|
|
1637
1648
|
|
|
1638
1649
|
test("blocks unauthorized requests", async () => {
|
|
1639
1650
|
const port = await getRandomPort();
|
|
1640
1651
|
|
|
1641
|
-
const server = new FastMCP<{id: number}>({
|
|
1642
|
-
name: "Test",
|
|
1643
|
-
version: "1.0.0",
|
|
1652
|
+
const server = new FastMCP<{ id: number }>({
|
|
1644
1653
|
authenticate: async () => {
|
|
1645
1654
|
throw new Response(null, {
|
|
1646
1655
|
status: 401,
|
|
1647
1656
|
statusText: "Unauthorized",
|
|
1648
1657
|
});
|
|
1649
1658
|
},
|
|
1659
|
+
name: "Test",
|
|
1660
|
+
version: "1.0.0",
|
|
1650
1661
|
});
|
|
1651
1662
|
|
|
1652
1663
|
await server.start({
|
|
1653
|
-
transportType: "sse",
|
|
1654
1664
|
sse: {
|
|
1655
1665
|
endpoint: "/sse",
|
|
1656
1666
|
port,
|
|
1657
1667
|
},
|
|
1668
|
+
transportType: "sse",
|
|
1658
1669
|
});
|
|
1659
1670
|
|
|
1660
1671
|
const client = new Client(
|
|
@@ -1674,4 +1685,4 @@ test("blocks unauthorized requests", async () => {
|
|
|
1674
1685
|
expect(async () => {
|
|
1675
1686
|
await client.connect(transport);
|
|
1676
1687
|
}).rejects.toThrow("SSE error: Non-200 status code (401)");
|
|
1677
|
-
});
|
|
1688
|
+
});
|