Metadata-Version: 2.4
Name: mcp-warden
Version: 0.1.3
Summary: MCP observability and control plane — audit logging, rate limiting, circuit breaker for any MCP server
Project-URL: Homepage, https://github.com/raj8github/mcp-warden
Project-URL: Repository, https://github.com/raj8github/mcp-warden
Project-URL: Issues, https://github.com/raj8github/mcp-warden/issues
Project-URL: Docs, https://github.com/raj8github/mcp-warden#readme
Project-URL: Changelog, https://github.com/raj8github/mcp-warden/releases
Author: Raj Shashi
License: MIT License
        
        Copyright (c) 2025 Raj Shashi
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: agent,ai,audit,claude,guardrail,llm,mcp,observability,proxy,rate-limit
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Logging
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.3; extra == 'dev'
Description-Content-Type: text/markdown

# 👁️ mcp-warden

**MCP observability and control plane.**

```bash
pip install mcp-warden

mcp-warden audit -- your-mcp-server [args...]
mcp-warden guard --max-calls-per-minute 30 --block-tool write_query -- any-mcp-server
mcp-warden both  --max-calls-per-minute 60 --max-response-kb 512 -- any-mcp-server
mcp-warden log   --tail 20
```

[![PyPI version](https://img.shields.io/pypi/v/mcp-warden.svg)](https://pypi.org/project/mcp-warden/)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![CI](https://github.com/raj8github/mcp-warden/actions/workflows/ci.yml/badge.svg)](https://github.com/raj8github/mcp-warden/actions)
[![Zero dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)]()

---

## The problem

MCP clients like Cline and Claude Desktop can call tools on any connected server with no visibility and no throttle.

An agent in a loop can:
- Call `sql_query` hundreds of times a minute, burning your API budget
- Pull back 50 MB of data in a single tool call
- Hit a tool you meant to leave off
- Fail repeatedly and nobody notices until the damage is done

mcp-warden fixes all of this — for **any** MCP server, without touching it.

---

## How it works

```
MCP client (Cline / Claude Desktop)
    │  stdin/stdout
    ▼
mcp-warden  ◄──── audit + guard
    │  subprocess stdin/stdout
    ▼
Upstream MCP server (any MCP server)
```

mcp-warden is a transparent JSON-RPC relay. The client never knows it's there. The upstream server never knows it's there. Every `tools/call` passes through the audit and guard layer in the middle.

**Latency impact:** ~0.1–0.5 ms per message — negligible against typical LLM tool call round trips of 100 ms to 10 s.

---

## Install

```bash
pip install mcp-warden
```

Zero runtime dependencies. Pure Python 3.9+ stdlib.

---

## Usage

### Audit — log everything

```bash
mcp-warden audit \
  --audit-log ~/.mcp_warden/audit.jsonl \
  --session-id cline \
  -- your-mcp-server [args...]
```

Each line of the JSONL log is a self-contained event:

```json
{"ts":"2025-03-04T10:22:01.234Z","session_id":"cline","direction":"request","msg_id":"1","method":"tools/call","tool":"sql_query","args":{"sql":"SELECT TOP 10 * FROM Product"}}
{"ts":"2025-03-04T10:22:01.376Z","session_id":"cline","direction":"response","msg_id":"1","method":"tools/call","tool":"sql_query","duration_ms":142.3,"content_len":4821,"is_error":false,"error_msg":null}
```

### Guard — rate limits + blocking

```bash
mcp-warden guard \
  --max-calls-per-minute 30 \
  --per-tool-limit sql_query:10 \
  --block-tool write_query \
  --max-response-kb 512 \
  --max-errors 5 \
  -- any-mcp-server
```

When a limit is hit, the agent gets a clear error:

```
Tool 'write_query' is in the blocked list.
Global rate limit reached (30 calls/min). Retry in ~42s.
Response too large (1024.0 KB > 512 KB limit). Consider narrowing your query.
Circuit breaker open — too many consecutive errors. Auto-reset in 58s.
```

### Both — recommended

```bash
mcp-warden both \
  --audit-log ~/.mcp_warden/audit.jsonl \
  --max-calls-per-minute 60 \
  --per-tool-limit sql_query:20 \
  --block-tool write_query \
  --max-response-kb 1024 \
  --max-errors 3 \
  -- your-mcp-server [args...]
```

### View the log

```bash
mcp-warden log --tail 20
mcp-warden log --tail 50 --filter-tool sql_query
mcp-warden log --errors-only
mcp-warden log --json | jq 'select(.is_error == true)'
```

---

## Claude Desktop / Cline setup

Create a wrapper script:

```bash
#!/bin/bash
# ~/.config/mcp_warden/mydb.sh
exec mcp-warden both \
  --audit-log ~/.mcp_warden/mydb.jsonl \
  --max-calls-per-minute 60 \
  --max-response-kb 1024 \
  --max-errors 3 \
  -- /path/to/your-mcp-server.sh
```

Reference it in your MCP config:

```json
{
  "mcpServers": {
    "mydb": { "command": "/Users/you/.config/mcp_warden/mydb.sh" }
  }
}
```

---

## Guard options

| Option | Default | Description |
|--------|---------|-------------|
| `--max-calls-per-minute N` | 0 (off) | Global cap across all tools per 60 s window |
| `--per-tool-limit TOOL:N` | — | Per-tool cap e.g. `sql_query:20` (repeatable) |
| `--block-tool TOOL` | — | Block a tool entirely (repeatable) |
| `--max-response-kb KB` | 0 (off) | Reject responses larger than this |
| `--max-errors N` | 0 (off) | Trip circuit breaker after N consecutive errors |
| `--circuit-cooldown SECS` | 60 | Seconds before circuit auto-resets |

---

## Audit log schema

| Field | Direction | Description |
|-------|-----------|-------------|
| `ts` | all | ISO-8601 UTC timestamp |
| `session_id` | all | Set via `--session-id` |
| `direction` | all | `request`, `response`, or `blocked` |
| `msg_id` | all | JSON-RPC message id |
| `method` | all | e.g. `tools/call`, `tools/list` |
| `tool` | all | Tool name (tools/call only) |
| `args` | request | Tool arguments (truncated at `--max-arg-bytes`) |
| `duration_ms` | response | Round-trip milliseconds |
| `content_len` | response | Response size in bytes |
| `is_error` | response | True if upstream returned an error |
| `error_msg` | response | Error message text |
| `reason` | blocked | Why the request was blocked |

---

## Python API

```python
from mcp_warden import MCPWarden, AuditLogger
from mcp_warden.guard import GuardConfig

proxy = MCPWarden(
    cmd=["your-mcp-server", "--arg", "value"],
    audit_logger=AuditLogger(path="./audit.jsonl", session_id="my-agent"),
    guard_config=GuardConfig(
        max_calls_per_minute=30,
        per_tool_limits={"sql_query": 10},
        blocked_tools=["write_query"],
        max_response_kb=512,
        max_errors_before_circuit_break=3,
    ),
)
proxy.run()
```

---

---

## Roadmap

- [ ] Async audit write queue (decouple disk I/O from relay path)
- [ ] HTTP/SSE transport support
- [ ] Prometheus metrics endpoint
- [ ] Per-session budget and cost tracking
- [ ] Webhook alerts on circuit break / blocked calls
- [ ] Web dashboard for log exploration

---

## Contributing

```bash
git clone https://github.com/raj8github/mcp-warden
cd mcp-warden
pip install -e ".[dev]"
pytest tests/ -v
```

See [CONTRIBUTING.md](CONTRIBUTING.md).

---

## License

MIT — see [LICENSE](LICENSE)
