protect-mcp 0.6.0 → 0.6.2

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/dist/index.js CHANGED
@@ -35022,6 +35022,7 @@ __export(index_exports, {
35022
35022
  ConfidentialGate: () => ConfidentialGate,
35023
35023
  ProtectGateway: () => ProtectGateway,
35024
35024
  ReceiptPropagator: () => ReceiptPropagator,
35025
+ ScopeBlindBridge: () => ScopeBlindBridge,
35025
35026
  anchorToRekor: () => anchorToRekor,
35026
35027
  buildDecisionContext: () => buildDecisionContext,
35027
35028
  checkRateLimit: () => checkRateLimit,
@@ -35048,6 +35049,7 @@ __export(index_exports, {
35048
35049
  exportJSONL: () => exportJSONL,
35049
35050
  formatReportMarkdown: () => formatReportMarkdown,
35050
35051
  formatSimulation: () => formatSimulation,
35052
+ forwardReceipt: () => forwardReceipt,
35051
35053
  generateC2PACommand: () => generateC2PACommand,
35052
35054
  generateCedarSchema: () => generateCedarSchema,
35053
35055
  generateDatasetCard: () => generateDatasetCard,
@@ -35058,6 +35060,7 @@ __export(index_exports, {
35058
35060
  generateSampleCedarPolicy: () => generateSampleCedarPolicy,
35059
35061
  generateSchemaStub: () => generateSchemaStub,
35060
35062
  generateVerifyReceiptSkill: () => generateVerifyReceiptSkill,
35063
+ getScopeBlindBridge: () => getScopeBlindBridge,
35061
35064
  getSignerInfo: () => getSignerInfo,
35062
35065
  getToolPolicy: () => getToolPolicy,
35063
35066
  hashReceipt: () => hashReceipt,
@@ -35424,11 +35427,40 @@ function validateCredentials(credentials) {
35424
35427
  var import_node_fs3 = require("fs");
35425
35428
  var signerState = null;
35426
35429
  var artifactsModule = null;
35430
+ var signingConfigured = false;
35431
+ var signingInitError = null;
35427
35432
  async function initSigning(config) {
35428
35433
  const warnings = [];
35434
+ signerState = null;
35435
+ artifactsModule = null;
35436
+ signingConfigured = Boolean(config && config.enabled !== false);
35437
+ signingInitError = null;
35429
35438
  if (!config || config.enabled === false) {
35430
35439
  return warnings;
35431
35440
  }
35441
+ if (!config.key_path) {
35442
+ signingInitError = "signing enabled but key_path is not configured";
35443
+ warnings.push(`signing: ${signingInitError}`);
35444
+ return warnings;
35445
+ }
35446
+ if (!(0, import_node_fs3.existsSync)(config.key_path)) {
35447
+ signingInitError = `key file not found at ${config.key_path}`;
35448
+ warnings.push(`signing: ${signingInitError} \u2014 run "protect-mcp init" to generate`);
35449
+ return warnings;
35450
+ }
35451
+ let keyData;
35452
+ try {
35453
+ keyData = JSON.parse((0, import_node_fs3.readFileSync)(config.key_path, "utf-8"));
35454
+ if (!keyData.privateKey || !keyData.publicKey) {
35455
+ signingInitError = "key file missing privateKey or publicKey fields";
35456
+ warnings.push(`signing: ${signingInitError}`);
35457
+ return warnings;
35458
+ }
35459
+ } catch (err) {
35460
+ signingInitError = `failed to load key file: ${err instanceof Error ? err.message : err}`;
35461
+ warnings.push(`signing: ${signingInitError}`);
35462
+ return warnings;
35463
+ }
35432
35464
  try {
35433
35465
  const moduleName = "@veritasacta/artifacts";
35434
35466
  artifactsModule = await import(
@@ -35436,37 +35468,48 @@ async function initSigning(config) {
35436
35468
  moduleName
35437
35469
  );
35438
35470
  } catch {
35439
- warnings.push("signing: @veritasacta/artifacts not available \u2014 receipts will be unsigned");
35471
+ signingInitError = "@veritasacta/artifacts not available";
35472
+ warnings.push(`signing: ${signingInitError} \u2014 enforce mode will fail closed`);
35440
35473
  return warnings;
35441
35474
  }
35442
- if (config.key_path) {
35443
- if (!(0, import_node_fs3.existsSync)(config.key_path)) {
35444
- warnings.push(`signing: key file not found at ${config.key_path} \u2014 run "protect-mcp init" to generate`);
35445
- return warnings;
35446
- }
35447
- try {
35448
- const keyData = JSON.parse((0, import_node_fs3.readFileSync)(config.key_path, "utf-8"));
35449
- if (!keyData.privateKey || !keyData.publicKey) {
35450
- warnings.push("signing: key file missing privateKey or publicKey fields");
35451
- return warnings;
35452
- }
35453
- signerState = {
35454
- privateKey: keyData.privateKey,
35455
- publicKey: keyData.publicKey,
35456
- kid: keyData.kid || artifactsModule.computeKid(keyData.publicKey),
35457
- issuer: config.issuer || keyData.issuer || "protect-mcp"
35458
- };
35459
- } catch (err) {
35460
- warnings.push(`signing: failed to load key file: ${err instanceof Error ? err.message : err}`);
35461
- }
35475
+ try {
35476
+ signerState = {
35477
+ privateKey: keyData.privateKey,
35478
+ publicKey: keyData.publicKey,
35479
+ kid: keyData.kid || artifactsModule.computeKid(keyData.publicKey),
35480
+ issuer: config.issuer || keyData.issuer || "protect-mcp"
35481
+ };
35482
+ } catch (err) {
35483
+ signingInitError = `failed to initialize signer: ${err instanceof Error ? err.message : err}`;
35484
+ artifactsModule = null;
35485
+ warnings.push(`signing: ${signingInitError} \u2014 enforce mode will fail closed`);
35462
35486
  }
35463
35487
  return warnings;
35464
35488
  }
35465
35489
  function signDecision(entry) {
35490
+ const artifactType = entry.decision === "deny" ? "gateway_restraint" : "decision_receipt";
35491
+ if (signingConfigured && signingInitError) {
35492
+ return {
35493
+ ok: false,
35494
+ signed: null,
35495
+ artifact_type: artifactType,
35496
+ warning: `signing initialization failed: ${signingInitError}`,
35497
+ error: signingInitError
35498
+ };
35499
+ }
35500
+ if (signingConfigured && (!signerState || !artifactsModule)) {
35501
+ const error = "signing was configured but no signer is ready";
35502
+ return {
35503
+ ok: false,
35504
+ signed: null,
35505
+ artifact_type: artifactType,
35506
+ warning: error,
35507
+ error
35508
+ };
35509
+ }
35466
35510
  if (!signerState || !artifactsModule) {
35467
- return { signed: null, artifact_type: "none" };
35511
+ return { ok: false, signed: null, artifact_type: "none" };
35468
35512
  }
35469
- const artifactType = entry.decision === "deny" ? "gateway_restraint" : "decision_receipt";
35470
35513
  try {
35471
35514
  const payload = {
35472
35515
  tool: entry.tool,
@@ -35507,14 +35550,18 @@ function signDecision(entry) {
35507
35550
  }
35508
35551
  );
35509
35552
  return {
35553
+ ok: true,
35510
35554
  signed: JSON.stringify(result.artifact),
35511
35555
  artifact_type: artifactType
35512
35556
  };
35513
35557
  } catch (err) {
35558
+ const message = err instanceof Error ? err.message : "unknown error";
35514
35559
  return {
35560
+ ok: false,
35515
35561
  signed: null,
35516
35562
  artifact_type: artifactType,
35517
- warning: `signing failed: ${err instanceof Error ? err.message : "unknown error"}`
35563
+ warning: `signing failed: ${message}`,
35564
+ error: message
35518
35565
  };
35519
35566
  }
35520
35567
  }
@@ -35527,7 +35574,7 @@ function getSignerInfo() {
35527
35574
  };
35528
35575
  }
35529
35576
  function isSigningEnabled() {
35530
- return signerState !== null && artifactsModule !== null;
35577
+ return signingConfigured && signingInitError === null && signerState !== null && artifactsModule !== null;
35531
35578
  }
35532
35579
 
35533
35580
  // src/external-pdp.ts
@@ -36655,8 +36702,20 @@ var ProtectGateway = class {
36655
36702
  this.evidenceStore.save();
36656
36703
  }
36657
36704
  }
36658
- } else if (signed.warning) {
36659
- process.stderr.write(`[PROTECT_MCP] Warning: ${signed.warning}
36705
+ } else if (signed.error) {
36706
+ const tombstone = JSON.stringify({
36707
+ type: "scopeblind.signing_failure.v1",
36708
+ request_id: log.request_id,
36709
+ tool: log.tool,
36710
+ decision: log.decision,
36711
+ error: signed.error,
36712
+ at: new Date(log.timestamp).toISOString()
36713
+ });
36714
+ try {
36715
+ (0, import_node_fs6.appendFileSync)(this.receiptFilePath, tombstone + "\n");
36716
+ } catch {
36717
+ }
36718
+ process.stderr.write(`[PROTECT_MCP_SIGNING_FAILURE] ${tombstone}
36660
36719
  `);
36661
36720
  }
36662
36721
  }
@@ -39629,6 +39688,159 @@ var import_node_http2 = require("http");
39629
39688
  var import_node_crypto4 = require("crypto");
39630
39689
  var import_node_fs9 = require("fs");
39631
39690
  var import_node_path5 = require("path");
39691
+
39692
+ // src/scopeblind-bridge.ts
39693
+ var DEFAULT_BASE = "https://scopeblind.com";
39694
+ var FLUSH_INTERVAL_MS = 5e3;
39695
+ var BATCH_MAX = 128;
39696
+ var BRASS_REFRESH_MARGIN_MS = 5 * 60 * 1e3;
39697
+ var ScopeBlindBridge = class {
39698
+ token;
39699
+ base;
39700
+ tenantOverride;
39701
+ cachedProof = null;
39702
+ queue = [];
39703
+ flushTimer = null;
39704
+ stats;
39705
+ shuttingDown = false;
39706
+ constructor(env = process.env) {
39707
+ this.token = env.SCOPEBLIND_TOKEN || null;
39708
+ this.base = (env.SCOPEBLIND_BASE || DEFAULT_BASE).replace(/\/$/, "");
39709
+ this.tenantOverride = env.SCOPEBLIND_TENANT || null;
39710
+ this.stats = {
39711
+ enabled: Boolean(this.token),
39712
+ tenant_slug: this.tenantOverride,
39713
+ forwarded_total: 0,
39714
+ rejected_total: 0,
39715
+ last_flush_at: null,
39716
+ last_error: null
39717
+ };
39718
+ if (this.enabled()) {
39719
+ this.flushTimer = setInterval(() => {
39720
+ void this.flush();
39721
+ }, FLUSH_INTERVAL_MS);
39722
+ if (typeof this.flushTimer === "object" && this.flushTimer && "unref" in this.flushTimer) {
39723
+ this.flushTimer.unref?.();
39724
+ }
39725
+ process.on("beforeExit", () => {
39726
+ void this.shutdown();
39727
+ });
39728
+ }
39729
+ }
39730
+ enabled() {
39731
+ return Boolean(this.token);
39732
+ }
39733
+ /** Push a signed receipt into the queue. Non-blocking. */
39734
+ forward(signedReceipt) {
39735
+ if (!this.enabled() || this.shuttingDown) return;
39736
+ this.queue.push(signedReceipt);
39737
+ if (this.queue.length >= BATCH_MAX) void this.flush();
39738
+ }
39739
+ /** Flush the queue. Safe to call concurrently. */
39740
+ async flush() {
39741
+ if (!this.enabled() || this.queue.length === 0) return;
39742
+ const batch = this.queue.splice(0, BATCH_MAX);
39743
+ try {
39744
+ const proof = await this.ensureBrassProof();
39745
+ const slug = this.tenantOverride || proof?.tenant_id;
39746
+ if (!slug) {
39747
+ this.queue.unshift(...batch);
39748
+ return;
39749
+ }
39750
+ this.stats.tenant_slug = slug;
39751
+ const res = await fetch(`${this.base}/fn/console/${slug}/receipts`, {
39752
+ method: "POST",
39753
+ headers: {
39754
+ "content-type": "application/json",
39755
+ authorization: `Bearer ${this.token}`,
39756
+ "user-agent": "protect-mcp/scopeblind-bridge"
39757
+ },
39758
+ body: JSON.stringify({ receipts: batch })
39759
+ });
39760
+ if (!res.ok) {
39761
+ const errBody = await res.text().catch(() => "");
39762
+ this.stats.last_error = `HTTP ${res.status} ${errBody.slice(0, 160)}`;
39763
+ this.stats.rejected_total += batch.length;
39764
+ if (res.status >= 500 && res.status !== 503) {
39765
+ this.queue.unshift(...batch);
39766
+ }
39767
+ return;
39768
+ }
39769
+ const body = await res.json().catch(() => ({}));
39770
+ this.stats.forwarded_total += body?.accepted ?? batch.length;
39771
+ this.stats.rejected_total += body?.rejected ?? 0;
39772
+ this.stats.last_flush_at = (/* @__PURE__ */ new Date()).toISOString();
39773
+ this.stats.last_error = null;
39774
+ } catch (err) {
39775
+ this.stats.last_error = String(err?.message || err);
39776
+ this.queue.unshift(...batch);
39777
+ }
39778
+ }
39779
+ /** Exchange SCOPEBLIND_TOKEN for a BRASS-v2 proof; refresh near expiry. */
39780
+ async ensureBrassProof() {
39781
+ if (!this.token) return null;
39782
+ const now = Date.now();
39783
+ if (this.cachedProof && Date.parse(this.cachedProof.expires_at) - now > BRASS_REFRESH_MARGIN_MS) {
39784
+ return this.cachedProof;
39785
+ }
39786
+ try {
39787
+ const res = await fetch(`${this.base}/fn/brass/issue`, {
39788
+ method: "POST",
39789
+ headers: {
39790
+ "content-type": "application/json",
39791
+ "user-agent": "protect-mcp/scopeblind-bridge"
39792
+ },
39793
+ body: JSON.stringify({
39794
+ token: this.token,
39795
+ scope: "protect-mcp-receipt-emit",
39796
+ ttl_seconds: 3600
39797
+ })
39798
+ });
39799
+ if (!res.ok) {
39800
+ const text = await res.text().catch(() => "");
39801
+ this.stats.last_error = `brass-issue: HTTP ${res.status} ${text.slice(0, 160)}`;
39802
+ return null;
39803
+ }
39804
+ const body = await res.json();
39805
+ if (!body?.auth_proof) {
39806
+ this.stats.last_error = "brass-issue: missing auth_proof in response";
39807
+ return null;
39808
+ }
39809
+ this.cachedProof = body.auth_proof;
39810
+ return this.cachedProof;
39811
+ } catch (err) {
39812
+ this.stats.last_error = `brass-issue: ${err?.message || err}`;
39813
+ return null;
39814
+ }
39815
+ }
39816
+ /**
39817
+ * Return a snapshot of bridge stats. Useful for `protect-mcp scopeblind status`.
39818
+ */
39819
+ getStats() {
39820
+ return {
39821
+ ...this.stats,
39822
+ queued: this.queue.length,
39823
+ brass_proof_expires_at: this.cachedProof?.expires_at || null
39824
+ };
39825
+ }
39826
+ /** Flush remaining receipts and stop the interval. Called on process exit. */
39827
+ async shutdown() {
39828
+ if (this.shuttingDown) return;
39829
+ this.shuttingDown = true;
39830
+ if (this.flushTimer) clearInterval(this.flushTimer);
39831
+ if (this.queue.length > 0) await this.flush();
39832
+ }
39833
+ };
39834
+ var singleton = null;
39835
+ function getScopeBlindBridge() {
39836
+ if (!singleton) singleton = new ScopeBlindBridge();
39837
+ return singleton;
39838
+ }
39839
+ function forwardReceipt(signedReceipt) {
39840
+ getScopeBlindBridge().forward(signedReceipt);
39841
+ }
39842
+
39843
+ // src/hook-server.ts
39632
39844
  var DEFAULT_PORT = 9377;
39633
39845
  var LOG_FILE3 = ".protect-mcp-log.jsonl";
39634
39846
  var RECEIPTS_FILE2 = ".protect-mcp-receipts.jsonl";
@@ -39836,7 +40048,7 @@ async function handlePreToolUse(input, state) {
39836
40048
  const hookLatency = Date.now() - hookStart;
39837
40049
  const denyKey = `${toolName}:${input.sessionId || "default"}`;
39838
40050
  state.denyCounter.delete(denyKey);
39839
- emitDecisionLog(state, {
40051
+ const emit = emitDecisionLog(state, {
39840
40052
  tool: toolName,
39841
40053
  decision: "allow",
39842
40054
  reason_code: state.cedarPolicies ? "cedar_allow" : state.jsonPolicy ? "policy_allow" : "observe_mode",
@@ -39848,6 +40060,15 @@ async function handlePreToolUse(input, state) {
39848
40060
  sandbox_state: detectSandboxState(),
39849
40061
  plan_receipt_id: state.activePlanReceiptId || void 0
39850
40062
  });
40063
+ if (state.enforce && emit.signingFailed) {
40064
+ return {
40065
+ hookSpecificOutput: {
40066
+ hookEventName: "PreToolUse",
40067
+ permissionDecision: "deny",
40068
+ permissionDecisionReason: `[ScopeBlind] "${toolName}" was blocked because its receipt could not be signed. Failing closed: a governed action that cannot be proven is not allowed.`
40069
+ }
40070
+ };
40071
+ }
39851
40072
  return {};
39852
40073
  }
39853
40074
  async function handlePostToolUse(input, state) {
@@ -40095,11 +40316,35 @@ function emitDecisionLog(state, entry) {
40095
40316
  } catch {
40096
40317
  }
40097
40318
  state.receiptBuffer.add(log.request_id, signed.signed);
40098
- } else if (signed.warning) {
40099
- process.stderr.write(`[PROTECT_MCP] Warning: ${signed.warning}
40319
+ try {
40320
+ const bridge = getScopeBlindBridge();
40321
+ if (bridge.enabled()) {
40322
+ const parsed = typeof signed.signed === "string" ? JSON.parse(signed.signed) : signed.signed;
40323
+ bridge.forward(parsed);
40324
+ }
40325
+ } catch (err) {
40326
+ process.stderr.write(`[PROTECT_MCP] ScopeBlind forward error: ${err instanceof Error ? err.message : err}
40327
+ `);
40328
+ }
40329
+ } else if (signed.error) {
40330
+ const tombstone = JSON.stringify({
40331
+ type: "scopeblind.signing_failure.v1",
40332
+ request_id: log.request_id,
40333
+ tool: log.tool,
40334
+ decision: log.decision,
40335
+ error: signed.error,
40336
+ at: new Date(log.timestamp).toISOString()
40337
+ });
40338
+ try {
40339
+ (0, import_node_fs9.appendFileSync)(state.receiptFilePath, tombstone + "\n");
40340
+ } catch {
40341
+ }
40342
+ process.stderr.write(`[PROTECT_MCP_SIGNING_FAILURE] ${tombstone}
40100
40343
  `);
40344
+ return { signingFailed: true };
40101
40345
  }
40102
40346
  }
40347
+ return { signingFailed: false };
40103
40348
  }
40104
40349
  async function routeHookEvent(input, state) {
40105
40350
  switch (input.hookEventName) {
@@ -42429,6 +42674,7 @@ function createSandboxServer() {
42429
42674
  ConfidentialGate,
42430
42675
  ProtectGateway,
42431
42676
  ReceiptPropagator,
42677
+ ScopeBlindBridge,
42432
42678
  anchorToRekor,
42433
42679
  buildDecisionContext,
42434
42680
  checkRateLimit,
@@ -42455,6 +42701,7 @@ function createSandboxServer() {
42455
42701
  exportJSONL,
42456
42702
  formatReportMarkdown,
42457
42703
  formatSimulation,
42704
+ forwardReceipt,
42458
42705
  generateC2PACommand,
42459
42706
  generateCedarSchema,
42460
42707
  generateDatasetCard,
@@ -42465,6 +42712,7 @@ function createSandboxServer() {
42465
42712
  generateSampleCedarPolicy,
42466
42713
  generateSchemaStub,
42467
42714
  generateVerifyReceiptSkill,
42715
+ getScopeBlindBridge,
42468
42716
  getSignerInfo,
42469
42717
  getToolPolicy,
42470
42718
  hashReceipt,
@@ -42509,6 +42757,36 @@ function createSandboxServer() {
42509
42757
  verifyEvidenceAttestation,
42510
42758
  verifyRekorAnchor
42511
42759
  });
42760
+ /**
42761
+ * scopeblind-bridge.ts
42762
+ *
42763
+ * Optional bridge between protect-mcp (local, MIT) and a paid ScopeBlind
42764
+ * tenant. When SCOPEBLIND_TOKEN is set in the environment, every signed
42765
+ * receipt that protect-mcp emits also gets forwarded to the tenant's
42766
+ * dashboard at https://scopeblind.com/console/<slug>.
42767
+ *
42768
+ * Lifecycle:
42769
+ * 1. On first use, exchange SCOPEBLIND_TOKEN for a short-lived BRASS-v2
42770
+ * auth proof from /fn/brass/issue. Cache the proof in memory until
42771
+ * ~5 minutes before expiry, then refresh.
42772
+ * 2. As receipts are emitted by hook-server.ts, push them into an
42773
+ * in-memory batch queue.
42774
+ * 3. Flush the queue every 5s (or when it reaches 128 receipts) by POSTing
42775
+ * to /fn/console/<slug>/receipts with Bearer SCOPEBLIND_TOKEN.
42776
+ *
42777
+ * Failure mode: forward errors NEVER throw upstream. protect-mcp continues
42778
+ * to mint and persist receipts locally regardless of dashboard availability.
42779
+ * The bridge logs failures to stderr (best-effort) and retries on the next
42780
+ * flush.
42781
+ *
42782
+ * Configuration:
42783
+ * SCOPEBLIND_TOKEN Tenant bearer token (from welcome email).
42784
+ * SCOPEBLIND_TENANT Optional slug override. By default we discover
42785
+ * the slug from the BRASS proof's tenant_id.
42786
+ * SCOPEBLIND_BASE Defaults to https://scopeblind.com.
42787
+ *
42788
+ * @license MIT
42789
+ */
42512
42790
  /*! Bundled license information:
42513
42791
 
42514
42792
  @noble/hashes/esm/utils.js:
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  formatSimulation,
7
7
  parseLogFile,
8
8
  simulate
9
- } from "./chunk-GQWJCHQV.mjs";
9
+ } from "./chunk-S4ICHNSP.mjs";
10
10
  import {
11
11
  ProtectGateway,
12
12
  buildDecisionContext,
@@ -18,7 +18,7 @@ import {
18
18
  resolveCredential,
19
19
  sendApprovalNotification,
20
20
  validateCredentials
21
- } from "./chunk-BYYWYSHM.mjs";
21
+ } from "./chunk-PLKRTBDR.mjs";
22
22
  import {
23
23
  createSandboxServer
24
24
  } from "./chunk-J6L4XCTE.mjs";
@@ -29,8 +29,11 @@ import {
29
29
  generateVerifyReceiptSkill
30
30
  } from "./chunk-NMZPXXL3.mjs";
31
31
  import {
32
+ ScopeBlindBridge,
33
+ forwardReceipt,
34
+ getScopeBlindBridge,
32
35
  startHookServer
33
- } from "./chunk-SPHLVRJ2.mjs";
36
+ } from "./chunk-3YCKR72H.mjs";
34
37
  import {
35
38
  checkRateLimit,
36
39
  evaluateCedar,
@@ -43,7 +46,7 @@ import {
43
46
  loadPolicy,
44
47
  parseRateLimit,
45
48
  signDecision
46
- } from "./chunk-YTBC72JJ.mjs";
49
+ } from "./chunk-UV53U6D4.mjs";
47
50
  import {
48
51
  ed25519,
49
52
  sha256
@@ -1934,6 +1937,7 @@ export {
1934
1937
  ConfidentialGate,
1935
1938
  ProtectGateway,
1936
1939
  ReceiptPropagator,
1940
+ ScopeBlindBridge,
1937
1941
  anchorToRekor,
1938
1942
  buildDecisionContext,
1939
1943
  checkRateLimit,
@@ -1960,6 +1964,7 @@ export {
1960
1964
  exportJSONL,
1961
1965
  formatReportMarkdown,
1962
1966
  formatSimulation,
1967
+ forwardReceipt,
1963
1968
  generateC2PACommand,
1964
1969
  generateCedarSchema,
1965
1970
  generateDatasetCard,
@@ -1970,6 +1975,7 @@ export {
1970
1975
  generateSampleCedarPolicy,
1971
1976
  generateSchemaStub,
1972
1977
  generateVerifyReceiptSkill,
1978
+ getScopeBlindBridge,
1973
1979
  getSignerInfo,
1974
1980
  getToolPolicy,
1975
1981
  hashReceipt,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "protect-mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "mcpName": "com.scopeblind/protect-mcp",
5
- "description": "Enterprise security gateway for MCP servers and Claude Code hooks. Cedar policies, Ed25519-signed receipts, swarm tracking, and tamper detection. Shadow or enforce mode.",
5
+ "description": "Cedar policy + signed receipts for AI agent decisions. Same primitive shipping in ScopeBlind cold-chain hardware. scopeblind.com/cold-chain",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "module": "dist/index.mjs",
@@ -62,6 +62,7 @@
62
62
  "url": "https://github.com/scopeblind/scopeblind-gateway/issues"
63
63
  },
64
64
  "dependencies": {
65
+ "@veritasacta/artifacts": "^0.2.2",
65
66
  "@veritasacta/protocol": "^0.1.0"
66
67
  },
67
68
  "optionalDependencies": {