Skip to content

Duplicate tool names across toolsets cause Anthropic 400 errors #2251

@aheritier

Description

@aheritier

Description

When an agent has multiple toolsets that produce tools with the same name, the Anthropic API rejects the request with HTTP 400: "tools: Tool names must be unique.". There is no deduplication anywhere in the tool collection pipeline.

Issue #1969 fixed this for the specific case of multiple LSP toolsets (via the LSP multiplexer in teamloader.go), but the general problem remains for all other toolset combinations.

Observed in session: cca99566-4277-457a-92fe-cfd877825c0b

Error:

all models failed: error receiving from stream: HTTP 400: POST
"https://ai-backend-service-stage.docker.com/proxy/v1/messages?beta=true": 400
Bad Request {"type":"error","error":{"type":"invalid_request_error",
"message":"tools: Tool names must be unique."}}

Steps to Reproduce

Option 1 — Duplicate built-in toolsets:

agents:
  root:
    model: anthropic/claude-sonnet-4-0
    instruction: You are a helpful assistant.
    toolsets:
      - type: filesystem
      - type: filesystem

Both filesystem toolsets produce identical tool names (read_file, write_file, edit_file, directory_tree, etc.).

Option 2 — Two unnamed MCP servers exposing the same tool names:

agents:
  root:
    model: anthropic/claude-sonnet-4-0
    instruction: You are a helpful assistant.
    toolsets:
      - type: mcp
        command: npx
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
      - type: mcp
        command: npx
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/home"]

Both MCP servers expose identically-named tools and neither has a name prefix configured.

Option 3 — MCP server colliding with a built-in:

agents:
  root:
    model: anthropic/claude-sonnet-4-0
    instruction: You are a helpful assistant.
    toolsets:
      - type: fetch
      - type: mcp
        command: npx
        args: ["-y", "@modelcontextprotocol/server-fetch"]

The built-in fetch toolset and the MCP fetch server both produce a tool named fetch.

Root Cause

Agent.Tools() in pkg/agent/agent.go collects tools from all toolsets via simple append with no deduplication. No downstream code checks for uniqueness either:

  1. Agent.Tools() (pkg/agent/agent.go) — appends from all toolsets, no dedup
  2. getTools() (pkg/runtime/loop.go) — passes tools through as-is
  3. convertTools() (pkg/model/provider/anthropic/client.go) — maps 1:1 to API params, no dedup
  4. Anthropic API rejects the request

Scenarios that produce duplicates

  • Two MCP servers without a name prefix (or with the same prefix) exposing same-named tools
  • An MCP server returning a tool that collides with a built-in name
  • Same toolset type configured twice in agent config
  • Dynamic MCP ToolListChanged notifications adding tools that collide with existing names

Suggested Fix

Add deduplication in Agent.Tools() — the single collection point where all tools converge before being sent to any provider. Keep the first occurrence of each tool name and log a warning for dropped duplicates.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/toolsFor features/issues/fixes related to the usage of built-in and MCP toolskind/bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions