Repository navigation
Conversation
- Preserve image blocks from MCP tool results alongside text content instead of dropping them or flattening them into text JSON. - Add unit tests verifying Pi tool results include image blocks and ignore malformed images.
- Extract stripped TypeScript source preparation to a top-level constant across test helper functions.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (1)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe Pi MCP extension converts MCP tool results into Pi content blocks. It preserves valid image blocks alongside text and structured content. Tests cover text-only, image-only, and image blocks without a MIME type. ChangesPi MCP result content
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~15 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: Merge Risk: ⚪ Minimal · up to The change can proceed through normal checks; no concrete merge-blocking issue remains. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Screenshot pixels now accompany existing tool results without changing access controls or tool permissions. Risk is low, but end-to-end image handling and responses to untrusted visual content are not fully validated. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Keep upstream migration IDs 59 and 60; move YSK to 61 and repair historical fork ledgers atomically after applying missing schema changes. Adapt selected upstream fixes for Pi approvals, MCP images, workspace discovery, provider worker starvation, concurrent worktree launches, primary runtime ownership, session refresh, DPoP URLs and embedded-render scrolling. Preserve fork lifecycle and notice behavior, and close the approval and authentication gaps found in review. Adapted from pingdotgg#16854, pingdotgg#15879, pingdotgg#17190, pingdotgg#16790, pingdotgg#17197, pingdotgg#17172, pingdotgg#17075, pingdotgg#17037, pingdotgg#17065. Co-authored-by: Adamulek123 <adam.bogucki2018@gmail.com> Co-authored-by: anntnzrb <anntnzrb@proton.me> Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-authored-by: Lakshmi Tanmay <lakshmi@voltcrash.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: Malte Sussdorff <malte.sussdorff@cognovis.de> Co-authored-by: sheehanmunim <sheehanmunim@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Dara Adedeji <daraadedeji07@gmail.com> Co-authored-by: Joseph Vidal <josephv4000@gmail.com>
Problem
Pi drops image blocks from T3 MCP tool results. With
preview_snapshot(and the device screenshot tool), the model receives the page metadata but never the screenshot pixels, even on an image-capable model. Fixes #15869.The Pi bridge extension's
formatMcpContentkeeps onlytextblocks andstructuredContent, and the registered tool'sexecutewraps that string as the only tool-result block (content: [{ type: "text", text }]). An image-only result is worse: it falls back toJSON.stringify(result), so the model gets the base64 as text.Change
formatMcpContentbecomesmcpToolContent, which returns Pi tool-result content directly:structuredContentare joined into one text block, exactly as before.dataandmimeTypeare strings) follow as Piimageblocks, the shape Pi'sAgentToolResult.contentaccepts.Pi already replaces tool-result images with a placeholder for models without image input (
packages/ai/src/api/transform-messages.ts), so this needs no capability check on our side. T3's own UI is unaffected:PiAdapterV2'scontentTextreads onlytextblocks, so no image bytes go over the websocket.The diff is limited to the extension source and its test. Pi is the only provider that reaches T3's MCP server through this T3-owned bridge; the others connect with their own MCP clients.
Scope and approval
This is the remaining gap from #13777, which ported Pi to V1 and also fixed this. It was closed after the V2 transition, and the closing comment asks for "a focused PR built on current main" for any gap that remains in the shipped implementation. The bug is tracked in #15869. That issue has not been triaged yet, so I'm submitting this under the small-fix exception for an obvious bug:
preview_snapshotbuilds an image block for the model (McpHttpServer.ts), and the Pi bridge discards it. The fix converts one function's output and changes no contract, setting, or default.Verification
Regression test.
apps/server/src/orchestration-v2/Adapters/piT3McpExtensionSource.test.tsloads the shipped extension source with a stub MCP endpoint, then calls the registered tool'sexecute. The tests cover four cases: text plus image, text only, image only, and a malformed image block.mainsource:Tests 2 failed | 5 passed (7). The failures are text plus image (expected 1 to equal 2content blocks) and image only (the image came back as a text block).Tests 7 passed (7).piT3McpInjection.test.tsalso passes (12/12 across both files).End-to-end with real Pi. Real Pi
1.0.2loaded the generated extension against a local stub MCP server whosepreview_snapshotreturns the same shape asMcpHttpServer(text,structuredContent, and a 64×64 solid-red PNG). The model wasclaude-haiku-4-5, and the prompt asked for the screenshot's dominant color, orNO_IMAGEif the result had none:mainNO_IMAGERedI also ran
tsc --noEmitforapps/server(clean) andvp lint/vp fmt --checkon both changed files.Not checked: a full T3 desktop/web turn calling the real
preview_snapshotagainst a live preview browser. The e2e run above used Pi's real extension loading and tool-result path, with only the MCP server stubbed.Made by Claude Opus 5.5 in omp.