@@ -5,12 +5,10 @@ import {
55 Result ,
66 type BaseContext ,
77 type LegacyContextFields ,
8+ type ZodLikeRequestSchema ,
89} from "@modelcontextprotocol/sdk/types.js" ;
910
1011type AppContext = BaseContext & LegacyContextFields ;
11- import { ZodLiteral , ZodObject } from "zod/v4" ;
12-
13- type MethodSchema = ZodObject < { method : ZodLiteral < string > } > ;
1412
1513/**
1614 * Per-event state: a singular `on*` handler (replace semantics) plus a
@@ -78,7 +76,7 @@ export abstract class ProtocolWithEvents<
7876 * schema on first use.
7977 */
8078 protected abstract readonly eventSchemas : {
81- [ K in keyof EventMap ] : MethodSchema ;
79+ [ K in keyof EventMap ] : ZodLikeRequestSchema ;
8280 } ;
8381
8482 /**
@@ -202,12 +200,15 @@ export abstract class ProtocolWithEvents<
202200
203201 // ── Handler registration with double-set protection ─────────────────
204202
205- // The two overrides below are arrow-function class fields rather than
206- // prototype methods so that Protocol's constructor — which registers its
207- // own ping/cancelled/progress handlers via `this.setRequestHandler`
208- // before our fields initialize — hits the base implementation and skips
209- // tracking. Converting these to proper methods would crash with
210- // `_registeredMethods` undefined during super().
203+ // These overrides are prototype methods, so Protocol's constructor (which
204+ // registers built-in ping/cancelled/progress handlers via
205+ // `this.setRequestHandler` during super()) dispatches here before our own
206+ // fields have initialized. The `_registeredMethods === undefined` guard
207+ // skips tracking during that window.
208+ //
209+ // The base method has four overloads in v2; we expose only the Zod-schema
210+ // form here since that is all this package uses. Subclasses retain the
211+ // typed (request, ctx) handler signature.
211212
212213 /**
213214 * Registers a request handler. Throws if a handler for the same method
@@ -216,11 +217,24 @@ export abstract class ProtocolWithEvents<
216217 *
217218 * @throws {Error } if a handler for this method is already registered.
218219 */
219- // eslint-disable-next-line @typescript-eslint/no-explicit-any
220- override setRequestHandler = ( ( ...args : any ) => {
221- this . _assertMethodNotRegistered ( args [ 0 ] , "setRequestHandler" ) ;
222- super . setRequestHandler ( ...( args as [ MethodSchema , ( ) => Result ] ) ) ;
223- } ) as Protocol < AppContext > [ "setRequestHandler" ] ;
220+ override setRequestHandler < T extends ZodLikeRequestSchema > (
221+ requestSchema : T ,
222+ handler : (
223+ request : ReturnType < T [ "parse" ] > ,
224+ ctx : AppContext ,
225+ ) => Result | Promise < Result > ,
226+ ) : void ;
227+ override setRequestHandler (
228+ schema : ZodLikeRequestSchema ,
229+ handler : ( request : unknown , ctx : AppContext ) => Result | Promise < Result > ,
230+ ) : void {
231+ if ( this . _registeredMethods === undefined ) {
232+ super . setRequestHandler ( schema , handler ) ;
233+ return ;
234+ }
235+ this . _assertMethodNotRegistered ( schema , "setRequestHandler" ) ;
236+ super . setRequestHandler ( schema , handler ) ;
237+ }
224238
225239 /**
226240 * Registers a notification handler. Throws if a handler for the same
@@ -229,11 +243,21 @@ export abstract class ProtocolWithEvents<
229243 *
230244 * @throws {Error } if a handler for this method is already registered.
231245 */
232- // eslint-disable-next-line @typescript-eslint/no-explicit-any
233- override setNotificationHandler = ( ( ...args : any ) => {
234- this . _assertMethodNotRegistered ( args [ 0 ] , "setNotificationHandler" ) ;
235- super . setNotificationHandler ( ...( args as [ MethodSchema , ( ) => void ] ) ) ;
236- } ) as Protocol < AppContext > [ "setNotificationHandler" ] ;
246+ override setNotificationHandler < T extends ZodLikeRequestSchema > (
247+ notificationSchema : T ,
248+ handler : ( notification : ReturnType < T [ "parse" ] > ) => void | Promise < void > ,
249+ ) : void ;
250+ override setNotificationHandler (
251+ schema : ZodLikeRequestSchema ,
252+ handler : ( notification : unknown ) => void | Promise < void > ,
253+ ) : void {
254+ if ( this . _registeredMethods === undefined ) {
255+ super . setNotificationHandler ( schema , handler ) ;
256+ return ;
257+ }
258+ this . _assertMethodNotRegistered ( schema , "setNotificationHandler" ) ;
259+ super . setNotificationHandler ( schema , handler ) ;
260+ }
237261
238262 /**
239263 * Warn if a request handler `on*` setter is replacing a previously-set
@@ -256,15 +280,30 @@ export abstract class ProtocolWithEvents<
256280 * Replace a request handler, bypassing double-set protection. Used by
257281 * `on*` request-handler setters that need replace semantics.
258282 */
259- // eslint-disable-next-line @typescript-eslint/no-explicit-any
260- protected replaceRequestHandler = ( ( ...args : any ) => {
261- const method = ( args [ 0 ] as MethodSchema ) . shape . method . value ;
262- this . _registeredMethods . add ( method ) ;
263- super . setRequestHandler ( ...( args as [ MethodSchema , ( ) => Result ] ) ) ;
264- } ) as Protocol < AppContext > [ "setRequestHandler" ] ;
283+ protected replaceRequestHandler < T extends ZodLikeRequestSchema > (
284+ requestSchema : T ,
285+ handler : (
286+ request : ReturnType < T [ "parse" ] > ,
287+ ctx : AppContext ,
288+ ) => Result | Promise < Result > ,
289+ ) : void ;
290+ protected replaceRequestHandler (
291+ schema : ZodLikeRequestSchema ,
292+ handler : ( request : unknown , ctx : AppContext ) => Result | Promise < Result > ,
293+ ) : void {
294+ this . _registeredMethods . add ( this . _methodOf ( schema ) ) ;
295+ super . setRequestHandler ( schema , handler ) ;
296+ }
265297
266- private _assertMethodNotRegistered ( schema : unknown , via : string ) : void {
267- const method = ( schema as MethodSchema ) . shape . method . value ;
298+ private _methodOf ( arg : ZodLikeRequestSchema | string ) : string {
299+ return typeof arg === "string" ? arg : arg . shape . method . value ;
300+ }
301+
302+ private _assertMethodNotRegistered (
303+ schema : ZodLikeRequestSchema | string ,
304+ via : string ,
305+ ) : void {
306+ const method = this . _methodOf ( schema ) ;
268307 if ( this . _registeredMethods . has ( method ) ) {
269308 throw new Error (
270309 `Handler for "${ method } " already registered (via ${ via } ). ` +
0 commit comments