AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

MCPAdapter Resume Fails When Server Generates New Elicitation Key Per Initial Call

When a LangGraph interrupt occurs in an MCP tool call that returns InputRequiredResult, resuming the graph causes MCPAdapter to issue a fresh initial tool call without the original request_state. If the server generates a new input-request key for each initial call, the adapter validates the saved answer against the new key and raises ValueError before sending the answer to the server.

highConfidence 95%LangchainAffected Vlangchain==1.4.0Affected Vlangchain-Core==1.6.2Affected Vlanggraph==1.2.11

Origin Analysis

MCPAdapter's _call_tool_with_interrupts does not preserve the original request_state across interrupts. On resume, it re-invokes the tool as a new initial call (without request_state), obtaining a new InputRequiredResult with potentially different keys. The saved LangGraph resume value (carrying responses for the original keys) is then matched against the new keys, leading to a key mismatch and error.
1. Create a FastMCP server with a tool that returns InputRequiredResult, generating a new request key each time it is called without request_state (e.g., key = f'question-{sequence}' when fresh=True). 2. Wrap the server with MCPAdapter and list tools. 3. Build a LangGraph StateGraph with a ToolNode using the adapter's tools, compile with InMemorySaver. 4. Invoke the graph with a tool call that triggers the interruption (initial call returns InputRequiredResult). 5. Resume the graph with Command(resume={'responses': {original_key: ElicitResult(action='accept', content={'yes': True})}}). 6. Observe ValueError: "Resuming the MCP tool 'confirm' needs an answer for every elicitation request, but these had none: question-<new_key>."

Fixing Code Block

Edge Case Audit

This patch assumes that the resume_data is correctly propagated from LangGraph's Command(resume=...) into the tool invocation. Multi-threaded or concurrent graph executions must ensure that resume_data is scoped per thread/run, not stored globally, to avoid cross-talk. Rollback recommendation: if issues arise, revert to the original MCPAdapter and use servers that generate stable keys per tool call. The patch relies on the MCP Python SDK's call_tool supporting request_state and input_responses; older SDK versions may lack these parameters, causing breakage. Test thoroughly with multi-round elicitation scenarios and reconstructed agent processes to confirm state preservation.

Ecosystem Topology