-
Notifications
You must be signed in to change notification settings - Fork 9.9k
Closed as not planned
Closed as not planned
Copy link
Description
Bug Description
All MCP tool calls crash with:
TypeError: undefined is not an object (evaluating 'output.output.toLowerCase')
This affects every MCP tool (Slack, fetch, grep_app, etc.) — 100% reproducible.
Root Cause
AI SDK v6.0.74 (released Feb 6, 2026) introduced createToolModelOutput() in stream-text.ts (line 1270) which changed the tool-result output structure:
Before (what OpenCode expects):
value.output = {
output: string,
metadata: Record<string, any>,
title: string,
attachments?: FilePart[]
}After (what AI SDK now returns):
value.output = {
type: 'text' | 'json' | 'error-text' | 'error-json' | 'execution-denied' | 'content',
value: string | JSONValue,
providerOptions?: ProviderOptions
}Crash Location
packages/opencode/src/session/processor.ts — tool-result case:
case "tool-result": {
const match = toolcalls[value.toolCallId]
if (match && match.state.status === "running") {
await Session.updatePart({
...match,
state: {
status: "completed",
input: value.input ?? match.state.input,
output: value.output.output, // ← undefined.toLowerCase() crashes here
metadata: value.output.metadata, // ← undefined
title: value.output.title, // ← undefined
attachments: value.output.attachments,
},
})
}
}Full Data Flow
- MCP tool execute (
mcp/index.ts→convertMcpTool()) returns MCP SDKCallToolResult:{ content: [{type: "text", text: "..."}], isError? } - AI SDK
execute-tool-call.tswraps it as{ type: 'tool-result', output: <raw result> } - AI SDK
stream-text.ts(line 1270) now passes output throughcreateToolModelOutput()→ transforms to{ type: 'text', value: '...' } - OpenCode
processor.tstries to access.output,.metadata,.titleon the new structure → crash
Why It Wasn't Caught
- OpenCode's built-in tools return
{ output, title, metadata }from their execute functions createToolModelOutput()wraps ALL tool outputs (including MCP) into the newToolResultOutputshape- The processor was never updated to handle the new shape
Suggested Fix
Option A: Convert MCP result in mcp/index.ts (recommended)
// In convertMcpTool(), wrap the execute return:
execute: async (args: unknown) => {
const result = await client.callTool(...)
const textContent = result.content
?.filter((c: any) => c.type === "text")
.map((c: any) => c.text)
.join("\n") ?? ""
return {
output: textContent,
title: mcpTool.name,
metadata: {},
}
},Option B: Handle new output shape in processor.ts
case "tool-result": {
const match = toolcalls[value.toolCallId]
if (match && match.state.status === "running") {
const raw = value.output ?? {}
// Handle both old format { output, metadata, title } and new AI SDK format { type, value }
const output = raw.output ?? raw.value ?? (typeof raw === "string" ? raw : JSON.stringify(raw))
const metadata = raw.metadata ?? {}
const title = raw.title ?? match.tool
await Session.updatePart({
...match,
state: {
status: "completed",
input: value.input ?? match.state.input,
output,
metadata,
title,
time: { start: match.state.time.start, end: Date.now() },
attachments: raw.attachments,
},
})
}
}Environment
- OpenCode: v1.1.56
- AI SDK: 6.0.74 (from pnpm catalog)
@modelcontextprotocol/sdk: 1.25.2- OS: macOS (darwin)
Reproduction
- Configure any MCP server in opencode.json
- Call any MCP tool
- Crash occurs immediately on tool result processing
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels