Summary
In v2, Protocol.setRequestHandler / setNotificationHandler require a method-string literal as the first argument and no longer accept the request/notification Zod schema object (the v1 API). Two consequences motivated this request while migrating a client:
-
v1-peer libraries break at runtime with a confusing error. Any library still on the v1 peer that calls client.setNotificationHandler(SomeNotificationSchema, handler) now throws:
'[object Object]' is not a spec notification method; pass schemas as the second argument to setNotificationHandler()
The schema stringifies to [object Object], so the message is hard to act on, and it fails at connect time rather than at build time.
-
Callers must hardcode magic string literals. setRequestHandler('tools/list', …) / setNotificationHandler('notifications/tools/list_changed', …) scatter bare method strings through app code instead of referencing a typed value.
Context
Found migrating the MCP Inspector to @modelcontextprotocol/client@2.0.0-beta.4. The Inspector renders MCP Apps via @modelcontextprotocol/ext-apps, which still peers on the v1 SDK and subscribes to tools/resources/prompts *_changed notifications with the schema-first API. Under v2 that throws the error above during the AppBridge connect handshake, so apps fail to load. We worked around it with a client-side proxy that reads the method literal off the schema's shape.method.value and forwards the method string — but that's exactly the translation the SDK is well-positioned to provide.
The *RequestSchema / *NotificationSchema objects still exist and still carry the method literal, so the method is derivable from the schema.
Proposals (either would help)
A. Re-accept the schema object as an overload, deriving the method from schema.shape.method:
setNotificationHandler(ToolListChangedNotificationSchema, handler) // v1-style, typed, no magic string
setNotificationHandler('notifications/tools/list_changed', handler) // still supported
This also restores backward-compat for v1-peer libraries, so nothing breaks at runtime.
B. Export typed method tokens/constants (e.g. a RequestMethods / NotificationMethods map) so callers reference a named value instead of a bare literal, keeping the method-string design but removing hardcoded strings.
At minimum, if the schema-first form stays unsupported, the thrown error could name the received schema's method (from shape.method.value) and suggest the string to pass — it would have turned a head-scratch into a one-line fix.
Versions
@modelcontextprotocol/client / core: 2.0.0-beta.4
Summary
In v2,
Protocol.setRequestHandler/setNotificationHandlerrequire a method-string literal as the first argument and no longer accept the request/notification Zod schema object (the v1 API). Two consequences motivated this request while migrating a client:v1-peer libraries break at runtime with a confusing error. Any library still on the v1 peer that calls
client.setNotificationHandler(SomeNotificationSchema, handler)now throws:The schema stringifies to
[object Object], so the message is hard to act on, and it fails at connect time rather than at build time.Callers must hardcode magic string literals.
setRequestHandler('tools/list', …)/setNotificationHandler('notifications/tools/list_changed', …)scatter bare method strings through app code instead of referencing a typed value.Context
Found migrating the MCP Inspector to
@modelcontextprotocol/client@2.0.0-beta.4. The Inspector renders MCP Apps via@modelcontextprotocol/ext-apps, which still peers on the v1 SDK and subscribes totools/resources/prompts*_changednotifications with the schema-first API. Under v2 that throws the error above during the AppBridge connect handshake, so apps fail to load. We worked around it with a client-side proxy that reads the method literal off the schema'sshape.method.valueand forwards the method string — but that's exactly the translation the SDK is well-positioned to provide.The
*RequestSchema/*NotificationSchemaobjects still exist and still carry the method literal, so the method is derivable from the schema.Proposals (either would help)
A. Re-accept the schema object as an overload, deriving the method from
schema.shape.method:This also restores backward-compat for v1-peer libraries, so nothing breaks at runtime.
B. Export typed method tokens/constants (e.g. a
RequestMethods/NotificationMethodsmap) so callers reference a named value instead of a bare literal, keeping the method-string design but removing hardcoded strings.At minimum, if the schema-first form stays unsupported, the thrown error could name the received schema's method (from
shape.method.value) and suggest the string to pass — it would have turned a head-scratch into a one-line fix.Versions
@modelcontextprotocol/client/core:2.0.0-beta.4