Plugin-bundled MCP server is double-registered in Cowork; interactive MCP-UI ("app") tools only render via the connector-UUID registration, not the mcp__plugin_… one
Summary
Installing a plugin that bundles a remote MCP server (.mcp.json) into Cowork produces two registrations of the same server:
- the plugin-bundled registration —
mcp__plugin_<plugin>_<server>__<tool> - an auto-registered user connector —
mcp__<uuid>__<tool>
Both expose the same tools. But Cowork's interactive-app / Live-Artifacts renderer is wired only to the connector (UUID) registration. When the model calls a tool that returns an MCP-UI resource (an interactive "app") via the plugin-bundled name, Cowork shows raw tool output instead of the interactive UI. The identical call via the connector-UUID name renders correctly.
This forces plugin authors to ship a PreToolUse hook that denies the plugin-bundled interactive tools and steers the model to re-issue against the connector registration — a workaround for what looks like a double-registration / routing bug.
Environment
- Claude Code / Cowork version:
Claude 1.11187.4 (584005) 2026-06-05T20:15:04.000Z - OS: macOS
26.3.1 - Plugin: a plugin bundling a remote HTTP MCP server via
.mcp.json, e.g.
``json``
{ "mcpServers": { "example": { "type": "http", "url": "https://mcp.example.com/mcp" } } }
- The MCP server exposes a tool that returns an MCP-UI resource (
ui://…) — i.e. an interactive app, not just text/JSON.
Steps to reproduce
- Build a plugin whose
.mcp.jsonregisters a remote MCP server (server key e.g.example) that exposes an interactive tool returning aui://…resource, e.g.open_widget. - Install the plugin in Cowork. Observe the same server's tools appear under both
mcp__plugin_<plugin>_example__open_widgetandmcp__<uuid>__open_widget. - Have the model call
mcp__plugin_<plugin>_example__open_widget. - Then call
mcp__<uuid>__open_widgetwith identical arguments.
Expected
Both registrations render the interactive MCP-UI app, or the plugin-bundled server is not double-registered as a separate connector at all (single canonical registration).
Actual
- The plugin-bundled call (step 3) returns raw output; the interactive UI does not display.
- The connector-UUID call (step 4) renders the interactive UI correctly.
Mechanism / corroborating evidence
This appears to be the interaction of two known behaviours:
- The Cowork artifact path routes MCP calls through a relay that requires a UUID server id and rejects non-UUID server names — see #55788 ("Live Artifacts
CoworkArtifacts.callMcpToolreject … non-UUID server name"). - Plugin + SDK double-load produces shadowing of duplicate server registrations — see #54858 (interactive MCP widget fails due to SDK double-load shadowing), #53535 ("Shadowing with no-ops to prevent SDK double-load"), and #50586 (a connector shown twice in
/plugin).
Net effect: the plugin-bundled registration is the one the model tends to call by default (stable name), but it is not the registration the interactive renderer is bound to.
Current workaround
A PreToolUse hook matching the plugin-bundled interactive tools that returns permissionDecision: "deny" with a reason instructing the model to re-issue the exact call against the connector-UUID registration. This works but is brittle (hard-codes the mcp__plugin_<plugin>_<server>__ prefix and the tool suffixes) and only mitigates the routing symptom — it does not fix the double-registration itself.
Suggested fix / questions
- Don't double-register a plugin-bundled MCP server as a separate UUID connector — keep a single canonical registration.
- If both must exist, bind the interactive-app renderer to whichever registration the model calls (route by tool, not by registration), so the plugin-bundled name renders too.
- At minimum, document the behaviour and the recommended workaround.
Related
- #55788 (open) — relay rejects non-UUID server name
- #54858 (closed) — interactive MCP widget fails via double-load shadowing
- #53535 (closed dup) — "Shadowing with no-ops to prevent SDK double-load"
- #50586 (closed) — connector listed twice in
/plugin - #47614 (open) — Cowork custom connectors use UUID as server name
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗