protect-mcp 0.5.1 → 0.5.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.
@@ -7,7 +7,7 @@ import {
7
7
  parseRateLimit,
8
8
  signDecision,
9
9
  startStatusServer
10
- } from "./chunk-V52W3XIN.mjs";
10
+ } from "./chunk-N4F76LTC.mjs";
11
11
 
12
12
  // src/evidence-store.ts
13
13
  import { readFileSync, writeFileSync, existsSync } from "fs";
@@ -232,7 +232,7 @@ function buildEntities(req) {
232
232
  }
233
233
  ];
234
234
  }
235
- async function evaluateCedar(policySet, req) {
235
+ async function evaluateCedar(policySet, req, schema) {
236
236
  const available = await ensureCedarWasm();
237
237
  if (!available) {
238
238
  return {
@@ -243,16 +243,21 @@ async function evaluateCedar(policySet, req) {
243
243
  }
244
244
  try {
245
245
  const agentId = req.agentId || req.tier;
246
+ const context = {
247
+ tier: req.tier,
248
+ ...req.context || {}
249
+ };
250
+ if (req.toolInput && Object.keys(req.toolInput).length > 0) {
251
+ context.input = req.toolInput;
252
+ }
246
253
  const authRequest = {
247
254
  principal: { type: "Agent", id: agentId },
248
255
  action: { type: "Action", id: "MCP::Tool::call" },
249
256
  resource: { type: "Tool", id: req.tool },
250
- context: {
251
- tier: req.tier,
252
- ...req.context || {}
253
- }
257
+ context
254
258
  };
255
259
  const entities = buildEntities(req);
260
+ const cedarSchema = schema?.schemaJson ?? null;
256
261
  let result;
257
262
  if (typeof cedarWasm.isAuthorized === "function") {
258
263
  result = cedarWasm.isAuthorized({
@@ -262,8 +267,7 @@ async function evaluateCedar(policySet, req) {
262
267
  action: authRequest.action,
263
268
  resource: authRequest.resource,
264
269
  context: authRequest.context,
265
- schema: null
266
- // No schema enforcement — Cedar still evaluates correctly
270
+ schema: cedarSchema
267
271
  });
268
272
  } else if (typeof cedarWasm.checkAuthorization === "function") {
269
273
  result = cedarWasm.checkAuthorization(
@@ -281,7 +285,7 @@ async function evaluateCedar(policySet, req) {
281
285
  action: authRequest.action,
282
286
  resource: authRequest.resource,
283
287
  context: authRequest.context,
284
- schema: null
288
+ schema: cedarSchema
285
289
  });
286
290
  } else {
287
291
  return {
@@ -11,7 +11,7 @@ import {
11
11
  loadPolicy,
12
12
  parseRateLimit,
13
13
  signDecision
14
- } from "./chunk-V52W3XIN.mjs";
14
+ } from "./chunk-N4F76LTC.mjs";
15
15
 
16
16
  // src/hook-server.ts
17
17
  import { createServer } from "http";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  meetsMinTier
3
- } from "./chunk-IUFFDQYZ.mjs";
3
+ } from "./chunk-IWDR5WU3.mjs";
4
4
  import {
5
5
  checkRateLimit,
6
6
  getToolPolicy,
7
7
  parseRateLimit
8
- } from "./chunk-V52W3XIN.mjs";
8
+ } from "./chunk-N4F76LTC.mjs";
9
9
 
10
10
  // src/simulate.ts
11
11
  import { readFileSync } from "fs";
package/dist/cli.js CHANGED
@@ -682,7 +682,7 @@ function buildEntities(req) {
682
682
  }
683
683
  ];
684
684
  }
685
- async function evaluateCedar(policySet, req) {
685
+ async function evaluateCedar(policySet, req, schema) {
686
686
  const available = await ensureCedarWasm();
687
687
  if (!available) {
688
688
  return {
@@ -693,16 +693,21 @@ async function evaluateCedar(policySet, req) {
693
693
  }
694
694
  try {
695
695
  const agentId = req.agentId || req.tier;
696
+ const context = {
697
+ tier: req.tier,
698
+ ...req.context || {}
699
+ };
700
+ if (req.toolInput && Object.keys(req.toolInput).length > 0) {
701
+ context.input = req.toolInput;
702
+ }
696
703
  const authRequest = {
697
704
  principal: { type: "Agent", id: agentId },
698
705
  action: { type: "Action", id: "MCP::Tool::call" },
699
706
  resource: { type: "Tool", id: req.tool },
700
- context: {
701
- tier: req.tier,
702
- ...req.context || {}
703
- }
707
+ context
704
708
  };
705
709
  const entities = buildEntities(req);
710
+ const cedarSchema = schema?.schemaJson ?? null;
706
711
  let result;
707
712
  if (typeof cedarWasm.isAuthorized === "function") {
708
713
  result = cedarWasm.isAuthorized({
@@ -712,8 +717,7 @@ async function evaluateCedar(policySet, req) {
712
717
  action: authRequest.action,
713
718
  resource: authRequest.resource,
714
719
  context: authRequest.context,
715
- schema: null
716
- // No schema enforcement — Cedar still evaluates correctly
720
+ schema: cedarSchema
717
721
  });
718
722
  } else if (typeof cedarWasm.checkAuthorization === "function") {
719
723
  result = cedarWasm.checkAuthorization(
@@ -731,7 +735,7 @@ async function evaluateCedar(policySet, req) {
731
735
  action: authRequest.action,
732
736
  resource: authRequest.resource,
733
737
  context: authRequest.context,
734
- schema: null
738
+ schema: cedarSchema
735
739
  });
736
740
  } else {
737
741
  return {
package/dist/cli.mjs CHANGED
@@ -3,17 +3,17 @@ import {
3
3
  formatSimulation,
4
4
  parseLogFile,
5
5
  simulate
6
- } from "./chunk-YKM6W6T7.mjs";
6
+ } from "./chunk-W4U5VNEC.mjs";
7
7
  import {
8
8
  ProtectGateway,
9
9
  validateCredentials
10
- } from "./chunk-IUFFDQYZ.mjs";
10
+ } from "./chunk-IWDR5WU3.mjs";
11
11
  import {
12
12
  initSigning,
13
13
  isCedarAvailable,
14
14
  loadCedarPolicies,
15
15
  loadPolicy
16
- } from "./chunk-V52W3XIN.mjs";
16
+ } from "./chunk-N4F76LTC.mjs";
17
17
  import "./chunk-PQJP2ZCI.mjs";
18
18
 
19
19
  // src/cli.ts
@@ -1282,7 +1282,7 @@ async function main() {
1282
1282
  if (useHttp) {
1283
1283
  const portIdx = args.indexOf("--port");
1284
1284
  const httpPort = portIdx >= 0 && args[portIdx + 1] ? parseInt(args[portIdx + 1]) : 3e3;
1285
- const { startHttpTransport } = await import("./http-transport-GXIXLVJQ.mjs");
1285
+ const { startHttpTransport } = await import("./http-transport-PWCK7JHZ.mjs");
1286
1286
  startHttpTransport({ port: httpPort, config, serverCommand: childCommand });
1287
1287
  return;
1288
1288
  }
@@ -89,7 +89,7 @@ function buildEntities(req) {
89
89
  }
90
90
  ];
91
91
  }
92
- async function evaluateCedar(policySet, req) {
92
+ async function evaluateCedar(policySet, req, schema) {
93
93
  const available = await ensureCedarWasm();
94
94
  if (!available) {
95
95
  return {
@@ -100,16 +100,21 @@ async function evaluateCedar(policySet, req) {
100
100
  }
101
101
  try {
102
102
  const agentId = req.agentId || req.tier;
103
+ const context = {
104
+ tier: req.tier,
105
+ ...req.context || {}
106
+ };
107
+ if (req.toolInput && Object.keys(req.toolInput).length > 0) {
108
+ context.input = req.toolInput;
109
+ }
103
110
  const authRequest = {
104
111
  principal: { type: "Agent", id: agentId },
105
112
  action: { type: "Action", id: "MCP::Tool::call" },
106
113
  resource: { type: "Tool", id: req.tool },
107
- context: {
108
- tier: req.tier,
109
- ...req.context || {}
110
- }
114
+ context
111
115
  };
112
116
  const entities = buildEntities(req);
117
+ const cedarSchema = schema?.schemaJson ?? null;
113
118
  let result;
114
119
  if (typeof cedarWasm.isAuthorized === "function") {
115
120
  result = cedarWasm.isAuthorized({
@@ -119,8 +124,7 @@ async function evaluateCedar(policySet, req) {
119
124
  action: authRequest.action,
120
125
  resource: authRequest.resource,
121
126
  context: authRequest.context,
122
- schema: null
123
- // No schema enforcement — Cedar still evaluates correctly
127
+ schema: cedarSchema
124
128
  });
125
129
  } else if (typeof cedarWasm.checkAuthorization === "function") {
126
130
  result = cedarWasm.checkAuthorization(
@@ -138,7 +142,7 @@ async function evaluateCedar(policySet, req) {
138
142
  action: authRequest.action,
139
143
  resource: authRequest.resource,
140
144
  context: authRequest.context,
141
- schema: null
145
+ schema: cedarSchema
142
146
  });
143
147
  } else {
144
148
  return {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  startHookServer
3
- } from "./chunk-IAJJA5IW.mjs";
4
- import "./chunk-V52W3XIN.mjs";
3
+ } from "./chunk-Q4KOQUKV.mjs";
4
+ import "./chunk-N4F76LTC.mjs";
5
5
  import "./chunk-PQJP2ZCI.mjs";
6
6
  export {
7
7
  startHookServer
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ProtectGateway
3
- } from "./chunk-IUFFDQYZ.mjs";
4
- import "./chunk-V52W3XIN.mjs";
3
+ } from "./chunk-IWDR5WU3.mjs";
4
+ import "./chunk-N4F76LTC.mjs";
5
5
  import "./chunk-PQJP2ZCI.mjs";
6
6
 
7
7
  // src/http-transport.ts
package/dist/index.d.mts CHANGED
@@ -539,6 +539,45 @@ interface CedarPolicySet {
539
539
  /** Filenames loaded */
540
540
  files: string[];
541
541
  }
542
+ interface CedarEvalRequest {
543
+ /** Tool name being called */
544
+ tool: string;
545
+ /** Trust tier of the agent */
546
+ tier: TrustTier;
547
+ /** Agent ID (optional) */
548
+ agentId?: string;
549
+ /** Additional context fields */
550
+ context?: Record<string, unknown>;
551
+ /** Tool input (for schema-validated evaluation) */
552
+ toolInput?: Record<string, unknown>;
553
+ }
554
+ /** Cedar schema for typed policy evaluation (generated by cedar-schema.ts) */
555
+ interface CedarSchema {
556
+ /** The schema as a JSON object for Cedar WASM */
557
+ schemaJson: Record<string, unknown> | null;
558
+ /** Namespace used in the schema */
559
+ namespace?: string;
560
+ }
561
+ /**
562
+ * Load all .cedar files from a directory and return a compiled policy set.
563
+ *
564
+ * Files are sorted alphabetically for deterministic digest computation.
565
+ * Throws if the directory doesn't exist or contains no .cedar files.
566
+ */
567
+ declare function loadCedarPolicies(dirPath: string): CedarPolicySet;
568
+ /**
569
+ * Evaluate a Cedar policy set against a tool call.
570
+ *
571
+ * Returns a standard ExternalDecision compatible with the gateway's
572
+ * decision pipeline. If Cedar WASM is not available, returns a
573
+ * fallback allow decision (fail-open, logged).
574
+ */
575
+ declare function evaluateCedar(policySet: CedarPolicySet, req: CedarEvalRequest, schema?: CedarSchema): Promise<ExternalDecision>;
576
+ /**
577
+ * Validate that Cedar WASM is available.
578
+ * Useful for CLI startup diagnostics.
579
+ */
580
+ declare function isCedarAvailable(): Promise<boolean>;
542
581
 
543
582
  /**
544
583
  * MCP tool-calling gateway that intercepts JSON-RPC requests,
@@ -1313,6 +1352,84 @@ declare function validateManifest(manifest: unknown): string[];
1313
1352
  */
1314
1353
  declare function validateEvidenceReceipt(receipt: unknown): string[];
1315
1354
 
1355
+ /**
1356
+ * @scopeblind/protect-mcp — Cedar Schema Generator for MCP Tools
1357
+ *
1358
+ * Auto-generates a Cedar authorization schema from MCP tool descriptions.
1359
+ * This enables typed Cedar policies that reference tool input attributes:
1360
+ *
1361
+ * permit(principal, action == Action::"read_file", resource)
1362
+ * when { context.input.path like "./workspace/*" };
1363
+ *
1364
+ * Compatible with cedar-policy/cedar-for-agents schema format.
1365
+ * Designed to replace `schema: null` in Cedar WASM evaluations.
1366
+ *
1367
+ * @see https://github.com/cedar-policy/cedar-for-agents
1368
+ * @standard RFC 8785 (JCS), Cedar Policy Language v4
1369
+ */
1370
+ /** MCP tool description from tools/list response */
1371
+ interface McpToolDescription {
1372
+ name: string;
1373
+ description?: string;
1374
+ inputSchema?: JsonSchema;
1375
+ }
1376
+ /** Subset of JSON Schema that MCP tools use */
1377
+ interface JsonSchema {
1378
+ type?: string | string[];
1379
+ properties?: Record<string, JsonSchema>;
1380
+ required?: string[];
1381
+ items?: JsonSchema;
1382
+ enum?: (string | number | boolean)[];
1383
+ format?: string;
1384
+ description?: string;
1385
+ additionalProperties?: boolean | JsonSchema;
1386
+ anyOf?: JsonSchema[];
1387
+ oneOf?: JsonSchema[];
1388
+ }
1389
+ /** Generated Cedar schema components */
1390
+ interface CedarSchemaResult {
1391
+ /** The .cedarschema text (human-readable Cedar schema format) */
1392
+ schemaText: string;
1393
+ /** The schema as a JSON object (for passing to Cedar WASM) */
1394
+ schemaJson: Record<string, unknown>;
1395
+ /** Number of tools mapped */
1396
+ toolCount: number;
1397
+ /** Tool names included */
1398
+ tools: string[];
1399
+ }
1400
+ interface SchemaGeneratorConfig {
1401
+ /** Namespace for generated types (default: "ScopeBlind") */
1402
+ namespace?: string;
1403
+ /** Include agent tier as principal attribute (default: true) */
1404
+ includeTier?: boolean;
1405
+ /** Include timestamp context (default: true) */
1406
+ includeTimestamp?: boolean;
1407
+ /** Include agent_id as principal attribute (default: true) */
1408
+ includeAgentId?: boolean;
1409
+ }
1410
+ /**
1411
+ * Generate a Cedar schema from MCP tool descriptions.
1412
+ *
1413
+ * Produces both human-readable .cedarschema text and the JSON
1414
+ * representation that Cedar WASM accepts.
1415
+ *
1416
+ * The generated schema defines:
1417
+ * - Agent entity type (principal) with tier and agent_id attributes
1418
+ * - Tool entity type (resource)
1419
+ * - One action per MCP tool, with typed input context
1420
+ * - A parent action "MCP::Tool::call" for blanket policies
1421
+ *
1422
+ * This enables policies like:
1423
+ * forbid(principal, action == Action::"execute_command", resource)
1424
+ * when { context.input has "command" && context.input.command like "rm *" };
1425
+ */
1426
+ declare function generateCedarSchema(tools: McpToolDescription[], config?: SchemaGeneratorConfig): CedarSchemaResult;
1427
+ /**
1428
+ * Generate a Cedar schema stub file for customization.
1429
+ * This is the starting point for users who want to extend the auto-generated schema.
1430
+ */
1431
+ declare function generateSchemaStub(namespace?: string): string;
1432
+
1316
1433
  /**
1317
1434
  * Sigstore Rekor Transparency Log Anchoring
1318
1435
  *
@@ -2639,4 +2756,4 @@ declare function confidentialInference(_prompt: string, _config: ConfidentialInf
2639
2756
  receipt: Record<string, unknown>;
2640
2757
  }>;
2641
2758
 
2642
- export { type ActionReceipt, type AdmissionResult, type AgentId, type AgentManifest, type ApprovalAssertion, type ApprovalChallenge, type ApprovalNotification, type ApprovalResult, type ArenaPayload, type ArenaReceipt, type AttestationDocument, type AttestationPayload, type AttestationProvider, type AttestationReceipt, type AttestationResult, type AuditBundle, type AuditBundleOptions, type BenchmarkPayload, type BenchmarkReceipt, type BuilderId, type C2PAAssertion, type C2PAIngredient, type C2PAManifest, type C2PAOptions, type CCRConnectorConfig, type CCRSessionContext, type CalibrationScore, type ComplianceReport, ConfidentialGate, type ConfidentialGateConfig, type ConfidentialInferenceConfig, type CredentialConfig, type DecisionContext, type DecisionLog, type DelegationReceipt, type DisclosureMode, type Ed25519PublicKey, type EvidenceAttestation, type EvidenceAttestationInput, type EvidenceIssuer, type EvidenceReceipt, type EvidenceReceiptBase, type EvidenceSummary, type EvidenceSummaryEntry, type EvidenceType, type ExternalDecision, type ExternalPDPConfig, type HFDatasetMetadata, type HFReceiptRow, type HookEventName, type HookInput, type HookResponse, type IssuerType, type JsonRpcRequest, type JsonRpcResponse, type LeaseCompatibility, type ManifestBuilder, type ManifestCapabilities, type ManifestConfig, type ManifestIdentity, type ManifestPresentation, type ManifestSignature, type ManifestStatus, type NotificationConfig, type PassportTokenClaims, type PayloadDigest, type PlanReceipt, type PolicyEngineMode, type PredictionReceipt, type PredictionResolution, type PropagatorConfig, type ProtectConfig, ProtectGateway, type ProtectPolicy, type RateLimit, ReceiptPropagator, type RedactedResult, type RedactionSalt, type RekorAnchor, type RekorVerification, type RestraintPayload, type RestraintReceipt, type SHA256Hash, type SafetyTranscript, type Sandbox, type SandboxConfig, type SandboxReceipt, type SandboxResult, type SandboxToolCall, type SigningConfig, type SimulationResult, type SimulationSummary, type SwarmContext, type TierOverrides, type TimingMetrics, type ToolPolicy, type TrustTier, type WorkPayload, type WorkReceipt, anchorToRekor, buildDecisionContext, checkRateLimit, collectSignedReceipts, computeCalibration, confidentialInference, createApprovalChallenge, createApprovalReceiptPayload, createAttestationField, createAuditBundle, createC2PAManifest, createDisclosurePackage, createEvidenceAttestation, createLogAnchorField, createReceiptChannel, createSandbox, destroySandbox, ed25519ToDIDKey, evaluateTier, exportC2PAManifestJSON, exportJSONL, formatReportMarkdown, formatSimulation, generateC2PACommand, generateDatasetCard, generateHFMetadata, generateReport, generateSafetyTranscript, getSignerInfo, getToolPolicy, hashReceipt, hashResponseBody, initSigning, isAgentId, isDisclosureMode, isEvidenceType, isManifestStatus, isSigningEnabled, listCredentialLabels, loadPolicy, manifestToVC, meetsMinTier, parseLogFile, parseNotificationConfigFromEnv, parseRateLimit, queryExternalPDP, receiptToVP, receiptsToHFRows, redactFields, resolveCredential, revealField, runInSandbox, sendApprovalNotification, signDecision, simulate, toCredentialRequestOptions, toManifoldFormat, toMetaculusFormat, validateCredentials, validateEvidenceReceipt, validateManifest, verifyActaC2PAAssertions, verifyAllCommitments, verifyApprovalAssertion, verifyCommitment, verifyEvidenceAttestation, verifyRekorAnchor };
2759
+ export { type ActionReceipt, type AdmissionResult, type AgentId, type AgentManifest, type ApprovalAssertion, type ApprovalChallenge, type ApprovalNotification, type ApprovalResult, type ArenaPayload, type ArenaReceipt, type AttestationDocument, type AttestationPayload, type AttestationProvider, type AttestationReceipt, type AttestationResult, type AuditBundle, type AuditBundleOptions, type BenchmarkPayload, type BenchmarkReceipt, type BuilderId, type C2PAAssertion, type C2PAIngredient, type C2PAManifest, type C2PAOptions, type CCRConnectorConfig, type CCRSessionContext, type CalibrationScore, type CedarEvalRequest, type CedarPolicySet, type CedarSchema, type CedarSchemaResult, type ComplianceReport, ConfidentialGate, type ConfidentialGateConfig, type ConfidentialInferenceConfig, type CredentialConfig, type DecisionContext, type DecisionLog, type DelegationReceipt, type DisclosureMode, type Ed25519PublicKey, type EvidenceAttestation, type EvidenceAttestationInput, type EvidenceIssuer, type EvidenceReceipt, type EvidenceReceiptBase, type EvidenceSummary, type EvidenceSummaryEntry, type EvidenceType, type ExternalDecision, type ExternalPDPConfig, type HFDatasetMetadata, type HFReceiptRow, type HookEventName, type HookInput, type HookResponse, type IssuerType, type JsonRpcRequest, type JsonRpcResponse, type LeaseCompatibility, type ManifestBuilder, type ManifestCapabilities, type ManifestConfig, type ManifestIdentity, type ManifestPresentation, type ManifestSignature, type ManifestStatus, type McpToolDescription, type NotificationConfig, type PassportTokenClaims, type PayloadDigest, type PlanReceipt, type PolicyEngineMode, type PredictionReceipt, type PredictionResolution, type PropagatorConfig, type ProtectConfig, ProtectGateway, type ProtectPolicy, type RateLimit, ReceiptPropagator, type RedactedResult, type RedactionSalt, type RekorAnchor, type RekorVerification, type RestraintPayload, type RestraintReceipt, type SHA256Hash, type SafetyTranscript, type Sandbox, type SandboxConfig, type SandboxReceipt, type SandboxResult, type SandboxToolCall, type SchemaGeneratorConfig, type SigningConfig, type SimulationResult, type SimulationSummary, type SwarmContext, type TierOverrides, type TimingMetrics, type ToolPolicy, type TrustTier, type WorkPayload, type WorkReceipt, anchorToRekor, buildDecisionContext, checkRateLimit, collectSignedReceipts, computeCalibration, confidentialInference, createApprovalChallenge, createApprovalReceiptPayload, createAttestationField, createAuditBundle, createC2PAManifest, createDisclosurePackage, createEvidenceAttestation, createLogAnchorField, createReceiptChannel, createSandbox, destroySandbox, ed25519ToDIDKey, evaluateCedar, evaluateTier, exportC2PAManifestJSON, exportJSONL, formatReportMarkdown, formatSimulation, generateC2PACommand, generateCedarSchema, generateDatasetCard, generateHFMetadata, generateReport, generateSafetyTranscript, generateSchemaStub, getSignerInfo, getToolPolicy, hashReceipt, hashResponseBody, initSigning, isAgentId, isCedarAvailable, isDisclosureMode, isEvidenceType, isManifestStatus, isSigningEnabled, listCredentialLabels, loadCedarPolicies, loadPolicy, manifestToVC, meetsMinTier, parseLogFile, parseNotificationConfigFromEnv, parseRateLimit, queryExternalPDP, receiptToVP, receiptsToHFRows, redactFields, resolveCredential, revealField, runInSandbox, sendApprovalNotification, signDecision, simulate, toCredentialRequestOptions, toManifoldFormat, toMetaculusFormat, validateCredentials, validateEvidenceReceipt, validateManifest, verifyActaC2PAAssertions, verifyAllCommitments, verifyApprovalAssertion, verifyCommitment, verifyEvidenceAttestation, verifyRekorAnchor };
package/dist/index.d.ts CHANGED
@@ -539,6 +539,45 @@ interface CedarPolicySet {
539
539
  /** Filenames loaded */
540
540
  files: string[];
541
541
  }
542
+ interface CedarEvalRequest {
543
+ /** Tool name being called */
544
+ tool: string;
545
+ /** Trust tier of the agent */
546
+ tier: TrustTier;
547
+ /** Agent ID (optional) */
548
+ agentId?: string;
549
+ /** Additional context fields */
550
+ context?: Record<string, unknown>;
551
+ /** Tool input (for schema-validated evaluation) */
552
+ toolInput?: Record<string, unknown>;
553
+ }
554
+ /** Cedar schema for typed policy evaluation (generated by cedar-schema.ts) */
555
+ interface CedarSchema {
556
+ /** The schema as a JSON object for Cedar WASM */
557
+ schemaJson: Record<string, unknown> | null;
558
+ /** Namespace used in the schema */
559
+ namespace?: string;
560
+ }
561
+ /**
562
+ * Load all .cedar files from a directory and return a compiled policy set.
563
+ *
564
+ * Files are sorted alphabetically for deterministic digest computation.
565
+ * Throws if the directory doesn't exist or contains no .cedar files.
566
+ */
567
+ declare function loadCedarPolicies(dirPath: string): CedarPolicySet;
568
+ /**
569
+ * Evaluate a Cedar policy set against a tool call.
570
+ *
571
+ * Returns a standard ExternalDecision compatible with the gateway's
572
+ * decision pipeline. If Cedar WASM is not available, returns a
573
+ * fallback allow decision (fail-open, logged).
574
+ */
575
+ declare function evaluateCedar(policySet: CedarPolicySet, req: CedarEvalRequest, schema?: CedarSchema): Promise<ExternalDecision>;
576
+ /**
577
+ * Validate that Cedar WASM is available.
578
+ * Useful for CLI startup diagnostics.
579
+ */
580
+ declare function isCedarAvailable(): Promise<boolean>;
542
581
 
543
582
  /**
544
583
  * MCP tool-calling gateway that intercepts JSON-RPC requests,
@@ -1313,6 +1352,84 @@ declare function validateManifest(manifest: unknown): string[];
1313
1352
  */
1314
1353
  declare function validateEvidenceReceipt(receipt: unknown): string[];
1315
1354
 
1355
+ /**
1356
+ * @scopeblind/protect-mcp — Cedar Schema Generator for MCP Tools
1357
+ *
1358
+ * Auto-generates a Cedar authorization schema from MCP tool descriptions.
1359
+ * This enables typed Cedar policies that reference tool input attributes:
1360
+ *
1361
+ * permit(principal, action == Action::"read_file", resource)
1362
+ * when { context.input.path like "./workspace/*" };
1363
+ *
1364
+ * Compatible with cedar-policy/cedar-for-agents schema format.
1365
+ * Designed to replace `schema: null` in Cedar WASM evaluations.
1366
+ *
1367
+ * @see https://github.com/cedar-policy/cedar-for-agents
1368
+ * @standard RFC 8785 (JCS), Cedar Policy Language v4
1369
+ */
1370
+ /** MCP tool description from tools/list response */
1371
+ interface McpToolDescription {
1372
+ name: string;
1373
+ description?: string;
1374
+ inputSchema?: JsonSchema;
1375
+ }
1376
+ /** Subset of JSON Schema that MCP tools use */
1377
+ interface JsonSchema {
1378
+ type?: string | string[];
1379
+ properties?: Record<string, JsonSchema>;
1380
+ required?: string[];
1381
+ items?: JsonSchema;
1382
+ enum?: (string | number | boolean)[];
1383
+ format?: string;
1384
+ description?: string;
1385
+ additionalProperties?: boolean | JsonSchema;
1386
+ anyOf?: JsonSchema[];
1387
+ oneOf?: JsonSchema[];
1388
+ }
1389
+ /** Generated Cedar schema components */
1390
+ interface CedarSchemaResult {
1391
+ /** The .cedarschema text (human-readable Cedar schema format) */
1392
+ schemaText: string;
1393
+ /** The schema as a JSON object (for passing to Cedar WASM) */
1394
+ schemaJson: Record<string, unknown>;
1395
+ /** Number of tools mapped */
1396
+ toolCount: number;
1397
+ /** Tool names included */
1398
+ tools: string[];
1399
+ }
1400
+ interface SchemaGeneratorConfig {
1401
+ /** Namespace for generated types (default: "ScopeBlind") */
1402
+ namespace?: string;
1403
+ /** Include agent tier as principal attribute (default: true) */
1404
+ includeTier?: boolean;
1405
+ /** Include timestamp context (default: true) */
1406
+ includeTimestamp?: boolean;
1407
+ /** Include agent_id as principal attribute (default: true) */
1408
+ includeAgentId?: boolean;
1409
+ }
1410
+ /**
1411
+ * Generate a Cedar schema from MCP tool descriptions.
1412
+ *
1413
+ * Produces both human-readable .cedarschema text and the JSON
1414
+ * representation that Cedar WASM accepts.
1415
+ *
1416
+ * The generated schema defines:
1417
+ * - Agent entity type (principal) with tier and agent_id attributes
1418
+ * - Tool entity type (resource)
1419
+ * - One action per MCP tool, with typed input context
1420
+ * - A parent action "MCP::Tool::call" for blanket policies
1421
+ *
1422
+ * This enables policies like:
1423
+ * forbid(principal, action == Action::"execute_command", resource)
1424
+ * when { context.input has "command" && context.input.command like "rm *" };
1425
+ */
1426
+ declare function generateCedarSchema(tools: McpToolDescription[], config?: SchemaGeneratorConfig): CedarSchemaResult;
1427
+ /**
1428
+ * Generate a Cedar schema stub file for customization.
1429
+ * This is the starting point for users who want to extend the auto-generated schema.
1430
+ */
1431
+ declare function generateSchemaStub(namespace?: string): string;
1432
+
1316
1433
  /**
1317
1434
  * Sigstore Rekor Transparency Log Anchoring
1318
1435
  *
@@ -2639,4 +2756,4 @@ declare function confidentialInference(_prompt: string, _config: ConfidentialInf
2639
2756
  receipt: Record<string, unknown>;
2640
2757
  }>;
2641
2758
 
2642
- export { type ActionReceipt, type AdmissionResult, type AgentId, type AgentManifest, type ApprovalAssertion, type ApprovalChallenge, type ApprovalNotification, type ApprovalResult, type ArenaPayload, type ArenaReceipt, type AttestationDocument, type AttestationPayload, type AttestationProvider, type AttestationReceipt, type AttestationResult, type AuditBundle, type AuditBundleOptions, type BenchmarkPayload, type BenchmarkReceipt, type BuilderId, type C2PAAssertion, type C2PAIngredient, type C2PAManifest, type C2PAOptions, type CCRConnectorConfig, type CCRSessionContext, type CalibrationScore, type ComplianceReport, ConfidentialGate, type ConfidentialGateConfig, type ConfidentialInferenceConfig, type CredentialConfig, type DecisionContext, type DecisionLog, type DelegationReceipt, type DisclosureMode, type Ed25519PublicKey, type EvidenceAttestation, type EvidenceAttestationInput, type EvidenceIssuer, type EvidenceReceipt, type EvidenceReceiptBase, type EvidenceSummary, type EvidenceSummaryEntry, type EvidenceType, type ExternalDecision, type ExternalPDPConfig, type HFDatasetMetadata, type HFReceiptRow, type HookEventName, type HookInput, type HookResponse, type IssuerType, type JsonRpcRequest, type JsonRpcResponse, type LeaseCompatibility, type ManifestBuilder, type ManifestCapabilities, type ManifestConfig, type ManifestIdentity, type ManifestPresentation, type ManifestSignature, type ManifestStatus, type NotificationConfig, type PassportTokenClaims, type PayloadDigest, type PlanReceipt, type PolicyEngineMode, type PredictionReceipt, type PredictionResolution, type PropagatorConfig, type ProtectConfig, ProtectGateway, type ProtectPolicy, type RateLimit, ReceiptPropagator, type RedactedResult, type RedactionSalt, type RekorAnchor, type RekorVerification, type RestraintPayload, type RestraintReceipt, type SHA256Hash, type SafetyTranscript, type Sandbox, type SandboxConfig, type SandboxReceipt, type SandboxResult, type SandboxToolCall, type SigningConfig, type SimulationResult, type SimulationSummary, type SwarmContext, type TierOverrides, type TimingMetrics, type ToolPolicy, type TrustTier, type WorkPayload, type WorkReceipt, anchorToRekor, buildDecisionContext, checkRateLimit, collectSignedReceipts, computeCalibration, confidentialInference, createApprovalChallenge, createApprovalReceiptPayload, createAttestationField, createAuditBundle, createC2PAManifest, createDisclosurePackage, createEvidenceAttestation, createLogAnchorField, createReceiptChannel, createSandbox, destroySandbox, ed25519ToDIDKey, evaluateTier, exportC2PAManifestJSON, exportJSONL, formatReportMarkdown, formatSimulation, generateC2PACommand, generateDatasetCard, generateHFMetadata, generateReport, generateSafetyTranscript, getSignerInfo, getToolPolicy, hashReceipt, hashResponseBody, initSigning, isAgentId, isDisclosureMode, isEvidenceType, isManifestStatus, isSigningEnabled, listCredentialLabels, loadPolicy, manifestToVC, meetsMinTier, parseLogFile, parseNotificationConfigFromEnv, parseRateLimit, queryExternalPDP, receiptToVP, receiptsToHFRows, redactFields, resolveCredential, revealField, runInSandbox, sendApprovalNotification, signDecision, simulate, toCredentialRequestOptions, toManifoldFormat, toMetaculusFormat, validateCredentials, validateEvidenceReceipt, validateManifest, verifyActaC2PAAssertions, verifyAllCommitments, verifyApprovalAssertion, verifyCommitment, verifyEvidenceAttestation, verifyRekorAnchor };
2759
+ export { type ActionReceipt, type AdmissionResult, type AgentId, type AgentManifest, type ApprovalAssertion, type ApprovalChallenge, type ApprovalNotification, type ApprovalResult, type ArenaPayload, type ArenaReceipt, type AttestationDocument, type AttestationPayload, type AttestationProvider, type AttestationReceipt, type AttestationResult, type AuditBundle, type AuditBundleOptions, type BenchmarkPayload, type BenchmarkReceipt, type BuilderId, type C2PAAssertion, type C2PAIngredient, type C2PAManifest, type C2PAOptions, type CCRConnectorConfig, type CCRSessionContext, type CalibrationScore, type CedarEvalRequest, type CedarPolicySet, type CedarSchema, type CedarSchemaResult, type ComplianceReport, ConfidentialGate, type ConfidentialGateConfig, type ConfidentialInferenceConfig, type CredentialConfig, type DecisionContext, type DecisionLog, type DelegationReceipt, type DisclosureMode, type Ed25519PublicKey, type EvidenceAttestation, type EvidenceAttestationInput, type EvidenceIssuer, type EvidenceReceipt, type EvidenceReceiptBase, type EvidenceSummary, type EvidenceSummaryEntry, type EvidenceType, type ExternalDecision, type ExternalPDPConfig, type HFDatasetMetadata, type HFReceiptRow, type HookEventName, type HookInput, type HookResponse, type IssuerType, type JsonRpcRequest, type JsonRpcResponse, type LeaseCompatibility, type ManifestBuilder, type ManifestCapabilities, type ManifestConfig, type ManifestIdentity, type ManifestPresentation, type ManifestSignature, type ManifestStatus, type McpToolDescription, type NotificationConfig, type PassportTokenClaims, type PayloadDigest, type PlanReceipt, type PolicyEngineMode, type PredictionReceipt, type PredictionResolution, type PropagatorConfig, type ProtectConfig, ProtectGateway, type ProtectPolicy, type RateLimit, ReceiptPropagator, type RedactedResult, type RedactionSalt, type RekorAnchor, type RekorVerification, type RestraintPayload, type RestraintReceipt, type SHA256Hash, type SafetyTranscript, type Sandbox, type SandboxConfig, type SandboxReceipt, type SandboxResult, type SandboxToolCall, type SchemaGeneratorConfig, type SigningConfig, type SimulationResult, type SimulationSummary, type SwarmContext, type TierOverrides, type TimingMetrics, type ToolPolicy, type TrustTier, type WorkPayload, type WorkReceipt, anchorToRekor, buildDecisionContext, checkRateLimit, collectSignedReceipts, computeCalibration, confidentialInference, createApprovalChallenge, createApprovalReceiptPayload, createAttestationField, createAuditBundle, createC2PAManifest, createDisclosurePackage, createEvidenceAttestation, createLogAnchorField, createReceiptChannel, createSandbox, destroySandbox, ed25519ToDIDKey, evaluateCedar, evaluateTier, exportC2PAManifestJSON, exportJSONL, formatReportMarkdown, formatSimulation, generateC2PACommand, generateCedarSchema, generateDatasetCard, generateHFMetadata, generateReport, generateSafetyTranscript, generateSchemaStub, getSignerInfo, getToolPolicy, hashReceipt, hashResponseBody, initSigning, isAgentId, isCedarAvailable, isDisclosureMode, isEvidenceType, isManifestStatus, isSigningEnabled, listCredentialLabels, loadCedarPolicies, loadPolicy, manifestToVC, meetsMinTier, parseLogFile, parseNotificationConfigFromEnv, parseRateLimit, queryExternalPDP, receiptToVP, receiptsToHFRows, redactFields, resolveCredential, revealField, runInSandbox, sendApprovalNotification, signDecision, simulate, toCredentialRequestOptions, toManifoldFormat, toMetaculusFormat, validateCredentials, validateEvidenceReceipt, validateManifest, verifyActaC2PAAssertions, verifyAllCommitments, verifyApprovalAssertion, verifyCommitment, verifyEvidenceAttestation, verifyRekorAnchor };
package/dist/index.js CHANGED
@@ -35041,18 +35041,21 @@ __export(index_exports, {
35041
35041
  createSandboxServer: () => createSandboxServer,
35042
35042
  destroySandbox: () => destroySandbox,
35043
35043
  ed25519ToDIDKey: () => ed25519ToDIDKey,
35044
+ evaluateCedar: () => evaluateCedar,
35044
35045
  evaluateTier: () => evaluateTier,
35045
35046
  exportC2PAManifestJSON: () => exportC2PAManifestJSON,
35046
35047
  exportJSONL: () => exportJSONL,
35047
35048
  formatReportMarkdown: () => formatReportMarkdown,
35048
35049
  formatSimulation: () => formatSimulation,
35049
35050
  generateC2PACommand: () => generateC2PACommand,
35051
+ generateCedarSchema: () => generateCedarSchema,
35050
35052
  generateDatasetCard: () => generateDatasetCard,
35051
35053
  generateHFMetadata: () => generateHFMetadata,
35052
35054
  generateHookSettings: () => generateHookSettings,
35053
35055
  generateReport: () => generateReport,
35054
35056
  generateSafetyTranscript: () => generateSafetyTranscript,
35055
35057
  generateSampleCedarPolicy: () => generateSampleCedarPolicy,
35058
+ generateSchemaStub: () => generateSchemaStub,
35056
35059
  generateVerifyReceiptSkill: () => generateVerifyReceiptSkill,
35057
35060
  getSignerInfo: () => getSignerInfo,
35058
35061
  getToolPolicy: () => getToolPolicy,
@@ -35060,11 +35063,13 @@ __export(index_exports, {
35060
35063
  hashResponseBody: () => hashResponseBody,
35061
35064
  initSigning: () => initSigning,
35062
35065
  isAgentId: () => isAgentId,
35066
+ isCedarAvailable: () => isCedarAvailable,
35063
35067
  isDisclosureMode: () => isDisclosureMode,
35064
35068
  isEvidenceType: () => isEvidenceType,
35065
35069
  isManifestStatus: () => isManifestStatus,
35066
35070
  isSigningEnabled: () => isSigningEnabled,
35067
35071
  listCredentialLabels: () => listCredentialLabels,
35072
+ loadCedarPolicies: () => loadCedarPolicies,
35068
35073
  loadPolicy: () => loadPolicy,
35069
35074
  manifestToVC: () => manifestToVC,
35070
35075
  meetsMinTier: () => meetsMinTier,
@@ -35731,7 +35736,7 @@ function buildEntities(req) {
35731
35736
  }
35732
35737
  ];
35733
35738
  }
35734
- async function evaluateCedar(policySet, req) {
35739
+ async function evaluateCedar(policySet, req, schema) {
35735
35740
  const available = await ensureCedarWasm();
35736
35741
  if (!available) {
35737
35742
  return {
@@ -35742,16 +35747,21 @@ async function evaluateCedar(policySet, req) {
35742
35747
  }
35743
35748
  try {
35744
35749
  const agentId = req.agentId || req.tier;
35750
+ const context = {
35751
+ tier: req.tier,
35752
+ ...req.context || {}
35753
+ };
35754
+ if (req.toolInput && Object.keys(req.toolInput).length > 0) {
35755
+ context.input = req.toolInput;
35756
+ }
35745
35757
  const authRequest = {
35746
35758
  principal: { type: "Agent", id: agentId },
35747
35759
  action: { type: "Action", id: "MCP::Tool::call" },
35748
35760
  resource: { type: "Tool", id: req.tool },
35749
- context: {
35750
- tier: req.tier,
35751
- ...req.context || {}
35752
- }
35761
+ context
35753
35762
  };
35754
35763
  const entities = buildEntities(req);
35764
+ const cedarSchema = schema?.schemaJson ?? null;
35755
35765
  let result;
35756
35766
  if (typeof cedarWasm.isAuthorized === "function") {
35757
35767
  result = cedarWasm.isAuthorized({
@@ -35761,8 +35771,7 @@ async function evaluateCedar(policySet, req) {
35761
35771
  action: authRequest.action,
35762
35772
  resource: authRequest.resource,
35763
35773
  context: authRequest.context,
35764
- schema: null
35765
- // No schema enforcement — Cedar still evaluates correctly
35774
+ schema: cedarSchema
35766
35775
  });
35767
35776
  } else if (typeof cedarWasm.checkAuthorization === "function") {
35768
35777
  result = cedarWasm.checkAuthorization(
@@ -35780,7 +35789,7 @@ async function evaluateCedar(policySet, req) {
35780
35789
  action: authRequest.action,
35781
35790
  resource: authRequest.resource,
35782
35791
  context: authRequest.context,
35783
- schema: null
35792
+ schema: cedarSchema
35784
35793
  });
35785
35794
  } else {
35786
35795
  return {
@@ -38381,6 +38390,273 @@ If swarm data exists, show the agent topology (coordinator \u2192 workers).
38381
38390
  `;
38382
38391
  }
38383
38392
 
38393
+ // src/cedar-schema.ts
38394
+ function jsonSchemaToCedarType(schema, namespace, path) {
38395
+ if (schema.enum) {
38396
+ return "String";
38397
+ }
38398
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
38399
+ switch (type) {
38400
+ case "string":
38401
+ if (schema.format === "date-time") return "String";
38402
+ if (schema.format === "uri") return "String";
38403
+ return "String";
38404
+ case "integer":
38405
+ case "number":
38406
+ return "Long";
38407
+ case "boolean":
38408
+ return "Bool";
38409
+ case "array":
38410
+ if (schema.items) {
38411
+ const itemType = jsonSchemaToCedarType(schema.items, namespace, path + "_item");
38412
+ return `Set<${itemType}>`;
38413
+ }
38414
+ return "Set<String>";
38415
+ // Default to Set<String> for untyped arrays
38416
+ case "object":
38417
+ if (schema.properties && Object.keys(schema.properties).length > 0) {
38418
+ const fields = Object.entries(schema.properties).map(([key, prop]) => {
38419
+ const cedarType = jsonSchemaToCedarType(prop, namespace, path + "_" + sanitizeIdentifier(key));
38420
+ const isRequired = schema.required?.includes(key) ?? false;
38421
+ return ` "${sanitizeIdentifier(key)}": ${cedarType}${isRequired ? "" : "?"}`;
38422
+ });
38423
+ return `{
38424
+ ${fields.join(",\n")}
38425
+ }`;
38426
+ }
38427
+ return "Record";
38428
+ // Empty objects
38429
+ default:
38430
+ return "String";
38431
+ }
38432
+ }
38433
+ function sanitizeIdentifier(name) {
38434
+ return name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^(\d)/, "_$1");
38435
+ }
38436
+ function cedarActionId(toolName) {
38437
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(toolName)) {
38438
+ return toolName;
38439
+ }
38440
+ return toolName;
38441
+ }
38442
+ function generateCedarSchema(tools, config = {}) {
38443
+ const ns = config.namespace || "ScopeBlind";
38444
+ const includeTier = config.includeTier !== false;
38445
+ const includeTimestamp = config.includeTimestamp !== false;
38446
+ const includeAgentId = config.includeAgentId !== false;
38447
+ const agentAttrs = [];
38448
+ if (includeTier) agentAttrs.push(' "tier": String');
38449
+ if (includeAgentId) agentAttrs.push(' "agent_id": String?');
38450
+ const sessionFields = [];
38451
+ if (includeTimestamp) sessionFields.push(' "timestamp": String?');
38452
+ sessionFields.push(' "hook_event": String?');
38453
+ const actionDeclarations = [];
38454
+ const inputTypeDeclarations = [];
38455
+ for (const tool of tools) {
38456
+ const actionName = cedarActionId(tool.name);
38457
+ const inputTypeName = `${sanitizeIdentifier(tool.name)}_Input`;
38458
+ if (tool.inputSchema?.properties && Object.keys(tool.inputSchema.properties).length > 0) {
38459
+ const fields = Object.entries(tool.inputSchema.properties).map(([key, prop]) => {
38460
+ const cedarType = jsonSchemaToCedarType(prop, ns, sanitizeIdentifier(tool.name) + "_" + sanitizeIdentifier(key));
38461
+ const isRequired = tool.inputSchema?.required?.includes(key) ?? false;
38462
+ return ` "${sanitizeIdentifier(key)}": ${cedarType}${isRequired ? "" : "?"}`;
38463
+ });
38464
+ inputTypeDeclarations.push(
38465
+ ` // Input type for tool: ${tool.name}` + (tool.description ? `
38466
+ // ${tool.description}` : "") + `
38467
+ type ${inputTypeName} = {
38468
+ ${fields.join(",\n")}
38469
+ };`
38470
+ );
38471
+ actionDeclarations.push(
38472
+ ` action "${actionName}" in [Action::"MCP::Tool::call"] appliesTo {
38473
+ principal: [Agent],
38474
+ resource: [Tool],
38475
+ context: {
38476
+ "input": ${inputTypeName},
38477
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
38478
+ }
38479
+ };`
38480
+ );
38481
+ } else {
38482
+ actionDeclarations.push(
38483
+ ` action "${actionName}" in [Action::"MCP::Tool::call"] appliesTo {
38484
+ principal: [Agent],
38485
+ resource: [Tool],
38486
+ context: {
38487
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
38488
+ }
38489
+ };`
38490
+ );
38491
+ }
38492
+ }
38493
+ actionDeclarations.push(
38494
+ ` // Blanket action for policies matching any tool call
38495
+ action "MCP::Tool::call" appliesTo {
38496
+ principal: [Agent],
38497
+ resource: [Tool],
38498
+ context: {
38499
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
38500
+ }
38501
+ };`
38502
+ );
38503
+ const schemaText = [
38504
+ `// Cedar schema for MCP tool governance`,
38505
+ `// Generated by protect-mcp from ${tools.length} tool description(s)`,
38506
+ `// Compatible with cedar-policy/cedar-for-agents`,
38507
+ ``,
38508
+ `namespace ${ns} {`,
38509
+ ``,
38510
+ ` // \u2500\u2500 Entity types \u2500\u2500`,
38511
+ ``,
38512
+ ` entity Agent${agentAttrs.length > 0 ? ` = {
38513
+ ${agentAttrs.join(",\n")}
38514
+ }` : ""};`,
38515
+ ``,
38516
+ ` entity Tool;`,
38517
+ ``,
38518
+ ...inputTypeDeclarations.length > 0 ? [` // \u2500\u2500 Tool input types \u2500\u2500`, ``, ...inputTypeDeclarations, ``] : [],
38519
+ ` // \u2500\u2500 Actions \u2500\u2500`,
38520
+ ``,
38521
+ ...actionDeclarations,
38522
+ ``,
38523
+ `}`,
38524
+ ``
38525
+ ].join("\n");
38526
+ const schemaJson = buildSchemaJson(tools, ns, config);
38527
+ return {
38528
+ schemaText,
38529
+ schemaJson,
38530
+ toolCount: tools.length,
38531
+ tools: tools.map((t) => t.name)
38532
+ };
38533
+ }
38534
+ function buildSchemaJson(tools, namespace, config) {
38535
+ const entityTypes = {
38536
+ Agent: {
38537
+ shape: {
38538
+ type: "Record",
38539
+ attributes: {
38540
+ ...config.includeTier !== false ? { tier: { type: "String", required: false } } : {},
38541
+ ...config.includeAgentId !== false ? { agent_id: { type: "String", required: false } } : {}
38542
+ }
38543
+ },
38544
+ memberOfTypes: []
38545
+ },
38546
+ Tool: {
38547
+ shape: { type: "Record", attributes: {} },
38548
+ memberOfTypes: []
38549
+ }
38550
+ };
38551
+ const actions = {};
38552
+ for (const tool of tools) {
38553
+ const contextAttrs = {
38554
+ tier: { type: "String", required: false }
38555
+ };
38556
+ if (config.includeTimestamp !== false) {
38557
+ contextAttrs["timestamp"] = { type: "String", required: false };
38558
+ }
38559
+ if (config.includeAgentId !== false) {
38560
+ contextAttrs["agent_id"] = { type: "String", required: false };
38561
+ }
38562
+ if (tool.inputSchema?.properties) {
38563
+ const inputAttrs = {};
38564
+ for (const [key, prop] of Object.entries(tool.inputSchema.properties)) {
38565
+ inputAttrs[sanitizeIdentifier(key)] = {
38566
+ type: jsonSchemaToSchemaJsonType(prop),
38567
+ required: tool.inputSchema.required?.includes(key) ?? false
38568
+ };
38569
+ }
38570
+ contextAttrs["input"] = {
38571
+ type: "Record",
38572
+ attributes: inputAttrs,
38573
+ required: false
38574
+ };
38575
+ }
38576
+ actions[tool.name] = {
38577
+ appliesTo: {
38578
+ principalTypes: ["Agent"],
38579
+ resourceTypes: ["Tool"],
38580
+ context: { type: "Record", attributes: contextAttrs }
38581
+ },
38582
+ memberOf: [{ id: "MCP::Tool::call" }]
38583
+ };
38584
+ }
38585
+ const blanketContext = {
38586
+ tier: { type: "String", required: false }
38587
+ };
38588
+ if (config.includeTimestamp !== false) {
38589
+ blanketContext["timestamp"] = { type: "String", required: false };
38590
+ }
38591
+ if (config.includeAgentId !== false) {
38592
+ blanketContext["agent_id"] = { type: "String", required: false };
38593
+ }
38594
+ actions["MCP::Tool::call"] = {
38595
+ appliesTo: {
38596
+ principalTypes: ["Agent"],
38597
+ resourceTypes: ["Tool"],
38598
+ context: { type: "Record", attributes: blanketContext }
38599
+ }
38600
+ };
38601
+ return {
38602
+ [namespace]: {
38603
+ entityTypes,
38604
+ actions
38605
+ }
38606
+ };
38607
+ }
38608
+ function jsonSchemaToSchemaJsonType(schema) {
38609
+ if (schema.enum) return "String";
38610
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
38611
+ switch (type) {
38612
+ case "string":
38613
+ return "String";
38614
+ case "integer":
38615
+ case "number":
38616
+ return "Long";
38617
+ case "boolean":
38618
+ return "EntityOrCommon";
38619
+ // Cedar JSON schema uses this for Bool
38620
+ case "array":
38621
+ return "Set";
38622
+ default:
38623
+ return "String";
38624
+ }
38625
+ }
38626
+ function generateSchemaStub(namespace = "ScopeBlind") {
38627
+ return [
38628
+ `// Cedar schema stub for protect-mcp`,
38629
+ `// This defines the principal and resource entity types.`,
38630
+ `// Tool-specific actions are auto-generated from MCP tools/list.`,
38631
+ `//`,
38632
+ `// Compatible with cedar-policy/cedar-for-agents @mcp_principal/@mcp_resource annotations.`,
38633
+ `// See: https://github.com/cedar-policy/cedar-for-agents`,
38634
+ ``,
38635
+ `namespace ${namespace} {`,
38636
+ ``,
38637
+ ` // @mcp_principal`,
38638
+ ` entity Agent = {`,
38639
+ ` "tier": String,`,
38640
+ ` "agent_id": String?`,
38641
+ ` };`,
38642
+ ``,
38643
+ ` // @mcp_resource`,
38644
+ ` entity Tool;`,
38645
+ ``,
38646
+ ` // @mcp_action`,
38647
+ ` action "MCP::Tool::call" appliesTo {`,
38648
+ ` principal: [Agent],`,
38649
+ ` resource: [Tool],`,
38650
+ ` context: {`,
38651
+ ` "tier": String`,
38652
+ ` }`,
38653
+ ` };`,
38654
+ ``,
38655
+ `}`,
38656
+ ``
38657
+ ].join("\n");
38658
+ }
38659
+
38384
38660
  // src/rekor-anchor.ts
38385
38661
  var import_node_crypto5 = require("crypto");
38386
38662
  var REKOR_API = "https://rekor.sigstore.dev/api/v1";
@@ -39807,18 +40083,21 @@ function createSandboxServer() {
39807
40083
  createSandboxServer,
39808
40084
  destroySandbox,
39809
40085
  ed25519ToDIDKey,
40086
+ evaluateCedar,
39810
40087
  evaluateTier,
39811
40088
  exportC2PAManifestJSON,
39812
40089
  exportJSONL,
39813
40090
  formatReportMarkdown,
39814
40091
  formatSimulation,
39815
40092
  generateC2PACommand,
40093
+ generateCedarSchema,
39816
40094
  generateDatasetCard,
39817
40095
  generateHFMetadata,
39818
40096
  generateHookSettings,
39819
40097
  generateReport,
39820
40098
  generateSafetyTranscript,
39821
40099
  generateSampleCedarPolicy,
40100
+ generateSchemaStub,
39822
40101
  generateVerifyReceiptSkill,
39823
40102
  getSignerInfo,
39824
40103
  getToolPolicy,
@@ -39826,11 +40105,13 @@ function createSandboxServer() {
39826
40105
  hashResponseBody,
39827
40106
  initSigning,
39828
40107
  isAgentId,
40108
+ isCedarAvailable,
39829
40109
  isDisclosureMode,
39830
40110
  isEvidenceType,
39831
40111
  isManifestStatus,
39832
40112
  isSigningEnabled,
39833
40113
  listCredentialLabels,
40114
+ loadCedarPolicies,
39834
40115
  loadPolicy,
39835
40116
  manifestToVC,
39836
40117
  meetsMinTier,
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  formatSimulation,
7
7
  parseLogFile,
8
8
  simulate
9
- } from "./chunk-YKM6W6T7.mjs";
9
+ } from "./chunk-W4U5VNEC.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-IUFFDQYZ.mjs";
21
+ } from "./chunk-IWDR5WU3.mjs";
22
22
  import {
23
23
  createSandboxServer
24
24
  } from "./chunk-SU2FZH7U.mjs";
@@ -30,17 +30,20 @@ import {
30
30
  } from "./chunk-UEHLYOJY.mjs";
31
31
  import {
32
32
  startHookServer
33
- } from "./chunk-IAJJA5IW.mjs";
33
+ } from "./chunk-Q4KOQUKV.mjs";
34
34
  import {
35
35
  checkRateLimit,
36
+ evaluateCedar,
36
37
  getSignerInfo,
37
38
  getToolPolicy,
38
39
  initSigning,
40
+ isCedarAvailable,
39
41
  isSigningEnabled,
42
+ loadCedarPolicies,
40
43
  loadPolicy,
41
44
  parseRateLimit,
42
45
  signDecision
43
- } from "./chunk-V52W3XIN.mjs";
46
+ } from "./chunk-N4F76LTC.mjs";
44
47
  import {
45
48
  collectSignedReceipts,
46
49
  createAuditBundle
@@ -202,6 +205,273 @@ function validateEvidenceReceipt(receipt) {
202
205
  return errors;
203
206
  }
204
207
 
208
+ // src/cedar-schema.ts
209
+ function jsonSchemaToCedarType(schema, namespace, path) {
210
+ if (schema.enum) {
211
+ return "String";
212
+ }
213
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
214
+ switch (type) {
215
+ case "string":
216
+ if (schema.format === "date-time") return "String";
217
+ if (schema.format === "uri") return "String";
218
+ return "String";
219
+ case "integer":
220
+ case "number":
221
+ return "Long";
222
+ case "boolean":
223
+ return "Bool";
224
+ case "array":
225
+ if (schema.items) {
226
+ const itemType = jsonSchemaToCedarType(schema.items, namespace, path + "_item");
227
+ return `Set<${itemType}>`;
228
+ }
229
+ return "Set<String>";
230
+ // Default to Set<String> for untyped arrays
231
+ case "object":
232
+ if (schema.properties && Object.keys(schema.properties).length > 0) {
233
+ const fields = Object.entries(schema.properties).map(([key, prop]) => {
234
+ const cedarType = jsonSchemaToCedarType(prop, namespace, path + "_" + sanitizeIdentifier(key));
235
+ const isRequired = schema.required?.includes(key) ?? false;
236
+ return ` "${sanitizeIdentifier(key)}": ${cedarType}${isRequired ? "" : "?"}`;
237
+ });
238
+ return `{
239
+ ${fields.join(",\n")}
240
+ }`;
241
+ }
242
+ return "Record";
243
+ // Empty objects
244
+ default:
245
+ return "String";
246
+ }
247
+ }
248
+ function sanitizeIdentifier(name) {
249
+ return name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^(\d)/, "_$1");
250
+ }
251
+ function cedarActionId(toolName) {
252
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(toolName)) {
253
+ return toolName;
254
+ }
255
+ return toolName;
256
+ }
257
+ function generateCedarSchema(tools, config = {}) {
258
+ const ns = config.namespace || "ScopeBlind";
259
+ const includeTier = config.includeTier !== false;
260
+ const includeTimestamp = config.includeTimestamp !== false;
261
+ const includeAgentId = config.includeAgentId !== false;
262
+ const agentAttrs = [];
263
+ if (includeTier) agentAttrs.push(' "tier": String');
264
+ if (includeAgentId) agentAttrs.push(' "agent_id": String?');
265
+ const sessionFields = [];
266
+ if (includeTimestamp) sessionFields.push(' "timestamp": String?');
267
+ sessionFields.push(' "hook_event": String?');
268
+ const actionDeclarations = [];
269
+ const inputTypeDeclarations = [];
270
+ for (const tool of tools) {
271
+ const actionName = cedarActionId(tool.name);
272
+ const inputTypeName = `${sanitizeIdentifier(tool.name)}_Input`;
273
+ if (tool.inputSchema?.properties && Object.keys(tool.inputSchema.properties).length > 0) {
274
+ const fields = Object.entries(tool.inputSchema.properties).map(([key, prop]) => {
275
+ const cedarType = jsonSchemaToCedarType(prop, ns, sanitizeIdentifier(tool.name) + "_" + sanitizeIdentifier(key));
276
+ const isRequired = tool.inputSchema?.required?.includes(key) ?? false;
277
+ return ` "${sanitizeIdentifier(key)}": ${cedarType}${isRequired ? "" : "?"}`;
278
+ });
279
+ inputTypeDeclarations.push(
280
+ ` // Input type for tool: ${tool.name}` + (tool.description ? `
281
+ // ${tool.description}` : "") + `
282
+ type ${inputTypeName} = {
283
+ ${fields.join(",\n")}
284
+ };`
285
+ );
286
+ actionDeclarations.push(
287
+ ` action "${actionName}" in [Action::"MCP::Tool::call"] appliesTo {
288
+ principal: [Agent],
289
+ resource: [Tool],
290
+ context: {
291
+ "input": ${inputTypeName},
292
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
293
+ }
294
+ };`
295
+ );
296
+ } else {
297
+ actionDeclarations.push(
298
+ ` action "${actionName}" in [Action::"MCP::Tool::call"] appliesTo {
299
+ principal: [Agent],
300
+ resource: [Tool],
301
+ context: {
302
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
303
+ }
304
+ };`
305
+ );
306
+ }
307
+ }
308
+ actionDeclarations.push(
309
+ ` // Blanket action for policies matching any tool call
310
+ action "MCP::Tool::call" appliesTo {
311
+ principal: [Agent],
312
+ resource: [Tool],
313
+ context: {
314
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
315
+ }
316
+ };`
317
+ );
318
+ const schemaText = [
319
+ `// Cedar schema for MCP tool governance`,
320
+ `// Generated by protect-mcp from ${tools.length} tool description(s)`,
321
+ `// Compatible with cedar-policy/cedar-for-agents`,
322
+ ``,
323
+ `namespace ${ns} {`,
324
+ ``,
325
+ ` // \u2500\u2500 Entity types \u2500\u2500`,
326
+ ``,
327
+ ` entity Agent${agentAttrs.length > 0 ? ` = {
328
+ ${agentAttrs.join(",\n")}
329
+ }` : ""};`,
330
+ ``,
331
+ ` entity Tool;`,
332
+ ``,
333
+ ...inputTypeDeclarations.length > 0 ? [` // \u2500\u2500 Tool input types \u2500\u2500`, ``, ...inputTypeDeclarations, ``] : [],
334
+ ` // \u2500\u2500 Actions \u2500\u2500`,
335
+ ``,
336
+ ...actionDeclarations,
337
+ ``,
338
+ `}`,
339
+ ``
340
+ ].join("\n");
341
+ const schemaJson = buildSchemaJson(tools, ns, config);
342
+ return {
343
+ schemaText,
344
+ schemaJson,
345
+ toolCount: tools.length,
346
+ tools: tools.map((t) => t.name)
347
+ };
348
+ }
349
+ function buildSchemaJson(tools, namespace, config) {
350
+ const entityTypes = {
351
+ Agent: {
352
+ shape: {
353
+ type: "Record",
354
+ attributes: {
355
+ ...config.includeTier !== false ? { tier: { type: "String", required: false } } : {},
356
+ ...config.includeAgentId !== false ? { agent_id: { type: "String", required: false } } : {}
357
+ }
358
+ },
359
+ memberOfTypes: []
360
+ },
361
+ Tool: {
362
+ shape: { type: "Record", attributes: {} },
363
+ memberOfTypes: []
364
+ }
365
+ };
366
+ const actions = {};
367
+ for (const tool of tools) {
368
+ const contextAttrs = {
369
+ tier: { type: "String", required: false }
370
+ };
371
+ if (config.includeTimestamp !== false) {
372
+ contextAttrs["timestamp"] = { type: "String", required: false };
373
+ }
374
+ if (config.includeAgentId !== false) {
375
+ contextAttrs["agent_id"] = { type: "String", required: false };
376
+ }
377
+ if (tool.inputSchema?.properties) {
378
+ const inputAttrs = {};
379
+ for (const [key, prop] of Object.entries(tool.inputSchema.properties)) {
380
+ inputAttrs[sanitizeIdentifier(key)] = {
381
+ type: jsonSchemaToSchemaJsonType(prop),
382
+ required: tool.inputSchema.required?.includes(key) ?? false
383
+ };
384
+ }
385
+ contextAttrs["input"] = {
386
+ type: "Record",
387
+ attributes: inputAttrs,
388
+ required: false
389
+ };
390
+ }
391
+ actions[tool.name] = {
392
+ appliesTo: {
393
+ principalTypes: ["Agent"],
394
+ resourceTypes: ["Tool"],
395
+ context: { type: "Record", attributes: contextAttrs }
396
+ },
397
+ memberOf: [{ id: "MCP::Tool::call" }]
398
+ };
399
+ }
400
+ const blanketContext = {
401
+ tier: { type: "String", required: false }
402
+ };
403
+ if (config.includeTimestamp !== false) {
404
+ blanketContext["timestamp"] = { type: "String", required: false };
405
+ }
406
+ if (config.includeAgentId !== false) {
407
+ blanketContext["agent_id"] = { type: "String", required: false };
408
+ }
409
+ actions["MCP::Tool::call"] = {
410
+ appliesTo: {
411
+ principalTypes: ["Agent"],
412
+ resourceTypes: ["Tool"],
413
+ context: { type: "Record", attributes: blanketContext }
414
+ }
415
+ };
416
+ return {
417
+ [namespace]: {
418
+ entityTypes,
419
+ actions
420
+ }
421
+ };
422
+ }
423
+ function jsonSchemaToSchemaJsonType(schema) {
424
+ if (schema.enum) return "String";
425
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
426
+ switch (type) {
427
+ case "string":
428
+ return "String";
429
+ case "integer":
430
+ case "number":
431
+ return "Long";
432
+ case "boolean":
433
+ return "EntityOrCommon";
434
+ // Cedar JSON schema uses this for Bool
435
+ case "array":
436
+ return "Set";
437
+ default:
438
+ return "String";
439
+ }
440
+ }
441
+ function generateSchemaStub(namespace = "ScopeBlind") {
442
+ return [
443
+ `// Cedar schema stub for protect-mcp`,
444
+ `// This defines the principal and resource entity types.`,
445
+ `// Tool-specific actions are auto-generated from MCP tools/list.`,
446
+ `//`,
447
+ `// Compatible with cedar-policy/cedar-for-agents @mcp_principal/@mcp_resource annotations.`,
448
+ `// See: https://github.com/cedar-policy/cedar-for-agents`,
449
+ ``,
450
+ `namespace ${namespace} {`,
451
+ ``,
452
+ ` // @mcp_principal`,
453
+ ` entity Agent = {`,
454
+ ` "tier": String,`,
455
+ ` "agent_id": String?`,
456
+ ` };`,
457
+ ``,
458
+ ` // @mcp_resource`,
459
+ ` entity Tool;`,
460
+ ``,
461
+ ` // @mcp_action`,
462
+ ` action "MCP::Tool::call" appliesTo {`,
463
+ ` principal: [Agent],`,
464
+ ` resource: [Tool],`,
465
+ ` context: {`,
466
+ ` "tier": String`,
467
+ ` }`,
468
+ ` };`,
469
+ ``,
470
+ `}`,
471
+ ``
472
+ ].join("\n");
473
+ }
474
+
205
475
  // src/rekor-anchor.ts
206
476
  import { createHash } from "crypto";
207
477
  var REKOR_API = "https://rekor.sigstore.dev/api/v1";
@@ -1452,18 +1722,21 @@ export {
1452
1722
  createSandboxServer,
1453
1723
  destroySandbox,
1454
1724
  ed25519ToDIDKey,
1725
+ evaluateCedar,
1455
1726
  evaluateTier,
1456
1727
  exportC2PAManifestJSON,
1457
1728
  exportJSONL,
1458
1729
  formatReportMarkdown,
1459
1730
  formatSimulation,
1460
1731
  generateC2PACommand,
1732
+ generateCedarSchema,
1461
1733
  generateDatasetCard,
1462
1734
  generateHFMetadata,
1463
1735
  generateHookSettings,
1464
1736
  generateReport,
1465
1737
  generateSafetyTranscript,
1466
1738
  generateSampleCedarPolicy,
1739
+ generateSchemaStub,
1467
1740
  generateVerifyReceiptSkill,
1468
1741
  getSignerInfo,
1469
1742
  getToolPolicy,
@@ -1471,11 +1744,13 @@ export {
1471
1744
  hashResponseBody,
1472
1745
  initSigning,
1473
1746
  isAgentId,
1747
+ isCedarAvailable,
1474
1748
  isDisclosureMode,
1475
1749
  isEvidenceType,
1476
1750
  isManifestStatus,
1477
1751
  isSigningEnabled,
1478
1752
  listCredentialLabels,
1753
+ loadCedarPolicies,
1479
1754
  loadPolicy,
1480
1755
  manifestToVC,
1481
1756
  meetsMinTier,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "protect-mcp",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "mcpName": "io.github.tomjwxf/protect-mcp",
5
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.",
6
6
  "main": "dist/index.js",