Metadata-Version: 2.4
Name: mcp-retry
Version: 0.1.0
Summary: Unified retry/backoff decorators for MCP servers - tenacity presets for httpx/requests API calls
Project-URL: Homepage, https://github.com/Buer2333/mcp-retry
Project-URL: Repository, https://github.com/Buer2333/mcp-retry
Project-URL: Bug Tracker, https://github.com/Buer2333/mcp-retry/issues
Author-email: Buer2333 <13869438+Buer2333@users.noreply.github.com>
License: MIT
License-File: LICENSE
Keywords: backoff,httpx,mcp,model-context-protocol,retry,tenacity
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: tenacity>=8.2.0
Provides-Extra: dev
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: requests>=2.28.0; extra == 'dev'
Provides-Extra: httpx
Requires-Dist: httpx>=0.27.0; extra == 'httpx'
Provides-Extra: requests
Requires-Dist: requests>=2.28.0; extra == 'requests'
Description-Content-Type: text/markdown

# mcp-retry

Tiny, opinionated retry/backoff decorators for [MCP](https://modelcontextprotocol.io) servers and other API clients. A thin preset layer over [tenacity](https://github.com/jd/tenacity): exponential backoff + jitter, retry on 429/5xx/network errors, log before each retry, re-raise on exhaustion.

Extracted from a fleet of production MCP servers (TikTok Shop, TikTok Ads, and others) so every server retries the same way instead of re-implementing tenacity incantations.

## Install

```bash
pip install mcp-retry            # core (tenacity only)
pip install "mcp-retry[httpx]"   # + httpx preset
```

## Usage

### httpx-based MCP servers (async)

```python
from mcp_retry import httpx_retry

@httpx_retry()
async def _do_request(self, url):
    response = await client.get(url)
    if response.status_code == 429 or response.status_code >= 500:
        response.raise_for_status()  # triggers retry
    return response
```

Retries on `httpx.RequestError` (connection errors, timeouts, DNS failures) and `httpx.HTTPStatusError`. Only call `raise_for_status()` for status codes you *want* retried (429/5xx) — 4xx client errors should surface immediately.

### requests-based projects (sync)

```python
from mcp_retry import requests_retry

@requests_retry()
def fetch(url):
    r = requests.get(url)
    if r.status_code == 429 or r.status_code >= 500:
        r.raise_for_status()
    return r
```

### Custom exceptions / tuning

```python
from mcp_retry import api_retry

@api_retry(max_attempts=5, min_wait=2, retryable_exceptions=(MyTransientError,))
def fragile_call():
    ...
```

Defaults: 3 attempts, exponential wait 1–30 s plus 0–2 s random jitter, warning-level log before each sleep, `reraise=True`.

## Why not just tenacity?

You should use tenacity — this *is* tenacity. `mcp-retry` just freezes one sane configuration (and the httpx/requests exception sets) behind a one-line decorator, so a dozen MCP servers stay consistent and a retry-policy change is a single-package bump instead of a dozen edits.

## License

[MIT](LICENSE)
