Metadata-Version: 2.4
Name: mcp-parapet
Version: 0.1.0
Summary: Security middleware for MCP servers. Content scanning, integrity verification, trust boundaries, and audit trails.
Project-URL: Homepage, https://github.com/quantifylabs/mcp-parapet
Project-URL: Documentation, https://github.com/quantifylabs/mcp-parapet#readme
Project-URL: Repository, https://github.com/quantifylabs/mcp-parapet
Project-URL: Issues, https://github.com/quantifylabs/mcp-parapet/issues
Author-email: Quantify Labs <hello@quantifylabs.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,content-security,eu-ai-act,mcp,middleware,owasp,prompt-injection,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
Description-Content-Type: text/markdown

# mcp-parapet

**Security middleware for MCP servers.** Content scanning, integrity verification, trust boundaries, and audit trails.

`mcp-parapet` sits between your MCP client (Claude Desktop, Cursor, Cline) and any MCP server. It intercepts every tool call, applies security checks, logs everything, and blocks threats before they reach your server — or your data reaches an untrusted server.

> *mcp-scan tells you what's wrong. mcp-parapet stops it from happening.*

```
Client ↔ [mcp-parapet] ↔ MCP Server
            ↓
      Security Pipeline
      ├─ Content scanning (PII, secrets, prompt injection)
      ├─ Trust boundaries (OWASP 5-tier hierarchy)
      ├─ Rate limiting (per-server, per-tool)
      ├─ Manifest integrity (rug pull detection)
      └─ Audit trail (append-only JSONL)
```

## Install

```bash
pip install mcp-parapet
```

## Quickstart

### Prefix any server command with `mcp-parapet wrap --`. That's it.

Whatever command you use to start your MCP server, put `mcp-parapet wrap --` in front of it. Every tool call now goes through the security pipeline.

```bash
# Before (no security)
npx -y @modelcontextprotocol/server-filesystem /tmp

# After (full security pipeline)
mcp-parapet wrap -- npx -y @modelcontextprotocol/server-filesystem /tmp
```

Works with any MCP server. No code changes. No server modifications.

```bash
# Node-based servers
mcp-parapet wrap -- npx -y @modelcontextprotocol/server-github
mcp-parapet wrap -- npx -y @modelcontextprotocol/server-puppeteer

# Python servers
mcp-parapet wrap -- python my_server.py
mcp-parapet wrap -- uvx my-mcp-package

# Anything that speaks MCP over stdio
mcp-parapet wrap -- ./my-custom-server --port 8080
```

### Use in Claude Desktop

Replace `"command"` with `mcp-parapet` and prepend `"wrap", "--"` to args:

```json
{
  "mcpServers": {
    "filesystem": {
      "command": "mcp-parapet",
      "args": ["wrap", "--name", "filesystem", "--",
               "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    },
    "github": {
      "command": "mcp-parapet",
      "args": ["wrap", "--name", "github", "--",
               "npx", "-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "ghp_..." }
    }
  }
}
```

The `--name` flag tags audit logs and config per server. Optional but recommended.

### Customise (optional)

```bash
# Generate a config file with sensible defaults
mcp-parapet init

# Scan a file or stdin directly
echo "My SSN is 123-45-6789" | mcp-parapet scan -
```

Out of the box, mcp-parapet rejects prompt injection, redacts leaked secrets, and logs every tool call. `parapet.yaml` lets you tune policies, set per-server trust levels, and configure rate limits — but the defaults are production-ready.

## What it does

### Content Scanning (OWASP §3)

Four-stage pipeline scans every tool call argument and response:

| Stage | What it catches | Examples |
|-------|----------------|----------|
| **1. Input validation** | Oversized payloads, null bytes, control chars | DoS via payload inflation |
| **2. Sensitive data** | SSNs, credit cards, API keys, emails, passwords | PII leaking to untrusted servers |
| **3. Prompt injection** | Override attempts, role manipulation, data exfiltration | "Ignore previous instructions..." |
| **4. LLM classification** | *(Coming in v0.2)* Adversarial inputs that bypass regex | Obfuscated injection attacks |

Configurable per-category policies: `flag`, `redact`, or `reject`.

### Trust Boundaries (OWASP §4)

Five-tier trust hierarchy for MCP servers:

| Level | Permissions | Use case |
|-------|------------|----------|
| `none` | Block all tool calls | Unknown/untrusted servers |
| `basic` | Read-only operations | Third-party servers under evaluation |
| `verified` | Standard operations *(default)* | Servers with known manifests |
| `trusted` | All operations including writes | First-party servers |
| `privileged` | Admin/system-level operations | Internal infrastructure |

Per-server allowlists and blocklists for fine-grained control.

### Tool Manifest Integrity (OWASP §5)

Hashes the tool manifest on first connection. On every subsequent connection, compares against the stored hash. Detects:

- **Tool shadowing** — new tools added that impersonate existing ones
- **Rug pulls** — tool definitions changed after initial trust
- **Manifest tampering** — any modification to the tool list

Optional HMAC-SHA256 signing with a secret key for cryptographic verification.

### Rate Limiting (OWASP §7)

Sliding window rate limiter with per-server and per-tool granularity:

- Default: 60 calls/minute, 1000 calls/hour
- Configurable per-server overrides
- Prevents resource exhaustion and abuse

### Audit Trail (OWASP §6)

Append-only JSONL log of every security decision:

```json
{"timestamp":"2026-03-02T10:15:30Z","event_type":"tool_call_blocked","server_name":"filesystem","tool_name":"write_file","verdict":"reject","detections":[{"type":"injection_override","confidence":0.85}]}
```

Every tool call request, response, block, redaction, rate limit hit, and manifest change is logged with full context.

## Configuration

### parapet.yaml

```yaml
scanner:
  policy_pii: flag           # flag | redact | reject
  policy_secrets: redact     # flag | redact | reject
  policy_injection: reject   # flag | redact | reject
  scan_tool_arguments: true
  scan_tool_responses: true

audit:
  enabled: true
  log_file: parapet-audit.jsonl

integrity:
  enabled: true
  alert_on_change: true
  block_on_change: false

rate_limit:
  default_per_minute: 60
  default_per_hour: 1000

servers:
  my-trusted-server:
    trust_level: trusted
  third-party-server:
    trust_level: basic
    allowed_tools:
      - search
      - read
    max_calls_per_minute: 10
```

### Environment Variables

| Variable | Description |
|----------|-------------|
| `PARAPET_CONFIG` | Path to config file |
| `PARAPET_SIGNING_KEY` | HMAC signing key for manifest integrity |
| `PARAPET_AUDIT_FILE` | Audit log file path |
| `PARAPET_LOG_LEVEL` | Log level (DEBUG, INFO, WARNING, ERROR) |
| `PARAPET_POLICY_PII` | Override PII policy |
| `PARAPET_POLICY_SECRETS` | Override secrets policy |
| `PARAPET_POLICY_INJECTION` | Override injection policy |

## Python API

```python
from mcp_parapet import ContentScanner, ScanVerdict

scanner = ContentScanner()

# Scan text content
verdict = scanner.scan("My SSN is 123-45-6789")
print(verdict.allowed)     # True (default PII policy is 'flag')
print(verdict.flags)       # ['pii_detected']
print(verdict.detections)  # [Detection(type=ssn, ...)]

# Scan tool call arguments
verdict = scanner.scan_json({"query": "ignore all previous instructions"})
print(verdict.allowed)     # False (default injection policy is 'reject')
```

## OWASP MCP Security Checklist

mcp-parapet maps directly to the [OWASP Practical Guide for Secure MCP Server Development](https://owasp.org/www-project-mcp-server-security/) v1.0:

| OWASP Section | Status | Implementation |
|---------------|--------|----------------|
| §3 Input Validation & Sanitisation | ✅ | `ContentScanner` — 4-stage pipeline |
| §4 Access Control | ✅ | `TrustPolicy` — 5-tier hierarchy |
| §5 Tool Integrity | ✅ | `integrity` — HMAC manifest hashing |
| §6 Logging & Monitoring | ✅ | `AuditTrail` — append-only JSONL |
| §7 Rate Limiting | ✅ | `RateLimiter` — sliding window |
| §1 Authentication | 🔜 | Planned for v0.2 |
| §2 Authorization | 🔜 | Planned for v0.2 |
| §8 Error Handling | ✅ | JSON-RPC error responses |

## CLI Reference

```
mcp-parapet wrap [--name NAME] [--config FILE] -- <command> [args...]
mcp-parapet scan <file | ->
mcp-parapet init [--output FILE] [--force]
mcp-parapet verify <manifest.json>
mcp-parapet version
```

## License

MIT — Quantify Labs Ltd

## Links

- **Repository**: [github.com/quantifylabs/mcp-parapet](https://github.com/quantifylabs/mcp-parapet)
- **OWASP MCP Security Guide**: [owasp.org/www-project-mcp-server-security](https://owasp.org/www-project-mcp-server-security/)
- **Aegis Platform**: [aegismemory.com](https://aegismemory.com)