What happens
kagent replaces an MCP tool's result with MCP_APP_RENDERED_NOTICE whenever the tool's definition declares _meta.ui.resourceUri. It does this even when the result itself contains no UI resource and carries the full text payload. The model receives the notice instead of the data.
Classification comes from the tool definition, not from the result.
Version
0.10.0-rc3, the current release.
kagent-controller ghcr.io/kagent-dev/kagent/controller:0.10.0-rc3
agent pod ghcr.io/kagent-dev/kagent/golang-adk:0.10.0-rc3
Reproduction
RemoteMCPServer pointing at https://mcp.atlassian.com/v1/mcp, Atlassian API token via headersFrom.
- Declarative
Agent, runtime: go, toolNames: [searchJiraIssuesUsingJql, getJiraIssue].
- Ask it to describe recent issues on a Jira board.
The agent replies that the results are displayed in an interactive format and states no field from them.
Evidence
1. The server returns the data
Using kagent's capability and client name:
curl -s -X POST https://mcp.atlassian.com/v1/mcp \
-H "Authorization: Bearer $TOKEN" \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2025-06-18",
"capabilities":{"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}}},
"clientInfo":{"name":"kagent-adk","version":"1"}}}'
tools/call on searchJiraIssuesUsingJql returns:
content block types: ['text']
has structuredContent: True
_meta keys: []
TEXT block: { "issues": [ { "id": "160217", "key": "GF-3687", ... } ] }
Text block with the full JSON, structuredContent present, no UI resource in the result.
2. The tool metadata is capability-gated
Same server, same token, two initialize calls.
capabilities: {} returns 13 tools, none carrying _meta.
capabilities containing io.modelcontextprotocol/ui returns 13 tools, and searchJiraIssuesUsingJql and getJiraIssue carry:
"_meta": {"ui": {"resourceUri": "ui://widget/jira-widget.html", "prefersBorder": true, ...}}
mcpUIClientCapabilities() in go/adk/pkg/mcp/mcp_ui.go advertises the extension on every connection. No per-server setting disables it.
3. kagent classifies from the definition
agentVisibleToolFilter reads mcpToolKindOf(t.Meta) during ListTools and records matching names in appToolNames. Agent log:
{"level":"info","caller":"agent/agent.go:111",
"msg":"Wiring MCP App model result callback","toolCount":2}
Both of the agent's two tools.
4. The callback discards the payload
compact_mcp_app_response:
compacted = {"content": [{"type": "text", "text": MCP_APP_RENDERED_NOTICE}]}
if "_meta" in response:
compacted["_meta"] = response["_meta"]
return compacted
The result is not inspected. go/adk/pkg/agent/mcp_apps.go does the same.
The notice reads: "The interactive UI for this tool has been rendered to the user and now updates live inside the app. Treat this as complete and do not call this tool again unless the user explicitly asks for it."
5. Session history keeps the real payload
The compaction runs in before_model against a deep copy, so GET /api/sessions/<id> shows the full tool output. Inspecting a session does not reveal the problem.
Scope
Any agent invoked over A2A or kagent invoke against a server that declares UI tools. There is no widget rendered and no human present, so the model is the only consumer of the tool result.
#2046 scopes MCP Apps to the chat interface. design/EP-2046-chat-mcp-ui-widgets.md lists per-server opt-in as an open question.
Possible fixes
- Compact only when the result contains a UI resource, rather than when the definition declares one.
- Keep the text content alongside the notice instead of replacing it.
- Allow a
RemoteMCPServer to opt out of the UI capability.
Checking whether an agent is affected
kubectl logs -n kagent deploy/<agent> | grep "Wiring MCP App model result callback"
A non-zero toolCount means the model does not receive those tools' output.
What happens
kagent replaces an MCP tool's result with
MCP_APP_RENDERED_NOTICEwhenever the tool's definition declares_meta.ui.resourceUri. It does this even when the result itself contains no UI resource and carries the full text payload. The model receives the notice instead of the data.Classification comes from the tool definition, not from the result.
Version
0.10.0-rc3, the current release.Reproduction
RemoteMCPServerpointing athttps://mcp.atlassian.com/v1/mcp, Atlassian API token viaheadersFrom.Agent,runtime: go,toolNames: [searchJiraIssuesUsingJql, getJiraIssue].The agent replies that the results are displayed in an interactive format and states no field from them.
Evidence
1. The server returns the data
Using kagent's capability and client name:
tools/callonsearchJiraIssuesUsingJqlreturns:Text block with the full JSON,
structuredContentpresent, no UI resource in the result.2. The tool metadata is capability-gated
Same server, same token, two
initializecalls.capabilities: {}returns 13 tools, none carrying_meta.capabilitiescontainingio.modelcontextprotocol/uireturns 13 tools, andsearchJiraIssuesUsingJqlandgetJiraIssuecarry:mcpUIClientCapabilities()ingo/adk/pkg/mcp/mcp_ui.goadvertises the extension on every connection. No per-server setting disables it.3. kagent classifies from the definition
agentVisibleToolFilterreadsmcpToolKindOf(t.Meta)duringListToolsand records matching names inappToolNames. Agent log:{"level":"info","caller":"agent/agent.go:111", "msg":"Wiring MCP App model result callback","toolCount":2}Both of the agent's two tools.
4. The callback discards the payload
compact_mcp_app_response:The result is not inspected.
go/adk/pkg/agent/mcp_apps.godoes the same.The notice reads: "The interactive UI for this tool has been rendered to the user and now updates live inside the app. Treat this as complete and do not call this tool again unless the user explicitly asks for it."
5. Session history keeps the real payload
The compaction runs in
before_modelagainst a deep copy, soGET /api/sessions/<id>shows the full tool output. Inspecting a session does not reveal the problem.Scope
Any agent invoked over A2A or
kagent invokeagainst a server that declares UI tools. There is no widget rendered and no human present, so the model is the only consumer of the tool result.#2046 scopes MCP Apps to the chat interface.
design/EP-2046-chat-mcp-ui-widgets.mdlists per-server opt-in as an open question.Possible fixes
RemoteMCPServerto opt out of the UI capability.Checking whether an agent is affected
A non-zero
toolCountmeans the model does not receive those tools' output.