anthropics / anthropics/claude-ai-mcp

`tool-input` held until tool completion deadlocks deferred tool results (ext-apps#390)

Offen
#170 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
mcp-apps
Vorherrschende Sprache
Keine Sprachdaten
Sterne
471
Forks
76
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

I'm building an MCP server where the model renders interactive widgets inline in chat for elicitation: the user makes a selection in the widget, and that choice feeds back into the tool result so the model can continue with it. This is the deferred-tool-result pattern documented in modelcontextprotocol/ext-apps#390 (described there as "basically fancy elicitation").

It works in a custom host I built, but deadlocks in Claude.ai.

## What happens

Traced with DevTools on a custom MCP server implementing the ext-apps#390 pattern (three tools: one model-visible deferred tool, one app-only data-fetch tool, one app-only selection tool):

1. Claude generates tool call arguments. `tool-input-partial` streams to the iframe as tokens arrive. Iframe is mounted, bridge handshake completes.
2. Claude sends `tools/call` to the MCP server. The tool handler awaits a Promise, waiting for the widget to call an app-only tool via `app.callServerTool()`.
3. Partials stop. `tool-input` is never sent. The widget's `ontoolinput` handler never fires, so it can't call `callServerTool()` to fetch its data or render interactive UI.
4. The MCP server blocks indefinitely. Claude spins until the user stops it.

If the user manually stops Claude, `tool-input` and `tool-result` are delivered and the widget renders with data correctly. Clicking the selection button does successfully call `callServerTool()` (confirmed in MCP server logs: the app-only selection tool is called). But by that point the deferred tool has been cancelled, so the selection resolves on the server with no pending promise to complete, and Claude has already stopped listening.

MCP server logs confirm `tools/call` arrives and the handler starts executing. No further MCP messages are exchanged after that.

Non-deferred tools on the same server render correctly, confirming that `tool-input` is sent for tools that return immediately.

## The deadlock

The model-visible tool is waiting for `callServerTool()` from the widget. The widget is waiting for `tool-input` to know its arguments and begin rendering. `tool-input` is waiting for the tool call to complete. Circular dependency.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.