Skip to content

ACP session/new fails when agent requires mcpServers: empty list coerced to None and dropped #38

Description

@frankliu7

Summary

session/new fails with Invalid params for any ACP agent whose schema requires mcpServers to be present, because an empty MCP server list is coerced to None and then dropped during serialization.

Hit this trying to run Devin CLI (devin acp) as a provider: custom ACP agent. Every run fails at pool init.

Reproduce

# agents.yml
agents:
  devin:
    type: acp
    provider: custom
    command: devin
    args: ["acp"]
    auto_approve: true
$ agentpool run devin "hello" --config agents.yml
...
  File ".../acp/client/connection.py", line 104, in new_session
    resp = await self._conn.send_request("session/new", dct)
acp.exceptions.RequestError: Invalid params
Error: Failed to initialize agent pool

Probing devin acp directly with raw JSON-RPC shows what the agent actually wants:

// params: {"cwd": "/tmp/x"}
{"error": {"code": -32602, "message": "Invalid params",
           "data": {"error": "missing field `mcpServers`",
                    "json": {"cwd": "/tmp/x"}, "phase": "deserialization"}}}

// params: {"cwd": "/tmp/x", "mcpServers": []}   → succeeds, session created

So the field must be present as an empty array; it may not be omitted.

Root cause

src/acp/agent/acp_agent_api.py coerces an empty sequence to None:

# line 97 (new_session) and line 113 (load_session)
mcp_servers=list(mcp_servers) if mcp_servers else None,

[] is falsy, so it becomes None. connection.new_session() then serializes with
exclude_none=True, which drops mcpServers entirely — producing a request the agent rejects.

Because line 113 has the same expression, session/load is affected too, so session resume
would fail against the same agents.

Fix

Distinguish "no list supplied" from "empty list":

mcp_servers=list(mcp_servers) if mcp_servers is not None else [],

Verified: patching line 97 alone makes it work end to end —

$ agentpool run devin "Reply with exactly: ACP-FIX-ALONE-OK and nothing else." --config agents.yml
devin: ACP-FIX-ALONE-OK

Related, but not required

src/agentpool/agents/acp_agent/acp_agent.py lines 375 and 698 pass mcp_servers or None,
which has the same empty-list-to-None intent. I tested reverting those to the original
or None while keeping only the acp_agent_api.py fix, and it still works — so they're
harmless once the API layer is correct. You may still want them for clarity.

Why it may be worth fixing beyond my case

ACP leaves mcpServers optionality to the agent, and agents disagree: some accept omission,
some require an empty array, and at least one other client codebase I looked at documents an
agent that rejects any entry in the list but accepts []. Sending [] rather than omitting
satisfies all three shapes, so it looks strictly safer than the current behaviour.

Environment

agentpool 2.9.18 (PyPI)
Python 3.14.6
OS macOS (darwin arm64)
agent Devin CLI 3000.2.17, devin acp

Happy to open a PR with the one-line change if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions