Artifacts can no longer call a local (stdio) MCP server: `host:` server form refused with `capabilities.mcp: unavailable`
Summary
Published artifacts could call a local stdio MCP server through the previouswindow.cowork.callMcpTool bridge. After the artifact runtime moved to theclaude.use('mcp') capability model, they cannot: the documented host:<name>
server form — the one intended for a server on the viewer's own device — is
refused at publish with
deploy 422: capabilities.mcp: unavailable
Two dashboards that had worked for weeks went dark simultaneously. Nothing on my
side changed; the runtime is served per page load, so the behaviour changed under
already-published pages.
What worked before
Both pages called a locally-registered stdio server (claude_desktop_config.json,python3 .../server.py) via window.cowork.callMcpTool('mcp__<server>__<tool>', args).
Verified working as of 2026-07-29 by reading the live artifact's own source, and
in daily use after that until 2026-08-25.
That local stdio servers were reachable from artifacts is also implied by
#55788, which reports Live Artifacts failing to reach them on cold start,
with a documented workaround (call the tool once in Claude Chat, after which the
artifact path works for the rest of the session). A cold-start bug is not
possible in a capability that never existed.
What happens now
window.cowork is gone — a probe enumerating window inside a live artifact
returns cowork: undefined, claude: { use: function }. Declaring the
replacement for a local server fails:
{"mcp": {"servers": [{"server": "host:<local-server-name>",
"tools": ["<one_tool>"]}]}}
| Attempt | Result |
|---|---|
| host: form, full tool list, existing artifact | 422 capabilities.mcp: unavailable |
| Same, plus contract: "latest" (ruling out a stale contract pin) | same 422 |
| host: form, one tool, brand-new artifact, published from Claude Code | same 422 |
| host: form, one tool, brand-new artifact, published from the desktop app | same 422 |
| Bare server name, one tool, same account | publishes normally |
| {"downloads": true}, same account | publishes normally |
The control that isolates it
The last two rows are the point. Same account, same capability, same single
tool — the only difference is the host: prefix. So mcp is available
here; the host: server form is what is refused.
Which also makes the error message misleading: capabilities.mcp: unavailable
names the capability when the unavailable thing is the server inside it. That
wording sent three separate debugging sessions down the wrong path before the
control above isolated it. Naming the rejected server instead would have saved
all three.
Why I think this is a regression rather than intended
mcp.d.ts for contract 0.2.23 specifies host:<name> as a server "running on
the VIEWER'S DEVICE, reached through the Claude app that shows the page" —
routed by the app rather than the relay, which keeps the viewer-scoped model
intact rather than breaking it. It is written in the future tense, twice
("once the shell routes host: calls to the app"), and hedged ("only the
Artifact's owner can use host servers for now").
So the capability appears designed and not yet routed, rather than removed on
purpose. I'd not have filed this if the contract didn't describe the path.
I'm aware the artifacts documentation currently states that a published page
can't call local MCP servers, and that the relay architecture (claude.ai making
the call with the viewer's connectors, page never seeing credentials) is
deliberate and sensible. My point is narrower: that support existed, it went
away, and the specified replacement can't be declared.
Questions
- Is
host:routing on the roadmap, and is there a rollout to opt into? - Is the refusal a per-account gate, or the absence of the routing for
everyone? The answer decides whether waiting is rational or whether I should
re-architect onto a remote connector.
- Could the 422 name the rejected server rather than the capability?
Environment
- Runtime contract 0.2.23
- Publish surfaces tested: Claude Code 2.1.224, and the macOS desktop app
- Artifact owner is the publisher in every test (host servers are documented as
owner-only)
- Local MCP server: stdio, registered in
claude_desktop_config.json
Possibly related
- #55788 — Live Artifacts reject local stdio servers on cold start; the relay
receives a server name where a UUID is expected. Open, has repro.
- #42453 — local MCP server tools disabled in Cowork while working in Claude
Chat Desktop. Closed as not planned, also labelled stale.