tmcp 1.3.0 → 1.4.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/package.json +2 -1
- package/src/index.d.ts +28 -1
- package/src/index.js +119 -22
- package/src/internal/internal.d.ts +8 -1
- package/src/validation/index.d.ts +19 -0
- package/src/validation/index.js +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tmcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "The main tmcp library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@standard-schema/spec": "^1.0.0",
|
|
36
36
|
"@types/json-schema": "^7.0.15",
|
|
37
|
+
"@types/node": "^24.0.13",
|
|
37
38
|
"publint": "^0.3.12"
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {ClientCapabilitiesType} ClientCapabilities
|
|
3
|
+
*/
|
|
1
4
|
/**
|
|
2
5
|
* @template {StandardSchemaV1} StandardSchema
|
|
3
6
|
*/
|
|
@@ -7,6 +10,21 @@ export class McpServer<StandardSchema extends StandardSchemaV1> {
|
|
|
7
10
|
* @param {ServerOptions<StandardSchema>} options
|
|
8
11
|
*/
|
|
9
12
|
constructor(server_info: ServerInfo, options: ServerOptions<StandardSchema>);
|
|
13
|
+
currentClientCapabilities(): {
|
|
14
|
+
roots?: {
|
|
15
|
+
listChanged?: boolean;
|
|
16
|
+
} & {
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
sampling?: {} & {
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
};
|
|
22
|
+
elicitation?: {} & {
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
};
|
|
25
|
+
} & {
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
};
|
|
10
28
|
/**
|
|
11
29
|
* @template {keyof McpEvents} TEvent
|
|
12
30
|
* @param {TEvent} event
|
|
@@ -58,17 +76,25 @@ export class McpServer<StandardSchema extends StandardSchemaV1> {
|
|
|
58
76
|
}, execute: (uri: string, params: Record<TVariables, string | string[]>) => Promise<ReadResourceResult> | ReadResourceResult): void;
|
|
59
77
|
/**
|
|
60
78
|
* @param {JSONRPCRequest} request
|
|
79
|
+
* @param {string} [session_id]
|
|
61
80
|
* @returns {ReturnType<JSONRPCServer['receive']>}
|
|
62
81
|
*/
|
|
63
|
-
receive(request: JSONRPCRequest): ReturnType<JSONRPCServer["receive"]>;
|
|
82
|
+
receive(request: JSONRPCRequest, session_id?: string): ReturnType<JSONRPCServer["receive"]>;
|
|
64
83
|
/**
|
|
65
84
|
* Send a notification for subscriptions
|
|
66
85
|
* @param {SubscriptionsKeys} what
|
|
67
86
|
* @param {string} id
|
|
68
87
|
*/
|
|
69
88
|
changed(what: SubscriptionsKeys, id: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* @template {StandardSchema} TSchema
|
|
91
|
+
* @param {TSchema} schema
|
|
92
|
+
* @returns {Promise<StandardSchemaV1.InferOutput<TSchema>>}
|
|
93
|
+
*/
|
|
94
|
+
elicitation<TSchema extends StandardSchema>(schema: TSchema): Promise<StandardSchemaV1.InferOutput<TSchema>>;
|
|
70
95
|
#private;
|
|
71
96
|
}
|
|
97
|
+
export type ClientCapabilities = ClientCapabilitiesType;
|
|
72
98
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
73
99
|
import type { McpEvents } from "./internal/internal.js";
|
|
74
100
|
import type { CallToolResult } from "./validation/index.js";
|
|
@@ -81,3 +107,4 @@ import { JSONRPCServer } from 'json-rpc-2.0';
|
|
|
81
107
|
import type { SubscriptionsKeys } from "./internal/internal.js";
|
|
82
108
|
import type { ServerInfo } from "./internal/internal.js";
|
|
83
109
|
import type { ServerOptions } from "./internal/internal.js";
|
|
110
|
+
import type { ClientCapabilities as ClientCapabilitiesType } from "./validation/index.js";
|
package/src/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
3
|
* @import { JSONRPCRequest, JSONRPCParams } from "json-rpc-2.0";
|
|
4
4
|
* @import { ExtractURITemplateVariables } from "./internal/uri-template.js";
|
|
5
|
-
* @import { CallToolResult, ReadResourceResult, GetPromptResult,
|
|
5
|
+
* @import { CallToolResult, ReadResourceResult, GetPromptResult, ClientCapabilities as ClientCapabilitiesType } from "./validation/index.js";
|
|
6
6
|
* @import { Tool, Completion, Prompt, Resource, ServerOptions, ServerInfo, SubscriptionsKeys, McpEvents } from "./internal/internal.js";
|
|
7
7
|
*/
|
|
8
8
|
import { JSONRPCServer, JSONRPCClient } from 'json-rpc-2.0';
|
|
@@ -12,16 +12,22 @@ import {
|
|
|
12
12
|
ReadResourceResultSchema,
|
|
13
13
|
GetPromptResultSchema,
|
|
14
14
|
CompleteResultSchema,
|
|
15
|
+
InitializeRequestSchema,
|
|
15
16
|
} from './validation/index.js';
|
|
17
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
16
18
|
import * as v from 'valibot';
|
|
17
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {ClientCapabilitiesType} ClientCapabilities
|
|
22
|
+
*/
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* @template {StandardSchemaV1} StandardSchema
|
|
20
26
|
*/
|
|
21
27
|
export class McpServer {
|
|
22
28
|
#server = new JSONRPCServer();
|
|
23
29
|
/**
|
|
24
|
-
* @type {JSONRPCClient | undefined}
|
|
30
|
+
* @type {JSONRPCClient<Record<string, any> | undefined> | undefined}
|
|
25
31
|
*/
|
|
26
32
|
#client;
|
|
27
33
|
#options;
|
|
@@ -49,24 +55,47 @@ export class McpServer {
|
|
|
49
55
|
#event_target = new EventTarget();
|
|
50
56
|
|
|
51
57
|
/**
|
|
52
|
-
* @type {Record<SubscriptionsKeys, Set<string
|
|
58
|
+
* @type {Record<SubscriptionsKeys, Map<string, Set<string | undefined>>>}
|
|
53
59
|
*/
|
|
54
60
|
#subscriptions = {
|
|
55
61
|
/**
|
|
56
|
-
* @type {Set<string
|
|
62
|
+
* @type {Map<string, Set<string>>}
|
|
57
63
|
*/
|
|
58
|
-
resource: new
|
|
64
|
+
resource: new Map(),
|
|
59
65
|
};
|
|
60
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @type {AsyncLocalStorage<string | undefined>}
|
|
69
|
+
*/
|
|
70
|
+
#session_storage = new AsyncLocalStorage();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @type {Map<string|undefined, ClientCapabilities>}
|
|
74
|
+
*/
|
|
75
|
+
#client_capabilities_map = new Map();
|
|
76
|
+
|
|
61
77
|
/**
|
|
62
78
|
* @param {ServerInfo} server_info
|
|
63
79
|
* @param {ServerOptions<StandardSchema>} options
|
|
64
80
|
*/
|
|
65
81
|
constructor(server_info, options) {
|
|
66
82
|
this.#options = options;
|
|
67
|
-
this.#server.addMethod('initialize', (
|
|
83
|
+
this.#server.addMethod('initialize', (initialize_request) => {
|
|
84
|
+
const validated_initialize = v.parse(
|
|
85
|
+
InitializeRequestSchema,
|
|
86
|
+
initialize_request,
|
|
87
|
+
);
|
|
88
|
+
this.#client_capabilities_map.set(
|
|
89
|
+
this.#session_id,
|
|
90
|
+
validated_initialize.capabilities,
|
|
91
|
+
);
|
|
92
|
+
this.#event_target.dispatchEvent(
|
|
93
|
+
new CustomEvent('initialize', {
|
|
94
|
+
detail: validated_initialize,
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
68
97
|
return {
|
|
69
|
-
protocolVersion,
|
|
98
|
+
protocolVersion: validated_initialize.protocolVersion,
|
|
70
99
|
...options,
|
|
71
100
|
serverInfo: server_info,
|
|
72
101
|
};
|
|
@@ -83,6 +112,30 @@ export class McpServer {
|
|
|
83
112
|
this.#init_completion();
|
|
84
113
|
}
|
|
85
114
|
|
|
115
|
+
get #session_id() {
|
|
116
|
+
return this.#session_storage.getStore();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get #client_capabilities() {
|
|
120
|
+
return this.#client_capabilities_map.get(this.#session_id);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
currentClientCapabilities() {
|
|
124
|
+
return this.#client_capabilities;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#lazyily_create_client() {
|
|
128
|
+
if (!this.#client) {
|
|
129
|
+
this.#client = new JSONRPCClient((payload, context = {}) => {
|
|
130
|
+
this.#event_target.dispatchEvent(
|
|
131
|
+
new CustomEvent('send', {
|
|
132
|
+
detail: { request: payload, context },
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
86
139
|
/**
|
|
87
140
|
* @template {keyof McpEvents} TEvent
|
|
88
141
|
* @param {TEvent} event
|
|
@@ -90,12 +143,8 @@ export class McpServer {
|
|
|
90
143
|
* @param {AddEventListenerOptions} [options]
|
|
91
144
|
*/
|
|
92
145
|
on(event, callback, options) {
|
|
93
|
-
if (event === 'send'
|
|
94
|
-
this.#
|
|
95
|
-
this.#event_target.dispatchEvent(
|
|
96
|
-
new CustomEvent('send', { detail: payload }),
|
|
97
|
-
);
|
|
98
|
-
});
|
|
146
|
+
if (event === 'send') {
|
|
147
|
+
this.#lazyily_create_client();
|
|
99
148
|
}
|
|
100
149
|
|
|
101
150
|
this.#event_target.addEventListener(
|
|
@@ -110,9 +159,10 @@ export class McpServer {
|
|
|
110
159
|
/**
|
|
111
160
|
* @param {string} method
|
|
112
161
|
* @param {JSONRPCParams} [params]
|
|
162
|
+
* @param {Record<string, any>} [extra]
|
|
113
163
|
*/
|
|
114
|
-
#notify(method, params) {
|
|
115
|
-
this.#client?.notify(method, params);
|
|
164
|
+
#notify(method, params, extra) {
|
|
165
|
+
this.#client?.notify(method, params, extra);
|
|
116
166
|
}
|
|
117
167
|
|
|
118
168
|
/**
|
|
@@ -243,7 +293,12 @@ export class McpServer {
|
|
|
243
293
|
|
|
244
294
|
if (this.#options.capabilities?.resources?.subscribe) {
|
|
245
295
|
this.#server.addMethod('resources/subscribe', async ({ uri }) => {
|
|
246
|
-
this.#subscriptions.resource.
|
|
296
|
+
let subscriptions = this.#subscriptions.resource.get(uri);
|
|
297
|
+
if (!subscriptions) {
|
|
298
|
+
subscriptions = new Set();
|
|
299
|
+
this.#subscriptions.resource.set(uri, subscriptions);
|
|
300
|
+
}
|
|
301
|
+
subscriptions.add(this.#session_id);
|
|
247
302
|
return {};
|
|
248
303
|
});
|
|
249
304
|
}
|
|
@@ -408,10 +463,14 @@ export class McpServer {
|
|
|
408
463
|
}
|
|
409
464
|
/**
|
|
410
465
|
* @param {JSONRPCRequest} request
|
|
466
|
+
* @param {string} [session_id]
|
|
411
467
|
* @returns {ReturnType<JSONRPCServer['receive']>}
|
|
412
468
|
*/
|
|
413
|
-
receive(request) {
|
|
414
|
-
return this.#
|
|
469
|
+
receive(request, session_id) {
|
|
470
|
+
return this.#session_storage.run(
|
|
471
|
+
session_id,
|
|
472
|
+
async () => await this.#server.receive(request),
|
|
473
|
+
);
|
|
415
474
|
}
|
|
416
475
|
|
|
417
476
|
/**
|
|
@@ -423,10 +482,48 @@ export class McpServer {
|
|
|
423
482
|
if (this.#subscriptions[what].has(id)) {
|
|
424
483
|
const resource = this.#resources.get(id);
|
|
425
484
|
if (!resource) return;
|
|
426
|
-
this.#
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
485
|
+
const sessions = this.#subscriptions[what].get(id);
|
|
486
|
+
this.#notify(
|
|
487
|
+
`notifications/resources/updated`,
|
|
488
|
+
{
|
|
489
|
+
uri: id,
|
|
490
|
+
title: resource.name,
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
sessions: sessions ? [...sessions] : undefined,
|
|
494
|
+
},
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @template {StandardSchema} TSchema
|
|
501
|
+
* @param {TSchema} schema
|
|
502
|
+
* @returns {Promise<StandardSchemaV1.InferOutput<TSchema>>}
|
|
503
|
+
*/
|
|
504
|
+
async elicitation(schema) {
|
|
505
|
+
if (!this.#client_capabilities?.elicitation)
|
|
506
|
+
throw new Error("Client doesn't support elicitation");
|
|
507
|
+
|
|
508
|
+
this.#lazyily_create_client();
|
|
509
|
+
let validated_result = schema['~standard'].validate(
|
|
510
|
+
await this.#client?.request(
|
|
511
|
+
'elicitation/create',
|
|
512
|
+
{
|
|
513
|
+
params: await this.#options.adapter.toJsonSchema(schema),
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
sessions: [this.#session_id],
|
|
517
|
+
},
|
|
518
|
+
),
|
|
519
|
+
);
|
|
520
|
+
if (validated_result instanceof Promise)
|
|
521
|
+
validated_result = await validated_result;
|
|
522
|
+
if (validated_result.issues) {
|
|
523
|
+
throw new Error(
|
|
524
|
+
`Invalid elicitation result: ${JSON.stringify(validated_result.issues)}`,
|
|
525
|
+
);
|
|
430
526
|
}
|
|
527
|
+
return validated_result.value;
|
|
431
528
|
}
|
|
432
529
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CallToolResult,
|
|
7
7
|
ReadResourceResult,
|
|
8
8
|
CompleteResult,
|
|
9
|
+
InitializeRequest,
|
|
9
10
|
} from '../validation/index.js';
|
|
10
11
|
|
|
11
12
|
export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
|
|
@@ -67,5 +68,11 @@ export type ServerInfo = {
|
|
|
67
68
|
export type SubscriptionsKeys = 'resource';
|
|
68
69
|
|
|
69
70
|
export type McpEvents = {
|
|
70
|
-
send: (message:
|
|
71
|
+
send: (message: {
|
|
72
|
+
request: JSONRPCRequest;
|
|
73
|
+
context: {
|
|
74
|
+
sessions?: string[] | undefined;
|
|
75
|
+
};
|
|
76
|
+
}) => void;
|
|
77
|
+
initialize: (initialize_request: InitializeRequest) => void;
|
|
71
78
|
};
|
|
@@ -675,6 +675,25 @@ export const CompleteResultSchema: v.LooseObjectSchema<{
|
|
|
675
675
|
}, undefined>;
|
|
676
676
|
readonly _meta: v.OptionalSchema<v.LooseObjectSchema<{}, undefined>, undefined>;
|
|
677
677
|
}, undefined>;
|
|
678
|
+
export const ClientCapabilitiesSchema: v.LooseObjectSchema<{
|
|
679
|
+
readonly roots: v.OptionalSchema<v.LooseObjectSchema<{
|
|
680
|
+
readonly listChanged: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
681
|
+
}, undefined>, undefined>;
|
|
682
|
+
readonly sampling: v.OptionalSchema<v.LooseObjectSchema<{}, undefined>, undefined>;
|
|
683
|
+
readonly elicitation: v.OptionalSchema<v.LooseObjectSchema<{}, undefined>, undefined>;
|
|
684
|
+
}, undefined>;
|
|
685
|
+
export const InitializeRequestSchema: v.LooseObjectSchema<{
|
|
686
|
+
readonly protocolVersion: v.StringSchema<undefined>;
|
|
687
|
+
readonly capabilities: v.LooseObjectSchema<{
|
|
688
|
+
readonly roots: v.OptionalSchema<v.LooseObjectSchema<{
|
|
689
|
+
readonly listChanged: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
690
|
+
}, undefined>, undefined>;
|
|
691
|
+
readonly sampling: v.OptionalSchema<v.LooseObjectSchema<{}, undefined>, undefined>;
|
|
692
|
+
readonly elicitation: v.OptionalSchema<v.LooseObjectSchema<{}, undefined>, undefined>;
|
|
693
|
+
}, undefined>;
|
|
694
|
+
}, undefined>;
|
|
695
|
+
export type ClientCapabilities = v.InferInput<typeof ClientCapabilitiesSchema>;
|
|
696
|
+
export type InitializeRequest = v.InferInput<typeof InitializeRequestSchema>;
|
|
678
697
|
export type CallToolResult = v.InferInput<typeof CallToolResultSchema>;
|
|
679
698
|
export type ReadResourceResult = v.InferInput<typeof ReadResourceResultSchema>;
|
|
680
699
|
export type GetPromptResult = v.InferInput<typeof GetPromptResultSchema>;
|
package/src/validation/index.js
CHANGED
|
@@ -231,6 +231,29 @@ export const CompleteResultSchema = v.looseObject({
|
|
|
231
231
|
_meta: v.optional(v.looseObject({})),
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
+
export const ClientCapabilitiesSchema = v.looseObject({
|
|
235
|
+
roots: v.optional(
|
|
236
|
+
v.looseObject({
|
|
237
|
+
listChanged: v.optional(v.boolean()),
|
|
238
|
+
}),
|
|
239
|
+
),
|
|
240
|
+
sampling: v.optional(v.looseObject({})),
|
|
241
|
+
elicitation: v.optional(v.looseObject({})),
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
export const InitializeRequestSchema = v.looseObject({
|
|
245
|
+
protocolVersion: v.string(),
|
|
246
|
+
capabilities: ClientCapabilitiesSchema,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @typedef {v.InferInput<typeof ClientCapabilitiesSchema>} ClientCapabilities
|
|
251
|
+
*/
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @typedef {v.InferInput<typeof InitializeRequestSchema>} InitializeRequest
|
|
255
|
+
*/
|
|
256
|
+
|
|
234
257
|
/**
|
|
235
258
|
* @typedef {v.InferInput<typeof CallToolResultSchema>} CallToolResult
|
|
236
259
|
*/
|