tmcp 1.18.1 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +264 -42
- package/package.json +18 -2
- package/src/index.js +241 -11
- package/src/internal/internal.d.ts +51 -0
- package/src/prompt.js +23 -0
- package/src/resource.js +20 -0
- package/src/template.js +27 -0
- package/src/tool.js +23 -0
- package/src/types/index.d.ts +1056 -79
- package/src/types/index.d.ts.map +33 -8
- package/src/validation/version.js +2 -2
package/README.md
CHANGED
|
@@ -217,6 +217,164 @@ tool.mix(
|
|
|
217
217
|
|
|
218
218
|
All helpers are typed, so TypeScript will prevent you from returning malformed payloads while cutting down the repetitive envelopes that used to appear in almost every handler.
|
|
219
219
|
|
|
220
|
+
## Defining Tools, Prompts, Resources, and Templates in Separate Files
|
|
221
|
+
|
|
222
|
+
For better code organization and reusability, you can define your tools, prompts, resources, and templates in separate files using the `defineTool`, `definePrompt`, `defineResource`, and `defineTemplate` utilities. This approach allows you to:
|
|
223
|
+
|
|
224
|
+
- **Organize by feature**: Group related tools in feature-specific modules
|
|
225
|
+
- **Reuse across servers**: Share common tools between different MCP servers
|
|
226
|
+
|
|
227
|
+
### Example Structure
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
// tools/calculator.js
|
|
231
|
+
import { defineTool } from 'tmcp/tool';
|
|
232
|
+
import { z } from 'zod';
|
|
233
|
+
|
|
234
|
+
export const addTool = defineTool(
|
|
235
|
+
{
|
|
236
|
+
name: 'add',
|
|
237
|
+
description: 'Add two numbers',
|
|
238
|
+
schema: z.object({
|
|
239
|
+
a: z.number(),
|
|
240
|
+
b: z.number(),
|
|
241
|
+
}),
|
|
242
|
+
},
|
|
243
|
+
async ({ a, b }) => ({
|
|
244
|
+
content: [{ type: 'text', text: `${a} + ${b} = ${a + b}` }],
|
|
245
|
+
}),
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
export const multiplyTool = defineTool(
|
|
249
|
+
{
|
|
250
|
+
name: 'multiply',
|
|
251
|
+
description: 'Multiply two numbers',
|
|
252
|
+
schema: z.object({
|
|
253
|
+
a: z.number(),
|
|
254
|
+
b: z.number(),
|
|
255
|
+
}),
|
|
256
|
+
},
|
|
257
|
+
async ({ a, b }) => ({
|
|
258
|
+
content: [{ type: 'text', text: `${a} × ${b} = ${a * b}` }],
|
|
259
|
+
}),
|
|
260
|
+
);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
// prompts/code-review.js
|
|
265
|
+
import { definePrompt } from 'tmcp/prompt';
|
|
266
|
+
import { z } from 'zod';
|
|
267
|
+
|
|
268
|
+
export const codeReviewPrompt = definePrompt(
|
|
269
|
+
{
|
|
270
|
+
name: 'code-review',
|
|
271
|
+
description: 'Generate code review prompt',
|
|
272
|
+
schema: z.object({
|
|
273
|
+
code: z.string(),
|
|
274
|
+
language: z.string(),
|
|
275
|
+
}),
|
|
276
|
+
},
|
|
277
|
+
async ({ code, language }) => ({
|
|
278
|
+
messages: [
|
|
279
|
+
{
|
|
280
|
+
role: 'user',
|
|
281
|
+
content: {
|
|
282
|
+
type: 'text',
|
|
283
|
+
text: `Review this ${language} code:\n\n${code}`,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
}),
|
|
288
|
+
);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
// resources/files.js
|
|
293
|
+
import { defineResource } from 'tmcp/resource';
|
|
294
|
+
import { readFile } from 'node:fs/promises';
|
|
295
|
+
|
|
296
|
+
export const readmeResource = defineResource(
|
|
297
|
+
{
|
|
298
|
+
name: 'readme',
|
|
299
|
+
description: 'Project README file',
|
|
300
|
+
uri: 'file://README.md',
|
|
301
|
+
},
|
|
302
|
+
async (uri) => ({
|
|
303
|
+
contents: [
|
|
304
|
+
{
|
|
305
|
+
uri,
|
|
306
|
+
mimeType: 'text/markdown',
|
|
307
|
+
text: await readFile(uri.replace('file://', ''), 'utf8'),
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
}),
|
|
311
|
+
);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
// templates/user-files.js
|
|
316
|
+
import { defineTemplate } from 'tmcp/template';
|
|
317
|
+
import { getUserFile } from '../api/users.js';
|
|
318
|
+
|
|
319
|
+
export const userFileTemplate = defineTemplate(
|
|
320
|
+
{
|
|
321
|
+
name: 'user-files',
|
|
322
|
+
description: 'Access user files by ID',
|
|
323
|
+
uri: 'users/{userId}/files/{filename}',
|
|
324
|
+
complete: {
|
|
325
|
+
userId: async (arg) => ({
|
|
326
|
+
completion: {
|
|
327
|
+
values: await searchUserIds(arg),
|
|
328
|
+
hasMore: false,
|
|
329
|
+
},
|
|
330
|
+
}),
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
async (uri, { userId, filename }) => ({
|
|
334
|
+
contents: [
|
|
335
|
+
{
|
|
336
|
+
uri,
|
|
337
|
+
mimeType: 'text/plain',
|
|
338
|
+
text: await getUserFile(userId, filename),
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
}),
|
|
342
|
+
);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
// server.js
|
|
347
|
+
import { McpServer } from 'tmcp';
|
|
348
|
+
import { ZodJsonSchemaAdapter } from '@tmcp/adapter-zod';
|
|
349
|
+
import { addTool, multiplyTool } from './tools/calculator.js';
|
|
350
|
+
import { codeReviewPrompt } from './prompts/code-review.js';
|
|
351
|
+
import { readmeResource } from './resources/files.js';
|
|
352
|
+
import { userFileTemplate } from './templates/user-files.js';
|
|
353
|
+
|
|
354
|
+
const server = new McpServer(
|
|
355
|
+
{
|
|
356
|
+
name: 'my-server',
|
|
357
|
+
version: '1.0.0',
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
adapter: new ZodJsonSchemaAdapter(),
|
|
361
|
+
},
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Register multiple tools at once
|
|
365
|
+
server.tools([addTool, multiplyTool]);
|
|
366
|
+
|
|
367
|
+
// Or register individually
|
|
368
|
+
server.tool(addTool);
|
|
369
|
+
|
|
370
|
+
// Same for prompts, resources, and templates
|
|
371
|
+
server.prompts([codeReviewPrompt]);
|
|
372
|
+
server.resources([readmeResource]);
|
|
373
|
+
server.templates([userFileTemplate]);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Adding the primitive to the server will error if the tool uses a different validation library than the one expressed in the adapter.
|
|
377
|
+
|
|
220
378
|
## API Reference
|
|
221
379
|
|
|
222
380
|
### McpServer
|
|
@@ -237,11 +395,12 @@ new McpServer(serverInfo, options);
|
|
|
237
395
|
|
|
238
396
|
#### Methods
|
|
239
397
|
|
|
240
|
-
##### `tool(definition, handler)`
|
|
398
|
+
##### `tool(definition, handler)` / `tools(definitions)`
|
|
241
399
|
|
|
242
|
-
Register
|
|
400
|
+
Register one or more tools with optional schema validation.
|
|
243
401
|
|
|
244
402
|
```javascript
|
|
403
|
+
// Register a single tool inline
|
|
245
404
|
server.tool(
|
|
246
405
|
{
|
|
247
406
|
name: 'tool-name',
|
|
@@ -250,83 +409,146 @@ server.tool(
|
|
|
250
409
|
},
|
|
251
410
|
async (input) => {
|
|
252
411
|
// Tool implementation
|
|
253
|
-
return
|
|
412
|
+
return result;
|
|
413
|
+
},
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
// Register a tool created with defineTool
|
|
417
|
+
import { defineTool } from 'tmcp/tool';
|
|
418
|
+
|
|
419
|
+
const myTool = defineTool(
|
|
420
|
+
{
|
|
421
|
+
name: 'tool-name',
|
|
422
|
+
description: 'Tool description',
|
|
423
|
+
schema: yourSchema,
|
|
424
|
+
},
|
|
425
|
+
async (input) => {
|
|
426
|
+
return result;
|
|
254
427
|
},
|
|
255
428
|
);
|
|
429
|
+
|
|
430
|
+
server.tool(myTool);
|
|
431
|
+
|
|
432
|
+
// Register multiple tools at once
|
|
433
|
+
server.tools([tool1, tool2, tool3]);
|
|
256
434
|
```
|
|
257
435
|
|
|
258
436
|
`sessionInfo` contains the latest `clientCapabilities`, `clientInfo`, and `logLevel` reported by the connected client. Built-in transports populate it automatically, so every handler can branch on client features without additional bookkeeping.
|
|
259
437
|
|
|
260
|
-
##### `prompt(definition, handler)`
|
|
438
|
+
##### `prompt(definition, handler)` / `prompts(definitions)`
|
|
261
439
|
|
|
262
|
-
Register
|
|
440
|
+
Register one or more prompt templates with optional schema validation.
|
|
263
441
|
|
|
264
442
|
```javascript
|
|
443
|
+
// Register a single prompt inline
|
|
265
444
|
server.prompt(
|
|
266
445
|
{
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
446
|
+
name: 'prompt-name',
|
|
447
|
+
description: 'Prompt description',
|
|
448
|
+
schema: yourSchema, // optional
|
|
449
|
+
complete: (arg, context) => ['completion1', 'completion2'] // optional
|
|
450
|
+
},
|
|
451
|
+
async (input) => {
|
|
452
|
+
// Prompt implementation
|
|
453
|
+
return { messages: [...] };
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
// Register a prompt created with definePrompt
|
|
458
|
+
import { definePrompt } from 'tmcp/prompt';
|
|
459
|
+
|
|
460
|
+
const myPrompt = definePrompt(
|
|
461
|
+
{
|
|
462
|
+
name: 'prompt-name',
|
|
463
|
+
description: 'Prompt description',
|
|
464
|
+
schema: yourSchema,
|
|
279
465
|
},
|
|
280
466
|
async (input) => {
|
|
281
|
-
|
|
282
|
-
return { messages: [...] };
|
|
467
|
+
return { messages: [...] };
|
|
283
468
|
}
|
|
284
469
|
);
|
|
470
|
+
|
|
471
|
+
server.prompt(myPrompt);
|
|
472
|
+
|
|
473
|
+
// Register multiple prompts at once
|
|
474
|
+
server.prompts([prompt1, prompt2, prompt3]);
|
|
285
475
|
```
|
|
286
476
|
|
|
287
|
-
##### `resource(definition, handler)`
|
|
477
|
+
##### `resource(definition, handler)` / `resources(definitions)`
|
|
288
478
|
|
|
289
|
-
Register
|
|
479
|
+
Register one or more static resources.
|
|
290
480
|
|
|
291
481
|
```javascript
|
|
482
|
+
// Register a single resource inline
|
|
292
483
|
server.resource(
|
|
293
484
|
{
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
485
|
+
name: 'resource-name',
|
|
486
|
+
description: 'Resource description',
|
|
487
|
+
uri: 'file://path/to/resource'
|
|
297
488
|
},
|
|
298
489
|
async (uri, params) => {
|
|
299
|
-
|
|
300
|
-
|
|
490
|
+
// Resource implementation
|
|
491
|
+
return { contents: [...] };
|
|
301
492
|
}
|
|
302
493
|
);
|
|
494
|
+
|
|
495
|
+
// Register a resource created with defineResource
|
|
496
|
+
import { defineResource } from 'tmcp/resource';
|
|
497
|
+
|
|
498
|
+
const myResource = defineResource(
|
|
499
|
+
{
|
|
500
|
+
name: 'resource-name',
|
|
501
|
+
description: 'Resource description',
|
|
502
|
+
uri: 'file://path/to/resource'
|
|
503
|
+
},
|
|
504
|
+
async (uri) => {
|
|
505
|
+
return { contents: [...] };
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
server.resource(myResource);
|
|
510
|
+
|
|
511
|
+
// Register multiple resources at once
|
|
512
|
+
server.resources([resource1, resource2, resource3]);
|
|
303
513
|
```
|
|
304
514
|
|
|
305
|
-
##### `template(definition, handler)`
|
|
515
|
+
##### `template(definition, handler)` / `templates(definitions)`
|
|
306
516
|
|
|
307
|
-
Register
|
|
517
|
+
Register one or more URI templates for dynamic resources.
|
|
308
518
|
|
|
309
519
|
```javascript
|
|
520
|
+
// Register a single template inline
|
|
310
521
|
server.template(
|
|
311
522
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
id: (arg, context) => ({
|
|
317
|
-
completion: {
|
|
318
|
-
values: ['id1', 'id2', 'id3'],
|
|
319
|
-
total: 3,
|
|
320
|
-
hasMore: false
|
|
321
|
-
}
|
|
322
|
-
})
|
|
323
|
-
} // optional
|
|
523
|
+
name: 'template-name',
|
|
524
|
+
description: 'Template description',
|
|
525
|
+
uri: 'file://path/{id}/resource',
|
|
526
|
+
complete: (arg, context) => ['id1', 'id2'] // optional
|
|
324
527
|
},
|
|
325
528
|
async (uri, params) => {
|
|
326
|
-
|
|
327
|
-
|
|
529
|
+
// Template implementation using params.id
|
|
530
|
+
return { contents: [...] };
|
|
328
531
|
}
|
|
329
532
|
);
|
|
533
|
+
|
|
534
|
+
// Register a template created with defineTemplate
|
|
535
|
+
import { defineTemplate } from 'tmcp/template';
|
|
536
|
+
|
|
537
|
+
const myTemplate = defineTemplate(
|
|
538
|
+
{
|
|
539
|
+
name: 'template-name',
|
|
540
|
+
description: 'Template description',
|
|
541
|
+
uri: 'file://path/{id}/resource',
|
|
542
|
+
},
|
|
543
|
+
async (uri, params) => {
|
|
544
|
+
return { contents: [...] };
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
server.template(myTemplate);
|
|
549
|
+
|
|
550
|
+
// Register multiple templates at once
|
|
551
|
+
server.templates([template1, template2, template3]);
|
|
330
552
|
```
|
|
331
553
|
|
|
332
554
|
##### `withContext<T>()`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tmcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "The main tmcp library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -21,6 +21,22 @@
|
|
|
21
21
|
"types": "./src/types/index.d.ts",
|
|
22
22
|
"default": "./src/index.js"
|
|
23
23
|
},
|
|
24
|
+
"./tool": {
|
|
25
|
+
"types": "./src/types/index.d.ts",
|
|
26
|
+
"default": "./src/tool.js"
|
|
27
|
+
},
|
|
28
|
+
"./prompt": {
|
|
29
|
+
"types": "./src/types/index.d.ts",
|
|
30
|
+
"default": "./src/prompt.js"
|
|
31
|
+
},
|
|
32
|
+
"./resource": {
|
|
33
|
+
"types": "./src/types/index.d.ts",
|
|
34
|
+
"default": "./src/resource.js"
|
|
35
|
+
},
|
|
36
|
+
"./template": {
|
|
37
|
+
"types": "./src/types/index.d.ts",
|
|
38
|
+
"default": "./src/template.js"
|
|
39
|
+
},
|
|
24
40
|
"./adapter": {
|
|
25
41
|
"types": "./src/types/index.d.ts",
|
|
26
42
|
"default": "./src/adapter.js"
|
|
@@ -48,7 +64,7 @@
|
|
|
48
64
|
"scripts": {
|
|
49
65
|
"test": "vitest",
|
|
50
66
|
"typecheck": "tsc --noEmit",
|
|
51
|
-
"generate:types": "dts-buddy && publint",
|
|
67
|
+
"generate:types": "dts-buddy && node ./scripts/fix-unique-symbol.ts && publint",
|
|
52
68
|
"prepublish": "pnpm generate:types"
|
|
53
69
|
}
|
|
54
70
|
}
|