protect-mcp 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -117
- package/dist/cli.js +4 -4
- package/dist/cli.mjs +4 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
# protect-mcp
|
|
2
2
|
|
|
3
|
-
Security gateway for MCP servers.
|
|
3
|
+
Security gateway for MCP servers. Shadow-mode logs by default, per-tool policies, optional local Ed25519 receipts, and verification-friendly audit output.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Current CLI path:** wrap any stdio MCP server as a transparent proxy. In shadow mode it logs every `tools/call` request and allows everything through. Add a policy file to enforce per-tool rules. Run `protect-mcp init` to generate local signing keys and config so the gateway can also emit signed receipts.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
# Shadow mode — log
|
|
10
|
+
# Shadow mode — log every tool call, enforce nothing
|
|
11
11
|
npx protect-mcp -- node my-server.js
|
|
12
12
|
|
|
13
|
-
#
|
|
13
|
+
# Generate keys + config template for local signing
|
|
14
14
|
npx protect-mcp init
|
|
15
15
|
|
|
16
|
-
#
|
|
17
|
-
npx protect-mcp --policy
|
|
16
|
+
# Shadow mode with local signing enabled
|
|
17
|
+
npx protect-mcp --policy protect-mcp.json -- node my-server.js
|
|
18
|
+
|
|
19
|
+
# Enforce mode
|
|
20
|
+
npx protect-mcp --policy protect-mcp.json --enforce -- node my-server.js
|
|
18
21
|
```
|
|
19
22
|
|
|
20
23
|
## What It Does
|
|
@@ -26,105 +29,28 @@ MCP Client ←stdin/stdout→ protect-mcp ←stdin/stdout→ your MCP server
|
|
|
26
29
|
```
|
|
27
30
|
|
|
28
31
|
It intercepts `tools/call` JSON-RPC requests and:
|
|
29
|
-
- **Shadow mode** (default): logs every tool call
|
|
30
|
-
- **Enforce mode**: applies policy rules
|
|
32
|
+
- **Shadow mode** (default): logs every tool call and allows everything through
|
|
33
|
+
- **Enforce mode**: applies per-tool policy rules such as `block`, `rate_limit`, and `min_tier`
|
|
34
|
+
- **Optional local signing**: when signing is configured, emits an Ed25519-signed receipt alongside the structured log
|
|
31
35
|
|
|
32
36
|
All other MCP messages (`initialize`, `tools/list`, notifications) pass through transparently.
|
|
33
37
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
### Trust-Tier Gating
|
|
37
|
-
|
|
38
|
-
Agents present signed manifests. protect-mcp evaluates them into trust tiers and gates tool access accordingly:
|
|
39
|
-
|
|
40
|
-
| Tier | Meaning | How Assigned |
|
|
41
|
-
|------|---------|--------------|
|
|
42
|
-
| `unknown` | No manifest, or invalid signature | Default |
|
|
43
|
-
| `signed-known` | Valid signed manifest | Automatic |
|
|
44
|
-
| `evidenced` | Manifest + sufficient evidence history | Automatic |
|
|
45
|
-
| `privileged` | Operator-granted elevated trust | Manual override |
|
|
46
|
-
|
|
47
|
-
Policy example — require `signed-known` for destructive tools:
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"default_tier": "unknown",
|
|
52
|
-
"tools": {
|
|
53
|
-
"delete_user": { "min_tier": "signed-known", "rate_limit": "5/hour" },
|
|
54
|
-
"read_file": { "require": "any" },
|
|
55
|
-
"*": { "rate_limit": "100/hour" }
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Credential Vault
|
|
61
|
-
|
|
62
|
-
Agents never see raw API keys. Credentials are resolved from environment variables at call time and injected transparently:
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{
|
|
66
|
-
"credentials": {
|
|
67
|
-
"stripe_api": {
|
|
68
|
-
"inject": "header",
|
|
69
|
-
"name": "Authorization",
|
|
70
|
-
"value_env": "STRIPE_SECRET_KEY"
|
|
71
|
-
},
|
|
72
|
-
"github_token": {
|
|
73
|
-
"inject": "header",
|
|
74
|
-
"name": "Authorization",
|
|
75
|
-
"value_env": "GITHUB_TOKEN"
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Decision logs reference credential labels (`stripe_api`), never values.
|
|
82
|
-
|
|
83
|
-
### Signed Decision Receipts
|
|
84
|
-
|
|
85
|
-
Every tool call produces an Ed25519-signed v2 artifact — independently verifiable, no trust required:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
[PROTECT_MCP_RECEIPT] {"v":2,"type":"decision_receipt","algorithm":"ed25519","kid":"kPrK...","issuer":"sb:protect","issued_at":"2026-03-21T10:00:00Z","payload":{"decision":"allow","tool":"read_file","tier":"signed-known","policy_digest":"a1b2c3d4","scope":"default","mode":"shadow"},"signature":"a1b2c3..."}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Verify with the CLI: `npx @veritasacta/verify receipt.json`
|
|
92
|
-
Verify in browser: [scopeblind.com/verify](https://scopeblind.com/verify)
|
|
93
|
-
|
|
94
|
-
### Bring Your Own Policy Engine (BYOPE)
|
|
95
|
-
|
|
96
|
-
Plug in OPA, Cerbos, or any HTTP policy endpoint:
|
|
97
|
-
|
|
98
|
-
```json
|
|
99
|
-
{
|
|
100
|
-
"policy_engine": "external",
|
|
101
|
-
"external": {
|
|
102
|
-
"endpoint": "http://localhost:8181/v1/data/mcp/allow",
|
|
103
|
-
"format": "opa",
|
|
104
|
-
"timeout_ms": 500,
|
|
105
|
-
"fallback": "deny"
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
```
|
|
38
|
+
## What Ships Today
|
|
109
39
|
|
|
110
|
-
|
|
40
|
+
- **Per-tool policies** — block destructive tools, rate-limit expensive ones, and attach minimum-tier requirements
|
|
41
|
+
- **Structured decision logs** — every decision is emitted to `stderr` with `[PROTECT_MCP]`
|
|
42
|
+
- **Optional local signed receipts** — generated when you run with a policy containing `signing.key_path`
|
|
43
|
+
- **Offline verification** — verify receipts or bundles with `npx @veritasacta/verify`
|
|
44
|
+
- **No account required** — local keys, local policy, local process
|
|
111
45
|
|
|
112
|
-
|
|
46
|
+
## Current Capability Boundaries
|
|
113
47
|
|
|
114
|
-
|
|
48
|
+
These are important before you roll this out or talk to users:
|
|
115
49
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"tenant": "my-service",
|
|
121
|
-
"receipts": [ ...signed artifacts... ],
|
|
122
|
-
"verification": {
|
|
123
|
-
"algorithm": "ed25519",
|
|
124
|
-
"signing_keys": [ ...JWK keys... ]
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
```
|
|
50
|
+
- **Signing is not automatic on the bare `npx protect-mcp -- ...` path.** That path logs decisions in shadow mode. For local signing, run `npx protect-mcp init` and then start the gateway with the generated policy file.
|
|
51
|
+
- **Tier-aware policy checks are live, but manifest admission is not wired into the default CLI/stdio path.** The CLI defaults sessions to `unknown` unless a host integration calls the admission API programmatically.
|
|
52
|
+
- **Credential config currently validates env-backed credential references and records credential labels in logs/receipts.** Generic per-call injection into arbitrary stdio tools is adapter-specific and is not performed by the default proxy path.
|
|
53
|
+
- **External PDP adapters and audit bundle helpers exist as exported utilities.** They are not yet fully wired into the default CLI path.
|
|
128
54
|
|
|
129
55
|
## Policy File
|
|
130
56
|
|
|
@@ -137,11 +63,17 @@ Export self-contained audit bundles for offline verification or compliance:
|
|
|
137
63
|
"read_tool": { "require": "any", "rate_limit": "100/hour" },
|
|
138
64
|
"*": { "rate_limit": "500/hour" }
|
|
139
65
|
},
|
|
140
|
-
"credentials": {
|
|
141
|
-
"api_key": { "inject": "header", "name": "Authorization", "value_env": "MY_API_KEY" }
|
|
142
|
-
},
|
|
143
66
|
"signing": {
|
|
144
|
-
"
|
|
67
|
+
"key_path": "./keys/gateway.json",
|
|
68
|
+
"issuer": "protect-mcp",
|
|
69
|
+
"enabled": true
|
|
70
|
+
},
|
|
71
|
+
"credentials": {
|
|
72
|
+
"internal_api": {
|
|
73
|
+
"inject": "env",
|
|
74
|
+
"name": "INTERNAL_API_KEY",
|
|
75
|
+
"value_env": "INTERNAL_API_KEY"
|
|
76
|
+
}
|
|
145
77
|
}
|
|
146
78
|
}
|
|
147
79
|
```
|
|
@@ -152,7 +84,7 @@ Export self-contained audit bundles for offline verification or compliance:
|
|
|
152
84
|
|-------|--------|-------------|
|
|
153
85
|
| `block` | `true` | Explicitly block this tool |
|
|
154
86
|
| `require` | `"any"`, `"none"` | Basic access requirement |
|
|
155
|
-
| `min_tier` | `"unknown"`, `"signed-known"`, `"evidenced"`, `"privileged"` | Minimum
|
|
87
|
+
| `min_tier` | `"unknown"`, `"signed-known"`, `"evidenced"`, `"privileged"` | Minimum tier required if your host sets admission state |
|
|
156
88
|
| `rate_limit` | `"N/unit"` | Rate limit (e.g. `"5/hour"`, `"100/day"`) |
|
|
157
89
|
|
|
158
90
|
Tool names match exactly, with `"*"` as a wildcard fallback.
|
|
@@ -170,7 +102,7 @@ Add to `claude_desktop_config.json`:
|
|
|
170
102
|
"command": "npx",
|
|
171
103
|
"args": [
|
|
172
104
|
"-y", "protect-mcp",
|
|
173
|
-
"--policy", "/path/to/
|
|
105
|
+
"--policy", "/path/to/protect-mcp.json",
|
|
174
106
|
"--enforce",
|
|
175
107
|
"--", "node", "my-server.js"
|
|
176
108
|
]
|
|
@@ -181,7 +113,7 @@ Add to `claude_desktop_config.json`:
|
|
|
181
113
|
|
|
182
114
|
### Cursor / VS Code
|
|
183
115
|
|
|
184
|
-
Same pattern — replace the server command with protect-mcp wrapping it.
|
|
116
|
+
Same pattern — replace the server command with `protect-mcp` wrapping it.
|
|
185
117
|
|
|
186
118
|
## CLI Options
|
|
187
119
|
|
|
@@ -193,14 +125,16 @@ Commands:
|
|
|
193
125
|
init Generate Ed25519 keypair + config template
|
|
194
126
|
|
|
195
127
|
Options:
|
|
196
|
-
--policy <path> Policy JSON file
|
|
197
|
-
--slug <slug> Service identifier for receipts
|
|
128
|
+
--policy <path> Policy/config JSON file
|
|
129
|
+
--slug <slug> Service identifier for logs/receipts
|
|
198
130
|
--enforce Enable enforcement mode (default: shadow)
|
|
199
131
|
--verbose Enable debug logging
|
|
200
132
|
--help Show help
|
|
201
133
|
```
|
|
202
134
|
|
|
203
|
-
## Programmatic
|
|
135
|
+
## Programmatic Hooks
|
|
136
|
+
|
|
137
|
+
The library also exposes the primitives that are not yet wired into the default CLI path:
|
|
204
138
|
|
|
205
139
|
```typescript
|
|
206
140
|
import {
|
|
@@ -211,30 +145,60 @@ import {
|
|
|
211
145
|
resolveCredential,
|
|
212
146
|
initSigning,
|
|
213
147
|
signDecision,
|
|
148
|
+
queryExternalPDP,
|
|
149
|
+
buildDecisionContext,
|
|
214
150
|
createAuditBundle,
|
|
215
151
|
} from 'protect-mcp';
|
|
216
152
|
```
|
|
217
153
|
|
|
218
|
-
|
|
154
|
+
Use these if you want to add:
|
|
155
|
+
- manifest admission before a session starts
|
|
156
|
+
- an external PDP (OPA, Cerbos, or a generic HTTP webhook)
|
|
157
|
+
- custom credential-brokered integrations
|
|
158
|
+
- audit bundle export around your own receipt store
|
|
219
159
|
|
|
220
|
-
|
|
160
|
+
## Decision Logs and Receipts
|
|
221
161
|
|
|
222
|
-
|
|
223
|
-
|
|
162
|
+
Every tool call emits structured JSON to `stderr`:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
[PROTECT_MCP] {"v":2,"tool":"read_file","decision":"allow","reason_code":"observe_mode","policy_digest":"none","mode":"shadow","timestamp":1710000000}
|
|
224
166
|
```
|
|
225
167
|
|
|
226
168
|
When signing is configured, a signed receipt follows:
|
|
227
169
|
|
|
170
|
+
```json
|
|
171
|
+
[PROTECT_MCP_RECEIPT] {"v":2,"type":"decision_receipt","algorithm":"ed25519","kid":"...","issuer":"protect-mcp","issued_at":"2026-03-22T00:00:00Z","payload":{"tool":"read_file","decision":"allow","policy_digest":"...","mode":"shadow","request_id":"..."},"signature":"..."}
|
|
228
172
|
```
|
|
229
|
-
|
|
173
|
+
|
|
174
|
+
Verify with the CLI: `npx @veritasacta/verify receipt.json`
|
|
175
|
+
Verify in browser: [scopeblind.com/verify](https://scopeblind.com/verify)
|
|
176
|
+
|
|
177
|
+
## Audit Bundles
|
|
178
|
+
|
|
179
|
+
The package exports a helper for self-contained audit bundles:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"format": "scopeblind:audit-bundle",
|
|
184
|
+
"version": 1,
|
|
185
|
+
"tenant": "my-service",
|
|
186
|
+
"receipts": ["..."],
|
|
187
|
+
"verification": {
|
|
188
|
+
"algorithm": "ed25519",
|
|
189
|
+
"signing_keys": ["..."]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
230
192
|
```
|
|
231
193
|
|
|
194
|
+
Use `createAuditBundle()` around your own collected signed receipts.
|
|
195
|
+
|
|
232
196
|
## Philosophy
|
|
233
197
|
|
|
234
|
-
- **Shadow first.** See what
|
|
235
|
-
- **Receipts
|
|
236
|
-
- **
|
|
237
|
-
- **
|
|
198
|
+
- **Shadow first.** See what agents are doing before you enforce anything.
|
|
199
|
+
- **Receipts beat dashboard-only logs.** Signed artifacts should be independently verifiable.
|
|
200
|
+
- **Keep the claims tight.** The default CLI path does not yet do everything the long-term architecture will support.
|
|
201
|
+
- **Layer on top of existing auth.** Don't rip out your stack just to add control and evidence.
|
|
238
202
|
|
|
239
203
|
## License
|
|
240
204
|
|
package/dist/cli.js
CHANGED
|
@@ -3228,7 +3228,7 @@ var ProtectGateway = class {
|
|
|
3228
3228
|
// src/cli.ts
|
|
3229
3229
|
function printHelp() {
|
|
3230
3230
|
process.stderr.write(`
|
|
3231
|
-
protect-mcp \u2014
|
|
3231
|
+
protect-mcp \u2014 Shadow-mode security gateway for MCP servers
|
|
3232
3232
|
|
|
3233
3233
|
Usage:
|
|
3234
3234
|
protect-mcp [options] -- <command> [args...]
|
|
@@ -3375,7 +3375,7 @@ async function handleInit(argv) {
|
|
|
3375
3375
|
${bold("protect-mcp initialized!")}
|
|
3376
3376
|
|
|
3377
3377
|
Created:
|
|
3378
|
-
${configPath} Config with shadow mode +
|
|
3378
|
+
${configPath} Config with shadow mode + optional local signing
|
|
3379
3379
|
${keyPath} Ed25519 signing keypair
|
|
3380
3380
|
|
|
3381
3381
|
${bold("Next steps:")}
|
|
@@ -3389,8 +3389,8 @@ ${bold("Your gateway public key:")}
|
|
|
3389
3389
|
${bold("Key ID (kid):")}
|
|
3390
3390
|
${keypair.kid}
|
|
3391
3391
|
|
|
3392
|
-
Shadow mode is the default \u2014 all tool calls are logged
|
|
3393
|
-
|
|
3392
|
+
Shadow mode is the default \u2014 all tool calls are logged and nothing is blocked.
|
|
3393
|
+
Run with the generated policy file if you also want local signed receipts. Add --enforce when ready.
|
|
3394
3394
|
`);
|
|
3395
3395
|
}
|
|
3396
3396
|
function bold(s) {
|
package/dist/cli.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
// src/cli.ts
|
|
10
10
|
function printHelp() {
|
|
11
11
|
process.stderr.write(`
|
|
12
|
-
protect-mcp \u2014
|
|
12
|
+
protect-mcp \u2014 Shadow-mode security gateway for MCP servers
|
|
13
13
|
|
|
14
14
|
Usage:
|
|
15
15
|
protect-mcp [options] -- <command> [args...]
|
|
@@ -156,7 +156,7 @@ async function handleInit(argv) {
|
|
|
156
156
|
${bold("protect-mcp initialized!")}
|
|
157
157
|
|
|
158
158
|
Created:
|
|
159
|
-
${configPath} Config with shadow mode +
|
|
159
|
+
${configPath} Config with shadow mode + optional local signing
|
|
160
160
|
${keyPath} Ed25519 signing keypair
|
|
161
161
|
|
|
162
162
|
${bold("Next steps:")}
|
|
@@ -170,8 +170,8 @@ ${bold("Your gateway public key:")}
|
|
|
170
170
|
${bold("Key ID (kid):")}
|
|
171
171
|
${keypair.kid}
|
|
172
172
|
|
|
173
|
-
Shadow mode is the default \u2014 all tool calls are logged
|
|
174
|
-
|
|
173
|
+
Shadow mode is the default \u2014 all tool calls are logged and nothing is blocked.
|
|
174
|
+
Run with the generated policy file if you also want local signed receipts. Add --enforce when ready.
|
|
175
175
|
`);
|
|
176
176
|
}
|
|
177
177
|
function bold(s) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "protect-mcp",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Security gateway for MCP servers.
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Security gateway for MCP servers. Shadow-mode logs by default, per-tool policies, optional local signing, and offline-verifiable receipts.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"url": "https://github.com/tomjwxf/scopeblind-gateway/issues"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@veritasacta/artifacts": "
|
|
52
|
+
"@veritasacta/artifacts": "^0.2.0"
|
|
53
53
|
},
|
|
54
54
|
"optionalDependencies": {
|
|
55
55
|
"@noble/curves": "^1.8.0",
|