protect-mcp 0.2.2 → 0.3.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 CHANGED
@@ -7,6 +7,9 @@ Security gateway for MCP servers. Shadow-mode logs by default, per-tool policies
7
7
  ## Quick Start
8
8
 
9
9
  ```bash
10
+ # Wrap an existing OpenClaw / MCP config into a usable pack
11
+ npx @scopeblind/passport wrap --runtime openclaw --config ./openclaw.json --policy email-safe
12
+
10
13
  # Shadow mode — log every tool call, enforce nothing
11
14
  npx protect-mcp -- node my-server.js
12
15
 
@@ -18,6 +21,9 @@ npx protect-mcp --policy protect-mcp.json -- node my-server.js
18
21
 
19
22
  # Enforce mode
20
23
  npx protect-mcp --policy protect-mcp.json --enforce -- node my-server.js
24
+
25
+ # Export an offline-verifiable audit bundle
26
+ npx protect-mcp bundle --output audit.json
21
27
  ```
22
28
 
23
29
  ## What It Does
@@ -39,7 +45,7 @@ All other MCP messages (`initialize`, `tools/list`, notifications) pass through
39
45
 
40
46
  - **Per-tool policies** — block destructive tools, rate-limit expensive ones, and attach minimum-tier requirements
41
47
  - **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`
48
+ - **Optional local signed receipts** — generated when you run with a policy containing `signing.key_path`, persisted to `.protect-mcp-receipts.jsonl`, and exposed at `http://127.0.0.1:9876/receipts`
43
49
  - **Offline verification** — verify receipts or bundles with `npx @veritasacta/verify`
44
50
  - **No account required** — local keys, local policy, local process
45
51
 
@@ -123,6 +129,10 @@ protect-mcp init
123
129
 
124
130
  Commands:
125
131
  init Generate Ed25519 keypair + config template
132
+ status Show decision stats and local passport identity
133
+ digest Generate a local human-readable summary
134
+ receipts Show recent persisted signed receipts
135
+ bundle Export an offline-verifiable audit bundle
126
136
 
127
137
  Options:
128
138
  --policy <path> Policy/config JSON file
@@ -0,0 +1,8 @@
1
+ import {
2
+ collectSignedReceipts,
3
+ createAuditBundle
4
+ } from "./chunk-5JXFV37Y.mjs";
5
+ export {
6
+ collectSignedReceipts,
7
+ createAuditBundle
8
+ };
@@ -0,0 +1,53 @@
1
+ // src/bundle.ts
2
+ function createAuditBundle(opts) {
3
+ const receipts = opts.receipts.filter(
4
+ (r) => r && typeof r === "object" && typeof r.signature === "string"
5
+ );
6
+ if (receipts.length === 0) {
7
+ throw new Error("Audit bundle requires at least one signed receipt");
8
+ }
9
+ const keyMap = /* @__PURE__ */ new Map();
10
+ for (const key of opts.signingKeys) {
11
+ if (!keyMap.has(key.kid)) {
12
+ keyMap.set(key.kid, key);
13
+ }
14
+ }
15
+ let timeRange = opts.timeRange || null;
16
+ if (!timeRange) {
17
+ const timestamps = receipts.map((r) => r.issued_at || r.timestamp).filter(Boolean).sort();
18
+ if (timestamps.length > 0) {
19
+ timeRange = {
20
+ from: timestamps[0],
21
+ to: timestamps[timestamps.length - 1]
22
+ };
23
+ }
24
+ }
25
+ return {
26
+ format: "scopeblind:audit-bundle",
27
+ version: 1,
28
+ exported_at: (/* @__PURE__ */ new Date()).toISOString(),
29
+ tenant: opts.tenant,
30
+ time_range: timeRange,
31
+ receipts,
32
+ anchors: opts.anchors || [],
33
+ verification: {
34
+ algorithm: "ed25519",
35
+ signing_keys: Array.from(keyMap.values()),
36
+ instructions: `Verify each receipt by: (1) remove the "signature" field, (2) canonicalize the remaining object with JCS (sorted keys at every level), (3) encode as UTF-8 bytes, (4) verify the Ed25519 signature using the signing key matching the receipt's "kid" field. CLI: npx @veritasacta/verify bundle.json --bundle`
37
+ }
38
+ };
39
+ }
40
+ function collectSignedReceipts(logs) {
41
+ return logs.filter((log) => log.v === 2).map((log) => {
42
+ const logRecord = log;
43
+ if (logRecord.receipt) {
44
+ return logRecord.receipt;
45
+ }
46
+ return logRecord;
47
+ }).filter((r) => typeof r.signature === "string");
48
+ }
49
+
50
+ export {
51
+ createAuditBundle,
52
+ collectSignedReceipts
53
+ };