Metadata-Version: 2.4
Name: mcp-server-shield
Version: 0.1.0
Summary: Author-side hardening primitives for Python MCP servers.
Project-URL: Homepage, https://github.com/Trihedron1240/mcp-server-shield
Project-URL: Issues, https://github.com/Trihedron1240/mcp-server-shield/issues
Project-URL: Source, https://github.com/Trihedron1240/mcp-server-shield
Author: mcp-server-shield contributors
License: Apache-2.0
License-File: LICENSE
Keywords: fastmcp,hardening,mcp,model-context-protocol,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software 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: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: pydantic<3,>=2.7
Requires-Dist: pyyaml<7,>=6.0.1
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.24; extra == 'otel'
Description-Content-Type: text/markdown

# mcp-server-shield

`mcp-server-shield` is a Python-first hardening library for MCP server authors. It is not
a scanner, gateway, proxy, or hosted security service. It protects the MCP tool function
boundary directly: validate arguments before execution, use safe wrappers for dangerous
operations, filter outputs before they reach the MCP client, lint tool descriptions, lock
tool manifests, and emit structured audit logs.

The project is built for the way FastMCP and the official Python MCP SDK expose tools:
ordinary Python functions decorated as tools.

## Install

```bash
pip install mcp-server-shield
```

For local development:

```bash
pip install -e ".[dev]"
```

## Quickstart

```python
from mcp_server_shield import ShieldPolicy, shield
from mcp_server_shield.output_filters import PromptInjectionFilter, SecretRedactor
from mcp_server_shield.validators import PathGuard, StringGuard, URLGuard

policy = ShieldPolicy.strict(
    paths={"file_path": PathGuard(root="./workspace", read=True, write=False)},
    urls={"url": URLGuard(allowed_schemes=["https"], allowed_hosts=["api.github.com"])},
    strings={
        "query": StringGuard(
            max_len=5000,
            deny_substrings=["ignore previous instructions"],
        )
    },
    output_filters=[SecretRedactor(), PromptInjectionFilter()],
)

@shield(policy)
def read_file(file_path: str) -> str:
    with open(file_path, encoding="utf-8") as handle:
        return handle.read()
```

## FastMCP Example

Use `@shield(policy)` closest to the function so FastMCP sees the preserved signature and
metadata after the wrapper is applied:

```python
from fastmcp import FastMCP
from mcp_server_shield import ShieldPolicy, shield
from mcp_server_shield.validators import PathGuard

mcp = FastMCP("secure-files")

policy = ShieldPolicy.strict(
    paths={"file_path": PathGuard(root="./workspace", read=True, write=False)},
)

@mcp.tool()
@shield(policy)
def read_file(file_path: str) -> str:
    with open(file_path, encoding="utf-8") as handle:
        return handle.read()
```

## Policy File Example

```yaml
policy_id: secure-fetch-v1
fail_closed: true
audit_log: logs/mcp-shield-audit.jsonl
paths:
  file_path:
    root: ./workspace
    read: true
    write: false
    allowed_extensions: [".txt", ".md"]
urls:
  url:
    allowed_schemes: ["https"]
    allowed_hosts: ["api.github.com"]
    allow_localhost: false
    allow_private_ips: false
strings:
  query:
    max_len: 5000
    deny_substrings: ["ignore previous instructions"]
output_filters:
  - type: secret_redactor
    redact_pii: true
  - type: prompt_injection
    action: redact
waivers:
  - id: WAIVER-001
    reason: Temporary partner endpoint migration.
    expires_on: 2026-06-30
    applies_to: ["URLGuard:url"]
    evidence:
      ticket: SEC-1234
```

Load it with:

```python
policy = ShieldPolicy.from_file("mcp-shield-policy.yaml")
```

## CLI

Lint tool descriptions:

```bash
mcp-shield lint-descriptions tools.json --json
```

Generate and verify a descriptor lockfile:

```bash
mcp-shield manifest generate tools.json --output mcp-shield.lock.json
mcp-shield manifest verify tools.json --lockfile mcp-shield.lock.json
```

Validate a policy file:

```bash
mcp-shield policy check mcp-shield-policy.yaml
```

Check the local installation:

```bash
mcp-shield doctor
```

## Threat Model

`mcp-server-shield` assumes MCP tool arguments, external URLs, filesystem paths, command
arguments, tool descriptions, and tool outputs may be attacker influenced. It focuses on
deterministic local controls for:

- Secret exposure and context over-sharing through output redaction.
- Command and argument injection through `safe_run`.
- Path traversal and symlink escape through `PathGuard`.
- SSRF, localhost access, and DNS rebinding risk through `URLGuard`.
- Tool poisoning through description linting and manifest locking.
- Audit gaps through JSONL audit events for allowed, denied, redacted, and errored calls.

## What This Library Does Not Solve

This library does not replace authentication, authorization, sandboxing, container policy,
dependency scanning, supply-chain review, network egress policy, or a full MCP gateway. It
does not claim to detect every prompt-injection phrase or every possible secret format. It
does not make unsafe business logic safe by itself. It gives MCP server authors reusable
secure-by-default primitives at the point where tool code handles untrusted data.
