protect-mcp 0.5.1 → 0.5.3
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 +2 -2
- package/dist/{chunk-IUFFDQYZ.mjs → chunk-BYYWYSHM.mjs} +1 -1
- package/dist/{chunk-YKM6W6T7.mjs → chunk-GQWJCHQV.mjs} +2 -2
- package/dist/{chunk-IAJJA5IW.mjs → chunk-HFM6K7E4.mjs} +1 -1
- package/dist/{chunk-UEHLYOJY.mjs → chunk-NMZPXXL3.mjs} +2 -0
- package/dist/{chunk-V52W3XIN.mjs → chunk-YTBC72JJ.mjs} +26 -9
- package/dist/cli.js +188 -14
- package/dist/cli.mjs +163 -9
- package/dist/hook-patterns.js +2 -0
- package/dist/hook-patterns.mjs +1 -1
- package/dist/hook-server.js +26 -9
- package/dist/hook-server.mjs +2 -2
- package/dist/{http-transport-GXIXLVJQ.mjs → http-transport-LNBENGXD.mjs} +2 -2
- package/dist/index.d.mts +125 -1
- package/dist/index.d.ts +125 -1
- package/dist/index.js +305 -9
- package/dist/index.mjs +280 -5
- package/package.json +2 -2
- package/policies/cedar/secrets-detection.cedar +113 -0
package/README.md
CHANGED
|
@@ -248,9 +248,9 @@ Self-contained offline-verifiable bundle with receipts + signing keys. Verify wi
|
|
|
248
248
|
|
|
249
249
|
## Standards & IP
|
|
250
250
|
|
|
251
|
-
- **IETF Internet-Draft**: [draft-farley-acta-signed-receipts-
|
|
251
|
+
- **IETF Internet-Draft**: [draft-farley-acta-signed-receipts-01](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/) — Signed Decision Receipts for Machine-to-Machine Access Control
|
|
252
252
|
- **Patent Status**: 4 Australian provisional patents pending (2025-2026) covering decision receipts with configurable disclosure, tool-calling gateway, agent manifests, and portable identity
|
|
253
|
-
- **Verification**:
|
|
253
|
+
- **Verification**: Apache-2.0 — `npx @veritasacta/verify --self-test`
|
|
254
254
|
- **Microsoft AGT Integration**: [PR #667](https://github.com/microsoft/agent-governance-toolkit/pull/667) — Cedar policy bridge for Agent Governance Toolkit
|
|
255
255
|
|
|
256
256
|
## License
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
meetsMinTier
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BYYWYSHM.mjs";
|
|
4
4
|
import {
|
|
5
5
|
checkRateLimit,
|
|
6
6
|
getToolPolicy,
|
|
7
7
|
parseRateLimit
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-YTBC72JJ.mjs";
|
|
9
9
|
|
|
10
10
|
// src/simulate.ts
|
|
11
11
|
import { readFileSync } from "fs";
|
|
@@ -272,6 +272,8 @@ context: inline
|
|
|
272
272
|
|
|
273
273
|
# ScopeBlind Receipt Verification
|
|
274
274
|
|
|
275
|
+
Every AI agent tool call gets a cryptographic receipt. Verify offline. No vendor trust required.
|
|
276
|
+
|
|
275
277
|
When the user asks to verify receipts or check the audit trail:
|
|
276
278
|
|
|
277
279
|
1. **Check for receipt files:**
|
|
@@ -130,7 +130,14 @@ function signDecision(entry) {
|
|
|
130
130
|
scope: entry.request_id,
|
|
131
131
|
// request scope
|
|
132
132
|
mode: entry.mode,
|
|
133
|
-
request_id: entry.request_id
|
|
133
|
+
request_id: entry.request_id,
|
|
134
|
+
// Spec version: ties every receipt to the IETF standard
|
|
135
|
+
spec: "draft-farley-acta-signed-receipts-01",
|
|
136
|
+
// Issuer certification: distinguishes VOPRF-backed receipts from self-signed ones
|
|
137
|
+
// - scopeblind:verified = issued via ScopeBlind VOPRF backend (paid tier)
|
|
138
|
+
// - self-signed = signed with local Ed25519 key (free tier, protect-mcp default)
|
|
139
|
+
// - uncertified = unsigned receipt (shadow mode, no signing configured)
|
|
140
|
+
issuer_certification: signerState ? "self-signed" : "uncertified"
|
|
134
141
|
};
|
|
135
142
|
if (entry.tier) payload.tier = entry.tier;
|
|
136
143
|
if (entry.credential_ref) payload.credential_ref = entry.credential_ref;
|
|
@@ -138,6 +145,12 @@ function signDecision(entry) {
|
|
|
138
145
|
payload.rate_limit_remaining = entry.rate_limit_remaining;
|
|
139
146
|
}
|
|
140
147
|
if (entry.policy_engine) payload.policy_engine = entry.policy_engine;
|
|
148
|
+
if (entry.hook_event) payload.hook_event = entry.hook_event;
|
|
149
|
+
if (entry.sandbox_state) payload.sandbox_state = entry.sandbox_state;
|
|
150
|
+
if (entry.timing) payload.timing = entry.timing;
|
|
151
|
+
if (entry.swarm) payload.swarm = entry.swarm;
|
|
152
|
+
if (entry.payload_digest) payload.payload_digest = entry.payload_digest;
|
|
153
|
+
if (entry.deny_iteration) payload.deny_iteration = entry.deny_iteration;
|
|
141
154
|
const result = artifactsModule.createSignedArtifact(
|
|
142
155
|
artifactType,
|
|
143
156
|
payload,
|
|
@@ -232,7 +245,7 @@ function buildEntities(req) {
|
|
|
232
245
|
}
|
|
233
246
|
];
|
|
234
247
|
}
|
|
235
|
-
async function evaluateCedar(policySet, req) {
|
|
248
|
+
async function evaluateCedar(policySet, req, schema) {
|
|
236
249
|
const available = await ensureCedarWasm();
|
|
237
250
|
if (!available) {
|
|
238
251
|
return {
|
|
@@ -243,16 +256,21 @@ async function evaluateCedar(policySet, req) {
|
|
|
243
256
|
}
|
|
244
257
|
try {
|
|
245
258
|
const agentId = req.agentId || req.tier;
|
|
259
|
+
const context = {
|
|
260
|
+
tier: req.tier,
|
|
261
|
+
...req.context || {}
|
|
262
|
+
};
|
|
263
|
+
if (req.toolInput && Object.keys(req.toolInput).length > 0) {
|
|
264
|
+
context.input = req.toolInput;
|
|
265
|
+
}
|
|
246
266
|
const authRequest = {
|
|
247
267
|
principal: { type: "Agent", id: agentId },
|
|
248
268
|
action: { type: "Action", id: "MCP::Tool::call" },
|
|
249
269
|
resource: { type: "Tool", id: req.tool },
|
|
250
|
-
context
|
|
251
|
-
tier: req.tier,
|
|
252
|
-
...req.context || {}
|
|
253
|
-
}
|
|
270
|
+
context
|
|
254
271
|
};
|
|
255
272
|
const entities = buildEntities(req);
|
|
273
|
+
const cedarSchema = schema?.schemaJson ?? null;
|
|
256
274
|
let result;
|
|
257
275
|
if (typeof cedarWasm.isAuthorized === "function") {
|
|
258
276
|
result = cedarWasm.isAuthorized({
|
|
@@ -262,8 +280,7 @@ async function evaluateCedar(policySet, req) {
|
|
|
262
280
|
action: authRequest.action,
|
|
263
281
|
resource: authRequest.resource,
|
|
264
282
|
context: authRequest.context,
|
|
265
|
-
schema:
|
|
266
|
-
// No schema enforcement — Cedar still evaluates correctly
|
|
283
|
+
schema: cedarSchema
|
|
267
284
|
});
|
|
268
285
|
} else if (typeof cedarWasm.checkAuthorization === "function") {
|
|
269
286
|
result = cedarWasm.checkAuthorization(
|
|
@@ -281,7 +298,7 @@ async function evaluateCedar(policySet, req) {
|
|
|
281
298
|
action: authRequest.action,
|
|
282
299
|
resource: authRequest.resource,
|
|
283
300
|
context: authRequest.context,
|
|
284
|
-
schema:
|
|
301
|
+
schema: cedarSchema
|
|
285
302
|
});
|
|
286
303
|
} else {
|
|
287
304
|
return {
|
package/dist/cli.js
CHANGED
|
@@ -411,7 +411,14 @@ function signDecision(entry) {
|
|
|
411
411
|
scope: entry.request_id,
|
|
412
412
|
// request scope
|
|
413
413
|
mode: entry.mode,
|
|
414
|
-
request_id: entry.request_id
|
|
414
|
+
request_id: entry.request_id,
|
|
415
|
+
// Spec version: ties every receipt to the IETF standard
|
|
416
|
+
spec: "draft-farley-acta-signed-receipts-01",
|
|
417
|
+
// Issuer certification: distinguishes VOPRF-backed receipts from self-signed ones
|
|
418
|
+
// - scopeblind:verified = issued via ScopeBlind VOPRF backend (paid tier)
|
|
419
|
+
// - self-signed = signed with local Ed25519 key (free tier, protect-mcp default)
|
|
420
|
+
// - uncertified = unsigned receipt (shadow mode, no signing configured)
|
|
421
|
+
issuer_certification: signerState ? "self-signed" : "uncertified"
|
|
415
422
|
};
|
|
416
423
|
if (entry.tier) payload.tier = entry.tier;
|
|
417
424
|
if (entry.credential_ref) payload.credential_ref = entry.credential_ref;
|
|
@@ -419,6 +426,12 @@ function signDecision(entry) {
|
|
|
419
426
|
payload.rate_limit_remaining = entry.rate_limit_remaining;
|
|
420
427
|
}
|
|
421
428
|
if (entry.policy_engine) payload.policy_engine = entry.policy_engine;
|
|
429
|
+
if (entry.hook_event) payload.hook_event = entry.hook_event;
|
|
430
|
+
if (entry.sandbox_state) payload.sandbox_state = entry.sandbox_state;
|
|
431
|
+
if (entry.timing) payload.timing = entry.timing;
|
|
432
|
+
if (entry.swarm) payload.swarm = entry.swarm;
|
|
433
|
+
if (entry.payload_digest) payload.payload_digest = entry.payload_digest;
|
|
434
|
+
if (entry.deny_iteration) payload.deny_iteration = entry.deny_iteration;
|
|
422
435
|
const result = artifactsModule.createSignedArtifact(
|
|
423
436
|
artifactType,
|
|
424
437
|
payload,
|
|
@@ -682,7 +695,7 @@ function buildEntities(req) {
|
|
|
682
695
|
}
|
|
683
696
|
];
|
|
684
697
|
}
|
|
685
|
-
async function evaluateCedar(policySet, req) {
|
|
698
|
+
async function evaluateCedar(policySet, req, schema) {
|
|
686
699
|
const available = await ensureCedarWasm();
|
|
687
700
|
if (!available) {
|
|
688
701
|
return {
|
|
@@ -693,16 +706,21 @@ async function evaluateCedar(policySet, req) {
|
|
|
693
706
|
}
|
|
694
707
|
try {
|
|
695
708
|
const agentId = req.agentId || req.tier;
|
|
709
|
+
const context = {
|
|
710
|
+
tier: req.tier,
|
|
711
|
+
...req.context || {}
|
|
712
|
+
};
|
|
713
|
+
if (req.toolInput && Object.keys(req.toolInput).length > 0) {
|
|
714
|
+
context.input = req.toolInput;
|
|
715
|
+
}
|
|
696
716
|
const authRequest = {
|
|
697
717
|
principal: { type: "Agent", id: agentId },
|
|
698
718
|
action: { type: "Action", id: "MCP::Tool::call" },
|
|
699
719
|
resource: { type: "Tool", id: req.tool },
|
|
700
|
-
context
|
|
701
|
-
tier: req.tier,
|
|
702
|
-
...req.context || {}
|
|
703
|
-
}
|
|
720
|
+
context
|
|
704
721
|
};
|
|
705
722
|
const entities = buildEntities(req);
|
|
723
|
+
const cedarSchema = schema?.schemaJson ?? null;
|
|
706
724
|
let result;
|
|
707
725
|
if (typeof cedarWasm.isAuthorized === "function") {
|
|
708
726
|
result = cedarWasm.isAuthorized({
|
|
@@ -712,8 +730,7 @@ async function evaluateCedar(policySet, req) {
|
|
|
712
730
|
action: authRequest.action,
|
|
713
731
|
resource: authRequest.resource,
|
|
714
732
|
context: authRequest.context,
|
|
715
|
-
schema:
|
|
716
|
-
// No schema enforcement — Cedar still evaluates correctly
|
|
733
|
+
schema: cedarSchema
|
|
717
734
|
});
|
|
718
735
|
} else if (typeof cedarWasm.checkAuthorization === "function") {
|
|
719
736
|
result = cedarWasm.checkAuthorization(
|
|
@@ -731,7 +748,7 @@ async function evaluateCedar(policySet, req) {
|
|
|
731
748
|
action: authRequest.action,
|
|
732
749
|
resource: authRequest.resource,
|
|
733
750
|
context: authRequest.context,
|
|
734
|
-
schema:
|
|
751
|
+
schema: cedarSchema
|
|
735
752
|
});
|
|
736
753
|
} else {
|
|
737
754
|
return {
|
|
@@ -4540,6 +4557,8 @@ context: inline
|
|
|
4540
4557
|
|
|
4541
4558
|
# ScopeBlind Receipt Verification
|
|
4542
4559
|
|
|
4560
|
+
Every AI agent tool call gets a cryptographic receipt. Verify offline. No vendor trust required.
|
|
4561
|
+
|
|
4543
4562
|
When the user asks to verify receipts or check the audit trail:
|
|
4544
4563
|
|
|
4545
4564
|
1. **Check for receipt files:**
|
|
@@ -6047,6 +6066,7 @@ function formatSimulation(summary) {
|
|
|
6047
6066
|
|
|
6048
6067
|
// src/cli.ts
|
|
6049
6068
|
init_cedar_evaluator();
|
|
6069
|
+
var import_meta = {};
|
|
6050
6070
|
function printHelp() {
|
|
6051
6071
|
process.stderr.write(`
|
|
6052
6072
|
protect-mcp \u2014 Enterprise security gateway for MCP servers & Claude Code hooks
|
|
@@ -6055,7 +6075,8 @@ Usage:
|
|
|
6055
6075
|
protect-mcp [options] -- <command> [args...]
|
|
6056
6076
|
protect-mcp serve [--port <port>] [--enforce] [--policy <path>] [--cedar <dir>]
|
|
6057
6077
|
protect-mcp init-hooks [--dir <path>] [--port <port>]
|
|
6058
|
-
protect-mcp quickstart
|
|
6078
|
+
protect-mcp quickstart [--connect]
|
|
6079
|
+
protect-mcp connect
|
|
6059
6080
|
protect-mcp init [--dir <path>]
|
|
6060
6081
|
protect-mcp demo
|
|
6061
6082
|
protect-mcp trace <receipt_id> [--endpoint <url>] [--depth <n>]
|
|
@@ -6080,6 +6101,7 @@ Commands:
|
|
|
6080
6101
|
serve Start HTTP hook server for Claude Code integration (port 9377)
|
|
6081
6102
|
init-hooks Generate Claude Code hook config + skill + sample Cedar policy
|
|
6082
6103
|
quickstart Zero-config onboarding: init + demo + show receipts in one command
|
|
6104
|
+
connect Create a ScopeBlind sandbox dashboard and configure receipt upload
|
|
6083
6105
|
init Generate config template, Ed25519 keypair, and sample policy
|
|
6084
6106
|
demo Start a demo server wrapped with protect-mcp (see receipts instantly)
|
|
6085
6107
|
doctor Check your setup: keys, policies, verifier, API connectivity
|
|
@@ -6094,6 +6116,8 @@ Examples:
|
|
|
6094
6116
|
protect-mcp serve --enforce --cedar ./cedar # Enforce Cedar policies
|
|
6095
6117
|
protect-mcp init-hooks # One-command Claude Code setup
|
|
6096
6118
|
protect-mcp quickstart
|
|
6119
|
+
protect-mcp quickstart --connect # Quickstart + create dashboard
|
|
6120
|
+
protect-mcp connect # Connect existing setup to dashboard
|
|
6097
6121
|
protect-mcp -- node my-server.js
|
|
6098
6122
|
protect-mcp init
|
|
6099
6123
|
protect-mcp demo
|
|
@@ -6675,7 +6699,83 @@ ${bold("protect-mcp bundle")}
|
|
|
6675
6699
|
|
|
6676
6700
|
`);
|
|
6677
6701
|
}
|
|
6678
|
-
async function
|
|
6702
|
+
async function createSandbox() {
|
|
6703
|
+
const { mkdirSync, writeFileSync: writeFileSync2, existsSync: existsSync7, readFileSync: readFileSync9 } = await import("fs");
|
|
6704
|
+
const { join: join6 } = await import("path");
|
|
6705
|
+
const { homedir } = await import("os");
|
|
6706
|
+
let response;
|
|
6707
|
+
try {
|
|
6708
|
+
response = await fetch("https://api.scopeblind.com/sandbox/create", { method: "POST" });
|
|
6709
|
+
} catch {
|
|
6710
|
+
process.stderr.write(yellow(" \u26A0 Could not create dashboard (offline or server unavailable).\n"));
|
|
6711
|
+
process.stderr.write(` Run 'npx protect-mcp connect' later to set up the dashboard.
|
|
6712
|
+
|
|
6713
|
+
`);
|
|
6714
|
+
return null;
|
|
6715
|
+
}
|
|
6716
|
+
if (!response.ok) {
|
|
6717
|
+
process.stderr.write(yellow(" \u26A0 Could not create dashboard (offline or server unavailable).\n"));
|
|
6718
|
+
process.stderr.write(` Run 'npx protect-mcp connect' later to set up the dashboard.
|
|
6719
|
+
|
|
6720
|
+
`);
|
|
6721
|
+
return null;
|
|
6722
|
+
}
|
|
6723
|
+
let data;
|
|
6724
|
+
try {
|
|
6725
|
+
data = await response.json();
|
|
6726
|
+
} catch {
|
|
6727
|
+
process.stderr.write(yellow(" \u26A0 Could not create dashboard (unexpected response).\n"));
|
|
6728
|
+
process.stderr.write(` Run 'npx protect-mcp connect' later to set up the dashboard.
|
|
6729
|
+
|
|
6730
|
+
`);
|
|
6731
|
+
return null;
|
|
6732
|
+
}
|
|
6733
|
+
const dashboardUrl = `https://scopeblind.com/t/${data.slug}`;
|
|
6734
|
+
const configDir = join6(homedir(), ".protect-mcp");
|
|
6735
|
+
if (!existsSync7(configDir)) {
|
|
6736
|
+
mkdirSync(configDir, { recursive: true });
|
|
6737
|
+
}
|
|
6738
|
+
const configPath = join6(configDir, "config.json");
|
|
6739
|
+
let existing = {};
|
|
6740
|
+
if (existsSync7(configPath)) {
|
|
6741
|
+
try {
|
|
6742
|
+
existing = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
6743
|
+
} catch {
|
|
6744
|
+
}
|
|
6745
|
+
}
|
|
6746
|
+
writeFileSync2(configPath, JSON.stringify({
|
|
6747
|
+
...existing,
|
|
6748
|
+
sandbox_slug: data.slug,
|
|
6749
|
+
dashboard_url: dashboardUrl
|
|
6750
|
+
}, null, 2) + "\n");
|
|
6751
|
+
return dashboardUrl;
|
|
6752
|
+
}
|
|
6753
|
+
async function handleConnect() {
|
|
6754
|
+
process.stderr.write(`
|
|
6755
|
+
${bold("protect-mcp connect")}
|
|
6756
|
+
`);
|
|
6757
|
+
process.stderr.write(`${"\u2500".repeat(50)}
|
|
6758
|
+
|
|
6759
|
+
`);
|
|
6760
|
+
process.stderr.write(` Creating ScopeBlind sandbox dashboard...
|
|
6761
|
+
|
|
6762
|
+
`);
|
|
6763
|
+
const dashboardUrl = await createSandbox();
|
|
6764
|
+
if (dashboardUrl) {
|
|
6765
|
+
process.stderr.write(green(` \u2713 Dashboard created: ${dashboardUrl}
|
|
6766
|
+
`));
|
|
6767
|
+
process.stderr.write(` Receipts will be uploaded automatically.
|
|
6768
|
+
`);
|
|
6769
|
+
process.stderr.write(dim(` Free tier: 20,000 receipts/month \u2014 no credit card required.
|
|
6770
|
+
`));
|
|
6771
|
+
process.stderr.write(`
|
|
6772
|
+
${"\u2500".repeat(50)}
|
|
6773
|
+
|
|
6774
|
+
`);
|
|
6775
|
+
}
|
|
6776
|
+
}
|
|
6777
|
+
async function handleQuickstart(argv) {
|
|
6778
|
+
const connectFlag = argv.includes("--connect");
|
|
6679
6779
|
const { mkdtempSync, writeFileSync: writeFileSync2, existsSync: existsSync7, mkdirSync, readFileSync: readFileSync9 } = await import("fs");
|
|
6680
6780
|
const { join: join6 } = await import("path");
|
|
6681
6781
|
const { tmpdir } = await import("os");
|
|
@@ -6695,9 +6795,13 @@ ${bold("protect-mcp quickstart")}
|
|
|
6695
6795
|
process.stdout.write(` 3. Start a demo MCP server with protect-mcp wrapping it
|
|
6696
6796
|
`);
|
|
6697
6797
|
process.stdout.write(` 4. Log signed receipts for every tool call
|
|
6698
|
-
|
|
6699
6798
|
`);
|
|
6700
|
-
|
|
6799
|
+
if (connectFlag) {
|
|
6800
|
+
process.stdout.write(` 5. Create a ScopeBlind dashboard for receipt viewing
|
|
6801
|
+
`);
|
|
6802
|
+
}
|
|
6803
|
+
process.stdout.write(`
|
|
6804
|
+
Working dir: ${dir}
|
|
6701
6805
|
|
|
6702
6806
|
`);
|
|
6703
6807
|
const keysDir = join6(dir, "keys");
|
|
@@ -6748,6 +6852,24 @@ ${bold("protect-mcp quickstart")}
|
|
|
6748
6852
|
process.stdout.write(` \u2713 Signing enabled (Ed25519)
|
|
6749
6853
|
|
|
6750
6854
|
`);
|
|
6855
|
+
if (connectFlag) {
|
|
6856
|
+
process.stdout.write(`${bold("Connecting to ScopeBlind dashboard...")}
|
|
6857
|
+
|
|
6858
|
+
`);
|
|
6859
|
+
const dashboardUrl = await createSandbox();
|
|
6860
|
+
if (dashboardUrl) {
|
|
6861
|
+
const updatedConfig = { ...config, dashboard_url: dashboardUrl };
|
|
6862
|
+
writeFileSync2(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
6863
|
+
process.stdout.write(green(` \u2713 Dashboard created: ${dashboardUrl}
|
|
6864
|
+
`));
|
|
6865
|
+
process.stdout.write(` Receipts will be uploaded automatically.
|
|
6866
|
+
`);
|
|
6867
|
+
process.stdout.write(dim(` Free tier: 20,000 receipts/month \u2014 no credit card required.
|
|
6868
|
+
`));
|
|
6869
|
+
process.stdout.write(`
|
|
6870
|
+
`);
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6751
6873
|
process.stdout.write(`${bold("Starting demo server...")}
|
|
6752
6874
|
|
|
6753
6875
|
`);
|
|
@@ -7149,7 +7271,55 @@ ${bold("protect-mcp init-hooks")}
|
|
|
7149
7271
|
|
|
7150
7272
|
`);
|
|
7151
7273
|
}
|
|
7274
|
+
async function sendInstallTelemetry() {
|
|
7275
|
+
try {
|
|
7276
|
+
const { existsSync: existsSync7, mkdirSync, writeFileSync: writeFileSync2, readFileSync: readFileSync9 } = await import("fs");
|
|
7277
|
+
const { join: join6, dirname } = await import("path");
|
|
7278
|
+
const { homedir } = await import("os");
|
|
7279
|
+
const { fileURLToPath } = await import("url");
|
|
7280
|
+
const markerDir = join6(homedir(), ".protect-mcp");
|
|
7281
|
+
const markerFile = join6(markerDir, ".telemetry-sent");
|
|
7282
|
+
if (existsSync7(markerFile) || process.env.PROTECT_MCP_TELEMETRY === "off") {
|
|
7283
|
+
return;
|
|
7284
|
+
}
|
|
7285
|
+
let version = "unknown";
|
|
7286
|
+
try {
|
|
7287
|
+
const thisDir = dirname(fileURLToPath(import_meta.url));
|
|
7288
|
+
const pkgPath = join6(thisDir, "..", "package.json");
|
|
7289
|
+
if (existsSync7(pkgPath)) {
|
|
7290
|
+
version = JSON.parse(readFileSync9(pkgPath, "utf-8")).version;
|
|
7291
|
+
}
|
|
7292
|
+
} catch {
|
|
7293
|
+
}
|
|
7294
|
+
const controller = new AbortController();
|
|
7295
|
+
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
7296
|
+
fetch("https://api.scopeblind.com/telemetry/install", {
|
|
7297
|
+
method: "POST",
|
|
7298
|
+
headers: { "Content-Type": "application/json" },
|
|
7299
|
+
body: JSON.stringify({
|
|
7300
|
+
package: "protect-mcp",
|
|
7301
|
+
version,
|
|
7302
|
+
os: process.platform,
|
|
7303
|
+
arch: process.arch,
|
|
7304
|
+
node: process.version,
|
|
7305
|
+
ts: Date.now()
|
|
7306
|
+
}),
|
|
7307
|
+
signal: controller.signal
|
|
7308
|
+
}).catch(() => {
|
|
7309
|
+
}).finally(() => clearTimeout(timeout));
|
|
7310
|
+
if (!existsSync7(markerDir)) {
|
|
7311
|
+
mkdirSync(markerDir, { recursive: true });
|
|
7312
|
+
}
|
|
7313
|
+
writeFileSync2(markerFile, String(Date.now()), "utf-8");
|
|
7314
|
+
process.stderr.write(
|
|
7315
|
+
"[protect-mcp] Anonymous install telemetry sent (disable: PROTECT_MCP_TELEMETRY=off)\n"
|
|
7316
|
+
);
|
|
7317
|
+
} catch {
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7152
7320
|
async function main() {
|
|
7321
|
+
sendInstallTelemetry().catch(() => {
|
|
7322
|
+
});
|
|
7153
7323
|
const args = process.argv.slice(2);
|
|
7154
7324
|
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
7155
7325
|
printHelp();
|
|
@@ -7177,9 +7347,13 @@ async function main() {
|
|
|
7177
7347
|
process.exit(0);
|
|
7178
7348
|
}
|
|
7179
7349
|
if (args[0] === "quickstart") {
|
|
7180
|
-
await handleQuickstart();
|
|
7350
|
+
await handleQuickstart(args.slice(1));
|
|
7181
7351
|
return;
|
|
7182
7352
|
}
|
|
7353
|
+
if (args[0] === "connect") {
|
|
7354
|
+
await handleConnect();
|
|
7355
|
+
process.exit(0);
|
|
7356
|
+
}
|
|
7183
7357
|
if (args[0] === "init") {
|
|
7184
7358
|
await handleInit(args.slice(1));
|
|
7185
7359
|
process.exit(0);
|