tmcp 1.15.5 → 1.16.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 CHANGED
@@ -129,6 +129,8 @@ server.tool(
129
129
  );
130
130
  ```
131
131
 
132
+ `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.
133
+
132
134
  ##### `prompt(definition, handler)`
133
135
 
134
136
  Register a prompt template with optional schema validation.
@@ -232,30 +234,34 @@ server.tool(
232
234
 
233
235
  ##### `ctx`
234
236
 
235
- Access the current request context, including session ID, auth info, and custom context.
237
+ Access the current request context, including session ID, auth info, client metadata, and custom context.
236
238
 
237
239
  ```javascript
238
240
  server.tool(
239
- {
240
- name: 'context-aware-tool',
241
- description: 'Tool that uses request context',
242
- },
243
- async () => {
244
- const { sessionId, auth, custom } = server.ctx;
245
-
246
- if (!custom?.userId) {
247
- throw new Error('User authentication required');
248
- }
249
-
250
- return {
251
- content: [
252
- {
253
- type: 'text',
254
- text: `Hello user ${custom.userId} in session ${sessionId}`,
255
- },
256
- ],
257
- };
258
- },
241
+ {
242
+ name: 'context-aware-tool',
243
+ description: 'Tool that uses request context',
244
+ },
245
+ async () => {
246
+ const { sessionId, auth, sessionInfo, custom } = server.ctx;
247
+
248
+ if (!custom?.userId) {
249
+ throw new Error('User authentication required');
250
+ }
251
+
252
+ if (sessionInfo?.clientInfo) {
253
+ console.log(`Serving ${sessionInfo.clientInfo.name}`);
254
+ }
255
+
256
+ return {
257
+ content: [
258
+ {
259
+ type: 'text',
260
+ text: `Hello user ${custom.userId} in session ${sessionId}`,
261
+ },
262
+ ],
263
+ };
264
+ },
259
265
  );
260
266
  ```
261
267
 
@@ -269,9 +275,14 @@ const response = server.receive(jsonRpcRequest);
269
275
 
270
276
  // With custom context (typically used by transports)
271
277
  const response = server.receive(jsonRpcRequest, {
272
- sessionId: 'session-123',
273
- auth: authInfo,
274
- custom: customContextData,
278
+ sessionId: 'session-123',
279
+ auth: authInfo,
280
+ sessionInfo: {
281
+ clientCapabilities,
282
+ clientInfo,
283
+ logLevel,
284
+ },
285
+ custom: customContextData,
275
286
  });
276
287
  ```
277
288
 
@@ -309,7 +320,7 @@ console.log(server.roots); // Access current roots
309
320
 
310
321
  ##### `changed(type, id)`
311
322
 
312
- Send notifications for subscriptions.
323
+ Send notifications for subscriptions. When you call `changed('resource', uri)` the server now emits a broadcast notification, and the built-in transports look up which sessions subscribed to that URI before delivering it.
313
324
 
314
325
  ```javascript
315
326
  server.changed('resource', 'file://path/to/resource');
@@ -380,13 +391,25 @@ server.log('error', 'Failed to connect to database', 'database-logger');
380
391
 
381
392
  Listen to server events.
382
393
 
394
+ Available events:
395
+
396
+ - `initialize` – fired after the client handshake with the parsed initialize payload
397
+ - `send` – emitted for point-to-point responses/notifications destined for the active session
398
+ - `broadcast` – emitted for fan-out notifications (for example `notifications/resources/updated`)
399
+ - `subscription` – raised when the client subscribes to a resource URI
400
+ - `loglevelchange` – fired when the client requests a different log level
401
+
383
402
  ```javascript
384
- server.on('initialize', (data) => {
385
- console.log('Client initialized:', data);
403
+ server.on('initialize', ({ clientInfo }) => {
404
+ console.log('Client initialized:', clientInfo?.name);
386
405
  });
387
406
 
388
- server.on('send', ({ request, context }) => {
389
- console.log('Sending request:', request);
407
+ server.on('send', ({ request }) => {
408
+ console.log('Sending message:', request);
409
+ });
410
+
411
+ server.on('broadcast', ({ request }) => {
412
+ console.log('Broadcasting:', request.method);
390
413
  });
391
414
  ```
392
415
 
@@ -516,9 +539,15 @@ server.on('initialize', (data) => {
516
539
  console.log('Client capabilities:', data.capabilities);
517
540
  });
518
541
 
519
- server.on('send', ({ request, context }) => {
542
+ server.on('send', ({ request }) => {
520
543
  console.log('Outgoing request:', request.method);
521
544
  });
545
+
546
+ server.on('broadcast', ({ request }) => {
547
+ if (request.method === 'notifications/resources/updated') {
548
+ console.log('Resource updated:', request.params.uri);
549
+ }
550
+ });
522
551
  ```
523
552
 
524
553
  ### Resource Subscriptions
@@ -923,7 +952,7 @@ server.prompt(
923
952
  );
924
953
  ```
925
954
 
926
- or enable a something based on client capabilities or info
955
+ or enable something based on client capabilities or info
927
956
 
928
957
  ```javascript
929
958
  server.prompt(
@@ -932,8 +961,8 @@ server.prompt(
932
961
  description: 'Claude Code prompt',
933
962
  enabled: () => {
934
963
  // Access session information
935
- const clientInfo = server.currentClientInfo();
936
- return clientInfo.name === 'Claude Code';
964
+ const clientInfo = server.ctx.sessionInfo?.clientInfo;
965
+ return clientInfo?.name === 'Claude Code';
937
966
  },
938
967
  },
939
968
  async (input) => {
@@ -958,8 +987,9 @@ server.prompt(
958
987
  description: 'fetch the repositories of the user',
959
988
  enabled: () => {
960
989
  // Access session information
961
- const clientInfo = server.currentClientCapabilities();
962
- return clientInfo.elicitation != null;
990
+ const clientCapabilities =
991
+ server.ctx.sessionInfo?.clientCapabilities;
992
+ return clientCapabilities?.elicitation != null;
963
993
  },
964
994
  },
965
995
  async (input) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmcp",
3
- "version": "1.15.5",
3
+ "version": "1.16.0",
4
4
  "description": "The main tmcp library",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -49,6 +49,7 @@ import { should_version_negotiation_fail } from './validation/version.js';
49
49
  * @template {Record<string, unknown> | undefined} [TCustom=undefined]
50
50
  * @typedef {Object} Context
51
51
  * @property {string} [sessionId]
52
+ * @property {{ clientCapabilities?: ClientCapabilitiesType, clientInfo?: ClientInfoType, logLevel?: LoggingLevel }} [sessionInfo]
52
53
  * @property {AuthInfo} [auth]
53
54
  * @property {TCustom} [custom]
54
55
  */
@@ -57,6 +58,10 @@ import { should_version_negotiation_fail } from './validation/version.js';
57
58
  * @typedef {IconsType} Icons
58
59
  */
59
60
 
61
+ /**
62
+ * @typedef {Record<SubscriptionsKeys, string[]>} Subscriptions
63
+ */
64
+
60
65
  /**
61
66
  * @template {Record<string, unknown> | undefined} TStructuredContent
62
67
  * @typedef {CallToolResultType<TStructuredContent>} CallToolResult
@@ -149,7 +154,7 @@ async function safe_enabled(enabled) {
149
154
  export class McpServer {
150
155
  #server = new JSONRPCServer();
151
156
  /**
152
- * @type {JSONRPCClient<Record<string, any> | undefined> | undefined}
157
+ * @type {JSONRPCClient<"broadcast" | "standalone"> | undefined}
153
158
  */
154
159
  #client;
155
160
  #options;
@@ -180,36 +185,11 @@ export class McpServer {
180
185
 
181
186
  #event_target = new EventTarget();
182
187
 
183
- /**
184
- * @type {Record<SubscriptionsKeys, Map<string, Set<string | undefined>>>}
185
- */
186
- #subscriptions = {
187
- /**
188
- * @type {Map<string, Set<string>>}
189
- */
190
- resource: new Map(),
191
- };
192
-
193
188
  /**
194
189
  * @type {AsyncLocalStorage<Context<CustomContext> & { progress_token?: string }>}
195
190
  */
196
191
  #ctx_storage = new AsyncLocalStorage();
197
192
 
198
- /**
199
- * @type {Map<string|undefined, ClientCapabilities>}
200
- */
201
- #client_capabilities_map = new Map();
202
-
203
- /**
204
- * @type {Map<string|undefined, ClientInfo>}
205
- */
206
- #client_info_map = new Map();
207
-
208
- /**
209
- * @type {Map<string|undefined, LoggingLevel>}
210
- */
211
- #session_log_levels = new Map();
212
-
213
193
  /**
214
194
  * @param {ServerInfo} server_info
215
195
  * @param {ServerOptions<StandardSchema>} options
@@ -224,8 +204,6 @@ export class McpServer {
224
204
  initialize_request,
225
205
  );
226
206
 
227
- const session_id = this.#session_id;
228
-
229
207
  // Validate protocol version format
230
208
  if (
231
209
  should_version_negotiation_fail(
@@ -245,18 +223,6 @@ export class McpServer {
245
223
  validated_initialize.protocolVersion,
246
224
  );
247
225
 
248
- // Store client capabilities
249
- this.#client_capabilities_map.set(
250
- session_id,
251
- validated_initialize.capabilities,
252
- );
253
-
254
- // Store client info
255
- this.#client_info_map.set(
256
- session_id,
257
- validated_initialize.clientInfo,
258
- );
259
-
260
226
  // Dispatch initialization event
261
227
  this.#event_target.dispatchEvent(
262
228
  new CustomEvent('initialize', {
@@ -324,10 +290,6 @@ export class McpServer {
324
290
  );
325
291
  }
326
292
 
327
- get #session_id() {
328
- return this.#ctx_storage.getStore()?.sessionId;
329
- }
330
-
331
293
  get #progress_token() {
332
294
  return this.#ctx_storage.getStore()?.progress_token;
333
295
  }
@@ -343,18 +305,20 @@ export class McpServer {
343
305
  }
344
306
 
345
307
  get #client_capabilities() {
346
- return this.#client_capabilities_map.get(this.#session_id);
308
+ return this.#ctx_storage.getStore()?.sessionInfo?.clientCapabilities;
347
309
  }
348
310
 
349
311
  /**
350
312
  * Get the client information (name, version, etc.) of the client that initiated the current request...useful if you want to do something different based on the client.
313
+ * @deprecated Use `server.ctx.sessionInfo.clientInfo` instead.
351
314
  */
352
315
  currentClientInfo() {
353
- return this.#client_info_map.get(this.#session_id);
316
+ return this.#ctx_storage.getStore()?.sessionInfo?.clientInfo;
354
317
  }
355
318
 
356
319
  /**
357
320
  * Get the client capabilities of the client that initiated the current request, you can use this to verify the client support something before invoking the respective method.
321
+ * @deprecated Use `server.ctx.sessionInfo.clientCapabilities` instead.
358
322
  */
359
323
  currentClientCapabilities() {
360
324
  return this.#client_capabilities;
@@ -362,10 +326,18 @@ export class McpServer {
362
326
 
363
327
  #lazyily_create_client() {
364
328
  if (!this.#client) {
365
- this.#client = new JSONRPCClient((payload, context = {}) => {
329
+ this.#client = new JSONRPCClient((payload, kind) => {
330
+ if (kind === 'broadcast') {
331
+ this.#event_target.dispatchEvent(
332
+ new CustomEvent('broadcast', {
333
+ detail: { request: payload },
334
+ }),
335
+ );
336
+ return;
337
+ }
366
338
  this.#event_target.dispatchEvent(
367
339
  new CustomEvent('send', {
368
- detail: { request: payload, context },
340
+ detail: { request: payload },
369
341
  }),
370
342
  );
371
343
  });
@@ -379,7 +351,7 @@ export class McpServer {
379
351
  * @param {AddEventListenerOptions} [options]
380
352
  */
381
353
  on(event, callback, options) {
382
- if (event === 'send') {
354
+ if (event === 'send' || event === 'broadcast') {
383
355
  this.#lazyily_create_client();
384
356
  }
385
357
 
@@ -400,10 +372,10 @@ export class McpServer {
400
372
  /**
401
373
  * @param {string} method
402
374
  * @param {JSONRPCParams} [params]
403
- * @param {Record<string, any>} [extra]
375
+ * @param {"broadcast" | "standalone"} [kind]
404
376
  */
405
- #notify(method, params, extra) {
406
- this.#client?.notify(method, params, extra);
377
+ #notify(method, params, kind = 'standalone') {
378
+ this.#client?.notify(method, params, kind);
407
379
  }
408
380
 
409
381
  /**
@@ -425,6 +397,7 @@ export class McpServer {
425
397
  title: tool.title || tool.description,
426
398
  description: tool.description,
427
399
  icons: tool.icons,
400
+ _meta: tool._meta,
428
401
  inputSchema: tool.schema
429
402
  ? await this.#options.adapter.toJsonSchema(
430
403
  tool.schema,
@@ -637,12 +610,11 @@ export class McpServer {
637
610
 
638
611
  if (this.#options.capabilities?.resources?.subscribe) {
639
612
  this.#server.addMethod('resources/subscribe', async ({ uri }) => {
640
- let subscriptions = this.#subscriptions.resource.get(uri);
641
- if (!subscriptions) {
642
- subscriptions = new Set();
643
- this.#subscriptions.resource.set(uri, subscriptions);
644
- }
645
- subscriptions.add(this.#session_id);
613
+ this.#event_target.dispatchEvent(
614
+ new CustomEvent('subscription', {
615
+ detail: { uri },
616
+ }),
617
+ );
646
618
  return {};
647
619
  });
648
620
  }
@@ -786,9 +758,7 @@ export class McpServer {
786
758
  const response = await this.#client?.request(
787
759
  'roots/list',
788
760
  undefined,
789
- {
790
- sessions: [this.#session_id],
791
- },
761
+ 'standalone',
792
762
  );
793
763
  this.roots = response?.roots || [];
794
764
  } catch {
@@ -819,26 +789,34 @@ export class McpServer {
819
789
  if (!this.#options.capabilities?.logging) return;
820
790
 
821
791
  this.#server.addMethod('logging/setLevel', ({ level }) => {
822
- this.#session_log_levels.set(this.#session_id, level);
792
+ this.#event_target.dispatchEvent(
793
+ new CustomEvent('loglevelchange', {
794
+ detail: { level },
795
+ }),
796
+ );
823
797
  return {};
824
798
  });
825
799
  }
826
800
 
827
801
  #notify_tools_list_changed() {
828
802
  if (this.#options.capabilities?.tools?.listChanged) {
829
- this.#notify('notifications/tools/list_changed', {});
803
+ this.#notify('notifications/tools/list_changed', {}, 'broadcast');
830
804
  }
831
805
  }
832
806
 
833
807
  #notify_prompts_list_changed() {
834
808
  if (this.#options.capabilities?.prompts?.listChanged) {
835
- this.#notify('notifications/prompts/list_changed', {});
809
+ this.#notify('notifications/prompts/list_changed', {}, 'broadcast');
836
810
  }
837
811
  }
838
812
 
839
813
  #notify_resources_list_changed() {
840
814
  if (this.#options.capabilities?.resources?.listChanged) {
841
- this.#notify('notifications/resources/list_changed', {});
815
+ this.#notify(
816
+ 'notifications/resources/list_changed',
817
+ {},
818
+ 'broadcast',
819
+ );
842
820
  }
843
821
  }
844
822
 
@@ -849,7 +827,7 @@ export class McpServer {
849
827
  * Tools will be invoked by the LLM when it thinks it needs to use them, you can use the annotations to provide additional information about the tool, like what it does, how to use it, etc.
850
828
  * @template {StandardSchema | undefined} [TSchema=undefined]
851
829
  * @template {StandardSchema | undefined} [TOutputSchema=undefined]
852
- * @param {{ name: string; description: string; title?: string; enabled?: ()=>boolean | Promise<boolean>; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; outputSchema?: StandardSchemaV1.InferOutput<TOutputSchema extends undefined ? never : TOutputSchema> extends Record<string, unknown> ? TOutputSchema : never; annotations?: ToolAnnotations } & Icons} options
830
+ * @param {{ name: string; _meta?: Record<string, any>; description: string; title?: string; enabled?: ()=>boolean | Promise<boolean>; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; outputSchema?: StandardSchemaV1.InferOutput<TOutputSchema extends undefined ? never : TOutputSchema> extends Record<string, unknown> ? TOutputSchema : never; annotations?: ToolAnnotations } & Icons} options
853
831
  * @param {TSchema extends undefined ? (()=>Promise<CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>> | CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>> | CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>)} execute
854
832
  */
855
833
  tool(
@@ -862,6 +840,7 @@ export class McpServer {
862
840
  annotations,
863
841
  enabled,
864
842
  icons,
843
+ _meta,
865
844
  },
866
845
  execute,
867
846
  ) {
@@ -875,6 +854,7 @@ export class McpServer {
875
854
  execute,
876
855
  annotations,
877
856
  icons,
857
+ _meta,
878
858
  });
879
859
  }
880
860
  /**
@@ -989,18 +969,6 @@ export class McpServer {
989
969
 
990
970
  // Check if it's a request or response
991
971
  if (validated_message.success) {
992
- // we want to set a default log level for each session
993
- // so that if the user calls `log` it can send a notification
994
- // to each client that didn't explicitly set a log level too
995
- if (
996
- !!this.#options.capabilities?.logging &&
997
- !this.#session_log_levels.has(ctx?.sessionId)
998
- ) {
999
- this.#session_log_levels.set(
1000
- ctx?.sessionId,
1001
- this.#options.logging?.default ?? 'info',
1002
- );
1003
- }
1004
972
  const progress_token = /** @type {string | undefined} */ (
1005
973
  validated_message.output.params?._meta?.progressToken
1006
974
  );
@@ -1035,28 +1003,16 @@ export class McpServer {
1035
1003
  } else if (what === 'resources') {
1036
1004
  this.#notify_resources_list_changed();
1037
1005
  } else {
1038
- if (
1039
- this.#subscriptions[
1040
- /** @type {SubscriptionsKeys} */ (what)
1041
- ].has(id)
1042
- ) {
1043
- const resource = this.#resources.get(id);
1044
- if (!resource) return;
1045
- const sessions =
1046
- this.#subscriptions[
1047
- /** @type {SubscriptionsKeys} */ (what)
1048
- ].get(id);
1049
- this.#notify(
1050
- `notifications/resources/updated`,
1051
- {
1052
- uri: id,
1053
- title: resource.name,
1054
- },
1055
- {
1056
- sessions: sessions ? [...sessions] : undefined,
1057
- },
1058
- );
1059
- }
1006
+ const resource = this.#resources.get(id);
1007
+ if (!resource) return;
1008
+ this.#notify(
1009
+ `notifications/resources/updated`,
1010
+ {
1011
+ uri: id,
1012
+ title: resource.name,
1013
+ },
1014
+ 'broadcast',
1015
+ );
1060
1016
  }
1061
1017
  }
1062
1018
 
@@ -1091,9 +1047,7 @@ export class McpServer {
1091
1047
  requestedSchema:
1092
1048
  await this.#options.adapter.toJsonSchema(schema),
1093
1049
  },
1094
- {
1095
- sessions: [this.#session_id],
1096
- },
1050
+ 'standalone',
1097
1051
  );
1098
1052
  const elicit_result = v.parse(ElicitResultSchema, result);
1099
1053
  let validated_result = schema['~standard'].validate(
@@ -1131,9 +1085,7 @@ export class McpServer {
1131
1085
  const response = await this.#client?.request(
1132
1086
  'sampling/createMessage',
1133
1087
  validated_request,
1134
- {
1135
- sessions: [this.#session_id],
1136
- },
1088
+ 'standalone',
1137
1089
  );
1138
1090
 
1139
1091
  // Validate and return the response
@@ -1149,18 +1101,12 @@ export class McpServer {
1149
1101
  */
1150
1102
  progress(progress, total = 1, message = undefined) {
1151
1103
  if (this.#progress_token != null) {
1152
- this.#notify(
1153
- 'notifications/progress',
1154
- {
1155
- progress,
1156
- total,
1157
- message,
1158
- progressToken: this.#progress_token,
1159
- },
1160
- {
1161
- sessions: this.#session_id ? [this.#session_id] : undefined,
1162
- },
1163
- );
1104
+ this.#notify('notifications/progress', {
1105
+ progress,
1106
+ total,
1107
+ message,
1108
+ progressToken: this.#progress_token,
1109
+ });
1164
1110
  }
1165
1111
  }
1166
1112
 
@@ -1179,33 +1125,21 @@ export class McpServer {
1179
1125
  );
1180
1126
  }
1181
1127
 
1182
- const sessions = [];
1183
-
1184
- const current_session_level = this.#session_log_levels.get(
1185
- this.#session_id,
1186
- );
1128
+ const current_session_level =
1129
+ this.#ctx_storage.getStore()?.sessionInfo?.logLevel ??
1130
+ this.#options.logging?.default ??
1131
+ 'info';
1187
1132
 
1188
1133
  if (
1189
1134
  current_session_level &&
1190
1135
  this.#should_log(level, current_session_level)
1191
1136
  ) {
1192
- sessions.push(this.#session_id);
1193
- }
1194
-
1195
- if (sessions.length === 0) return;
1196
-
1197
- // Send the log notification to the client
1198
- this.#notify(
1199
- 'notifications/message',
1200
- {
1137
+ this.#notify('notifications/message', {
1201
1138
  level,
1202
1139
  data,
1203
1140
  logger,
1204
- },
1205
- {
1206
- sessions,
1207
- },
1208
- );
1141
+ });
1142
+ }
1209
1143
  }
1210
1144
 
1211
1145
  /**
@@ -20,6 +20,7 @@ export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>, TOutp
20
20
  outputSchema?: TOutputSchema;
21
21
  title?: string;
22
22
  annotations?: ToolAnnotations;
23
+ _meta?: Record<string, unknown>;
23
24
  enabled?: () => boolean | Promise<boolean>;
24
25
  execute: (
25
26
  input?: StandardSchemaV1.InferInput<TSchema>,
@@ -96,9 +97,11 @@ export type SubscriptionsKeys = SubscriptionsKeysObj["with_args"];
96
97
  export type McpEvents = {
97
98
  send: (message: {
98
99
  request: JSONRPCRequest;
99
- context: {
100
- sessions?: string[] | undefined;
101
- };
100
+ }) => void;
101
+ broadcast: (message: {
102
+ request: JSONRPCRequest;
102
103
  }) => void;
103
104
  initialize: (initialize_request: InitializeRequestParams) => void;
105
+ subscription: (subscriptions_request: { uri: string }) => void;
106
+ loglevelchange: (change: { level: LoggingLevel }) => void;
104
107
  };
@@ -23,6 +23,7 @@ declare module 'tmcp' {
23
23
  get ctx(): Context<CustomContext>;
24
24
  /**
25
25
  * Get the client information (name, version, etc.) of the client that initiated the current request...useful if you want to do something different based on the client.
26
+ * @deprecated Use `server.ctx.sessionInfo.clientInfo` instead.
26
27
  */
27
28
  currentClientInfo(): {
28
29
  icons?: {
@@ -37,6 +38,7 @@ declare module 'tmcp' {
37
38
  } | undefined;
38
39
  /**
39
40
  * Get the client capabilities of the client that initiated the current request, you can use this to verify the client support something before invoking the respective method.
41
+ * @deprecated Use `server.ctx.sessionInfo.clientCapabilities` instead.
40
42
  */
41
43
  currentClientCapabilities(): {
42
44
  experimental?: {} | undefined;
@@ -54,8 +56,9 @@ declare module 'tmcp' {
54
56
  *
55
57
  * Tools will be invoked by the LLM when it thinks it needs to use them, you can use the annotations to provide additional information about the tool, like what it does, how to use it, etc.
56
58
  * */
57
- tool<TSchema extends StandardSchema | undefined = undefined, TOutputSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, outputSchema, annotations, enabled, icons, }: {
59
+ tool<TSchema extends StandardSchema | undefined = undefined, TOutputSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, outputSchema, annotations, enabled, icons, _meta, }: {
58
60
  name: string;
61
+ _meta?: Record<string, any>;
59
62
  description: string;
60
63
  title?: string;
61
64
  enabled?: () => boolean | Promise<boolean>;
@@ -182,10 +185,16 @@ declare module 'tmcp' {
182
185
  };
183
186
  export type Context<TCustom extends Record<string, unknown> | undefined = undefined> = {
184
187
  sessionId?: string | undefined;
188
+ sessionInfo?: {
189
+ clientCapabilities?: ClientCapabilities_1;
190
+ clientInfo?: ClientInfo_1;
191
+ logLevel?: LoggingLevel;
192
+ } | undefined;
185
193
  auth?: AuthInfo | undefined;
186
194
  custom?: TCustom | undefined;
187
195
  };
188
196
  export type Icons = Icons_1;
197
+ export type Subscriptions = Record<SubscriptionsKeys, string[]>;
189
198
  export type CallToolResult<TStructuredContent extends Record<string, unknown> | undefined> = CallToolResult_1<TStructuredContent>;
190
199
  export type ReadResourceResult = ReadResourceResult_1;
191
200
  export type GetPromptResult = GetPromptResult_1;
@@ -222,14 +231,22 @@ declare module 'tmcp' {
222
231
  'resources': [];
223
232
  }
224
233
 
234
+ type SubscriptionsKeysObj = {
235
+ [K in keyof ChangedArgs as ChangedArgs[K]["length"] extends 0 ? "without_args" : "with_args"]: K
236
+ };
237
+
238
+ type SubscriptionsKeys = SubscriptionsKeysObj["with_args"];
239
+
225
240
  type McpEvents = {
226
241
  send: (message: {
227
242
  request: JSONRPCRequest;
228
- context: {
229
- sessions?: string[] | undefined;
230
- };
243
+ }) => void;
244
+ broadcast: (message: {
245
+ request: JSONRPCRequest;
231
246
  }) => void;
232
247
  initialize: (initialize_request: InitializeRequestParams) => void;
248
+ subscription: (subscriptions_request: { uri: string }) => void;
249
+ loglevelchange: (change: { level: LoggingLevel_1 }) => void;
233
250
  };
234
251
  /**
235
252
  * A successful (non-error) response to a request.
@@ -237,7 +254,7 @@ declare module 'tmcp' {
237
254
  const JSONRPCResponseSchema: v.StrictObjectSchema<{
238
255
  readonly jsonrpc: v.LiteralSchema<"2.0", undefined>;
239
256
  readonly id: v.UnionSchema<[v.StringSchema<undefined>, v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>]>], undefined>;
240
- readonly result: v.ObjectSchema<{
257
+ readonly result: v.LooseObjectSchema<{
241
258
  /**
242
259
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
243
260
  * for notes on _meta usage.
@@ -4,6 +4,7 @@
4
4
  "names": [
5
5
  "McpServer",
6
6
  "Icons",
7
+ "Subscriptions",
7
8
  "ReadResourceResult",
8
9
  "GetPromptResult",
9
10
  "ClientCapabilities",
@@ -17,6 +18,8 @@
17
18
  "Completion",
18
19
  "ServerOptions",
19
20
  "ChangedArgs",
21
+ "SubscriptionsKeysObj",
22
+ "SubscriptionsKeys",
20
23
  "McpEvents",
21
24
  "JSONRPCResponseSchema",
22
25
  "IconsSchema",
@@ -61,6 +64,6 @@
61
64
  null,
62
65
  null
63
66
  ],
64
- "mappings": ";;;;;cAoJaA,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aC81CyBC,KAAKA;;aAuBQC,kBAAkBA;aAGrBC,eAAeA;aAvBZC,kBAAkBA;aAUKC,UAAUA;aAmBzBC,0BAA0BA;aAGjCC,mBAAmBA;aAY9BC,QAAQA;aASJC,YAAYA;aA/CVC,UAAUA;aAqDZC,YAAYA;MCphDtDC,UAAUA;;;;;MAyCVC,aAAaA;;;;;;;;;;;;;MAabC,WAAWA;;;;;;;MAaXC,SAASA;;;;;;;;;;;;ODKRC,qBAAqBA;;;;;;;;;;;OAgHrBC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoBXC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAUpBC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;OA6BxBC,6BAA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuB7BC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmMxBC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8GdC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+PxBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BrBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4GrBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEpBC,kBAAkBA;OAuGlBC,gCAAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8ChCC,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6GzBC,kBAAkBA;;;;;;;;;;;;;;;;;;OAkFlBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;MAiI2BC,kBAAkBA;;;;;MAUbC,uBAAuBA;;;;;;;;;;;;;MAahCC,cAAcA;;;;MAwBbC,eAAeA;;MAMfC,eAAeA;;;ME5iDnEC,IAAIA;;;;;;;MAOJC,cAAcA;;;;;;;MAOdC,cAAcA;;;;;MAKdC,qBAAqBA;;;;;;;;;;;;;;;;;MAiBrBC,4BAA4BA;;;;;;MAMrBC,2BAA2BA;;;;;;;OCjC1BC,iBAAiBA;;;;;;;;;;;;;;;;cAAjBA,iBAAiBA",
67
+ "mappings": ";;;;;cAyJaA,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aCw1CyBC,KAAKA;aDp7CFC,aAAaA;;aC28CHC,kBAAkBA;aAGrBC,eAAeA;aAvBZC,kBAAkBA;aAUKC,UAAUA;aAmBzBC,0BAA0BA;aAGjCC,mBAAmBA;aAY9BC,QAAQA;aASJC,YAAYA;aA/CVC,UAAUA;aAqDZC,YAAYA;MClhDtDC,UAAUA;;;;;MAyCVC,aAAaA;;;;;;;;;;;;;MAabC,WAAWA;;;;;;;MAOlBC,oBAAoBA;;;;MAIbC,iBAAiBA;;MAEjBC,SAASA;;;;;;;;;;;;;;ODGRC,qBAAqBA;;;;;;;;;;;OAgHrBC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoBXC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAUpBC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;OA6BxBC,6BAA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuB7BC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmMxBC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8GdC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+PxBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BrBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4GrBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEpBC,kBAAkBA;OAuGlBC,gCAAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8ChCC,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6GzBC,kBAAkBA;;;;;;;;;;;;;;;;;;OAkFlBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;MAiI2BC,kBAAkBA;;;;;MAUbC,uBAAuBA;;;;;;;;;;;;;MAahCC,cAAcA;;;;MAwBbC,eAAeA;;MAMfC,eAAeA;;;ME3iDnEC,IAAIA;;;;;;;MAOJC,cAAcA;;;;;;;MAOdC,cAAcA;;;;;MAKdC,qBAAqBA;;;;;;;;;;;;;;;;;MAiBrBC,4BAA4BA;;;;;;MAMrBC,2BAA2BA;;;;;;;OCjC1BC,iBAAiBA;;;;;;;;;;;;;;;;cAAjBA,iBAAiBA",
65
68
  "ignoreList": []
66
69
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable jsdoc/no-undefined-types */
2
1
  import * as v from 'valibot';
3
2
  export const LATEST_PROTOCOL_VERSION = '2025-06-18';
4
3
  export const DEFAULT_NEGOTIATED_PROTOCOL_VERSION = '2025-03-26';
@@ -62,7 +61,7 @@ export const NotificationSchema = v.object({
62
61
  method: v.string(),
63
62
  params: v.optional(BaseNotificationParamsSchema),
64
63
  });
65
- export const ResultSchema = v.object({
64
+ export const ResultSchema = v.looseObject({
66
65
  /**
67
66
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
68
67
  * for notes on _meta usage.