-
Notifications
You must be signed in to change notification settings - Fork 971
fix(mcp): pass structuredContent and _meta through to model-visible tool output #2596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@moonshot-ai/kimi-code': patch | ||
| --- | ||
|
|
||
| MCP tool results now surface the spec-defined `structuredContent` field and `_meta` server metadata to the model as a serialized `<mcp-structured-result>` block, instead of silently dropping them. Servers that return their machine-readable contract in these fields work the same as on other MCP hosts. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,6 +146,35 @@ export async function mcpResultToExecutableOutput( | |
| } | ||
|
|
||
| const wrapped = wrapMediaOnly(converted, qualifiedToolName); | ||
| // Structured payloads (structuredContent per MCP spec, plus server metadata | ||
| // in _meta) carry machine-readable contracts such as browser-handoff URLs. | ||
| // Appended AFTER the media wrap so a media-only result keeps its | ||
| // <mcp_tool_result> attribution, and BEFORE the text budget so oversized | ||
| // payloads stay bounded. Literal closing tags inside the serialized | ||
| // payload are stripped so server data cannot fake an early end of the | ||
| // block. | ||
| const structuredExtras: Record<string, unknown> = {}; | ||
| if (result.structuredContent !== undefined) { | ||
| structuredExtras['structuredContent'] = result.structuredContent; | ||
| } | ||
| if (result._meta !== undefined) { | ||
| structuredExtras['_meta'] = result._meta; | ||
| } | ||
|
Comment on lines
+160
to
+162
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an MCP Apps-compatible server returns Useful? React with 👍 / 👎.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point — partially adopted in #2600: |
||
| if (Object.keys(structuredExtras).length > 0) { | ||
| try { | ||
| const serialized = JSON.stringify(structuredExtras).replaceAll( | ||
| '</mcp-structured-result>', | ||
| '', | ||
| ); | ||
| wrapped.push({ | ||
| type: 'text', | ||
| text: `\n<mcp-structured-result>\n${serialized}\n</mcp-structured-result>`, | ||
| }); | ||
| } catch { | ||
| // Non-serialisable payloads are dropped rather than failing the call. | ||
| } | ||
| } | ||
|
|
||
| const budgeted = applyTextBudget(wrapped); | ||
| const compressed = await compressImageContentParts(budgeted.parts, { | ||
| telemetry: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under
packages/agent-core-v2, implementation comments are supposed to be confined to the top-of-file/** */role block; this new explanatory block sits insidemcpResultToExecutableOutput, so it violates the scoped convention. Please move any durable module-level rationale to the file header or drop the inline narration.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in #2600 — commentary moved to the module header per the agent-core-v2 convention.