tmcp 1.2.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/README.md +3 -0
- package/package.json +4 -3
- package/src/index.d.ts +43 -13
- package/src/index.js +157 -39
- package/src/internal/internal.d.ts +21 -6
- package/src/validation/index.d.ts +701 -0
- package/src/validation/index.js +271 -0
package/README.md
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
> [!WARNING]
|
|
2
|
+
> Unfortunately i published the 1.0 by mistake...this package is currently under heavy development so there will be breaking changes in minors...threat this `1.x` as the `0.x` of any other package. Sorry for the disservice, every breaking will be properly labeled in the PR name.
|
|
3
|
+
|
|
1
4
|
# tmcp
|
|
2
5
|
|
|
3
6
|
A lightweight, schema-agnostic Model Context Protocol (MCP) server implementation with unified API design.
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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",
|
|
7
7
|
"keywords": [],
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/paoloricciuti/tmcp.git",
|
|
10
|
+
"url": "git+https://github.com/paoloricciuti/tmcp.git",
|
|
11
11
|
"directory": "packages/tmcp"
|
|
12
12
|
},
|
|
13
13
|
"author": "Paolo Ricciuti",
|
|
@@ -34,12 +34,13 @@
|
|
|
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": {
|
|
40
41
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
41
42
|
"typecheck": "tsc --noEmit",
|
|
42
|
-
"generate:types": "
|
|
43
|
+
"generate:types": "find ./src -name \"*.d.ts\" -not -path \"./src/internal/*\" -delete && tsc ./src/*.js --declaration --emitDeclarationOnly --target esnext --allowJs --moduleresolution nodenext --module nodenext && publint",
|
|
43
44
|
"prepublish": "pnpm generate:types"
|
|
44
45
|
}
|
|
45
46
|
}
|
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
|
|
@@ -17,64 +35,76 @@ export class McpServer<StandardSchema extends StandardSchemaV1> {
|
|
|
17
35
|
/**
|
|
18
36
|
* @template {StandardSchema | undefined} [TSchema=undefined]
|
|
19
37
|
* @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never }} options
|
|
20
|
-
* @param {TSchema extends undefined ? (()=>Promise<
|
|
38
|
+
* @param {TSchema extends undefined ? (()=>Promise<CallToolResult> | CallToolResult) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult> | CallToolResult)} execute
|
|
21
39
|
*/
|
|
22
40
|
tool<TSchema extends StandardSchema | undefined = undefined>({ name, description, schema }: {
|
|
23
41
|
name: string;
|
|
24
42
|
description: string;
|
|
25
43
|
schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never;
|
|
26
|
-
}, execute: TSchema extends undefined ? (() => Promise<
|
|
44
|
+
}, execute: TSchema extends undefined ? (() => Promise<CallToolResult> | CallToolResult) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult> | CallToolResult)): void;
|
|
27
45
|
/**
|
|
28
46
|
* @template {StandardSchema | undefined} [TSchema=undefined]
|
|
29
|
-
* @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; complete?: TSchema extends undefined ? never : Partial<Record<keyof (StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>), Completion
|
|
30
|
-
* @param {TSchema extends undefined ? (()=>Promise<
|
|
47
|
+
* @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; complete?: NoInfer<TSchema extends undefined ? never : Partial<Record<keyof (StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>), Completion>>> }} options
|
|
48
|
+
* @param {TSchema extends undefined ? (()=>Promise<GetPromptResult> | GetPromptResult) : (input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<GetPromptResult> | GetPromptResult} execute
|
|
31
49
|
*/
|
|
32
50
|
prompt<TSchema extends StandardSchema | undefined = undefined>({ name, description, schema, complete }: {
|
|
33
51
|
name: string;
|
|
34
52
|
description: string;
|
|
35
53
|
schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never;
|
|
36
|
-
complete?: TSchema extends undefined ? never : Partial<Record<keyof StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>, Completion
|
|
37
|
-
}, execute: TSchema extends undefined ? (() => Promise<
|
|
54
|
+
complete?: NoInfer<TSchema extends undefined ? never : Partial<Record<keyof StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>, Completion>>>;
|
|
55
|
+
}, execute: TSchema extends undefined ? (() => Promise<GetPromptResult> | GetPromptResult) : (input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<GetPromptResult> | GetPromptResult): void;
|
|
38
56
|
/**
|
|
39
57
|
* @param {{ name: string; description: string; uri: string }} options
|
|
40
|
-
* @param {(uri: string) => Promise<
|
|
58
|
+
* @param {(uri: string) => Promise<ReadResourceResult> | ReadResourceResult} execute
|
|
41
59
|
*/
|
|
42
60
|
resource({ name, description, uri }: {
|
|
43
61
|
name: string;
|
|
44
62
|
description: string;
|
|
45
63
|
uri: string;
|
|
46
|
-
}, execute: (uri: string) => Promise<
|
|
64
|
+
}, execute: (uri: string) => Promise<ReadResourceResult> | ReadResourceResult): void;
|
|
47
65
|
/**
|
|
48
66
|
* @template {string} TUri
|
|
49
67
|
* @template {ExtractURITemplateVariables<TUri>} TVariables
|
|
50
|
-
* @param {{ name: string; description: string; uri: TUri; complete?: TVariables extends never ? never : Partial<Record<TVariables, Completion
|
|
51
|
-
* @param {(uri: string, params: Record<TVariables, string | string[]>) => Promise<
|
|
68
|
+
* @param {{ name: string; description: string; uri: TUri; complete?: NoInfer<TVariables extends never ? never : Partial<Record<TVariables, Completion>>> }} options
|
|
69
|
+
* @param {(uri: string, params: Record<TVariables, string | string[]>) => Promise<ReadResourceResult> | ReadResourceResult} execute
|
|
52
70
|
*/
|
|
53
71
|
template<TUri extends string, TVariables extends ExtractURITemplateVariables<TUri>>({ name, description, uri, complete }: {
|
|
54
72
|
name: string;
|
|
55
73
|
description: string;
|
|
56
74
|
uri: TUri;
|
|
57
|
-
complete?: TVariables extends never ? never : Partial<Record<TVariables, Completion
|
|
58
|
-
}, execute: (uri: string, params: Record<TVariables, string | string[]>) => Promise<
|
|
75
|
+
complete?: NoInfer<TVariables extends never ? never : Partial<Record<TVariables, Completion>>>;
|
|
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";
|
|
100
|
+
import type { CallToolResult } from "./validation/index.js";
|
|
74
101
|
import type { Completion } from "./internal/internal.js";
|
|
102
|
+
import type { GetPromptResult } from "./validation/index.js";
|
|
103
|
+
import type { ReadResourceResult } from "./validation/index.js";
|
|
75
104
|
import type { ExtractURITemplateVariables } from "./internal/uri-template.js";
|
|
76
105
|
import type { JSONRPCRequest } from "json-rpc-2.0";
|
|
77
106
|
import { JSONRPCServer } from 'json-rpc-2.0';
|
|
78
107
|
import type { SubscriptionsKeys } from "./internal/internal.js";
|
|
79
108
|
import type { ServerInfo } from "./internal/internal.js";
|
|
80
109
|
import type { ServerOptions } from "./internal/internal.js";
|
|
110
|
+
import type { ClientCapabilities as ClientCapabilitiesType } from "./validation/index.js";
|
package/src/index.js
CHANGED
|
@@ -2,10 +2,24 @@
|
|
|
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, ClientCapabilities as ClientCapabilitiesType } from "./validation/index.js";
|
|
5
6
|
* @import { Tool, Completion, Prompt, Resource, ServerOptions, ServerInfo, SubscriptionsKeys, McpEvents } from "./internal/internal.js";
|
|
6
7
|
*/
|
|
7
8
|
import { JSONRPCServer, JSONRPCClient } from 'json-rpc-2.0';
|
|
8
9
|
import { UriTemplateMatcher } from 'uri-template-matcher';
|
|
10
|
+
import {
|
|
11
|
+
CallToolResultSchema,
|
|
12
|
+
ReadResourceResultSchema,
|
|
13
|
+
GetPromptResultSchema,
|
|
14
|
+
CompleteResultSchema,
|
|
15
|
+
InitializeRequestSchema,
|
|
16
|
+
} from './validation/index.js';
|
|
17
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
18
|
+
import * as v from 'valibot';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {ClientCapabilitiesType} ClientCapabilities
|
|
22
|
+
*/
|
|
9
23
|
|
|
10
24
|
/**
|
|
11
25
|
* @template {StandardSchemaV1} StandardSchema
|
|
@@ -13,7 +27,7 @@ import { UriTemplateMatcher } from 'uri-template-matcher';
|
|
|
13
27
|
export class McpServer {
|
|
14
28
|
#server = new JSONRPCServer();
|
|
15
29
|
/**
|
|
16
|
-
* @type {JSONRPCClient | undefined}
|
|
30
|
+
* @type {JSONRPCClient<Record<string, any> | undefined> | undefined}
|
|
17
31
|
*/
|
|
18
32
|
#client;
|
|
19
33
|
#options;
|
|
@@ -41,24 +55,47 @@ export class McpServer {
|
|
|
41
55
|
#event_target = new EventTarget();
|
|
42
56
|
|
|
43
57
|
/**
|
|
44
|
-
* @type {Record<SubscriptionsKeys, Set<string
|
|
58
|
+
* @type {Record<SubscriptionsKeys, Map<string, Set<string | undefined>>>}
|
|
45
59
|
*/
|
|
46
60
|
#subscriptions = {
|
|
47
61
|
/**
|
|
48
|
-
* @type {Set<string
|
|
62
|
+
* @type {Map<string, Set<string>>}
|
|
49
63
|
*/
|
|
50
|
-
resource: new
|
|
64
|
+
resource: new Map(),
|
|
51
65
|
};
|
|
52
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
|
+
|
|
53
77
|
/**
|
|
54
78
|
* @param {ServerInfo} server_info
|
|
55
79
|
* @param {ServerOptions<StandardSchema>} options
|
|
56
80
|
*/
|
|
57
81
|
constructor(server_info, options) {
|
|
58
82
|
this.#options = options;
|
|
59
|
-
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
|
+
);
|
|
60
97
|
return {
|
|
61
|
-
protocolVersion,
|
|
98
|
+
protocolVersion: validated_initialize.protocolVersion,
|
|
62
99
|
...options,
|
|
63
100
|
serverInfo: server_info,
|
|
64
101
|
};
|
|
@@ -75,6 +112,30 @@ export class McpServer {
|
|
|
75
112
|
this.#init_completion();
|
|
76
113
|
}
|
|
77
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
|
+
|
|
78
139
|
/**
|
|
79
140
|
* @template {keyof McpEvents} TEvent
|
|
80
141
|
* @param {TEvent} event
|
|
@@ -82,12 +143,8 @@ export class McpServer {
|
|
|
82
143
|
* @param {AddEventListenerOptions} [options]
|
|
83
144
|
*/
|
|
84
145
|
on(event, callback, options) {
|
|
85
|
-
if (event === 'send'
|
|
86
|
-
this.#
|
|
87
|
-
this.#event_target.dispatchEvent(
|
|
88
|
-
new CustomEvent('send', { detail: payload }),
|
|
89
|
-
);
|
|
90
|
-
});
|
|
146
|
+
if (event === 'send') {
|
|
147
|
+
this.#lazyily_create_client();
|
|
91
148
|
}
|
|
92
149
|
|
|
93
150
|
this.#event_target.addEventListener(
|
|
@@ -102,9 +159,10 @@ export class McpServer {
|
|
|
102
159
|
/**
|
|
103
160
|
* @param {string} method
|
|
104
161
|
* @param {JSONRPCParams} [params]
|
|
162
|
+
* @param {Record<string, any>} [extra]
|
|
105
163
|
*/
|
|
106
|
-
#notify(method, params) {
|
|
107
|
-
this.#client?.notify(method, params);
|
|
164
|
+
#notify(method, params, extra) {
|
|
165
|
+
this.#client?.notify(method, params, extra);
|
|
108
166
|
}
|
|
109
167
|
|
|
110
168
|
/**
|
|
@@ -139,7 +197,7 @@ export class McpServer {
|
|
|
139
197
|
throw new Error(`Tool ${name} not found`);
|
|
140
198
|
}
|
|
141
199
|
if (!tool.schema) {
|
|
142
|
-
return tool.execute();
|
|
200
|
+
return v.parse(CallToolResultSchema, await tool.execute());
|
|
143
201
|
}
|
|
144
202
|
let validated_args = tool.schema['~standard'].validate(args);
|
|
145
203
|
if (validated_args instanceof Promise)
|
|
@@ -149,7 +207,10 @@ export class McpServer {
|
|
|
149
207
|
`Invalid arguments for tool ${name}: ${JSON.stringify(validated_args.issues)}`,
|
|
150
208
|
);
|
|
151
209
|
}
|
|
152
|
-
return
|
|
210
|
+
return v.parse(
|
|
211
|
+
CallToolResultSchema,
|
|
212
|
+
await tool.execute(validated_args.value),
|
|
213
|
+
);
|
|
153
214
|
},
|
|
154
215
|
);
|
|
155
216
|
}
|
|
@@ -204,7 +265,10 @@ export class McpServer {
|
|
|
204
265
|
throw new Error(`Tool ${name} not found`);
|
|
205
266
|
}
|
|
206
267
|
if (!prompt.schema) {
|
|
207
|
-
return
|
|
268
|
+
return v.parse(
|
|
269
|
+
GetPromptResultSchema,
|
|
270
|
+
await prompt.execute(),
|
|
271
|
+
);
|
|
208
272
|
}
|
|
209
273
|
let validated_args = prompt.schema['~standard'].validate(args);
|
|
210
274
|
if (validated_args instanceof Promise)
|
|
@@ -214,7 +278,10 @@ export class McpServer {
|
|
|
214
278
|
`Invalid arguments for tool ${name}: ${JSON.stringify(validated_args.issues)}`,
|
|
215
279
|
);
|
|
216
280
|
}
|
|
217
|
-
return
|
|
281
|
+
return v.parse(
|
|
282
|
+
GetPromptResultSchema,
|
|
283
|
+
await prompt.execute(validated_args.value),
|
|
284
|
+
);
|
|
218
285
|
},
|
|
219
286
|
);
|
|
220
287
|
}
|
|
@@ -226,7 +293,12 @@ export class McpServer {
|
|
|
226
293
|
|
|
227
294
|
if (this.#options.capabilities?.resources?.subscribe) {
|
|
228
295
|
this.#server.addMethod('resources/subscribe', async ({ uri }) => {
|
|
229
|
-
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);
|
|
230
302
|
return {};
|
|
231
303
|
});
|
|
232
304
|
}
|
|
@@ -281,9 +353,15 @@ export class McpServer {
|
|
|
281
353
|
if (resource.template) {
|
|
282
354
|
if (!params)
|
|
283
355
|
throw new Error('Missing parameters for template resource');
|
|
284
|
-
return
|
|
356
|
+
return v.parse(
|
|
357
|
+
ReadResourceResultSchema,
|
|
358
|
+
await resource.execute(uri, params),
|
|
359
|
+
);
|
|
285
360
|
}
|
|
286
|
-
return
|
|
361
|
+
return v.parse(
|
|
362
|
+
ReadResourceResultSchema,
|
|
363
|
+
await resource.execute(uri),
|
|
364
|
+
);
|
|
287
365
|
});
|
|
288
366
|
}
|
|
289
367
|
/**
|
|
@@ -299,19 +377,17 @@ export class McpServer {
|
|
|
299
377
|
if (!complete) return null;
|
|
300
378
|
const actual_complete = complete[argument.name];
|
|
301
379
|
if (!actual_complete) return null;
|
|
302
|
-
return
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
},
|
|
307
|
-
};
|
|
380
|
+
return v.parse(
|
|
381
|
+
CompleteResultSchema,
|
|
382
|
+
actual_complete(argument.value, context),
|
|
383
|
+
);
|
|
308
384
|
},
|
|
309
385
|
);
|
|
310
386
|
}
|
|
311
387
|
/**
|
|
312
388
|
* @template {StandardSchema | undefined} [TSchema=undefined]
|
|
313
389
|
* @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never }} options
|
|
314
|
-
* @param {TSchema extends undefined ? (()=>Promise<
|
|
390
|
+
* @param {TSchema extends undefined ? (()=>Promise<CallToolResult> | CallToolResult) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult> | CallToolResult)} execute
|
|
315
391
|
*/
|
|
316
392
|
tool({ name, description, schema }, execute) {
|
|
317
393
|
if (this.#options.capabilities?.tools?.listChanged) {
|
|
@@ -325,8 +401,8 @@ export class McpServer {
|
|
|
325
401
|
}
|
|
326
402
|
/**
|
|
327
403
|
* @template {StandardSchema | undefined} [TSchema=undefined]
|
|
328
|
-
* @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; complete?: TSchema extends undefined ? never : Partial<Record<keyof (StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>), Completion
|
|
329
|
-
* @param {TSchema extends undefined ? (()=>Promise<
|
|
404
|
+
* @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; complete?: NoInfer<TSchema extends undefined ? never : Partial<Record<keyof (StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>), Completion>>> }} options
|
|
405
|
+
* @param {TSchema extends undefined ? (()=>Promise<GetPromptResult> | GetPromptResult) : (input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<GetPromptResult> | GetPromptResult} execute
|
|
330
406
|
*/
|
|
331
407
|
prompt({ name, description, schema, complete }, execute) {
|
|
332
408
|
if (complete) {
|
|
@@ -358,7 +434,7 @@ export class McpServer {
|
|
|
358
434
|
}
|
|
359
435
|
/**
|
|
360
436
|
* @param {{ name: string; description: string; uri: string }} options
|
|
361
|
-
* @param {(uri: string) => Promise<
|
|
437
|
+
* @param {(uri: string) => Promise<ReadResourceResult> | ReadResourceResult} execute
|
|
362
438
|
*/
|
|
363
439
|
resource({ name, description, uri }, execute) {
|
|
364
440
|
this.#resource({
|
|
@@ -372,8 +448,8 @@ export class McpServer {
|
|
|
372
448
|
/**
|
|
373
449
|
* @template {string} TUri
|
|
374
450
|
* @template {ExtractURITemplateVariables<TUri>} TVariables
|
|
375
|
-
* @param {{ name: string; description: string; uri: TUri; complete?: TVariables extends never ? never : Partial<Record<TVariables, Completion
|
|
376
|
-
* @param {(uri: string, params: Record<TVariables, string | string[]>) => Promise<
|
|
451
|
+
* @param {{ name: string; description: string; uri: TUri; complete?: NoInfer<TVariables extends never ? never : Partial<Record<TVariables, Completion>>> }} options
|
|
452
|
+
* @param {(uri: string, params: Record<TVariables, string | string[]>) => Promise<ReadResourceResult> | ReadResourceResult} execute
|
|
377
453
|
*/
|
|
378
454
|
template({ name, description, uri, complete }, execute) {
|
|
379
455
|
this.#resource({
|
|
@@ -387,10 +463,14 @@ export class McpServer {
|
|
|
387
463
|
}
|
|
388
464
|
/**
|
|
389
465
|
* @param {JSONRPCRequest} request
|
|
466
|
+
* @param {string} [session_id]
|
|
390
467
|
* @returns {ReturnType<JSONRPCServer['receive']>}
|
|
391
468
|
*/
|
|
392
|
-
receive(request) {
|
|
393
|
-
return this.#
|
|
469
|
+
receive(request, session_id) {
|
|
470
|
+
return this.#session_storage.run(
|
|
471
|
+
session_id,
|
|
472
|
+
async () => await this.#server.receive(request),
|
|
473
|
+
);
|
|
394
474
|
}
|
|
395
475
|
|
|
396
476
|
/**
|
|
@@ -402,10 +482,48 @@ export class McpServer {
|
|
|
402
482
|
if (this.#subscriptions[what].has(id)) {
|
|
403
483
|
const resource = this.#resources.get(id);
|
|
404
484
|
if (!resource) return;
|
|
405
|
-
this.#
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
+
);
|
|
409
526
|
}
|
|
527
|
+
return validated_result.value;
|
|
410
528
|
}
|
|
411
529
|
}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
import { JSONRPCRequest } from 'json-rpc-2.0';
|
|
3
3
|
import { JsonSchemaAdapter } from '../adapter.js';
|
|
4
|
+
import {
|
|
5
|
+
GetPromptResult,
|
|
6
|
+
CallToolResult,
|
|
7
|
+
ReadResourceResult,
|
|
8
|
+
CompleteResult,
|
|
9
|
+
InitializeRequest,
|
|
10
|
+
} from '../validation/index.js';
|
|
4
11
|
|
|
5
12
|
export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
|
|
6
13
|
description: string;
|
|
7
14
|
schema: TSchema;
|
|
8
15
|
execute: (
|
|
9
16
|
input?: StandardSchemaV1.InferInput<TSchema>,
|
|
10
|
-
) => Promise<
|
|
17
|
+
) => Promise<CallToolResult> | CallToolResult;
|
|
11
18
|
};
|
|
12
19
|
|
|
13
20
|
export type Completion = (
|
|
14
21
|
query: string,
|
|
15
22
|
context: { arguments: Record<string, string> },
|
|
16
|
-
) =>
|
|
23
|
+
) => CompleteResult;
|
|
17
24
|
|
|
18
25
|
export type Prompt<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
|
|
19
26
|
description: string;
|
|
20
27
|
schema: TSchema;
|
|
21
28
|
execute: (
|
|
22
29
|
input?: StandardSchemaV1.InferInput<TSchema>,
|
|
23
|
-
) => Promise<
|
|
30
|
+
) => Promise<GetPromptResult> | GetPromptResult;
|
|
24
31
|
};
|
|
25
32
|
|
|
26
33
|
export type Resource =
|
|
@@ -31,13 +38,15 @@ export type Resource =
|
|
|
31
38
|
execute: (
|
|
32
39
|
uri: string,
|
|
33
40
|
params: Record<string, string | string[]>,
|
|
34
|
-
) => Promise<
|
|
41
|
+
) => Promise<ReadResourceResult> | ReadResourceResult;
|
|
35
42
|
}
|
|
36
43
|
| {
|
|
37
44
|
description: string;
|
|
38
45
|
name: string;
|
|
39
46
|
template: false;
|
|
40
|
-
execute: (
|
|
47
|
+
execute: (
|
|
48
|
+
uri: string,
|
|
49
|
+
) => Promise<ReadResourceResult> | ReadResourceResult;
|
|
41
50
|
};
|
|
42
51
|
|
|
43
52
|
export type ServerOptions<TSchema extends StandardSchemaV1> = {
|
|
@@ -59,5 +68,11 @@ export type ServerInfo = {
|
|
|
59
68
|
export type SubscriptionsKeys = 'resource';
|
|
60
69
|
|
|
61
70
|
export type McpEvents = {
|
|
62
|
-
send: (message:
|
|
71
|
+
send: (message: {
|
|
72
|
+
request: JSONRPCRequest;
|
|
73
|
+
context: {
|
|
74
|
+
sessions?: string[] | undefined;
|
|
75
|
+
};
|
|
76
|
+
}) => void;
|
|
77
|
+
initialize: (initialize_request: InitializeRequest) => void;
|
|
63
78
|
};
|