-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Describe the bug
When using McpServer
or Server
, any previously assigned onclose
, onmessage
, and onerror
handlers get overwritten by the underlying Protocol.connect
. This behavior prevents attaching custom logic (e.g., cleanup tasks on onclose
) outside of the protocol, as those handlers will be silently lost.
You can see the code here:
https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/shared/protocol.ts#L267-L287
This design makes the Transport interface harder to extend or compose with custom application-level logic.
To Reproduce
Steps to reproduce the behavior:
- Assign a custom
onclose
handler to a transport:
transport.onclose = () => {
console.log('Cleanup logic called');
};
- Pass the transport into
Protocol.connect(transport)
- Close the connection
- The custom
onclose
handler will never be called.
Expected behavior
I expected Protocol to preserve or compose with the existing handlers (e.g. call them in addition), or for the Transport interface to support multiple listeners (e.g. addEventListener-style).
Alternatively, documentation should clearly mention that using Protocol takes exclusive ownership of the transport event handlers.
Additional context
This became an issue when I tried to delete the transport from a session map on onclose. However, the handler was silently overwritten by the protocol logic and was never triggered.
Since I was already using a custom Transport implementation to support Web API-style request/response, I just extended my custom class to handle additional headers and invoke them accordingly as a workaround.
For reference, here’s my use case:
https://github.com/nichtsam/nichtsam.com/blob/dev/app/routes/mcp%2B/mcp.server.ts
Thanks for the great library! I’d love to know if this behavior is by design, or if there’s potential for an enhancement.