Skip to content

fix(mcp-scan): preserve complete MCP tool results - #727

Merged
boy-hack merged 3 commits into
Tencent:mainfrom
LuckVd:fix/726-mcp-tool-results
Oct 28, 2026
Merged

boy-hack merged 3 commits into
Tencent:mainfrom
LuckVd:fix/726-mcp-tool-results

Conversation

@LuckVd

@LuckVd LuckVd commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

I fixed dynamic MCP tool-result handling so the agent no longer loses later content blocks or structured results. I preserve the legacy single-text and single-media return shapes when no extra metadata is present, and include structured_content (including explicit JSON null), is_error, top-level meta, and text-block annotations/metadata when they are present. For multi-block results, I place readable text before structured data, metadata, and opaque media, while labeling each original content index to make the display-order change explicit. This prevents earlier opaque media from hiding later evidence that fits within the existing history preview; the preview's length cap still applies to unusually long text.

Scope note

InputRequiredResult is a separate interactive SDK result, not a CallToolResult content variant. This PR does not enable allow_input_required=True; the SDK default continues to reject that response because the dynamic scanner has no elicitation-response flow.

Type of change

  • Bug fix
  • New feature
  • Fingerprint rule (data/fingerprints/)
  • Vulnerability rule (data/vuln/)
  • MCP security plugin (data/mcp/)
  • Jailbreak evaluation dataset (data/eval/)
  • Documentation
  • Other (please describe)

How was this tested?

  • cd mcp-scan && .venv/bin/python -m pytest -q pytests/test_mcp_sdk_v2.py — 13 passed. Covers singleton compatibility, multiple text/media/resource blocks, structured_content including explicit null, is_error, result/block metadata, empty-success behavior, explicit rejection of InputRequiredResult, and late evidence through ToolDispatcher._format_result into BaseAgent._build_history_tool_result.
  • cd mcp-scan && .venv/bin/python -m pytest -q pytests/ --ignore=pytests/test_surrogate_sanitization.py — 59 passed.
  • Full MCP suite — 63 passed, 2 failed in untouched pytests/test_surrogate_sanitization.py (lines 84 and 102). I reran that file on clean origin/main; the same two tests fail before scanner code runs because os.path.join() combines a string temp directory with a bytes filename (TypeError: Can't mix strings and bytes in path components).
  • go build ./... — passed.
  • ruff check and ruff format --check on the changed Python files — passed; git diff --check — clean.
  • cd mcp-scan && PYTHONPATH=$PWD .venv/bin/python main.py --help — passed.

Related issue

Fixes #726

Checklist

  • go build ./... succeeds locally
  • I followed the existing file/rule format conventions for this contribution type
  • I have not introduced hardcoded secrets or credentials

@boy-hack boy-hack left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified locally on top of latest main (33768c5):

  • The fix correctly addresses the truncation reported in #726: content[0] slicing is replaced by full-result serialization that preserves all content blocks, structuredContent, isError, result _meta, and per-block annotations/meta.
  • Good backward-compat touch: the single-block/no-metadata fast path keeps the historical plain str return, so existing consumers see no behavioral change for simple results.
  • Sensible ordering (status → text → structuredContent → result meta → metadata → media) keeps readable text ahead of opaque media blobs in the agent's bounded preview.
  • Tests: new coverage passes locally (multi-block, is_error, structuredContent, result meta, input-required/unsupported types). Full-suite failure set is identical to the main baseline (9 pre-existing environmental failures in test_dispatcher / test_protocol_negotiation / test_surrogate_sanitization, unrelated to this change).
  • CI green after re-running the stuck fork workflow.

Thanks for the high-quality fix and the detailed issue report!

@boy-hack
boy-hack merged commit 7b62e47 into Tencent:main Oct 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP dynamic scan drops later content from MCP tool results

2 participants