Skip to main content
Glama
samsgates

MCP Shield Runtime

by samsgates
README.md
# MCP Shield Runtime

**Control every MCP tool call before it executes.**

MCP Shield Runtime is a local-first security gateway for Model Context Protocol clients and servers. It provides parameter-level policies, tool visibility filtering, approval gates, emergency deny rules, secret redaction, tool-contract drift detection, rate limiting, and tamper-evident audit records.

> Project status: production-oriented preview. The core gateway and controls are working and tested, but the project has not yet completed an independent security audit. Use staged rollout and least-privilege upstream credentials for production environments.

## Why this project exists

An allowlist that says an agent may use `read_file` or `send_email` is not enough. Security decisions must consider the concrete path, recipient, repository, branch, URL, command, environment, identity, detected data, and prior approval.

```text
AI client
   |
   v
MCP Shield Runtime
   |  policy, approval, DLP, contract lock, audit
   v
MCP server
```

### Architecture

![MCP Shield Runtime architecture diagram](media_assets/architech_diagram.png)

## How it works

![MCP Shield Runtime request workflow](media_assets/howits_works.png)

## Features

- Stdio proxy for local MCP servers
- Streamable HTTP reverse proxy
- MCP 2026 routing-header validation and generation
- Client-independent parameter-level policy decisions
- Built-in emergency blocks for secret paths, private metadata URLs, and destructive commands
- Human approval with retry grants
- Tool discovery filtering
- Tool schema and description lockfile
- Response secret redaction
- Tamper-evident hash-chained audit log with optional HMAC signatures
- Per-user, per-server, per-tool token-bucket rate limiting
- Local dashboard and approval queue
- Zero runtime npm dependencies
- Docker hardening example
- Node built-in test suite and CodeQL workflow

## Requirements

- Node.js 22 or newer
- An existing MCP server
- JSON policy and configuration files

## Quick start

```bash
git clone https://github.com/your-org/mcp-shield-runtime.git
cd mcp-shield-runtime
npm install
npm run check
node src/cli.js init --dir .mcp-shield
```

### Protect a local stdio server

```bash
node src/cli.js run \
  --config .mcp-shield/config.json \
  -- node examples/risky-demo-server.js
```

Example MCP client configuration:

```json
{
  "mcpServers": {
    "protected-demo": {
      "command": "node",
      "args": [
        "/absolute/path/mcp-shield-runtime/src/cli.js",
        "run",
        "--config",
        "/absolute/path/mcp-shield-runtime/.mcp-shield/config.json",
        "--",
        "node",
        "/absolute/path/mcp-shield-runtime/examples/risky-demo-server.js"
      ]
    }
  }
}
```

### Protect a remote Streamable HTTP server

```bash
node src/cli.js gateway \
  --config config/default.config.json \
  --upstream https://upstream.example.com/mcp
```

Point the MCP client to `http://127.0.0.1:7777/mcp`. The local dashboard is at `http://127.0.0.1:7777/`.

## Approval flow

When a call requires approval, the gateway returns JSON-RPC error `-32070` with an approval ID.

```bash
node src/cli.js approvals list --config .mcp-shield/config.json
node src/cli.js approvals approve apr_ID \
  --config .mcp-shield/config.json \
  --ttl 300
```

Retry the identical tool call. The approval is scoped to the request fingerprint and expiration.

## Example policy

```json
{
  "version": 1,
  "defaults": { "decision": "deny" },
  "rules": [
    {
      "id": "allow-repository-read",
      "priority": 100,
      "match": {
        "methods": ["tools/call"],
        "tools": ["read_file"],
        "arguments": {
          "path": {
            "within": ["${workspace}"],
            "exclude": ["**/.env", "**/.ssh/**", "**/*.pem"]
          }
        }
      },
      "effect": { "decision": "allow" }
    },
    {
      "id": "approve-write",
      "priority": 90,
      "match": {
        "methods": ["tools/call"],
        "tools": ["write_file", "push_files"]
      },
      "effect": {
        "decision": "require_approval",
        "approvalTtlSeconds": 300
      }
    }
  ]
}
```

See [Policy reference](docs/POLICY_REFERENCE.md).

## Security model

The gateway enforces what it can observe at the MCP boundary. A protocol proxy cannot fully constrain a local server process after launch. Strong filesystem and network isolation requires a container, operating-system sandbox, or workload boundary.

Important deployment rules:

1. Keep upstream credentials least-privileged.
2. Bind the dashboard to localhost unless an API token and TLS termination are configured.
3. Enable HMAC audit signing.
4. Use a container or operating-system sandbox for untrusted local servers.
5. Set `allowSseWithoutInspection` to `false` for tools requiring response DLP.
6. Pin upstream package and container versions.
7. Review tool-contract changes before enabling `blockSchemaDrift`.

Read [SECURITY.md](SECURITY.md) and [Threat model](docs/THREAT_MODEL.md).

## Commands

```text
mcp-shield init
mcp-shield gateway
mcp-shield run -- COMMAND
mcp-shield policy test
mcp-shield approvals list|approve|deny
mcp-shield audit list|verify
mcp-shield contracts list|approve
mcp-shield scan
mcp-shield doctor
```

## Protocol compatibility

The proxy is protocol-neutral for JSON-RPC messages and can forward legacy and modern MCP traffic. The HTTP gateway validates or generates modern `Mcp-Method` and `Mcp-Name` routing headers. Stateful legacy HTTP servers may require upstream session handling specific to their deployment.

The project intentionally keeps policy logic separate from the official MCP SDK. SDK-backed client and server adapters can be added without moving the trusted policy core.

## Documentation

- [Architecture](docs/ARCHITECTURE.md)
- [Policy reference](docs/POLICY_REFERENCE.md)
- [Deployment guide](docs/DEPLOYMENT.md)
- [Threat model](docs/THREAT_MODEL.md)
- [Roadmap](docs/ROADMAP.md)
- [Contributing](CONTRIBUTING.md)

## License

Apache License 2.0.