[FEATURE] Honour MCP Annotations.Audience on tool-result content blocks

Status Open
Maintainer reply None cached
Activity 3 comments · opened Jun 29, 2026

Problem Statement

When a Claude Code session uses MCP servers heavily (e.g. an MCP filesystem server, mcp__fetch__fetch, perplexity, webcrawler.ai, ...) and the agent makes many tool calls that return long text bodies (e.g. reading a few hundred lines of a file), the entire body of every MCP tool response is rendered in the interactive TUI. The transcript becomes dominated by tool output rather than by the agent's actual reasoning and conclusions.

Built-in tools like Read collapse to a single line (Read 10 lines), so the same workflow with the built-in stays readable. There is no equivalent collapsing for MCP tool output, even though the MCP specification has a standard mechanism for this.

Proposed Solution

Honour the MCP specification's Annotations.Audience field on tool-result content blocks:

  • A content block whose annotations.audience includes "user" but not "assistant" is intended for the user-visible UI. Render it in the TUI; do not forward it to the model.
  • A content block whose annotations.audience includes "assistant" but not "user" is intended for the model. Forward it to the model; render only a compact summary line in the TUI (similar to how the built-in Read shows Read N lines).
  • A content block with both, or neither (the current default for most servers), keeps the current rendering behaviour for back-compat.

This lets each MCP server decide, per response, what the human and the model should see. It is the standard MCP mechanism for exactly this kind of split, defined in the MCP spec under Annotations.

Alternative Solutions

  • A global "collapse MCP tool output" setting like #56423, or the --quiet flag proposed in #9340. Useful for users who want a uniform default, but neither gives the server any way to express "this particular response should show a short summary in the TUI but a long body to the model" on a per-call basis. The two approaches are complementary; honouring Annotations.Audience adds an axis the global flag cannot reach.
  • Wrapping the MCP server in a custom client (the same pattern that turns the built-in Read into Read 10 lines). Not portable across MCP servers and pushes the problem onto every server author.

Priority

Medium — Would be very helpful

Feature Category

MCP server integration

Use Case Example

I am building an MCP server that exposes filesystem tools. For a read tool I want the agent's user to see a single TUI line Read 10 lines from /path/to/file.md, while the agent itself receives the full file content (numbered cat -n style, exactly like the built-in Read).

I tried this against Claude Code 2.1.x by returning two content blocks from a Go-SDK-based MCP server:

return &mcp.CallToolResult{
    Content: []mcp.Content{
        &mcp.TextContent{
            Text:        "Read 10 lines from /path/to/file.md",
            Annotations: &mcp.Annotations{Audience: []mcp.Role{"user"}},
        },
        &mcp.TextContent{
            Text:        fullCatNStyleBody,
            Annotations: &mcp.Annotations{Audience: []mcp.Role{"assistant"}},
        },
    },
}, nil, nil

Observed behaviour:

  • The TUI showed both content blocks back-to-back (the summary line, then the full numbered body underneath), exactly as if Annotations.Audience had not been set at all.
  • The model also saw both blocks concatenated into a single string in its tool result.

Annotations.Audience appears to have no effect on either rendering or model-side delivery.

Additional Context

  • MCP specification, Annotations: <https://modelcontextprotocol.io/specification> (see the Annotations type with audience, priority, and lastModified fields).
  • MCP Go SDK type definition: github.com/modelcontextprotocol/go-sdk@v1.6.1/mcp/protocol.go, lines 16–37:

``go
type Annotations struct {
Audience []Role // intended customer ("user", "assistant", or both)
LastModified string
Priority float64
}
``

Each TextContent / ImageContent / etc. carries an optional *Annotations pointer (mcp/content.go).

  • Related but distinct asks:
  • #56423 — global "collapse tool outputs" setting
  • #9340 — --quiet flag to suppress tool call output
  • #69919 — /context collapse for the MCP tool list (not tool output)
  • #36857 — docs missing collapsed "Queried {server}" display for MCP read/search tool calls

This request is narrower and orthogonal: it asks the client to honour an existing spec hint so MCP servers can drive the user/model split themselves, rather than relying on a global setting.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

View original on GitHub ↗

3 Comments

github-actions[bot] · 2 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/27104

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

Dave-London · 1 month ago

This split really does belong with the server — a global collapse flag can't express "short summary to the user, full body to the model" per response, which is exactly what Annotations.Audience is for. The complementary lever, until clients honor it, is servers just not emitting bloated output in the first place: I build Pare as MCP wrappers that return compact, schema-validated JSON instead of raw CLI text (~85% fewer tokens for the same result), so the model-side payload stays small regardless of TUI handling. Would still very much want Audience honored for the human-facing summary, though.

hhowwl · 18 days ago

Another use case for this, from the file-delivery side. Our MCP connector's deliverable is a Word document for a non-technical end user, and there is currently no way for a tool to hand a file to the user at all. Honoring audience: ["user"] is the cheapest fix for that: forwarding bytes to the model is O(file size) in context, while a user-audience block the client renders and does not forward is free. Details, what we tried, and measurements are in anthropics/claude-ai-mcp#287.