Tool-Calling LLM Agents Under Realistic MCP Faults: Scale Does Not Purchase Fault Tolerance
Organizations: SnT, University of Luxembourg · Tilburg University · Gran Sasso Science Institute · University of Naples Federico II
Abstract
LLM agents increasingly rely on external tools exposed via the Model Context Protocol (MCP), yet current benchmarks assume tools respond correctly and on time, leaving agent resilience to realistic tool failures untested. We introduce MCP-Injector, a drop-in, protocol-aware fault-injection middleware that interposes on the MCP tool-call path with controlled persistence (permanent, transient, intermittent) and seedable schedules. Its fault model is calibrated to the observed incident distribution (failure mode x persistence) of the public MCP ecosystem, mined from 57,240 issue and pull-request threads across 1,774 open-source MCP repositories. In a 1,350-cell experiment crossing two backbone sizes (20B, 120B), three agent stacks (custom multi-round plan-and-execute, OpenAI Agents SDK, LangChain), and three fault injection conditions, we find that faults drawn from this permanent-heavy stress profile cause severe quality degradation (task-completion score falls by 60%, from 8.08 to 3.23 out of 10), and that scale does not purchase fault tolerance for the two gpt-oss backbones we test: the 120B retains no larger share of its fault-free score under faults (resilience-ratio model, ), and its completion rate under faults is, if anything, lower (91.1% vs. 95.6%; difference 4.4 points, 95% CI ). Agent stacks differ in how well they absorb faults, which suggests that framework-level error handling matters more than model scale. These results demonstrate that capability benchmarks alone can mask operational brittleness, motivating protocol-aware fault injection as a complementary evaluation dimension for tool-calling agents.
Figures & tables
| ID | Operator | Class | Effect |
|---|---|---|---|
| OP0 | Null injector | n/a | Passthrough (no mutation) |
| OP1 | Minor mistake | Content | Random character replacement |
| OP2 | Incorrect output | Content | Word-level substitution |
| OP3 | Invalid output | Content | Type coercion (e.g., str int) |
| OP4 | Explicit error | Content | Returns MCP error message |
| OP5 | Delayed response | Timing | Artificial sleep before return |
| Failure Mode | Interm. | Perm. | Trans. | Uncert. | Total |
|---|---|---|---|---|---|
| DELAYED_RESPONSE | 51 | 157 | 1 | 24 | 233 |
| EXPLICIT_ERROR | 669 | 9,075 | 97 | 552 | 10,393 |
| INCORRECT_OUTPUT | 155 | 1,733 | 1 | 50 | 1,939 |
| INVALID_OUTPUT | 47 | 511 | 1 | 25 | 584 |
| MINOR_MISTAKE | 15 | 177 | 0 | 10 | 202 |
| SILENT_DROP | 167 | 963 | 4 | 83 | 1,217 |
Appendix figures & tables9 assets
Supplementary material from the paper’s appendix.
Appendix
| Operator (mode) | Persistence | Count | prob. | act. p | Derivation of act. p |
|---|---|---|---|---|---|
| OP5 (DELAYED_RESPONSE) | INTERMITTENT | 51 | 0.0037 | 0.0975 | |
| PERMANENT | 157 | 0.0114 | n/a | n/a | |
| TRANSIENT | 1 | 0.0001 | 1.0 | fixed | |
| OP4 (EXPLICIT_ERROR) | INTERMITTENT | 669 | 0.0484 | 0.0221 | |
| PERMANENT | 9075 | 0.6565 | n/a | n/a | |
| TRANSIENT | 97 | 0.0070 | 1.0 | fixed |
| Model | Stack | Proxy-off | OP0 | OPP |
|---|---|---|---|---|
| 20b | LangChain | 100.0 [95.1, 100.0] | 100.0 [95.1, 100.0] | 97.3 [90.8, 99.3] |
| MCPBench | 100.0 [95.1, 100.0] | 100.0 [95.1, 100.0] | 94.7 [87.1, 97.9] | |
| OpenAI | 96.0 [88.9, 98.6] | 97.3 [90.8, 99.3] | 94.7 [87.1, 97.9] | |
| Pooled | 98.7 [96.2, 99.5] | 99.1 [96.8, 99.8] | 95.6 [92.0, 97.6] | |
| 120b | LangChain | 94.7 [87.1, 97.9] | 96.0 [88.9, 98.6] | 94.7 [87.1, 97.9] |
| MCPBench | 100.0 [95.1, 100.0] | 100.0 [95.1, 100.0] | 90.7 [82.0, 95.4] |
| Metric | OP0 | OPP | % Drop | |
|---|---|---|---|---|
| Task completion | 8.08 | 3.23 | 4.85 | 60 |
| Tool selection | 8.10 | 3.36 | 4.74 | 59 |
| Planning eff. | 7.51 | 2.49 | 5.02 | 67 |
| Task fulfillment | 8.07 | 3.37 | 4.70 | 58 |
| Grounded fulfillment † | 7.70 | 2.83 | 4.87 | 63 |
| Grounding | 8.09 | 3.10 | 5.00 | 62 |
| MCPBench | OpenAI (Agents SDK) | LangChain ( create_agent ) | |
|---|---|---|---|
| Orchestration pattern | Multi-round plan-and-execute with JSON planner output | Single message loop with native function calling | ReAct state graph on LangGraph (agent/tools nodes) |
| Tool invocation | Structured JSON prompt ( planned_tools list) | Native function calling ( tool_choice required) | Native tool calling on ChatOpenAI |
| Parallel tool calls | Explicit per-round, per-server semaphore | SDK-level fan-out | asyncio.gather in ToolNode |
| Tool-error handling | Error text added to accumulated information buffer | Returned as isError tool result | Caught by middleware, returned as tool message |
| Tool-call retry policy | LLM decides (next round) | LLM decides (next turn) | LLM decides (next agent step) |
| Stop decision | Explicit should_continue Boolean per round | Implicit (assistant message with no tool calls) | Implicit (AIMessage with no tool calls) |
LLM Agent Reliability
Large language model (LLM) agent reliability concerns dependable, safe, and verifiable behavior across tools, multi-step tasks, and changing environments.
See all 826 papers