Skip to content

fix(mcp): send empty object instead of nil arguments in CallTool#2460

Open
alexrexby wants to merge 1 commit intosipeed:mainfrom
alexrexby:fix-mcp-nil-args
Open

fix(mcp): send empty object instead of nil arguments in CallTool#2460
alexrexby wants to merge 1 commit intosipeed:mainfrom
alexrexby:fix-mcp-nil-args

Conversation

@alexrexby
Copy link
Copy Markdown

Problem

MCP servers built on the official TypeScript SDK validate tool call arguments with Zod. When PicoClaw invokes a tool that has no required parameters, it currently passes a nil map[string]any to mcp.CallToolParams.Arguments, which the Go SDK serializes as JSON null. Zod-based servers reject this with:

```
expected record, received null
path: params.arguments
```

The most prominent affected server is @playwright/mcp, which makes every parameter-less browser tool unusable from PicoClaw — browser_snapshot, browser_take_screenshot, browser_tabs, etc. all fail immediately on first call.

Reproduction

  1. Add a Playwright MCP server to `config.json`:
    ```json
    "tools": {
    "mcp": {
    "enabled": true,
    "servers": {
    "playwright": {
    "enabled": true,
    "command": "npx",
    "args": ["-y", "@playwright/mcp@latest", "--headless"]
    }
    }
    }
    }
    ```
  2. Ask the agent: "Open example.com and tell me the page title"
  3. Agent calls `browser_navigate` (works), then `browser_snapshot` → fails with the Zod error above.

Fix

Normalize a nil arguments map to an empty map before constructing `CallToolParams`. JSON marshalling then produces `{}` instead of `null`, which Zod accepts.

Six lines, no behaviour change for tools that already pass non-nil arguments.

Verified

End-to-end against `@playwright/mcp@latest` running headless Chromium inside the launcher Docker image. `browser_navigate` + `browser_snapshot` now succeed and the agent returns the page title in 6-7 seconds.

Happy to add a unit test in `pkg/mcp/manager_test.go` if maintainers want it — just say the word.

MCP servers built on the Zod-based TypeScript SDK (notably
@playwright/mcp) reject `arguments: null` with
"expected record, received null" when a tool has no required parameters.
The Go SDK happily forwards a nil map as JSON null, which breaks every
parameter-less browser_* tool from Playwright MCP.

Always normalize a nil arguments map to an empty map before building
CallToolParams. Verified end-to-end against @playwright/mcp@latest
running headless Chromium inside the launcher Docker image —
browser_navigate + browser_snapshot now succeed instead of erroring out.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Alex seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@sipeed-bot sipeed-bot bot added type: bug Something isn't working domain: tool go Pull requests that update go code labels Apr 9, 2026
Copy link
Copy Markdown
Collaborator

@afjcjsbx afjcjsbx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi, good catch! thanks for the fix, would you add also a unit test? 🙏

stpwin added a commit to stpwin/picoclaw that referenced this pull request Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: tool go Pull requests that update go code type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants