anthropics / anthropics/claude-code

Artifacts can no longer call a local (stdio) MCP server: `host:` server form refused with `capabilities.mcp: unavailable`

Aperta
#89,904 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub
area:mcp bug has repro
Lingua principale
Python
Stelle
145k
Fork
23.1k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

### 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`.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Ambito
api, backend
Tipo di issue
Bug
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.