tmcp 1.9.0 → 1.10.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmcp",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "The main tmcp library",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * @import { JSONRPCRequest, JSONRPCParams } from "json-rpc-2.0";
5
5
  * @import { ExtractURITemplateVariables } from "./internal/uri-template.js";
6
6
  * @import { CallToolResult, ReadResourceResult, GetPromptResult, ClientCapabilities as ClientCapabilitiesType, JSONRPCRequest as JSONRPCRequestType, JSONRPCResponse, CreateMessageRequestParams, CreateMessageResult, Resource, LoggingLevel, ToolAnnotations } from "./validation/index.js";
7
- * @import { Tool, Completion, Prompt, StoredResource, ServerOptions, ServerInfo, SubscriptionsKeys, McpEvents, Context as ContextType } from "./internal/internal.js";
7
+ * @import { Tool, Completion, Prompt, StoredResource, ServerOptions, ServerInfo, SubscriptionsKeys, McpEvents } from "./internal/internal.js";
8
8
  */
9
9
  import { JSONRPCClient, JSONRPCServer } from 'json-rpc-2.0';
10
10
  import { AsyncLocalStorage } from 'node:async_hooks';
@@ -92,7 +92,7 @@ export class McpServer {
92
92
  #client;
93
93
  #options;
94
94
  /**
95
- * @type {Map<string, Tool<any>>}
95
+ * @type {Map<string, Tool<any, any>>}
96
96
  */
97
97
  #tools = new Map();
98
98
  /**
@@ -328,12 +328,25 @@ export class McpServer {
328
328
  name,
329
329
  title: tool.title || tool.description,
330
330
  description: tool.description,
331
- annotations: tool.annotations,
331
+
332
332
  inputSchema: tool.schema
333
333
  ? await this.#options.adapter.toJsonSchema(
334
334
  tool.schema,
335
335
  )
336
336
  : { type: 'object', properties: {} },
337
+ ...(tool.outputSchema
338
+ ? {
339
+ outputSchema:
340
+ await this.#options.adapter.toJsonSchema(
341
+ tool.outputSchema,
342
+ ),
343
+ }
344
+ : {}),
345
+ ...(tool.annotations
346
+ ? {
347
+ annotations: tool.annotations,
348
+ }
349
+ : {}),
337
350
  };
338
351
  }),
339
352
  );
@@ -348,22 +361,57 @@ export class McpServer {
348
361
  if (!tool) {
349
362
  throw new McpError(-32601, `Tool ${name} not found`);
350
363
  }
351
- if (!tool.schema) {
352
- return v.parse(CallToolResultSchema, await tool.execute());
353
- }
354
- let validated_args = tool.schema['~standard'].validate(args);
355
- if (validated_args instanceof Promise)
356
- validated_args = await validated_args;
357
- if (validated_args.issues) {
358
- throw new McpError(
359
- -32602,
360
- `Invalid arguments for tool ${name}: ${JSON.stringify(validated_args.issues)}`,
361
- );
364
+
365
+ // Validate input arguments if schema is provided
366
+ let validated_args = args;
367
+ if (tool.schema) {
368
+ let validation_result =
369
+ tool.schema['~standard'].validate(args);
370
+ if (validation_result instanceof Promise)
371
+ validation_result = await validation_result;
372
+ if (validation_result.issues) {
373
+ throw new McpError(
374
+ -32602,
375
+ `Invalid arguments for tool ${name}: ${JSON.stringify(validation_result.issues)}`,
376
+ );
377
+ }
378
+ validated_args = validation_result.value;
362
379
  }
363
- return v.parse(
380
+
381
+ // Execute the tool
382
+ const tool_result = tool.schema
383
+ ? await tool.execute(validated_args)
384
+ : await tool.execute();
385
+
386
+ console.log({ tool_result });
387
+
388
+ // Parse the basic result structure
389
+ const parsed_result = v.parse(
364
390
  CallToolResultSchema,
365
- await tool.execute(validated_args.value),
391
+ tool_result,
366
392
  );
393
+
394
+ // If tool has outputSchema, validate and populate structuredContent
395
+ if (
396
+ tool.outputSchema &&
397
+ parsed_result.structuredContent !== undefined
398
+ ) {
399
+ let output_validation = tool.outputSchema[
400
+ '~standard'
401
+ ].validate(parsed_result.structuredContent);
402
+ if (output_validation instanceof Promise)
403
+ output_validation = await output_validation;
404
+ if (output_validation.issues) {
405
+ throw new McpError(
406
+ -32603,
407
+ `Tool ${name} returned invalid structured content: ${JSON.stringify(output_validation.issues)}`,
408
+ );
409
+ }
410
+ // Update with validated structured content
411
+ parsed_result.structuredContent = output_validation.value;
412
+ }
413
+
414
+ return parsed_result;
367
415
  },
368
416
  );
369
417
  }
@@ -600,7 +648,7 @@ export class McpServer {
600
648
  #init_completion() {
601
649
  this.#server.addMethod(
602
650
  'completion/complete',
603
- ({ argument, ref, context }) => {
651
+ async ({ argument, ref, context }) => {
604
652
  const completions = this.#completions[ref.type];
605
653
  if (!completions) return null;
606
654
  const complete = completions.get(ref.uri ?? ref.name);
@@ -609,7 +657,7 @@ export class McpServer {
609
657
  if (!actual_complete) return null;
610
658
  return v.parse(
611
659
  CompleteResultSchema,
612
- actual_complete(argument.value, context),
660
+ await actual_complete(argument.value, context),
613
661
  );
614
662
  },
615
663
  );
@@ -627,10 +675,14 @@ export class McpServer {
627
675
  }
628
676
  /**
629
677
  * @template {StandardSchema | undefined} [TSchema=undefined]
630
- * @param {{ name: string; description: string; title?: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; annotations?: ToolAnnotations }} options
631
- * @param {TSchema extends undefined ? (()=>Promise<CallToolResult> | CallToolResult) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult> | CallToolResult)} execute
678
+ * @template {StandardSchema | undefined} [TOutputSchema=undefined]
679
+ * @param {{ name: string; description: string; title?: string; 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 }} options
680
+ * @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
632
681
  */
633
- tool({ name, description, title, schema, annotations }, execute) {
682
+ tool(
683
+ { name, description, title, schema, outputSchema, annotations },
684
+ execute,
685
+ ) {
634
686
  if (this.#options.capabilities?.tools?.listChanged) {
635
687
  this.#notify('notifications/tools/list_changed', {});
636
688
  }
@@ -638,6 +690,7 @@ export class McpServer {
638
690
  description,
639
691
  title,
640
692
  schema,
693
+ outputSchema,
641
694
  execute,
642
695
  annotations,
643
696
  });
@@ -13,9 +13,10 @@ import {
13
13
  ToolAnnotations
14
14
  } from '../validation/index.js';
15
15
 
16
- export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
16
+ export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>, TOutputSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
17
17
  description: string;
18
18
  schema: TSchema;
19
+ outputSchema?: TOutputSchema;
19
20
  title?: string;
20
21
  annotations?: ToolAnnotations;
21
22
  execute: (
@@ -26,7 +27,7 @@ export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
26
27
  export type Completion = (
27
28
  query: string,
28
29
  context: { arguments: Record<string, string> },
29
- ) => CompleteResult;
30
+ ) => CompleteResult | Promise<CompleteResult>;
30
31
 
31
32
  export type Prompt<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
32
33
  description: string;
@@ -23,13 +23,14 @@ declare module 'tmcp' {
23
23
 
24
24
  on<TEvent extends keyof McpEvents>(event: TEvent, callback: McpEvents[TEvent], options?: AddEventListenerOptions): () => void;
25
25
 
26
- tool<TSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, annotations }: {
26
+ tool<TSchema extends StandardSchema | undefined = undefined, TOutputSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, outputSchema, annotations }: {
27
27
  name: string;
28
28
  description: string;
29
29
  title?: string;
30
30
  schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never;
31
+ outputSchema?: StandardSchemaV1.InferOutput<TOutputSchema extends undefined ? never : TOutputSchema> extends Record<string, unknown> ? TOutputSchema : never;
31
32
  annotations?: ToolAnnotations;
32
- }, execute: TSchema extends undefined ? (() => Promise<CallToolResult> | CallToolResult) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult> | CallToolResult)): void;
33
+ }, execute: 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>>)): void;
33
34
 
34
35
  prompt<TSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, complete }: {
35
36
  name: string;
@@ -116,7 +117,7 @@ declare module 'tmcp' {
116
117
  type Completion = (
117
118
  query: string,
118
119
  context: { arguments: Record<string, string> },
119
- ) => CompleteResult;
120
+ ) => CompleteResult | Promise<CompleteResult>;
120
121
 
121
122
  type ServerOptions<TSchema extends StandardSchemaV1> = {
122
123
  capabilities?: ServerCapabilities;
@@ -895,7 +896,11 @@ declare module 'tmcp' {
895
896
  type ClientCapabilities_1 = v.InferInput<typeof ClientCapabilitiesSchema>;
896
897
  type ServerCapabilities = v.InferInput<typeof ServerCapabilitiesSchema>;
897
898
  type InitializeRequestParams = v.InferInput<typeof InitializeRequestParamsSchema>;
898
- type CallToolResult = v.InferInput<typeof CallToolResultSchema>;
899
+ type CallToolResult<TStructuredContent extends Record<string, unknown> | undefined> = Omit<v.InferInput<typeof CallToolResultSchema>, "structuredContent"> & (undefined extends TStructuredContent ? {
900
+ structuredContent?: undefined;
901
+ } : {
902
+ structuredContent: TStructuredContent;
903
+ });
899
904
  type ReadResourceResult = v.InferInput<typeof ReadResourceResultSchema>;
900
905
  type GetPromptResult = v.InferInput<typeof GetPromptResultSchema>;
901
906
  type CompleteResult = v.InferInput<typeof CompleteResultSchema>;
@@ -24,7 +24,6 @@
24
24
  "CompleteResultSchema",
25
25
  "ServerCapabilities",
26
26
  "InitializeRequestParams",
27
- "CallToolResult",
28
27
  "ReadResourceResult",
29
28
  "GetPromptResult",
30
29
  "CompleteResult",
@@ -56,6 +55,6 @@
56
55
  null,
57
56
  null
58
57
  ],
59
- "mappings": ";;;;;cAsFaA,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aCi3CsCC,kBAAkBA;MC96ClEC,UAAUA;;;;;MAsCVC,aAAaA;;;;;;;;;;;;;MAabC,UAAUA;;;;;;MAMVC,iBAAiBA;;MAEjBC,SAASA;;;;;;;;;;;;ODgBRC,qBAAqBA;;;;;;;;;;;;;;OAuGrBC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;OA6BxBC,6BAA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuB7BC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmMxBC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4GdC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8PxBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BrBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2GrBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEpBC,kBAAkBA;OAuGlBC,gCAAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8ChCC,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+LzBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;MA8H2BC,kBAAkBA;MASbC,uBAAuBA;MAGhCC,cAAcA;MAGVC,kBAAkBA;MAGrBC,eAAeA;MAGhBC,cAAcA;MAGFC,0BAA0BA;MAGjCC,mBAAmBA;MAY9BC,QAAQA;MAMDC,eAAeA;MAGlBC,YAAYA;MAGTC,eAAeA;;ME5/CnEC,IAAIA;;;;;;;MAOJC,cAAcA;;;;;;;MAOdC,cAAcA;;;;;MAKdC,qBAAqBA;;;;;;;;;;;;;;;;;MAiBrBC,4BAA4BA;;;;;;MAMrBC,2BAA2BA;;;;;;;OCjC1BC,iBAAiBA;;;;;;;;;;;;;;;;cAAjBA,iBAAiBA",
58
+ "mappings": ";;;;;cAsFaA,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aCi3CsCC,kBAAkBA;MC76ClEC,UAAUA;;;;;MAsCVC,aAAaA;;;;;;;;;;;;;MAabC,UAAUA;;;;;;MAMVC,iBAAiBA;;MAEjBC,SAASA;;;;;;;;;;;;ODeRC,qBAAqBA;;;;;;;;;;;;;;OAuGrBC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;OA6BxBC,6BAA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuB7BC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmMxBC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4GdC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8PxBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BrBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2GrBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEpBC,kBAAkBA;OAuGlBC,gCAAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8ChCC,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+LzBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;MA8H2BC,kBAAkBA;MASbC,uBAAuBA;;;;;;MAO5BC,kBAAkBA;MAGrBC,eAAeA;MAGhBC,cAAcA;MAGFC,0BAA0BA;MAGjCC,mBAAmBA;MAY9BC,QAAQA;MAMDC,eAAeA;MAGlBC,YAAYA;MAGTC,eAAeA;;ME7/CnEC,IAAIA;;;;;;;MAOJC,cAAcA;;;;;;;MAOdC,cAAcA;;;;;MAKdC,qBAAqBA;;;;;;;;;;;;;;;;;MAiBrBC,4BAA4BA;;;;;;MAMrBC,2BAA2BA;;;;;;;OCjC1BC,iBAAiBA;;;;;;;;;;;;;;;;cAAjBA,iBAAiBA",
60
59
  "ignoreList": []
61
60
  }
@@ -1492,7 +1492,8 @@ export const ServerResultSchema = v.union([
1492
1492
  * @typedef {v.InferInput<typeof InitializeRequestParamsSchema>} InitializeRequestParams
1493
1493
  */
1494
1494
  /**
1495
- * @typedef {v.InferInput<typeof CallToolResultSchema>} CallToolResult
1495
+ * @template {Record<string, unknown> | undefined} TStructuredContent
1496
+ * @typedef {Omit<v.InferInput<typeof CallToolResultSchema>, "structuredContent"> & (undefined extends TStructuredContent ? { structuredContent?: undefined } : { structuredContent: TStructuredContent })} CallToolResult
1496
1497
  */
1497
1498
  /**
1498
1499
  * @typedef {v.InferInput<typeof ReadResourceResultSchema>} ReadResourceResult