diff --git a/packages/opencode/src/mcp/catalog.ts b/packages/opencode/src/mcp/catalog.ts index db2d8a4e3f..66d126128e 100644 --- a/packages/opencode/src/mcp/catalog.ts +++ b/packages/opencode/src/mcp/catalog.ts @@ -64,6 +64,7 @@ export function convertTool(mcpTool: MCPToolDef, client: Client, timeout?: numbe timeout, }, ) + if (!isCallToolResult(result)) return result if (result.isError) throw new Error(errorText(result)) if (result.structuredContent === undefined || result.structuredContent === null) return result return { @@ -74,6 +75,10 @@ export function convertTool(mcpTool: MCPToolDef, client: Client, timeout?: numbe }) } +function isCallToolResult(result: Awaited>): result is CallToolResult { + return "content" in result && Array.isArray(result.content) +} + function errorText(result: CallToolResult) { const content = result.content.flatMap((item) => { if (item.type === "text") return [item.text] diff --git a/packages/opencode/test/mcp/catalog.test.ts b/packages/opencode/test/mcp/catalog.test.ts index 694bd2e24e..6140cc8e3a 100644 --- a/packages/opencode/test/mcp/catalog.test.ts +++ b/packages/opencode/test/mcp/catalog.test.ts @@ -9,7 +9,7 @@ const definition = { inputSchema: { type: "object" as const, properties: {} }, } -function tool(result: CallToolResult) { +function tool(result: CallToolResult | { toolResult: unknown }) { const callTool = mock(async () => result) const converted = convertTool(definition, { callTool } as unknown as Client) if (!converted.execute) throw new Error("expected executable tool") @@ -31,6 +31,13 @@ describe("mcp catalog", () => { expect(converted.callTool).toHaveBeenCalledTimes(1) }) + test("returns task tool results", async () => { + const result = { toolResult: { taskId: "task-1" } } + const converted = tool(result) + + await expect(converted.execute({}, { toolCallId: "call-1", messages: [] })).resolves.toBe(result) + }) + test("throws MCP tool errors with text and structured diagnostics", async () => { const converted = tool({ isError: true,