protect-mcp 0.7.3 → 0.7.5
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/CHANGELOG.md +48 -0
- package/README.md +155 -7
- package/dist/{bundle-XTR3YMPO.mjs → bundle-YUUHAG7O.mjs} +1 -1
- package/dist/{chunk-G67NUBML.mjs → chunk-6E2DHBAR.mjs} +21 -6
- package/dist/chunk-JCMDLN5I.mjs +1053 -0
- package/dist/{chunk-LYKNULYU.mjs → chunk-LJQOALYR.mjs} +152 -0
- package/dist/{chunk-5JXFV37Y.mjs → chunk-PM2ZO57M.mjs} +10 -2
- package/dist/{chunk-J6L4XCTE.mjs → chunk-SETXVE2K.mjs} +77 -2
- package/dist/{chunk-OHUTUFTC.mjs → chunk-VTPZ4G5I.mjs} +19 -15
- package/dist/{chunk-546U3A7R.mjs → chunk-WIPWNWMJ.mjs} +93 -2
- package/dist/chunk-WV4DKYE4.mjs +486 -0
- package/dist/cli.js +4609 -546
- package/dist/cli.mjs +2215 -40
- package/dist/demo-server.d.mts +3 -0
- package/dist/demo-server.d.ts +3 -0
- package/dist/demo-server.js +77 -2
- package/dist/demo-server.mjs +1 -1
- package/dist/{ed25519-DZMMNNVE.mjs → ed25519-BSHMMVNX.mjs} +1 -1
- package/dist/hook-server.js +128 -24
- package/dist/hook-server.mjs +2 -2
- package/dist/{http-transport-R5AO7X6D.mjs → http-transport-JBORN27G.mjs} +3 -3
- package/dist/index.d.mts +158 -10
- package/dist/index.d.ts +158 -10
- package/dist/index.js +2704 -108
- package/dist/index.mjs +1208 -261
- package/dist/receipt-registry-6CAOY6RP.mjs +279 -0
- package/dist/signing-committed-QXCW24RF.mjs +15 -0
- package/package.json +2 -2
- package/dist/chunk-ZBKJANP7.mjs +0 -145
package/dist/demo-server.d.mts
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* - delete_file (destructive, blocked by default policy)
|
|
13
13
|
* - web_search (rate-limited)
|
|
14
14
|
* - deploy (high-privilege)
|
|
15
|
+
* - github_create_pr (source-control mutation)
|
|
16
|
+
* - send_email (external communication)
|
|
17
|
+
* - pms_book_fill (mock portfolio-management booking)
|
|
15
18
|
*/
|
|
16
19
|
/**
|
|
17
20
|
* Smithery sandbox server — returns a McpServer instance
|
package/dist/demo-server.d.ts
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* - delete_file (destructive, blocked by default policy)
|
|
13
13
|
* - web_search (rate-limited)
|
|
14
14
|
* - deploy (high-privilege)
|
|
15
|
+
* - github_create_pr (source-control mutation)
|
|
16
|
+
* - send_email (external communication)
|
|
17
|
+
* - pms_book_fill (mock portfolio-management booking)
|
|
15
18
|
*/
|
|
16
19
|
/**
|
|
17
20
|
* Smithery sandbox server — returns a McpServer instance
|
package/dist/demo-server.js
CHANGED
|
@@ -35064,6 +35064,48 @@ var TOOLS = [
|
|
|
35064
35064
|
},
|
|
35065
35065
|
required: ["environment"]
|
|
35066
35066
|
}
|
|
35067
|
+
},
|
|
35068
|
+
{
|
|
35069
|
+
name: "github_create_pr",
|
|
35070
|
+
description: "Create a GitHub pull request",
|
|
35071
|
+
inputSchema: {
|
|
35072
|
+
type: "object",
|
|
35073
|
+
properties: {
|
|
35074
|
+
repo: { type: "string", description: "Repository name" },
|
|
35075
|
+
branch: { type: "string", description: "Source branch" },
|
|
35076
|
+
title: { type: "string", description: "Pull request title" }
|
|
35077
|
+
},
|
|
35078
|
+
required: ["repo", "branch", "title"]
|
|
35079
|
+
}
|
|
35080
|
+
},
|
|
35081
|
+
{
|
|
35082
|
+
name: "send_email",
|
|
35083
|
+
description: "Send an email",
|
|
35084
|
+
inputSchema: {
|
|
35085
|
+
type: "object",
|
|
35086
|
+
properties: {
|
|
35087
|
+
to: { type: "string", description: "Recipient email address" },
|
|
35088
|
+
subject: { type: "string", description: "Subject line" },
|
|
35089
|
+
body: { type: "string", description: "Message body" }
|
|
35090
|
+
},
|
|
35091
|
+
required: ["to", "subject"]
|
|
35092
|
+
}
|
|
35093
|
+
},
|
|
35094
|
+
{
|
|
35095
|
+
name: "pms_book_fill",
|
|
35096
|
+
description: "Book a fill into the mock portfolio management system",
|
|
35097
|
+
inputSchema: {
|
|
35098
|
+
type: "object",
|
|
35099
|
+
properties: {
|
|
35100
|
+
account: { type: "string", description: "Portfolio or fund account" },
|
|
35101
|
+
symbol: { type: "string", description: "Instrument symbol" },
|
|
35102
|
+
side: { type: "string", enum: ["BUY", "SELL"] },
|
|
35103
|
+
quantity: { type: "number" },
|
|
35104
|
+
price: { type: "number" },
|
|
35105
|
+
strategy: { type: "string" }
|
|
35106
|
+
},
|
|
35107
|
+
required: ["account", "symbol", "side", "quantity", "price"]
|
|
35108
|
+
}
|
|
35067
35109
|
}
|
|
35068
35110
|
];
|
|
35069
35111
|
function handleRequest(request) {
|
|
@@ -35073,7 +35115,7 @@ function handleRequest(request) {
|
|
|
35073
35115
|
id: request.id,
|
|
35074
35116
|
result: {
|
|
35075
35117
|
protocolVersion: "2024-11-05",
|
|
35076
|
-
serverInfo: { name: "protect-mcp-demo", version: "0.5.3" },
|
|
35118
|
+
serverInfo: { name: "protect-mcp-demo", version: process.env.PROTECT_MCP_VERSION || "0.5.3" },
|
|
35077
35119
|
capabilities: { tools: {} }
|
|
35078
35120
|
}
|
|
35079
35121
|
});
|
|
@@ -35111,6 +35153,15 @@ Contents: Hello from protect-mcp demo server!`;
|
|
|
35111
35153
|
case "deploy":
|
|
35112
35154
|
resultText = `[demo] Deployed to ${args.environment || "staging"}${args.reason ? ` (reason: ${args.reason})` : ""}`;
|
|
35113
35155
|
break;
|
|
35156
|
+
case "github_create_pr":
|
|
35157
|
+
resultText = `[demo] Created PR in ${args.repo || "scopeblind/demo"} from ${args.branch || "agent/demo"}: ${args.title || "Agent change"}`;
|
|
35158
|
+
break;
|
|
35159
|
+
case "send_email":
|
|
35160
|
+
resultText = `[demo] Drafted email to ${args.to || "pm@example.com"}: ${args.subject || "Agent update"}`;
|
|
35161
|
+
break;
|
|
35162
|
+
case "pms_book_fill":
|
|
35163
|
+
resultText = `[demo] Booked ${args.side || "BUY"} ${args.quantity || 0} ${args.symbol || "AAPL"} @ ${args.price || 0} into ${args.account || "Demo Fund"} (${args.strategy || "Unassigned"})`;
|
|
35164
|
+
break;
|
|
35114
35165
|
default:
|
|
35115
35166
|
resultText = `[demo] Unknown tool: ${toolName}`;
|
|
35116
35167
|
}
|
|
@@ -35150,7 +35201,7 @@ function createSandboxServer() {
|
|
|
35150
35201
|
const { z } = require_zod();
|
|
35151
35202
|
const server = new McpServer({
|
|
35152
35203
|
name: "protect-mcp",
|
|
35153
|
-
version: "0.4.5",
|
|
35204
|
+
version: process.env.PROTECT_MCP_VERSION || "0.4.5",
|
|
35154
35205
|
description: "Security gateway for MCP servers. Per-tool policies, Ed25519-signed receipts, human approval gates, trust tiers."
|
|
35155
35206
|
});
|
|
35156
35207
|
server.tool(
|
|
@@ -35183,6 +35234,30 @@ function createSandboxServer() {
|
|
|
35183
35234
|
{ environment: z.enum(["staging", "production"]).describe("Target environment"), reason: z.string().optional().describe("Deployment reason") },
|
|
35184
35235
|
async (args) => ({ content: [{ type: "text", text: `[demo] Deployed to ${args.environment}` }] })
|
|
35185
35236
|
);
|
|
35237
|
+
server.tool("github_create_pr", "Create a GitHub pull request", {
|
|
35238
|
+
repo: z.string(),
|
|
35239
|
+
branch: z.string(),
|
|
35240
|
+
title: z.string()
|
|
35241
|
+
}, async (args) => ({
|
|
35242
|
+
content: [{ type: "text", text: `[demo] PR created in ${args.repo} from ${args.branch}: ${args.title}` }]
|
|
35243
|
+
}));
|
|
35244
|
+
server.tool("send_email", "Send an email", {
|
|
35245
|
+
to: z.string(),
|
|
35246
|
+
subject: z.string(),
|
|
35247
|
+
body: z.string().optional()
|
|
35248
|
+
}, async (args) => ({
|
|
35249
|
+
content: [{ type: "text", text: `[demo] Email prepared for ${args.to}: ${args.subject}` }]
|
|
35250
|
+
}));
|
|
35251
|
+
server.tool("pms_book_fill", "Book a fill into a mock PMS", {
|
|
35252
|
+
account: z.string(),
|
|
35253
|
+
symbol: z.string(),
|
|
35254
|
+
side: z.enum(["BUY", "SELL"]),
|
|
35255
|
+
quantity: z.number(),
|
|
35256
|
+
price: z.number(),
|
|
35257
|
+
strategy: z.string().optional()
|
|
35258
|
+
}, async (args) => ({
|
|
35259
|
+
content: [{ type: "text", text: `[demo] Booked ${args.side} ${args.quantity} ${args.symbol} @ ${args.price} into ${args.account}` }]
|
|
35260
|
+
}));
|
|
35186
35261
|
return server;
|
|
35187
35262
|
}
|
|
35188
35263
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/demo-server.mjs
CHANGED
package/dist/hook-server.js
CHANGED
|
@@ -24,7 +24,7 @@ __export(hook_server_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(hook_server_exports);
|
|
26
26
|
var import_node_http2 = require("http");
|
|
27
|
-
var
|
|
27
|
+
var import_node_crypto4 = require("crypto");
|
|
28
28
|
var import_node_fs5 = require("fs");
|
|
29
29
|
var import_node_path3 = require("path");
|
|
30
30
|
|
|
@@ -320,6 +320,7 @@ function signDecision(entry) {
|
|
|
320
320
|
if (entry.timing) payload.timing = entry.timing;
|
|
321
321
|
if (entry.swarm) payload.swarm = entry.swarm;
|
|
322
322
|
if (entry.payload_digest) payload.payload_digest = entry.payload_digest;
|
|
323
|
+
if (entry.action_readback) payload.action_readback = entry.action_readback;
|
|
323
324
|
if (entry.deny_iteration) payload.deny_iteration = entry.deny_iteration;
|
|
324
325
|
const result = artifactsModule.createSignedArtifact(
|
|
325
326
|
artifactType,
|
|
@@ -613,6 +614,95 @@ function getScopeBlindBridge() {
|
|
|
613
614
|
return singleton;
|
|
614
615
|
}
|
|
615
616
|
|
|
617
|
+
// src/action-readback.ts
|
|
618
|
+
var import_node_crypto3 = require("crypto");
|
|
619
|
+
var SECRET_KEY_RE = /(api[_-]?key|authorization|bearer|credential|password|secret|session|token|private[_-]?key)/i;
|
|
620
|
+
var DESTINATION_KEYS = [
|
|
621
|
+
"path",
|
|
622
|
+
"file_path",
|
|
623
|
+
"filePath",
|
|
624
|
+
"url",
|
|
625
|
+
"uri",
|
|
626
|
+
"endpoint",
|
|
627
|
+
"host",
|
|
628
|
+
"hostname",
|
|
629
|
+
"repo",
|
|
630
|
+
"repository",
|
|
631
|
+
"branch",
|
|
632
|
+
"channel",
|
|
633
|
+
"to",
|
|
634
|
+
"recipient",
|
|
635
|
+
"symbol",
|
|
636
|
+
"account",
|
|
637
|
+
"bucket",
|
|
638
|
+
"database",
|
|
639
|
+
"table",
|
|
640
|
+
"service"
|
|
641
|
+
];
|
|
642
|
+
function stableStringify(value) {
|
|
643
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
644
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
645
|
+
const obj = value;
|
|
646
|
+
return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`).join(",")}}`;
|
|
647
|
+
}
|
|
648
|
+
function redact(value, path = [], redacted = [], disclosed = [], depth = 0) {
|
|
649
|
+
if (depth > 4) return "[truncated-depth]";
|
|
650
|
+
if (value === null || value === void 0) return value;
|
|
651
|
+
if (typeof value !== "object") {
|
|
652
|
+
if (path.length > 0) disclosed.push(path.join("."));
|
|
653
|
+
if (typeof value === "string" && value.length > 240) return `${value.slice(0, 240)}...`;
|
|
654
|
+
return value;
|
|
655
|
+
}
|
|
656
|
+
if (Array.isArray(value)) {
|
|
657
|
+
return value.slice(0, 20).map((item, idx) => redact(item, [...path, String(idx)], redacted, disclosed, depth + 1));
|
|
658
|
+
}
|
|
659
|
+
const out = {};
|
|
660
|
+
for (const [key, child] of Object.entries(value)) {
|
|
661
|
+
const childPath = [...path, key];
|
|
662
|
+
if (SECRET_KEY_RE.test(key)) {
|
|
663
|
+
redacted.push(childPath.join("."));
|
|
664
|
+
out[key] = "[redacted]";
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
out[key] = redact(child, childPath, redacted, disclosed, depth + 1);
|
|
668
|
+
}
|
|
669
|
+
return out;
|
|
670
|
+
}
|
|
671
|
+
function firstStringValue(input, keys) {
|
|
672
|
+
for (const key of keys) {
|
|
673
|
+
const value = input[key];
|
|
674
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
675
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
676
|
+
}
|
|
677
|
+
return void 0;
|
|
678
|
+
}
|
|
679
|
+
function actionFor(tool, input) {
|
|
680
|
+
const explicit = firstStringValue(input, ["action", "operation", "method", "verb", "command"]);
|
|
681
|
+
if (explicit) return explicit.length > 90 ? `${explicit.slice(0, 90)}...` : explicit;
|
|
682
|
+
return tool;
|
|
683
|
+
}
|
|
684
|
+
function buildActionReadback(tool, input) {
|
|
685
|
+
const normalized = input && typeof input === "object" && !Array.isArray(input) ? input : { value: input };
|
|
686
|
+
const canonical = stableStringify(normalized);
|
|
687
|
+
const redactedFields = [];
|
|
688
|
+
const disclosedFields = [];
|
|
689
|
+
const payloadPreview = redact(normalized, [], redactedFields, disclosedFields);
|
|
690
|
+
const action = actionFor(tool, normalized);
|
|
691
|
+
const destination = firstStringValue(normalized, DESTINATION_KEYS);
|
|
692
|
+
const summary = destination ? `${tool} -> ${destination}` : `${tool} request`;
|
|
693
|
+
return {
|
|
694
|
+
tool,
|
|
695
|
+
action,
|
|
696
|
+
destination,
|
|
697
|
+
payload_preview: payloadPreview,
|
|
698
|
+
payload_hash: (0, import_node_crypto3.createHash)("sha256").update(canonical).digest("hex"),
|
|
699
|
+
payload_bytes: Buffer.byteLength(canonical, "utf-8"),
|
|
700
|
+
disclosed_fields: [...new Set(disclosedFields)].slice(0, 80),
|
|
701
|
+
redacted_fields: [...new Set(redactedFields)].slice(0, 80),
|
|
702
|
+
summary
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
616
706
|
// src/hook-server.ts
|
|
617
707
|
var DEFAULT_PORT = 9377;
|
|
618
708
|
var LOG_FILE = ".protect-mcp-log.jsonl";
|
|
@@ -641,7 +731,7 @@ function computePayloadDigest(input) {
|
|
|
641
731
|
return void 0;
|
|
642
732
|
}
|
|
643
733
|
return {
|
|
644
|
-
input_hash: (0,
|
|
734
|
+
input_hash: (0, import_node_crypto4.createHash)("sha256").update(content).digest("hex"),
|
|
645
735
|
input_size: size,
|
|
646
736
|
truncated: true,
|
|
647
737
|
preview: content.slice(0, 256)
|
|
@@ -654,7 +744,7 @@ function computeOutputDigest(output) {
|
|
|
654
744
|
return void 0;
|
|
655
745
|
}
|
|
656
746
|
return {
|
|
657
|
-
output_hash: (0,
|
|
747
|
+
output_hash: (0, import_node_crypto4.createHash)("sha256").update(content).digest("hex"),
|
|
658
748
|
output_size: size
|
|
659
749
|
};
|
|
660
750
|
}
|
|
@@ -677,13 +767,14 @@ function detectSandboxState() {
|
|
|
677
767
|
async function handlePreToolUse(input, state) {
|
|
678
768
|
const hookStart = Date.now();
|
|
679
769
|
const toolName = input.toolName || "unknown";
|
|
680
|
-
const requestId = input.toolUseId || (0,
|
|
770
|
+
const requestId = input.toolUseId || (0, import_node_crypto4.randomUUID)().slice(0, 12);
|
|
681
771
|
state.inflightTools.set(requestId, {
|
|
682
772
|
tool: toolName,
|
|
683
773
|
startedAt: hookStart,
|
|
684
774
|
requestId
|
|
685
775
|
});
|
|
686
776
|
const payloadDigest = computePayloadDigest(input.toolInput);
|
|
777
|
+
const actionReadback = buildActionReadback(toolName, input.toolInput || {});
|
|
687
778
|
const swarm = {
|
|
688
779
|
...state.swarmContext,
|
|
689
780
|
...input.agentId && { agent_id: input.agentId },
|
|
@@ -723,6 +814,7 @@ async function handlePreToolUse(input, state) {
|
|
|
723
814
|
swarm: swarm.team_name ? swarm : void 0,
|
|
724
815
|
timing: { hook_latency_ms: hookLatency2, started_at: hookStart },
|
|
725
816
|
payload_digest: payloadDigest,
|
|
817
|
+
action_readback: actionReadback,
|
|
726
818
|
deny_iteration: denyCount,
|
|
727
819
|
sandbox_state: detectSandboxState(),
|
|
728
820
|
plan_receipt_id: state.activePlanReceiptId || void 0
|
|
@@ -757,6 +849,7 @@ async function handlePreToolUse(input, state) {
|
|
|
757
849
|
swarm: swarm.team_name ? swarm : void 0,
|
|
758
850
|
timing: { hook_latency_ms: hookLatency2, started_at: hookStart },
|
|
759
851
|
payload_digest: payloadDigest,
|
|
852
|
+
action_readback: actionReadback,
|
|
760
853
|
sandbox_state: detectSandboxState()
|
|
761
854
|
});
|
|
762
855
|
return {
|
|
@@ -781,6 +874,7 @@ async function handlePreToolUse(input, state) {
|
|
|
781
874
|
swarm: swarm.team_name ? swarm : void 0,
|
|
782
875
|
timing: { hook_latency_ms: hookLatency2, started_at: hookStart },
|
|
783
876
|
payload_digest: payloadDigest,
|
|
877
|
+
action_readback: actionReadback,
|
|
784
878
|
sandbox_state: detectSandboxState()
|
|
785
879
|
});
|
|
786
880
|
return {
|
|
@@ -801,13 +895,15 @@ async function handlePreToolUse(input, state) {
|
|
|
801
895
|
hook_event: "PreToolUse",
|
|
802
896
|
swarm: swarm.team_name ? swarm : void 0,
|
|
803
897
|
timing: { hook_latency_ms: hookLatency2, started_at: hookStart },
|
|
898
|
+
payload_digest: payloadDigest,
|
|
899
|
+
action_readback: actionReadback,
|
|
804
900
|
sandbox_state: detectSandboxState()
|
|
805
901
|
});
|
|
806
902
|
return {
|
|
807
903
|
hookSpecificOutput: {
|
|
808
904
|
hookEventName: "PreToolUse",
|
|
809
905
|
permissionDecision: "ask",
|
|
810
|
-
permissionDecisionReason: `[ScopeBlind]
|
|
906
|
+
permissionDecisionReason: `[ScopeBlind] Approval required for exactly this action: ${actionReadback.summary}. Payload hash: ${actionReadback.payload_hash.slice(0, 16)}\u2026 Policy: ${state.policyDigest}`
|
|
811
907
|
}
|
|
812
908
|
};
|
|
813
909
|
}
|
|
@@ -852,6 +948,7 @@ async function handlePreToolUse(input, state) {
|
|
|
852
948
|
swarm: swarm.team_name ? swarm : void 0,
|
|
853
949
|
timing: { hook_latency_ms: hookLatency, started_at: hookStart },
|
|
854
950
|
payload_digest: payloadDigest,
|
|
951
|
+
action_readback: actionReadback,
|
|
855
952
|
sandbox_state: detectSandboxState(),
|
|
856
953
|
plan_receipt_id: state.activePlanReceiptId || void 0
|
|
857
954
|
});
|
|
@@ -868,7 +965,7 @@ async function handlePreToolUse(input, state) {
|
|
|
868
965
|
}
|
|
869
966
|
async function handlePostToolUse(input, state) {
|
|
870
967
|
const toolName = input.toolName || "unknown";
|
|
871
|
-
const requestId = input.toolUseId || (0,
|
|
968
|
+
const requestId = input.toolUseId || (0, import_node_crypto4.randomUUID)().slice(0, 12);
|
|
872
969
|
const now = Date.now();
|
|
873
970
|
const inflight = state.inflightTools.get(requestId);
|
|
874
971
|
const timing = {
|
|
@@ -880,7 +977,7 @@ async function handlePostToolUse(input, state) {
|
|
|
880
977
|
state.inflightTools.delete(requestId);
|
|
881
978
|
}
|
|
882
979
|
const outputDigest = computeOutputDigest(input.toolResult);
|
|
883
|
-
const receiptId = (0,
|
|
980
|
+
const receiptId = (0, import_node_crypto4.randomUUID)().slice(0, 8);
|
|
884
981
|
const policyName = state.cedarPolicies ? `cedar:${state.policyDigest}` : state.policyDigest;
|
|
885
982
|
const additionalContext = `[ScopeBlind] Tool call receipted. Policy: ${policyName}. Decision: allow. Receipt: #${receiptId}.` + (timing.tool_duration_ms !== void 0 ? ` Duration: ${timing.tool_duration_ms}ms.` : "") + (timing.hook_latency_ms !== void 0 ? ` Overhead: ${timing.hook_latency_ms}ms.` : "");
|
|
886
983
|
emitDecisionLog(state, {
|
|
@@ -912,7 +1009,7 @@ function handleSubagentStart(input, state) {
|
|
|
912
1009
|
tool: `subagent:${agentId}`,
|
|
913
1010
|
decision: "allow",
|
|
914
1011
|
reason_code: "subagent_started",
|
|
915
|
-
request_id: (0,
|
|
1012
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
916
1013
|
hook_event: "SubagentStart",
|
|
917
1014
|
swarm: {
|
|
918
1015
|
...state.swarmContext,
|
|
@@ -933,7 +1030,7 @@ function handleSubagentStop(input, state) {
|
|
|
933
1030
|
tool: `subagent:${agentId}`,
|
|
934
1031
|
decision: "allow",
|
|
935
1032
|
reason_code: "subagent_stopped",
|
|
936
|
-
request_id: (0,
|
|
1033
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
937
1034
|
hook_event: "SubagentStop",
|
|
938
1035
|
swarm: {
|
|
939
1036
|
...state.swarmContext,
|
|
@@ -948,7 +1045,7 @@ function handleTaskCreated(input, state) {
|
|
|
948
1045
|
tool: `task:${input.taskId || "unknown"}`,
|
|
949
1046
|
decision: "allow",
|
|
950
1047
|
reason_code: "task_created",
|
|
951
|
-
request_id: (0,
|
|
1048
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
952
1049
|
hook_event: "TaskCreated",
|
|
953
1050
|
swarm: {
|
|
954
1051
|
...state.swarmContext,
|
|
@@ -962,7 +1059,7 @@ function handleTaskCompleted(input, state) {
|
|
|
962
1059
|
tool: `task:${input.taskId || "unknown"}`,
|
|
963
1060
|
decision: "allow",
|
|
964
1061
|
reason_code: "task_completed",
|
|
965
|
-
request_id: (0,
|
|
1062
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
966
1063
|
hook_event: "TaskCompleted",
|
|
967
1064
|
swarm: state.swarmContext
|
|
968
1065
|
});
|
|
@@ -973,7 +1070,7 @@ function handleSessionStart(input, state) {
|
|
|
973
1070
|
tool: "session",
|
|
974
1071
|
decision: "allow",
|
|
975
1072
|
reason_code: "session_started",
|
|
976
|
-
request_id: input.sessionId || (0,
|
|
1073
|
+
request_id: input.sessionId || (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
977
1074
|
hook_event: "SessionStart",
|
|
978
1075
|
swarm: state.swarmContext,
|
|
979
1076
|
sandbox_state: detectSandboxState()
|
|
@@ -996,7 +1093,7 @@ function handleSessionEnd(input, state) {
|
|
|
996
1093
|
tool: "session",
|
|
997
1094
|
decision: "allow",
|
|
998
1095
|
reason_code: "session_ended",
|
|
999
|
-
request_id: input.sessionId || (0,
|
|
1096
|
+
request_id: input.sessionId || (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
1000
1097
|
hook_event: "SessionEnd",
|
|
1001
1098
|
swarm: state.swarmContext
|
|
1002
1099
|
});
|
|
@@ -1007,7 +1104,7 @@ function handleTeammateIdle(input, state) {
|
|
|
1007
1104
|
tool: `teammate:${input.agentId || "unknown"}`,
|
|
1008
1105
|
decision: "allow",
|
|
1009
1106
|
reason_code: "teammate_idle",
|
|
1010
|
-
request_id: (0,
|
|
1107
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
1011
1108
|
hook_event: "TeammateIdle",
|
|
1012
1109
|
swarm: {
|
|
1013
1110
|
...state.swarmContext,
|
|
@@ -1035,7 +1132,7 @@ function handleConfigChange(input, state) {
|
|
|
1035
1132
|
tool: "config",
|
|
1036
1133
|
decision: "deny",
|
|
1037
1134
|
reason_code: "config_tamper_detected",
|
|
1038
|
-
request_id: (0,
|
|
1135
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
1039
1136
|
hook_event: "ConfigChange",
|
|
1040
1137
|
swarm: state.swarmContext
|
|
1041
1138
|
});
|
|
@@ -1044,7 +1141,7 @@ function handleConfigChange(input, state) {
|
|
|
1044
1141
|
tool: "config",
|
|
1045
1142
|
decision: "allow",
|
|
1046
1143
|
reason_code: "config_changed",
|
|
1047
|
-
request_id: (0,
|
|
1144
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
1048
1145
|
hook_event: "ConfigChange"
|
|
1049
1146
|
});
|
|
1050
1147
|
}
|
|
@@ -1066,7 +1163,7 @@ function handleStop(input, state) {
|
|
|
1066
1163
|
tool: "session",
|
|
1067
1164
|
decision: "allow",
|
|
1068
1165
|
reason_code: "agent_stopped",
|
|
1069
|
-
request_id: (0,
|
|
1166
|
+
request_id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
1070
1167
|
hook_event: "Stop",
|
|
1071
1168
|
swarm: state.swarmContext
|
|
1072
1169
|
});
|
|
@@ -1074,8 +1171,8 @@ function handleStop(input, state) {
|
|
|
1074
1171
|
}
|
|
1075
1172
|
function emitDecisionLog(state, entry) {
|
|
1076
1173
|
const mode = state.enforce ? "enforce" : "shadow";
|
|
1077
|
-
const otelTraceId = (0,
|
|
1078
|
-
const otelSpanId = (0,
|
|
1174
|
+
const otelTraceId = (0, import_node_crypto4.randomBytes)(16).toString("hex");
|
|
1175
|
+
const otelSpanId = (0, import_node_crypto4.randomBytes)(8).toString("hex");
|
|
1079
1176
|
const log = {
|
|
1080
1177
|
v: 2,
|
|
1081
1178
|
tool: entry.tool || "unknown",
|
|
@@ -1083,7 +1180,7 @@ function emitDecisionLog(state, entry) {
|
|
|
1083
1180
|
reason_code: entry.reason_code || "default_allow",
|
|
1084
1181
|
policy_digest: state.policyDigest,
|
|
1085
1182
|
policy_engine: state.cedarPolicies ? "cedar" : "built-in",
|
|
1086
|
-
request_id: entry.request_id || (0,
|
|
1183
|
+
request_id: entry.request_id || (0, import_node_crypto4.randomUUID)().slice(0, 12),
|
|
1087
1184
|
timestamp: Date.now(),
|
|
1088
1185
|
mode,
|
|
1089
1186
|
otel_trace_id: otelTraceId,
|
|
@@ -1264,7 +1361,7 @@ async function startHookServer(options = {}) {
|
|
|
1264
1361
|
res.end(JSON.stringify({
|
|
1265
1362
|
status: "ok",
|
|
1266
1363
|
server: "protect-mcp-hooks",
|
|
1267
|
-
version:
|
|
1364
|
+
version: process.env.PROTECT_MCP_VERSION || "unknown",
|
|
1268
1365
|
uptime_ms: Date.now() - state.startTime,
|
|
1269
1366
|
mode: enforce ? "enforce" : "shadow",
|
|
1270
1367
|
policy_digest: policyDigest,
|
|
@@ -1351,9 +1448,10 @@ async function startHookServer(options = {}) {
|
|
|
1351
1448
|
const pad = (s, n = 46) => s.padEnd(n);
|
|
1352
1449
|
w(`
|
|
1353
1450
|
`);
|
|
1354
|
-
w(` protect-mcp
|
|
1451
|
+
w(process.env.PROTECT_MCP_VERSION ? ` protect-mcp v${process.env.PROTECT_MCP_VERSION}
|
|
1452
|
+
` : ` protect-mcp
|
|
1355
1453
|
`);
|
|
1356
|
-
w(` ScopeBlind \
|
|
1454
|
+
w(` ScopeBlind \xB7 https://scopeblind.com
|
|
1357
1455
|
`);
|
|
1358
1456
|
w(`
|
|
1359
1457
|
`);
|
|
@@ -1381,7 +1479,13 @@ async function startHookServer(options = {}) {
|
|
|
1381
1479
|
`);
|
|
1382
1480
|
w(`
|
|
1383
1481
|
`);
|
|
1384
|
-
w(` deny is authoritative
|
|
1482
|
+
w(` deny is authoritative: it cannot be overridden.
|
|
1483
|
+
`);
|
|
1484
|
+
w(`
|
|
1485
|
+
`);
|
|
1486
|
+
w(` See your record npx protect-mcp record
|
|
1487
|
+
`);
|
|
1488
|
+
w(` a searchable view of every decision, all on this machine
|
|
1385
1489
|
`);
|
|
1386
1490
|
w(`
|
|
1387
1491
|
`);
|
package/dist/hook-server.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProtectGateway
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-VTPZ4G5I.mjs";
|
|
4
|
+
import "./chunk-WIPWNWMJ.mjs";
|
|
5
5
|
import "./chunk-PQJP2ZCI.mjs";
|
|
6
6
|
|
|
7
7
|
// src/http-transport.ts
|
|
@@ -34,7 +34,7 @@ async function startHttpTransport(options) {
|
|
|
34
34
|
res.end(JSON.stringify({
|
|
35
35
|
status: "ok",
|
|
36
36
|
server: "protect-mcp",
|
|
37
|
-
version:
|
|
37
|
+
version: process.env.PROTECT_MCP_VERSION || "unknown",
|
|
38
38
|
transport: "streamable-http",
|
|
39
39
|
mode: config.policy ? config.enforce ? "enforce" : "shadow" : "shadow",
|
|
40
40
|
wrapping: serverCommand.join(" ")
|