anthropics / anthropics/claude-code
Artifacts can no longer call a local (stdio) MCP server: `host:` server form refused with `capabilities.mcp: unavailable`
- Langage dominant
- Python
- Étoiles
- 145k
- Forks
- 23.1k
- Métriques de merge des PR
- Métriques de PR en attente
Description
### Summary
Published artifacts could call a **local stdio MCP server** through the previous
`window.cowork.callMcpTool` bridge. After the artifact runtime moved to the
`claude.use('mcp')` capability model, they cannot: the documented `host:`
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____', 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:
```json
{"mcp": {"servers": [{"server": "host:",
"tools": [""]}]}}
```
| 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:` 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
1. Is `host:` routing on the roadmap, and is there a rollout to opt into?
2. 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.
3. 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`.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Piste de recherche
Start with the runtime contract's mcp.d.ts for contract 0.2.23 and the publish validation that handles the host: server form. Compare that path with the working bare server form and inspect how capabilities.mcp: unavailable is produced. Done would establish whether host routing is implemented or gated, and ensure any rejection identifies the server rather than only the capability.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Domaine
- api, backend
- Type d'issue
- Bug
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100