Python: Preserve MCP Host payloads in AG-UI history - #7971
Conversation
|
likebean HaoFeng Zhao (@ronronner02) Shivani . (@Shivani767) This draft follows the MCP result discussions in #7959 and #7897: it leaves #7866 model-content selection/deduplication to #7897 and adds the orthogonal core-to-AG-UI contract that preserves the full Host payload through live events, |
There was a problem hiding this comment.
Pull request overview
Preserves complete MCP Host payloads across AG-UI events, snapshots, approvals, and history replay while retaining model-facing results separately.
Changes:
- Adds a core MCP Host-payload marker, including error propagation.
- Projects payloads through AG-UI live, snapshot, approval, and replay paths.
- Adds regression tests and documents the transport contract.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
python/packages/core/agent_framework/_mcp.py |
Preserves MCP Host payloads. |
python/packages/core/agent_framework/_tools.py |
Propagates exception metadata. |
python/packages/core/tests/core/test_mcp.py |
Tests payload persistence and errors. |
python/packages/ag-ui/agent_framework_ag_ui/_utils.py |
Adds payload extraction and replay helpers. |
python/packages/ag-ui/agent_framework_ag_ui/_run_common.py |
Projects live and snapshot payloads. |
python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py |
Converts persisted payloads and model sidecars. |
python/packages/ag-ui/agent_framework_ag_ui/_agent_run.py |
Handles approval-resolved payloads. |
python/packages/ag-ui/tests/ag_ui/test_run_common.py |
Tests events, snapshots, and approvals. |
python/packages/ag-ui/tests/ag_ui/test_message_adapters.py |
Tests history reload and fallback. |
docs/specs/004-python-function-calling-loop.md |
Documents the MCP Host contract. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
9b7426c to
f197df3
Compare
f197df3 to
118b567
Compare
|
/review |
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (1 commit(s)): 118b5673f3f4
Model: gpt-5.6-sol-fast
Overview
The change cleanly separates complete MCP Host payloads from model-facing results, attaches the payload only once, and adds provenance, safe error fallback, rich-content replay, approval, and outbound-isolation guards. Two Medium risks remain: complete untrusted Host payloads are retained without a byte bound, and model-item serialization is eagerly performed for ordinary non-MCP results even though its output is discarded.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (2 medium) across 2 files. Details are attached to the affected lines below.
Affected areas: python/packages/ag-ui/agent_framework_ag_ui/_run_common.py, python/packages/core/agent_framework/_mcp.py
118b567 to
b84adcf
Compare
There was a problem hiding this comment.
MAF Automated Review — Iteration 2
Result: Findings reported
Scope: full PR (1 commit(s)): b84adcf3b867
Model: gpt-5.6-sol-fast
Overview
The change cleanly separates bounded MCP Host payloads from model-facing results and adds strong coverage for custom parsers, errors, rich content, approvals, and model-safe outbound requests. The marker is attached once, replay strips it from model items, and ordinary tools avoid the new serialization path. Residual risk remains because oversized payloads are fully copied before the cap is checked, retained payloads have no cumulative history budget, and the persisted-core-Message conversion path is not wired into a supported production surface.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
3 verified findings remained after source verification (3 medium) across 3 files. Details are attached to the affected lines below.
Affected areas: python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py, python/packages/ag-ui/agent_framework_ag_ui/_run_common.py, python/packages/core/agent_framework/_mcp.py
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
b84adcf to
76f2417
Compare
|
/review |
There was a problem hiding this comment.
MAF Automated Review — Iteration 3
Result: Findings reported
Scope: full PR (1 commit(s)): 76f2417562b1
Model: gpt-5.6-sol-fast
Overview
The change cleanly separates bounded MCP Host payloads from model-facing results, preserves rich replay content, and adds coverage for ordinary, approval, error, snapshot, and persisted-history paths. Its per-result preflight, model-safe outbound conversion, provenance marker, error redaction, and newest-first Host-content budget address the previously reported data-loss and direct payload-growth risks. Two residual issues remain: server-controlled metadata can expand into an unbudgeted replay sidecar large enough to exhaust shared process resources, and the new constructor option shifts established positional parameters.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (1 high, 1 medium) across 2 files. Details are attached to the affected lines below.
Affected areas: python/packages/ag-ui/agent_framework_ag_ui/_utils.py, python/packages/core/agent_framework/_mcp.py
|
|
||
| serialized_items: list[dict[str, Any]] = [] | ||
| for item in items: | ||
| serialized = item.to_dict() |
There was a problem hiding this comment.
The 8 MiB history cap does not cover this replay sidecar, and to_dict() retains each item's server-controlled _meta. Because core stamps the same _meta on every parsed MCP item, a sub-1 MiB result with many items can expand to hundreds of MiB in _agentFrameworkModelContent before _bound_host_payload_history() measures only content, exhausting shared process memory/bandwidth and persisting outside the cap. Please bound the serialized sidecar as part of the aggregate budget or avoid replicating _meta while preserving the model-facing replay data.
| sampling_approval_callback: SamplingApprovalCallback | None = None, | ||
| sampling_max_tokens: int | None = _DEFAULT_SAMPLING_MAX_TOKENS, | ||
| sampling_max_requests: int | None = _DEFAULT_SAMPLING_MAX_REQUESTS, | ||
| max_host_payload_size_bytes: int | None = _DEFAULT_MCP_HOST_PAYLOAD_SIZE_BYTES, |
There was a problem hiding this comment.
max_host_payload_size_bytes was inserted before existing positional parameters. Third-party MCPTool subclasses or concrete-tool callers that passed additional_properties (or any later option) positionally now bind that value to this parameter and can fail during construction at max_host_payload_size_bytes <= 0 (for example, a dictionary raises TypeError). Please preserve the established positional ordering by appending this option after existing parameters, or introduce it as keyword-only without shifting them.
Motivation & Context
MCP Apps need model-visible tool output and Host/UI hydration data to remain separate. Agent Framework currently loses the complete MCP
CallToolResultwhen AG-UI replaces streamed events withMESSAGES_SNAPSHOTor rebuilds persisted history, causing widgets to disappear after a run or reload.This is orthogonal to #7866 and draft PR #7897. That work selects and deduplicates model-visible MCP content; this change preserves the complete Host payload across AG-UI surfaces without exposing UI-only JSON to the model.
Description & Review Guide
CallToolResult, including successful and error payloads, under a private core-ownedadditional_propertiesmarker.TOOL_CALL_RESULTevents,MESSAGES_SNAPSHOT, and the supportedagent_framework_messages_to_agui_host_history()conversion API.TOOL_RESULT_DISPLAY_KEYbehavior and compatibility with supported core versions that predate the marker.AGUIChatClientoutbound requests remain model-safe.Related Issue
Fixes #7959
Draft PR #7897 addresses #7866's model-content selection and deduplication; it does not preserve Host/UI payloads and is intentionally not duplicated here.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.