Skip to main content

MCP-Rescue

A lightweight semantic recovery layer for MCP tool failures.

MCP-Rescue turns MCP tool errors into structured recovery decisions. It combines error classification with tool metadata so an agent or runtime can decide whether to retry, repair arguments, ask the user, or stop.

Why MCP-Rescue?

Same error, different tool semantics, different recovery decisions.

Both of these tools can fail with connection timeout, but retrying them has different consequences:

Tool Read-only Idempotent Destructive Recovery decision
get_weather True True False RETRY
send_email False False False ASK_USER

Retrying a weather query is usually safe. Retrying an email operation after a timeout may send the same email twice: the original request might have succeeded before the connection failed.

MCP-Rescue makes that distinction explicit and returns a decision your runtime can enforce.

Local setup

Use Python 3.10 or later. The current development environment uses Python 3.14.3 and mcp==2.2.0.

From the repository root, create a virtual environment:

python -m venv .venv

Activate it on macOS or Linux:

source .venv/bin/activate

Or on Windows PowerShell:

.\.venv\Scripts\Activate.ps1

Install the MCP dependency and test runner:

python -m pip install "mcp==2.2.0" pytest

Run the examples and commands below from the repository root.

Quick start

This example uses a sample failed MCP result and runs without an MCP server or an API key:

from mcp.types import CallToolResult, TextContent

from mcp_rescue.api import rescue_mcp_result
from mcp_rescue.models import ToolInfo
from mcp_rescue.runtime import allow_automatic_retry


tool = ToolInfo(
    name="get_weather",
    read_only=True,
    idempotent=True,
    destructive=False,
)

result = CallToolResult(
    is_error=True,
    content=[TextContent(type="text", text="connection timeout")],
)

if result.is_error:
    rescued = rescue_mcp_result(result, tool)

    print(rescued.category)
    print(rescued.action)
    print(rescued.retryable)

    if allow_automatic_retry(rescued):
        print("Automatic retry is allowed.")

Output:

ErrorCategory.TRANSIENT_NETWORK
RecoveryAction.RETRY
True
Automatic retry is allowed.

For an actual tool call, use the same error check inside your async code with an initialized MCP client:

result = await mcp_client.call_tool("get_weather", {})

if result.is_error:
    rescued = rescue_mcp_result(result, tool)
    automatic_retry_allowed = allow_automatic_retry(rescued)
    # Let your runtime handle the decision and enforce retry limits.

rescue_mcp_result() handles failed results only. Passing a successful result raises ValueError. The current adapter expects the is_error attribute used by the MCP dependency above and reads the first text content block.

For error strings, exceptions, or dictionaries, use the lower-level API:

from mcp_rescue.classifier import rescue_error

rescued = rescue_error("connection timeout", tool)

How it works

Agent / LLM
    |
    v
MCP client -> MCP tool -> Failed result
                              |
                              v
                         MCP-Rescue
                         1. Parse the error
                         2. Normalize and classify
                         3. Decide recovery using the error and tool metadata
                              |
                              v
                         RescueError
                              |
                              v
                         Agent / Runtime

Each RescueError contains:

Field Meaning
category What kind of failure occurred.
action What the caller should do next.
retryable Whether the current policy permits a retry.
message The error text used for classification.
confidence A rule-match score: currently 1.0 for a match and 0.0 for an unknown error.

Classification currently uses deterministic message-matching rules and requires no LLM call. The runtime remains responsible for executing recovery actions, enforcing retry limits, and choosing backoff delays.

Recovery decisions

The current policy maps recognized errors as follows:

Error category Example message Recovery action Retryable
RATE_LIMIT 429 Too Many Requests BACKOFF True
INVALID_ARGUMENT Invalid argument REPAIR_ARGUMENTS False
AUTHENTICATION 401 Unauthorized REAUTHENTICATE False
PERMISSION 403 Forbidden STOP False
NOT_FOUND 404 Not Found STOP False
TRANSIENT_NETWORK connection timeout RETRY or ASK_USER Depends on tool metadata
UPSTREAM_UNAVAILABLE 503 Service Unavailable BACKOFF True
BUSINESS_RULE Booking date must be in the future ASK_USER False
UNKNOWN An unrecognized error message STOP False

REPLAN is also defined in RecoveryAction, but the current policy does not emit it. Business-rule detection currently recognizes the booking message shown above; additional domain rules require extending the normalizer.

Tool-aware retry safety

For TRANSIENT_NETWORK errors, MCP-Rescue checks the caller-supplied ToolInfo:

  • Missing metadata or a destructive tool produces ASK_USER with retryable=False.
  • A non-destructive tool that is read-only or idempotent produces RETRY with retryable=True.
  • Other tools produce ASK_USER with retryable=False.

For example, the same timeout with this metadata requires user input:

email_tool = ToolInfo(
    name="send_email",
    read_only=False,
    idempotent=False,
    destructive=False,
)

rescued = rescue_error("connection timeout", email_tool)
print(rescued.action)     # RecoveryAction.ASK_USER
print(rescued.retryable)  # False

allow_automatic_retry(rescued) returns True only when retryable=True and the action is RETRY or BACKOFF. It checks the decision; it does not execute a retry or independently inspect the tool.

Current policy limit: tool metadata affects transient network errors only. RATE_LIMIT and UPSTREAM_UNAVAILABLE currently produce retryable BACKOFF decisions regardless of tool metadata. Runtimes handling side effects should apply their own safety checks to those decisions.

Agent integration

The Qwen demo connects Qwen to the local MCP demo server, classifies a failed booking call, and returns a recovery report to the model:

User requests booking(date="2026-01-01")
    -> Qwen requests the booking tool
    -> MCP demo server raises "Booking date must be in the future"
    -> MCP-Rescue returns BUSINESS_RULE / ASK_USER / retryable=False
    -> Qwen receives the recovery report and can ask for a future date

The server deliberately rejects that fixed date to demonstrate a business-rule failure.

To run the demo, install the additional dependency:

python -m pip install "openai==3.13.0"

Set DASHSCOPE_API_KEY in your environment, then run from the repository root:

python -m examples.qwen_mcp_demo

This demo makes live Qwen API calls. It shows the first tool call, the recovery report, and the model's follow-up response; it does not implement a full recovery loop.

Project structure

mcp_rescue/
|-- api.py           # Public MCP result entry point
|-- models.py        # Error categories, actions, and tool metadata
|-- parser.py        # Convert error inputs into RawError
|-- normalizer.py    # Classify error messages
|-- decision.py      # Choose recovery actions
|-- classifier.py    # Compose parsing, normalization, and decisions
|-- runtime.py       # Check whether a decision allows automatic retry
+-- adapters/
    +-- mcp.py       # Extract error text from failed MCP results
examples/           # MCP server, clients, and agent demos
tests/              # Unit and pipeline tests

Development

Run the test suite without external API credentials:

python -m pytest tests/ -q

The suite covers parsing, normalization, recovery decisions, tool-aware retry safety, runtime gating, MCP result adaptation, and the public API. Specifying tests/ excludes live API example scripts from test discovery.

Project status

MCP-Rescue is an early-stage project focused on error normalization, structured recovery decisions, and agent integration. MCP-Rescue is currently preparing for its first v0.1.0 release.

Metadata

Release files for mcp-rescue 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-rescue 0.1.0
File Size Uploaded Provenance Actions
mcp_rescue-0.1.0.tar.gz 15.4 kB Without provenance Details for mcp_rescue-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mcp-rescue 0.1.0
File Interpreter ABI Platform Actions
mcp_rescue-0.1.0-py3-none-any.whl Python 3 none any Details for mcp_rescue-0.1.0-py3-none-any.whl

Total release size: 26.1 kB

Release files / mcp_rescue-0.1.0.tar.gz

Download URL mcp_rescue-0.1.0.tar.gz
Size 15.4 kB
Tags Source
SHA-256 checksum
How to use checksums
0ceb708194e5171474c747e548e8f7fd9bf715d21dd1a6444d28b440b09dcbd5
BLAKE2b-256 checksum
How to use checksums
e65616698d9e21e9ad632f32c830c4a6bb57b0401fa3dac06cfb97eb46629418
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / mcp_rescue-0.1.0-py3-none-any.whl

Download URL mcp_rescue-0.1.0-py3-none-any.whl
Size 10.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74671f5b97bb9ed137ad4068fbbbded2519b0e7c223500eea73069a0e3b22188
BLAKE2b-256 checksum
How to use checksums
6bae2ba3adc023e9cf6f7949e615c64130ad4acdae3a0e344c64e223855e09f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Security for mcp-rescue 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page