Explorar o código

fix(mcp): prefer content over structured output (#34505)

Aiden Cline hai 2 meses
pai
achega
fd213e6df6

+ 1 - 1
packages/opencode/src/mcp/catalog.ts

@@ -72,7 +72,7 @@ export function convertTool(mcpTool: MCPToolDef, client: Client, timeout?: numbe
             .filter((text) => text.trim())
             .join("\n\n") || "MCP tool returned an error",
         )
-      if (result.structuredContent === undefined || result.structuredContent === null) return result
+      if (result.content.length > 0 || result.structuredContent === undefined || result.structuredContent === null) return result
       return {
         ...result,
         content: [{ type: "text" as const, text: JSON.stringify(result.structuredContent) }],

+ 48 - 0
packages/opencode/test/mcp/catalog.test.ts

@@ -0,0 +1,48 @@
+import { describe, expect, test } from "bun:test"
+import type { Client } from "@modelcontextprotocol/sdk/client/index.js"
+import { McpCatalog } from "@/mcp/catalog"
+
+const options = { toolCallId: "call_mcp", abortSignal: new AbortController().signal } as any
+
+function clientReturning(result: unknown) {
+  return {
+    callTool: async () => result,
+  } as unknown as Client
+}
+
+function mcpTool() {
+  return {
+    name: "screenshot",
+    description: "Take a screenshot",
+    inputSchema: {
+      type: "object",
+      properties: {},
+      additionalProperties: false,
+    },
+  } as any
+}
+
+describe("McpCatalog.convertTool", () => {
+  test("preserves content when structuredContent is also present", async () => {
+    const content = [{ type: "image" as const, mimeType: "image/png", data: "AAAA" }]
+    const structuredContent = { image: { mimeType: "image/png", data: "AAAA" } }
+    const converted = McpCatalog.convertTool(mcpTool(), clientReturning({ content, structuredContent }))
+
+    const output = await converted.execute?.({}, options)
+
+    expect(output).toMatchObject({ content, structuredContent })
+  })
+
+  test("falls back to structuredContent only when content is absent", async () => {
+    const structuredContent = { results: [{ title: "one" }] }
+    const converted = McpCatalog.convertTool(mcpTool(), clientReturning({ content: [], structuredContent }))
+
+    const output = await converted.execute?.({}, options)
+
+    expect(output).toMatchObject({
+      structuredContent,
+      content: [{ type: "text", text: JSON.stringify(structuredContent) }],
+    })
+  })
+
+})