@@ -9,6 +9,7 @@ import type {
99 CreateTaskServerContext ,
1010 GetPromptResult ,
1111 Implementation ,
12+ JsonSchemaType ,
1213 ListPromptsResult ,
1314 ListResourcesResult ,
1415 ListToolsResult ,
@@ -30,6 +31,8 @@ import type {
3031import {
3132 assertCompleteRequestPrompt ,
3233 assertCompleteRequestResourceTemplate ,
34+ isStandardSchema ,
35+ isZodRawShape ,
3336 normalizeRawShapeSchema ,
3437 promptArgumentsFromStandardSchema ,
3538 ProtocolError ,
@@ -43,6 +46,7 @@ import type * as z from 'zod/v4';
4346
4447import type { ToolTaskHandler } from '../experimental/tasks/interfaces.js' ;
4548import { ExperimentalMcpServerTasks } from '../experimental/tasks/mcpServer.js' ;
49+ import { fromJsonSchema } from '../fromJsonSchema.js' ;
4650import { getCompleter , isCompletable } from './completable.js' ;
4751import type { ServerOptions } from './server.js' ;
4852import { Server } from './server.js' ;
@@ -920,6 +924,105 @@ export class McpServer {
920924 ) ;
921925 }
922926
927+ /**
928+ * Registers a tool using the legacy variadic overloads (v1-style).
929+ *
930+ * **Note:** Use {@linkcode registerTool} for new code.
931+ *
932+ * @deprecated Prefer {@linkcode registerTool} with an explicit config object.
933+ */
934+ tool (
935+ name : string ,
936+ paramsSchemaOrAnnotations : StandardSchemaWithJSON | ToolAnnotations | Record < string , unknown > ,
937+ cb : DeprecatedVariadicToolCallback
938+ ) : RegisteredTool ;
939+
940+ /**
941+ * @deprecated Prefer {@linkcode registerTool}.
942+ */
943+ tool (
944+ name : string ,
945+ description : string ,
946+ paramsSchemaOrAnnotations : StandardSchemaWithJSON | ToolAnnotations | Record < string , unknown > ,
947+ cb : DeprecatedVariadicToolCallback
948+ ) : RegisteredTool ;
949+
950+ /**
951+ * Legacy `tool()` implementation. Parses arguments for the overloads declared above.
952+ */
953+ tool ( name : string , ...rest : unknown [ ] ) : RegisteredTool {
954+ if ( this . _registeredTools [ name ] ) {
955+ throw new Error ( `Tool ${ name } is already registered` ) ;
956+ }
957+
958+ let description : string | undefined ;
959+ let inputSchema : StandardSchemaWithJSON | undefined ;
960+ let annotations : ToolAnnotations | undefined ;
961+
962+ if ( typeof rest [ 0 ] === 'string' ) {
963+ description = rest . shift ( ) as string ;
964+ }
965+
966+ if ( rest . length > 1 ) {
967+ const firstArg = rest [ 0 ] ;
968+
969+ if ( typeof firstArg === 'object' && firstArg !== null && ! Array . isArray ( firstArg ) ) {
970+ const record = firstArg as Record < string , unknown > ;
971+
972+ if ( isZodRawShape ( record ) || isStandardSchema ( record ) ) {
973+ inputSchema = normalizeRawShapeSchema ( record as StandardSchemaWithJSON | ZodRawShape ) ;
974+ rest . shift ( ) ;
975+
976+ if (
977+ rest . length > 1 &&
978+ typeof rest [ 0 ] === 'object' &&
979+ rest [ 0 ] !== null &&
980+ ! Array . isArray ( rest [ 0 ] ) &&
981+ isToolAnnotationsOnlyObject ( rest [ 0 ] as Record < string , unknown > )
982+ ) {
983+ annotations = rest . shift ( ) as ToolAnnotations ;
984+ }
985+ } else if ( isLikelyPlainJsonSchemaObject ( record ) ) {
986+ inputSchema = fromJsonSchema ( record as JsonSchemaType ) ;
987+ rest . shift ( ) ;
988+
989+ if (
990+ rest . length > 1 &&
991+ typeof rest [ 0 ] === 'object' &&
992+ rest [ 0 ] !== null &&
993+ ! Array . isArray ( rest [ 0 ] ) &&
994+ isToolAnnotationsOnlyObject ( rest [ 0 ] as Record < string , unknown > )
995+ ) {
996+ annotations = rest . shift ( ) as ToolAnnotations ;
997+ }
998+ } else if ( isToolAnnotationsOnlyObject ( record ) ) {
999+ annotations = rest . shift ( ) as ToolAnnotations ;
1000+ } else {
1001+ throw new TypeError (
1002+ `Tool "${ name } ": unrecognized third argument. Expected a Standard Schema, Zod raw shape ({ field: z.string() }), plain JSON Schema (e.g. { type: "object", properties: {...} }), or ToolAnnotations (${ [ ...TOOL_ANNOTATION_KEYS ] . join ( ', ' ) } ).`
1003+ ) ;
1004+ }
1005+ }
1006+ }
1007+
1008+ const callback = rest [ 0 ] ;
1009+ if ( typeof callback !== 'function' ) {
1010+ throw new TypeError ( `Tool "${ name } ": last argument must be the handler callback` ) ;
1011+ }
1012+
1013+ return this . _createRegisteredTool (
1014+ name ,
1015+ undefined ,
1016+ description ,
1017+ inputSchema ,
1018+ undefined ,
1019+ annotations ,
1020+ { taskSupport : 'forbidden' } ,
1021+ undefined ,
1022+ callback as ToolCallback < StandardSchemaWithJSON | undefined >
1023+ ) ;
1024+ }
1025+
9231026 /**
9241027 * Registers a prompt with a config object and callback.
9251028 *
@@ -1147,6 +1250,14 @@ export type ToolCallback<Args extends StandardSchemaWithJSON | undefined = undef
11471250 Args
11481251> ;
11491252
1253+ /**
1254+ * Callback type for deprecated {@linkcode McpServer.tool} positional overloads.
1255+ * Intentionally loose: plain JSON Schema (wrapped via {@linkcode fromJsonSchema}) does not participate in overload inference.
1256+ */
1257+ export type DeprecatedVariadicToolCallback =
1258+ | ( ( args : unknown , ctx : ServerContext ) => CallToolResult | Promise < CallToolResult > )
1259+ | ( ( ctx : ServerContext ) => CallToolResult | Promise < CallToolResult > ) ;
1260+
11501261/**
11511262 * Supertype that can handle both regular tools (simple callback) and task-based tools (task handler object).
11521263 */
@@ -1185,6 +1296,69 @@ export type RegisteredTool = {
11851296 remove ( ) : void ;
11861297} ;
11871298
1299+ const TOOL_ANNOTATION_KEYS = new Set ( [ 'title' , 'readOnlyHint' , 'destructiveHint' , 'idempotentHint' , 'openWorldHint' ] ) ;
1300+
1301+ /** Structural hints that a plain object is JSON Schema (wire-shape) rather than {@linkcode ToolAnnotations}. */
1302+ const JSON_SCHEMA_SHAPE_KEYS = [
1303+ 'type' ,
1304+ 'properties' ,
1305+ 'items' ,
1306+ 'required' ,
1307+ 'additionalProperties' ,
1308+ '$schema' ,
1309+ '$ref' ,
1310+ '$defs' ,
1311+ 'definitions' ,
1312+ 'oneOf' ,
1313+ 'anyOf' ,
1314+ 'allOf' ,
1315+ 'not' ,
1316+ 'enum' ,
1317+ 'const' ,
1318+ 'minimum' ,
1319+ 'maximum' ,
1320+ 'minLength' ,
1321+ 'maxLength' ,
1322+ 'pattern' ,
1323+ 'format' ,
1324+ 'minItems' ,
1325+ 'maxItems' ,
1326+ 'prefixItems' ,
1327+ 'description'
1328+ ] as const ;
1329+
1330+ function isToolAnnotationsOnlyObject ( obj : Record < string , unknown > ) : boolean {
1331+ const keys = Object . keys ( obj ) ;
1332+ if ( keys . length === 0 ) {
1333+ return false ;
1334+ }
1335+ for ( const key of keys ) {
1336+ if ( ! TOOL_ANNOTATION_KEYS . has ( key ) ) {
1337+ return false ;
1338+ }
1339+ }
1340+ for ( const [ k , v ] of Object . entries ( obj ) ) {
1341+ if ( k === 'title' ) {
1342+ if ( typeof v !== 'string' ) {
1343+ return false ;
1344+ }
1345+ } else if ( typeof v !== 'boolean' ) {
1346+ return false ;
1347+ }
1348+ }
1349+ return true ;
1350+ }
1351+
1352+ function isLikelyPlainJsonSchemaObject ( obj : Record < string , unknown > ) : boolean {
1353+ if ( Object . keys ( obj ) . length === 0 ) {
1354+ return false ;
1355+ }
1356+ if ( isToolAnnotationsOnlyObject ( obj ) ) {
1357+ return false ;
1358+ }
1359+ return JSON_SCHEMA_SHAPE_KEYS . some ( k => k in obj ) ;
1360+ }
1361+
11881362/**
11891363 * Creates an executor that invokes the handler with the appropriate arguments.
11901364 * When `inputSchema` is defined, the handler is called with `(args, ctx)`.
0 commit comments