Package: @mcp-ui/client@7.1.1
Summary
AppRenderer emits an unhandled promise rejection — Error: Not connected — when it sends a host-context-change notification to a sandbox iframe whose transport has already been torn down. Because the send is fire-and-forget (not awaited/caught), the rejection escapes any onError handling and reaches the browser's global unhandledrejection handler, so it surfaces in the console and in error-tracking tools (Sentry, etc.).
The card itself renders fine — this is a benign teardown race, but it produces persistent noise in production error monitoring.
Conditions
The host re-renders frequently (e.g. an LLM chat streaming responses), which rebuilds the bridge, and the user can disconnect/reconnect or navigate away. When a setHostContext fires around the moment the transport closes (unmount / disconnect / bridge rebuild), the notification is sent over a closed transport.
Stack signature (minified, production build)
Error: Not connected
<transport>.notification
<bridge>.sendHostContextChange
<bridge>.setHostContext
mechanism: onunhandledrejection, handled: no
(The setHostContext → sendHostContextChange → notification chain is the tell.)
Expected
Pushing a host-context update to an already-closed / not-yet-connected transport should not produce an unhandled rejection. Either:
- guard the send (
if (transport.connected) …), or
- swallow/catch the
Not connected rejection internally (it is non-actionable for the host), or
- surface it through the component's
onError callback instead of the global handler,
so hosts don't have to filter it out at the Sentry/console layer.
Workaround (host side)
We currently drop it in our Sentry beforeSend and preventDefault() it in an unhandledrejection listener, matched narrowly on message === "Not connected" + the onunhandledrejection mechanism. Would prefer not to string-match a third-party message long-term.
Environment
@mcp-ui/client 7.1.1
- React 19, Next.js (App Router), Chrome
AppRenderer with a separate-origin sandbox proxy
Package:
@mcp-ui/client@7.1.1Summary
AppRendereremits an unhandled promise rejection —Error: Not connected— when it sends ahost-context-changenotification to a sandbox iframe whose transport has already been torn down. Because the send is fire-and-forget (not awaited/caught), the rejection escapes anyonErrorhandling and reaches the browser's globalunhandledrejectionhandler, so it surfaces in the console and in error-tracking tools (Sentry, etc.).The card itself renders fine — this is a benign teardown race, but it produces persistent noise in production error monitoring.
Conditions
The host re-renders frequently (e.g. an LLM chat streaming responses), which rebuilds the bridge, and the user can disconnect/reconnect or navigate away. When a
setHostContextfires around the moment the transport closes (unmount / disconnect / bridge rebuild), the notification is sent over a closed transport.Stack signature (minified, production build)
(The
setHostContext → sendHostContextChange → notificationchain is the tell.)Expected
Pushing a host-context update to an already-closed / not-yet-connected transport should not produce an unhandled rejection. Either:
if (transport.connected) …), orNot connectedrejection internally (it is non-actionable for the host), oronErrorcallback instead of the global handler,so hosts don't have to filter it out at the Sentry/console layer.
Workaround (host side)
We currently drop it in our Sentry
beforeSendandpreventDefault()it in anunhandledrejectionlistener, matched narrowly onmessage === "Not connected"+ theonunhandledrejectionmechanism. Would prefer not to string-match a third-party message long-term.Environment
@mcp-ui/client7.1.1AppRendererwith a separate-origin sandbox proxy