MCP tool call fails with invalid_union on state.input despite #9667 fix #7085

Open
opened 2026-02-16 18:06:08 -05:00 by yindo · 3 comments
Owner

Originally created by @nghyane on GitHub (Jan 21, 2026).

Originally assigned to: @thdxr on GitHub.

Environment

Bug Description

MCP tool calls fail with invalid_union validation error on state.input even though PR #9667 fix is included in v1.1.28.

Error

{
  "code": "invalid_union",
  "errors": [
    [{"expected": "record", "code": "invalid_type", "path": ["state", "input"], "message": "Invalid input: expected record, received undefined"}],
    [{"expected": "object", "code": "invalid_type", "path": ["part"], "message": "Invalid input: expected object, received undefined"},
     {"expected": "string", "code": "invalid_type", "path": ["delta"], "message": "Invalid input: expected string, received undefined"}],
    [{"expected": "object", "code": "invalid_type", "path": ["part"], "message": "Invalid input: expected object, received undefined"},
     {"expected": "string", "code": "invalid_type", "path": ["delta"], "message": "Invalid input: expected string, received undefined"}]
  ],
  "path": [],
  "message": "Invalid input"
}

Reproduction Steps

  1. Install notebooklm-mcp: uv tool install notebooklm-mcp-server
  2. Configure in opencode.json:
    {
      "mcp": {
        "notebooklm-mcp": {
          "command": "notebooklm-mcp"
        }
      }
    }
    
  3. Start opencode and call any tool (e.g. notebook_list)
  4. Error occurs immediately

Notes

  • Same MCP server works perfectly with Gemini CLI - confirms MCP response format is correct
  • PR #9667 fix only covers tool-result and tool-error events in processor.ts
  • Error seems to occur at a different phase (possibly tool-call or initial state creation)
  • The union schema expects either {state: {input: record}} or {part, delta} but receives neither

Expected Behavior

MCP tools should work the same as they do in Gemini CLI.

Related

Originally created by @nghyane on GitHub (Jan 21, 2026). Originally assigned to: @thdxr on GitHub. ## Environment - **opencode version:** v1.1.28 - **MCP Server:** notebooklm-mcp (https://github.com/jacob-bd/notebooklm-mcp) - **OS:** macOS ## Bug Description MCP tool calls fail with `invalid_union` validation error on `state.input` even though PR #9667 fix is included in v1.1.28. ## Error ```json { "code": "invalid_union", "errors": [ [{"expected": "record", "code": "invalid_type", "path": ["state", "input"], "message": "Invalid input: expected record, received undefined"}], [{"expected": "object", "code": "invalid_type", "path": ["part"], "message": "Invalid input: expected object, received undefined"}, {"expected": "string", "code": "invalid_type", "path": ["delta"], "message": "Invalid input: expected string, received undefined"}], [{"expected": "object", "code": "invalid_type", "path": ["part"], "message": "Invalid input: expected object, received undefined"}, {"expected": "string", "code": "invalid_type", "path": ["delta"], "message": "Invalid input: expected string, received undefined"}] ], "path": [], "message": "Invalid input" } ``` ## Reproduction Steps 1. Install `notebooklm-mcp`: `uv tool install notebooklm-mcp-server` 2. Configure in opencode.json: ```json { "mcp": { "notebooklm-mcp": { "command": "notebooklm-mcp" } } } ``` 3. Start opencode and call any tool (e.g. `notebook_list`) 4. Error occurs immediately ## Notes - **Same MCP server works perfectly with Gemini CLI** - confirms MCP response format is correct - PR #9667 fix only covers `tool-result` and `tool-error` events in processor.ts - Error seems to occur at a different phase (possibly `tool-call` or initial state creation) - The union schema expects either `{state: {input: record}}` or `{part, delta}` but receives neither ## Expected Behavior MCP tools should work the same as they do in Gemini CLI. ## Related - #9666 (original issue) - #9667 (partial fix)
Author
Owner

@github-actions[bot] commented on GitHub (Jan 21, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #9020: Claude models fail on MCP tools with no required parameters (undefined vs {}) - Same invalid_union error on state.input with undefined parameters
  • #9666: MCP tool results fail schema validation when input is undefined - Original related issue that PR #9667 partially addressed
  • #8102: MCP Tool JSON Parsing Errors on OpenCode (GLM-4.7) - Similar MCP tool execution failures with notebooklm-mcp
  • #9594: Opencode crashes after couple of tool call by the AI - Possible consequence of the same validation issue

The error pattern suggests the issue may extend beyond tool-result/tool-error events to earlier phases of tool call handling, particularly when MCP tools receive undefined arguments from Claude models.

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Jan 21, 2026): This issue might be a duplicate of existing issues. Please check: - #9020: Claude models fail on MCP tools with no required parameters (undefined vs {}) - Same invalid_union error on state.input with undefined parameters - #9666: MCP tool results fail schema validation when input is undefined - Original related issue that PR #9667 partially addressed - #8102: MCP Tool JSON Parsing Errors on OpenCode (GLM-4.7) - Similar MCP tool execution failures with notebooklm-mcp - #9594: Opencode crashes after couple of tool call by the AI - Possible consequence of the same validation issue The error pattern suggests the issue may extend beyond tool-result/tool-error events to earlier phases of tool call handling, particularly when MCP tools receive undefined arguments from Claude models. Feel free to ignore if none of these address your specific case.
Author
Owner

@nghyane commented on GitHub (Jan 21, 2026):

Root Cause Found

After investigation, the error undefined is not an object (evaluating 'toolCall.input.trim') comes from AI SDK (ai@5.0.119), not opencode directly.

Location

node_modules/ai/dist/index.js line 2004:

const parseResult = toolCall.input.trim() === "" ? ...

Why it fails

  • MCP spec uses arguments field for tool calls, not input
  • When MCP tools have no arguments (e.g., notebook_list), toolCall.input is undefined
  • AI SDK calls .trim() on undefined → crash

MCP Spec Reference (2025-06-18)

{
  "method": "tools/call",
  "params": {
    "name": "notebook_list",
    "arguments": {}  // ← MCP uses "arguments", not "input"
  }
}

Workaround (local patch)

# In AI SDK dist/index.js
sed -i '' 's/toolCall\.input\.trim()/(toolCall.input ?? "").trim()/g' node_modules/ai/dist/index.js

Conclusion

  • notebooklm-mcp: Correct per MCP spec
  • AI SDK (vercel/ai): Bug - assumes input always exists
  • opencode: Schema too strict for state.input (separate issue, PR #9667 partial fix)

Should file upstream issue on vercel/ai repo.

@nghyane commented on GitHub (Jan 21, 2026): ## Root Cause Found After investigation, the error `undefined is not an object (evaluating 'toolCall.input.trim')` comes from **AI SDK** (`ai@5.0.119`), not opencode directly. ### Location `node_modules/ai/dist/index.js` line 2004: ```javascript const parseResult = toolCall.input.trim() === "" ? ... ``` ### Why it fails - MCP spec uses `arguments` field for tool calls, not `input` - When MCP tools have no arguments (e.g., `notebook_list`), `toolCall.input` is `undefined` - AI SDK calls `.trim()` on `undefined` → crash ### MCP Spec Reference (2025-06-18) ```json { "method": "tools/call", "params": { "name": "notebook_list", "arguments": {} // ← MCP uses "arguments", not "input" } } ``` ### Workaround (local patch) ```bash # In AI SDK dist/index.js sed -i '' 's/toolCall\.input\.trim()/(toolCall.input ?? "").trim()/g' node_modules/ai/dist/index.js ``` ### Conclusion - **notebooklm-mcp**: ✅ Correct per MCP spec - **AI SDK (vercel/ai)**: ❌ Bug - assumes `input` always exists - **opencode**: ❌ Schema too strict for `state.input` (separate issue, PR #9667 partial fix) Should file upstream issue on `vercel/ai` repo.
Author
Owner

@nghyane commented on GitHub (Jan 21, 2026):

Confirmed Fix

Tested the patch and it works. notebooklm-mcp tools now function correctly with opencode.

Required Changes (2 files)

1. packages/opencode/src/session/message-v2.ts
Make input optional with default in all ToolState schemas:

// ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError
input: z.record(z.string(), z.any()).optional().default({}),

2. AI SDK node_modules/ai/dist/index.js (line ~2004)

// Before:
const parseResult = toolCall.input.trim() === "" ? ...

// After:
const parseResult = (toolCall.input ?? "").trim() === "" ? ...

Note

The AI SDK issue should also be reported upstream to vercel/ai since it's the root cause - MCP spec uses arguments field, and when tools have no args, toolCall.input is undefined.

@nghyane commented on GitHub (Jan 21, 2026): ## ✅ Confirmed Fix Tested the patch and it **works**. notebooklm-mcp tools now function correctly with opencode. ### Required Changes (2 files) **1. `packages/opencode/src/session/message-v2.ts`** Make `input` optional with default in all ToolState schemas: ```typescript // ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError input: z.record(z.string(), z.any()).optional().default({}), ``` **2. AI SDK `node_modules/ai/dist/index.js` (line ~2004)** ```javascript // Before: const parseResult = toolCall.input.trim() === "" ? ... // After: const parseResult = (toolCall.input ?? "").trim() === "" ? ... ``` ### Note The AI SDK issue should also be reported upstream to `vercel/ai` since it's the root cause - MCP spec uses `arguments` field, and when tools have no args, `toolCall.input` is `undefined`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#7085