OpenHands / OpenHands/software-agent-sdk

MCP server connection failure at startup aborts the whole conversation (should degrade, not 500)

Open
#4,454 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug mcp priority:medium release-note-required
Dominant language
Python
Stars
1.1k
Forks
539
Avg merge
1d 19h
Merged PRs (30d)
137

Description

Summary

If an MCP server is unreachable when a conversation starts, the entire conversation creation fails with a 500 (MCPError: MCP Connection Failure). A single bad/unreachable MCP server takes down the whole conversation instead of the agent starting normally without that server's tools.

MCP servers are optional, best-effort tool sources. A failure to connect to one at startup should be reported (logged / surfaced as a non-fatal warning) and skipped, letting the conversation start with the tools that did load — not abort the conversation.

Observed behavior

Starting a new conversation whose agent has an MCP server that can't be reached returns HTTP 500:

POST /api/conversations -> 500
{"detail":"Internal Server Error","exception":"MCP Connection Failure","error_id":"…",
 "traceback":"… openhands/sdk/mcp/client.py, line 105, in sync_close … "}

Reproduced in Agent Canvas: a new conversation with an agent profile whose skills/config pull in an MCP server that isn't reachable fails at creation. (Notably, ACP agents forward MCP to the subprocess and are more tolerant, so the same MCP being down only breaks the SDK-native agent path — the conversation never starts.)

Root cause (code)

create_mcp_tools() builds a single MCPClient for all configured servers and connects eagerly during agent initialization. Any connection error propagates and aborts creation:

  • openhands-sdk/openhands/sdk/mcp/client.pyMCPClient.connect() wraps a failed __aenter__ and raises:
    async def connect(self) -> None:
        try:
            await self.__aenter__()
        except RuntimeError as exc:
            raise MCPError("MCP Connection Failure") from exc
    
  • openhands-sdk/openhands/sdk/mcp/utils.pycreate_mcp_tools() runs _connect_and_list_tools and re-raises on timeout (MCPTimeoutError) or any BaseException after closing the client. There is no per-server isolation: one failing server fails the whole call.
  • This propagates up through the agent's _initialize() (openhands-sdk/openhands/sdk/agent/base.py) into conversation start, so the API returns 500 and no conversation is created.

The sync_close/anyio frames people see in the traceback are the cleanup after the initial connect already failed — not the root cause.

Expected behavior

A startup MCP connection/timeout failure should be non-fatal:

  • Log a clear warning naming the server(s) that failed and why.
  • Start the conversation with the tools from the servers that connected (and none, if all failed).
  • Optionally surface the failure to the client as a warning/notice rather than a 500, so the UI can show "MCP server X unavailable" without blocking work.

In other words: treat MCP servers as best-effort. A dead MCP server should degrade the toolset, not kill the conversation.

Suggested direction (non-prescriptive)
  • Connect servers independently (or catch per server) so one failure doesn't abort the rest.
  • In create_mcp_tools() / the provider path, catch connect/timeout errors per server, log them, and return a client with whatever tools succeeded.
  • Keep a strict/opt-in mode for callers who do want a hard failure when a required MCP server is down (e.g. a strict= flag), but default to tolerant.
Environment
  • openhands-agent-server / openhands-sdk 1.40.1 (release), reproduced independently of any local branch.
  • macOS, Agent Canvas backend (SDK-native agent profile).
Notes

Reported by a user via Agent Canvas; confirmed it reproduces on the released build (not tied to any in-flight PR).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read openhands-sdk/openhands/sdk/mcp/utils.py and client.py, then trace create_mcp_tools() through agent/base.py during conversation creation. Reproduce the unreachable-server POST scenario and verify that failed servers are warned about, successful tools remain available, and the conversation starts without a 500.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.