Most MCP examples focus on successful tool calls. That is useful for getting started, but production systems also need to handle calls that stall, exceed their timeout, get cancelled, or lose their connection.
I started building MCP Failure Lab to make those failure paths controlled, repeatable, and easier to test.
What is MCP Failure Lab?
MCP Failure Lab is an open-source TypeScript toolkit for testing how MCP clients and related systems respond to failure conditions.
The project currently includes:
- Deterministic
delay,hang, anddisconnectfault tools - A TypeScript CLI and stdio MCP server
- A code-first scenario runner
- Success, error, timeout, and duration assertions
- Unit and integration tests
- CI, coverage, dependency, and security checks
Instead of relying on unreliable network conditions or arbitrary sleeps, the goal is to provide explicit failure behavior that can be reproduced in a test suite.
Why build this?
A successful tool call only proves the happy path.
It does not tell us whether a client:
- Enforces request timeouts
- Cancels work correctly
- Cleans up resources after failure
- Distinguishes tool errors from transport failures
- Recovers after a connection is interrupted
- Produces useful diagnostic information
These behaviors become increasingly important as MCP integrations move beyond local experiments.
Current architecture
Fault tools are registered directly on an MCP server. Tests connect through MCP transports and exercise the same protocol path used by real tool calls.
The scenario runner adds a small testing layer around those calls. A scenario describes:
- Which tool to call
- Which arguments to provide
- The request timeout
- The expected outcome
- Optional duration limits
The runner records the observed result and evaluates the configured assertions.
This keeps the project code-first, type-safe, and suitable for existing TypeScript test suites.
What comes next?
The project is still early, and there are several areas where contributions would be valuable:
- Add end-to-end CLI coverage
- Add structured scenario reports
- Define a target-client adapter contract
- Add Streamable HTTP support
Each issue includes its expected behavior, acceptance criteria, limitations, and relevant files.
Before starting substantial work, please comment on the issue with your proposed approach and ask to be assigned. This helps avoid duplicated work and gives us a place to discuss the design first.
Contributions are welcome
If you work with MCP, TypeScript, resilience testing, or developer tooling, I would value your feedback.
You can contribute code, review the design, improve documentation, test the project, or suggest failure modes that are worth supporting.
MCP Failure Lab is available on GitHub:
https://github.com/anilloutombam/mcp-failure-lab
If the project is useful to you, consider starring it, opening a discussion, or picking up one of the contributor-ready issues. I would be glad to build it with others.
Top comments (1)
This is a useful project because deterministic fault injection makes resilience behavior reviewable instead of anecdotal. The failure mode I would add first is ambiguous completion: the server finishes a side effect, but the response is dropped or the client times out just before receiving it. A retry can then duplicate the mutation even though both client and server behaved “correctly.”
That scenario needs assertions beyond outcome and duration: whether cancellation reached the handler, whether work continued after cancellation, how many side effects occurred, and whether retrying with the same operation ID converged on one result. A small fake ledger exposed by the lab would let tests assert those invariants.
For Streamable HTTP, I would also vary failure position: before headers, mid-SSE frame, after a complete response but before connection close, and during session resumption. Add concurrency and backpressure cases too—a hung request should not starve unrelated calls. The best report would show protocol events and application side effects on one timeline, which makes “timeout” much less ambiguous.