tmcp 1.15.4 → 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.4",
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,41 +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, string>}
210
- */
211
- #negotiated_protocol_versions = new Map();
212
-
213
- /**
214
- * @type {Map<string|undefined, LoggingLevel>}
215
- */
216
- #session_log_levels = new Map();
217
-
218
193
  /**
219
194
  * @param {ServerInfo} server_info
220
195
  * @param {ServerOptions<StandardSchema>} options
@@ -229,8 +204,6 @@ export class McpServer {
229
204
  initialize_request,
230
205
  );
231
206
 
232
- const session_id = this.#session_id;
233
-
234
207
  // Validate protocol version format
235
208
  if (
236
209
  should_version_negotiation_fail(
@@ -250,24 +223,6 @@ export class McpServer {
250
223
  validated_initialize.protocolVersion,
251
224
  );
252
225
 
253
- // Store negotiated protocol version
254
- this.#negotiated_protocol_versions.set(
255
- session_id,
256
- negotiated_version,
257
- );
258
-
259
- // Store client capabilities
260
- this.#client_capabilities_map.set(
261
- session_id,
262
- validated_initialize.capabilities,
263
- );
264
-
265
- // Store client info
266
- this.#client_info_map.set(
267
- session_id,
268
- validated_initialize.clientInfo,
269
- );
270
-
271
226
  // Dispatch initialization event
272
227
  this.#event_target.dispatchEvent(
273
228
  new CustomEvent('initialize', {
@@ -335,10 +290,6 @@ export class McpServer {
335
290
  );
336
291
  }
337
292
 
338
- get #session_id() {
339
- return this.#ctx_storage.getStore()?.sessionId;
340
- }
341
-
342
293
  get #progress_token() {
343
294
  return this.#ctx_storage.getStore()?.progress_token;
344
295
  }
@@ -354,18 +305,20 @@ export class McpServer {
354
305
  }
355
306
 
356
307
  get #client_capabilities() {
357
- return this.#client_capabilities_map.get(this.#session_id);
308
+ return this.#ctx_storage.getStore()?.sessionInfo?.clientCapabilities;
358
309
  }
359
310
 
360
311
  /**
361
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.
362
314
  */
363
315
  currentClientInfo() {
364
- return this.#client_info_map.get(this.#session_id);
316
+ return this.#ctx_storage.getStore()?.sessionInfo?.clientInfo;
365
317
  }
366
318
 
367
319
  /**
368
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.
369
322
  */
370
323
  currentClientCapabilities() {
371
324
  return this.#client_capabilities;
@@ -373,10 +326,18 @@ export class McpServer {
373
326
 
374
327
  #lazyily_create_client() {
375
328
  if (!this.#client) {
376
- 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
+ }
377
338
  this.#event_target.dispatchEvent(
378
339
  new CustomEvent('send', {
379
- detail: { request: payload, context },
340
+ detail: { request: payload },
380
341
  }),
381
342
  );
382
343
  });
@@ -390,7 +351,7 @@ export class McpServer {
390
351
  * @param {AddEventListenerOptions} [options]
391
352
  */
392
353
  on(event, callback, options) {
393
- if (event === 'send') {
354
+ if (event === 'send' || event === 'broadcast') {
394
355
  this.#lazyily_create_client();
395
356
  }
396
357
 
@@ -411,10 +372,10 @@ export class McpServer {
411
372
  /**
412
373
  * @param {string} method
413
374
  * @param {JSONRPCParams} [params]
414
- * @param {Record<string, any>} [extra]
375
+ * @param {"broadcast" | "standalone"} [kind]
415
376
  */
416
- #notify(method, params, extra) {
417
- this.#client?.notify(method, params, extra);
377
+ #notify(method, params, kind = 'standalone') {
378
+ this.#client?.notify(method, params, kind);
418
379
  }
419
380
 
420
381
  /**
@@ -436,6 +397,7 @@ export class McpServer {
436
397
  title: tool.title || tool.description,
437
398
  description: tool.description,
438
399
  icons: tool.icons,
400
+ _meta: tool._meta,
439
401
  inputSchema: tool.schema
440
402
  ? await this.#options.adapter.toJsonSchema(
441
403
  tool.schema,
@@ -648,12 +610,11 @@ export class McpServer {
648
610
 
649
611
  if (this.#options.capabilities?.resources?.subscribe) {
650
612
  this.#server.addMethod('resources/subscribe', async ({ uri }) => {
651
- let subscriptions = this.#subscriptions.resource.get(uri);
652
- if (!subscriptions) {
653
- subscriptions = new Set();
654
- this.#subscriptions.resource.set(uri, subscriptions);
655
- }
656
- subscriptions.add(this.#session_id);
613
+ this.#event_target.dispatchEvent(
614
+ new CustomEvent('subscription', {
615
+ detail: { uri },
616
+ }),
617
+ );
657
618
  return {};
658
619
  });
659
620
  }
@@ -797,9 +758,7 @@ export class McpServer {
797
758
  const response = await this.#client?.request(
798
759
  'roots/list',
799
760
  undefined,
800
- {
801
- sessions: [this.#session_id],
802
- },
761
+ 'standalone',
803
762
  );
804
763
  this.roots = response?.roots || [];
805
764
  } catch {
@@ -830,26 +789,34 @@ export class McpServer {
830
789
  if (!this.#options.capabilities?.logging) return;
831
790
 
832
791
  this.#server.addMethod('logging/setLevel', ({ level }) => {
833
- this.#session_log_levels.set(this.#session_id, level);
792
+ this.#event_target.dispatchEvent(
793
+ new CustomEvent('loglevelchange', {
794
+ detail: { level },
795
+ }),
796
+ );
834
797
  return {};
835
798
  });
836
799
  }
837
800
 
838
801
  #notify_tools_list_changed() {
839
802
  if (this.#options.capabilities?.tools?.listChanged) {
840
- this.#notify('notifications/tools/list_changed', {});
803
+ this.#notify('notifications/tools/list_changed', {}, 'broadcast');
841
804
  }
842
805
  }
843
806
 
844
807
  #notify_prompts_list_changed() {
845
808
  if (this.#options.capabilities?.prompts?.listChanged) {
846
- this.#notify('notifications/prompts/list_changed', {});
809
+ this.#notify('notifications/prompts/list_changed', {}, 'broadcast');
847
810
  }
848
811
  }
849
812
 
850
813
  #notify_resources_list_changed() {
851
814
  if (this.#options.capabilities?.resources?.listChanged) {
852
- this.#notify('notifications/resources/list_changed', {});
815
+ this.#notify(
816
+ 'notifications/resources/list_changed',
817
+ {},
818
+ 'broadcast',
819
+ );
853
820
  }
854
821
  }
855
822
 
@@ -860,7 +827,7 @@ export class McpServer {
860
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.
861
828
  * @template {StandardSchema | undefined} [TSchema=undefined]
862
829
  * @template {StandardSchema | undefined} [TOutputSchema=undefined]
863
- * @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
864
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
865
832
  */
866
833
  tool(
@@ -873,6 +840,7 @@ export class McpServer {
873
840
  annotations,
874
841
  enabled,
875
842
  icons,
843
+ _meta,
876
844
  },
877
845
  execute,
878
846
  ) {
@@ -886,6 +854,7 @@ export class McpServer {
886
854
  execute,
887
855
  annotations,
888
856
  icons,
857
+ _meta,
889
858
  });
890
859
  }
891
860
  /**
@@ -1000,18 +969,6 @@ export class McpServer {
1000
969
 
1001
970
  // Check if it's a request or response
1002
971
  if (validated_message.success) {
1003
- // we want to set a default log level for each session
1004
- // so that if the user calls `log` it can send a notification
1005
- // to each client that didn't explicitly set a log level too
1006
- if (
1007
- !!this.#options.capabilities?.logging &&
1008
- !this.#session_log_levels.has(ctx?.sessionId)
1009
- ) {
1010
- this.#session_log_levels.set(
1011
- ctx?.sessionId,
1012
- this.#options.logging?.default ?? 'info',
1013
- );
1014
- }
1015
972
  const progress_token = /** @type {string | undefined} */ (
1016
973
  validated_message.output.params?._meta?.progressToken
1017
974
  );
@@ -1046,28 +1003,16 @@ export class McpServer {
1046
1003
  } else if (what === 'resources') {
1047
1004
  this.#notify_resources_list_changed();
1048
1005
  } else {
1049
- if (
1050
- this.#subscriptions[
1051
- /** @type {SubscriptionsKeys} */ (what)
1052
- ].has(id)
1053
- ) {
1054
- const resource = this.#resources.get(id);
1055
- if (!resource) return;
1056
- const sessions =
1057
- this.#subscriptions[
1058
- /** @type {SubscriptionsKeys} */ (what)
1059
- ].get(id);
1060
- this.#notify(
1061
- `notifications/resources/updated`,
1062
- {
1063
- uri: id,
1064
- title: resource.name,
1065
- },
1066
- {
1067
- sessions: sessions ? [...sessions] : undefined,
1068
- },
1069
- );
1070
- }
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
+ );
1071
1016
  }
1072
1017
  }
1073
1018
 
@@ -1102,9 +1047,7 @@ export class McpServer {
1102
1047
  requestedSchema:
1103
1048
  await this.#options.adapter.toJsonSchema(schema),
1104
1049
  },
1105
- {
1106
- sessions: [this.#session_id],
1107
- },
1050
+ 'standalone',
1108
1051
  );
1109
1052
  const elicit_result = v.parse(ElicitResultSchema, result);
1110
1053
  let validated_result = schema['~standard'].validate(
@@ -1142,9 +1085,7 @@ export class McpServer {
1142
1085
  const response = await this.#client?.request(
1143
1086
  'sampling/createMessage',
1144
1087
  validated_request,
1145
- {
1146
- sessions: [this.#session_id],
1147
- },
1088
+ 'standalone',
1148
1089
  );
1149
1090
 
1150
1091
  // Validate and return the response
@@ -1160,18 +1101,12 @@ export class McpServer {
1160
1101
  */
1161
1102
  progress(progress, total = 1, message = undefined) {
1162
1103
  if (this.#progress_token != null) {
1163
- this.#notify(
1164
- 'notifications/progress',
1165
- {
1166
- progress,
1167
- total,
1168
- message,
1169
- progressToken: this.#progress_token,
1170
- },
1171
- {
1172
- sessions: this.#session_id ? [this.#session_id] : undefined,
1173
- },
1174
- );
1104
+ this.#notify('notifications/progress', {
1105
+ progress,
1106
+ total,
1107
+ message,
1108
+ progressToken: this.#progress_token,
1109
+ });
1175
1110
  }
1176
1111
  }
1177
1112
 
@@ -1190,29 +1125,21 @@ export class McpServer {
1190
1125
  );
1191
1126
  }
1192
1127
 
1193
- const sessions = [];
1194
-
1195
- for (let [session_id, session_log_level] of this.#session_log_levels) {
1196
- // Check if the current log level should be sent based on severity
1197
- if (this.#should_log(level, session_log_level)) {
1198
- sessions.push(session_id);
1199
- }
1200
- }
1201
-
1202
- if (sessions.length === 0) return;
1128
+ const current_session_level =
1129
+ this.#ctx_storage.getStore()?.sessionInfo?.logLevel ??
1130
+ this.#options.logging?.default ??
1131
+ 'info';
1203
1132
 
1204
- // Send the log notification to the client
1205
- this.#notify(
1206
- 'notifications/message',
1207
- {
1133
+ if (
1134
+ current_session_level &&
1135
+ this.#should_log(level, current_session_level)
1136
+ ) {
1137
+ this.#notify('notifications/message', {
1208
1138
  level,
1209
1139
  data,
1210
1140
  logger,
1211
- },
1212
- {
1213
- sessions,
1214
- },
1215
- );
1141
+ });
1142
+ }
1216
1143
  }
1217
1144
 
1218
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.