ux(mcp): tool errors are invisible to the human — Claude Code renders isError results empty; surface them via plugin PostToolUse hook + stderr #70
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sixfold-space/madtea#70
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observed (2026-07-14, live session)
madtea returns tool failures in the MCP-spec-correct shape —
CallToolResultwithIsError=trueand the message as a text content block (internal/mcp/register.go,arg_suggest.go) — and the model receives the text fine (e.g.API error 429: rate limited by server — still throttled after 1 attempt(s)andAPI error 404: The target couldn't be found.). But when I expand the MCP tool call in the Claude Code UI, the result pane is empty: the harness does not renderisErrorresult content. I only learn of failures if the failure is narrated in the conversation.The wire shape is correct and verified — this is a harness display gap. But errors going dark is bad enough to work around on our side.
Ask (work around the harness, without breaking the spec)
tool_response, and on an error result emits a user-visible message (hooksystemMessageoutput) carrying the tool name + error text (bounded, e.g. first ~500 chars). The model's view is unchanged; I see every madtea tool failure inline. Cover both tool-name prefixes (direct registrationmcp__madtea__*, and the plugin-era prefix if any caches still carry it).~/.cache/madtea/serve.log; ensure every IsError tool result is logged there too (tool name, action, error text) so failures are greppable after the fact.notifications/messageas the workaround: the current MCP draft spec deprecates the Logging feature entirely (SEP-2577; suggested migration is stderr or OpenTelemetry), so building on it now would be adopting a deprecated feature. KeepIsErrorin-band exactly as-is — it stays the spec-correct model-facing channel.isErrorresults empty) — tracked here so the workaround can be retired when fixed. Reproduction: any failing madtea call, e.g.madt_issues action=get number=99999.Acceptance
IsError=true+ text unchanged.notifications/message) for this path.