@@ -295,11 +295,51 @@ type TimeoutInfo = {
295295 onTimeout : ( ) => void ;
296296} ;
297297
298+ /**
299+ * Declares the request and notification vocabulary a `Protocol` subclass speaks.
300+ *
301+ * Supplying a concrete `ProtocolSpec` as `Protocol`'s second type argument gives method-name
302+ * autocomplete and params/result correlation on the typed overloads of `setRequestHandler`
303+ * and `setNotificationHandler`. The default leaves them string-keyed and untyped.
304+ */
305+ export type ProtocolSpec = {
306+ requests ?: Record < string , { params ?: unknown ; result : unknown } > ;
307+ notifications ?: Record < string , { params ?: unknown } > ;
308+ } ;
309+
310+ /**
311+ * The {@linkcode ProtocolSpec} that describes the standard MCP method vocabulary, derived from
312+ * {@linkcode RequestTypeMap}, {@linkcode ResultTypeMap} and {@linkcode NotificationTypeMap}.
313+ */
314+ export type McpSpec = {
315+ requests : { [ M in RequestMethod ] : { params : RequestTypeMap [ M ] [ 'params' ] ; result : ResultTypeMap [ M ] } } ;
316+ notifications : { [ M in NotificationMethod ] : { params : NotificationTypeMap [ M ] [ 'params' ] } } ;
317+ } ;
318+
319+ type _Requests < SpecT extends ProtocolSpec > = NonNullable < SpecT [ 'requests' ] > ;
320+ type _Notifications < SpecT extends ProtocolSpec > = NonNullable < SpecT [ 'notifications' ] > ;
321+
322+ /**
323+ * Method-name keys from a {@linkcode ProtocolSpec}'s `requests` map, or `never` for the
324+ * unconstrained default `ProtocolSpec`. Making the keys `never` for the default disables the
325+ * spec-typed overloads on `setRequestHandler` until the caller supplies a concrete `SpecT`.
326+ */
327+ export type SpecRequests < SpecT extends ProtocolSpec > = string extends keyof _Requests < SpecT > ? never : keyof _Requests < SpecT > & string ;
328+
329+ /** See {@linkcode SpecRequests}. */
330+ export type SpecNotifications < SpecT extends ProtocolSpec > = string extends keyof _Notifications < SpecT >
331+ ? never
332+ : keyof _Notifications < SpecT > & string ;
333+
298334/**
299335 * Implements MCP protocol framing on top of a pluggable transport, including
300336 * features like request/response linking, notifications, and progress.
337+ *
338+ * `Protocol` is abstract; `Client` and `Server` are the concrete role-specific implementations.
339+ * Subclasses (such as MCP-dialect protocols like MCP Apps) can supply a {@linkcode ProtocolSpec}
340+ * as the second type argument to get method-name autocomplete on their own vocabulary.
301341 */
302- export abstract class Protocol < ContextT extends BaseContext > {
342+ export abstract class Protocol < ContextT extends BaseContext = BaseContext , SpecT extends ProtocolSpec = McpSpec > {
303343 private _transport ?: Transport ;
304344 private _requestMessageId = 0 ;
305345 private _requestHandlers : Map < string , ( request : JSONRPCRequest , ctx : ContextT ) => Promise < Result > > = new Map ( ) ;
@@ -1029,10 +1069,19 @@ export abstract class Protocol<ContextT extends BaseContext> {
10291069 * Any method string; the supplied schema validates incoming `params`. Absent or undefined
10301070 * `params` are normalized to `{}` (after stripping `_meta`) before validation, so for
10311071 * no-params methods use `z.object({})`. `paramsSchema` may be any Standard Schema (Zod,
1032- * Valibot, ArkType, etc.).
1072+ * Valibot, ArkType, etc.). When `method` is listed in this instance's
1073+ * {@linkcode ProtocolSpec}, params and result types are inferred from `SpecT`.
10331074 * - **Zod schema** — `setRequestHandler(RequestZodSchema, (request, ctx) => …)`. The method
10341075 * name is read from the schema's `method` literal; the handler receives the parsed request.
10351076 */
1077+ setRequestHandler < K extends SpecRequests < SpecT > , P extends StandardSchemaV1 < _Requests < SpecT > [ K ] [ 'params' ] > > (
1078+ method : K ,
1079+ paramsSchema : P ,
1080+ handler : (
1081+ params : StandardSchemaV1 . InferOutput < P > ,
1082+ ctx : ContextT
1083+ ) => _Requests < SpecT > [ K ] [ 'result' ] | Promise < _Requests < SpecT > [ K ] [ 'result' ] >
1084+ ) : void ;
10361085 setRequestHandler < M extends RequestMethod > (
10371086 method : M ,
10381087 handler : ( request : RequestTypeMap [ M ] , ctx : ContextT ) => Result | Promise < Result >
@@ -1059,7 +1108,10 @@ export abstract class Protocol<ContextT extends BaseContext> {
10591108 ) ;
10601109 }
10611110 if ( maybeHandler === undefined ) {
1062- return this . _setRequestHandlerByMethod ( method , schemaOrHandler as ( request : Request , ctx : ContextT ) => Result | Promise < Result > ) ;
1111+ return this . _setRequestHandlerByMethod (
1112+ method ,
1113+ schemaOrHandler as ( request : Request , ctx : ContextT ) => Result | Promise < Result >
1114+ ) ;
10631115 }
10641116
10651117 this . assertRequestHandlerCapability ( method ) ;
@@ -1124,8 +1176,15 @@ export abstract class Protocol<ContextT extends BaseContext> {
11241176 *
11251177 * Mirrors {@linkcode setRequestHandler}: a two-arg spec-method form (handler receives the full
11261178 * notification object), a three-arg form with a `paramsSchema` (handler receives validated
1127- * `params`), and a Zod-schema form (method read from the schema's `method` literal).
1179+ * `params`), and a Zod-schema form (method read from the schema's `method` literal). When the
1180+ * three-arg form's `method` is listed in this instance's {@linkcode ProtocolSpec}, the params
1181+ * type is inferred from `SpecT`.
11281182 */
1183+ setNotificationHandler < K extends SpecNotifications < SpecT > , P extends StandardSchemaV1 < _Notifications < SpecT > [ K ] [ 'params' ] > > (
1184+ method : K ,
1185+ paramsSchema : P ,
1186+ handler : ( params : StandardSchemaV1 . InferOutput < P > ) => void | Promise < void >
1187+ ) : void ;
11291188 setNotificationHandler < M extends NotificationMethod > (
11301189 method : M ,
11311190 handler : ( notification : NotificationTypeMap [ M ] ) => void | Promise < void >
0 commit comments