@vaultys/mcp-agent 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/audit.js CHANGED
@@ -96,8 +96,13 @@ async function main() {
96
96
  const jobId = record.job_id;
97
97
  const decision = record.decision;
98
98
  const tool = record.tool;
99
- if (receipt.broker_signature && typeof receipt.broker_signature === "string") {
100
- receipt.broker_signature = Buffer.from(receipt.broker_signature, "base64");
99
+ if (receipt.broker_signature) {
100
+ if (typeof receipt.broker_signature === "string") {
101
+ receipt.broker_signature = Buffer.from(receipt.broker_signature, "base64");
102
+ }
103
+ else if (typeof receipt.broker_signature === "object" && receipt.broker_signature.data) {
104
+ receipt.broker_signature = Buffer.from(receipt.broker_signature.data);
105
+ }
101
106
  }
102
107
  let verified = false;
103
108
  let sigStatus = "⏭ no key";
package/dist/src/audit.js CHANGED
@@ -91,8 +91,13 @@ async function main() {
91
91
  const decision = record.decision;
92
92
  const tool = record.tool;
93
93
  // Restore Buffer types for signature
94
- if (receipt.broker_signature && typeof receipt.broker_signature === "string") {
95
- receipt.broker_signature = Buffer.from(receipt.broker_signature, "base64");
94
+ if (receipt.broker_signature) {
95
+ if (typeof receipt.broker_signature === "string") {
96
+ receipt.broker_signature = Buffer.from(receipt.broker_signature, "base64");
97
+ }
98
+ else if (typeof receipt.broker_signature === "object" && receipt.broker_signature.data) {
99
+ receipt.broker_signature = Buffer.from(receipt.broker_signature.data);
100
+ }
96
101
  }
97
102
  let verified = false;
98
103
  let sigStatus = "⏭ no key";
@@ -31,11 +31,13 @@ export interface CapabilityMapping {
31
31
  * tools can resolve relative paths to absolute paths matching the policy globs.
32
32
  */
33
33
  export declare const DEFAULT_TOOL_MAPPINGS: Record<string, CapabilityMapping>;
34
+ export declare function setAuditDir(dir: string): void;
34
35
  export interface PolicyMiddlewareOptions {
35
36
  serverIdManager: IdManager;
36
37
  signedPolicy: PolicyBundle;
37
38
  toolMappings?: Record<string, CapabilityMapping>;
38
39
  workspaceRoot?: string;
40
+ auditDir?: string;
39
41
  }
40
42
  export interface ToolCallResult {
41
43
  decision: "allow" | "deny";
@@ -79,7 +79,10 @@ function resolveWorkspacePath(raw, workspaceRoot) {
79
79
  return path.join(workspaceRoot ?? "/workspace", raw);
80
80
  }
81
81
  // ── Audit persistence ──
82
- const AUDIT_DIR = path.resolve("audit");
82
+ let AUDIT_DIR = path.resolve("audit");
83
+ export function setAuditDir(dir) {
84
+ AUDIT_DIR = path.resolve(dir);
85
+ }
83
86
  function ensureAuditDir() {
84
87
  if (!fs.existsSync(AUDIT_DIR)) {
85
88
  fs.mkdirSync(AUDIT_DIR, { recursive: true });
@@ -87,11 +90,18 @@ function ensureAuditDir() {
87
90
  }
88
91
  function persistReceipt(jobId, receipt, meta) {
89
92
  ensureAuditDir();
93
+ // Serialize broker_signature as base64 string for JSON storage
94
+ const serializedReceipt = {
95
+ ...receipt,
96
+ broker_signature: receipt.broker_signature
97
+ ? Buffer.from(receipt.broker_signature).toString("base64")
98
+ : undefined,
99
+ };
90
100
  const record = {
91
101
  job_id: jobId,
92
102
  timestamp: new Date().toISOString(),
93
103
  ...meta,
94
- receipt,
104
+ receipt: serializedReceipt,
95
105
  };
96
106
  const filePath = path.join(AUDIT_DIR, `${jobId}.json`);
97
107
  fs.writeFileSync(filePath, JSON.stringify(record, null, 2));
@@ -100,7 +110,10 @@ function persistReceipt(jobId, receipt, meta) {
100
110
  * Create policy-enforced middleware that wraps MCP tool handlers.
101
111
  */
102
112
  export function createPolicyMiddleware(options) {
103
- const { serverIdManager, signedPolicy, toolMappings = DEFAULT_TOOL_MAPPINGS, workspaceRoot = process.cwd(), } = options;
113
+ const { serverIdManager, signedPolicy, toolMappings = DEFAULT_TOOL_MAPPINGS, workspaceRoot = process.cwd(), auditDir, } = options;
114
+ if (auditDir) {
115
+ setAuditDir(auditDir);
116
+ }
104
117
  const em = new ExecutionManager(serverIdManager);
105
118
  /**
106
119
  * Wrap a tool call: evaluate policy, run handler if allowed, sign receipt.
@@ -25,6 +25,7 @@ import { createPolicyMiddleware } from "./policyMiddleware.js";
25
25
  import { registerFilesystemTools } from "./tools/filesystem.js";
26
26
  import { registerShellTool } from "./tools/shell.js";
27
27
  import { registerNetworkTool } from "./tools/network.js";
28
+ import { registerAuditTool } from "./tools/audit.js";
28
29
  import { registerResources } from "./resources/index.js";
29
30
  // ── Configuration ──
30
31
  const WORKSPACE_ROOT = path.resolve(process.env.WORKSPACE_ROOT ?? process.cwd());
@@ -68,6 +69,7 @@ async function main() {
68
69
  registerFilesystemTools(mcpServer, middleware, WORKSPACE_ROOT);
69
70
  registerShellTool(mcpServer, middleware, WORKSPACE_ROOT);
70
71
  registerNetworkTool(mcpServer, middleware);
72
+ registerAuditTool(mcpServer, serverIdm);
71
73
  // 7. Register resources (audit trail, policy, identity)
72
74
  registerResources(mcpServer, serverIdm, signedPolicy);
73
75
  // 8. Connect via stdio transport
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Audit verification MCP tool — lets Claude verify the cryptographic audit trail.
3
+ *
4
+ * Tool:
5
+ * verify_audit — verify all signed receipts, report valid/invalid/tampered
6
+ */
7
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import type { IdManager } from "@vaultys/id";
9
+ export declare function registerAuditTool(server: McpServer, serverIdManager: IdManager): void;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Audit verification MCP tool — lets Claude verify the cryptographic audit trail.
3
+ *
4
+ * Tool:
5
+ * verify_audit — verify all signed receipts, report valid/invalid/tampered
6
+ */
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { z } from "zod";
10
+ import { ExecutionManager } from "@vaultys/id";
11
+ const AUDIT_DIR = path.resolve("audit");
12
+ function restoreSignature(receipt) {
13
+ if (receipt.broker_signature) {
14
+ if (typeof receipt.broker_signature === "string") {
15
+ receipt.broker_signature = Buffer.from(receipt.broker_signature, "base64");
16
+ }
17
+ else if (typeof receipt.broker_signature === "object" && receipt.broker_signature.data) {
18
+ receipt.broker_signature = Buffer.from(receipt.broker_signature.data);
19
+ }
20
+ }
21
+ }
22
+ export function registerAuditTool(server, serverIdManager) {
23
+ server.tool("verify_audit", "Verify the cryptographic audit trail. Checks all signed receipts for tampering. Returns verification results for each receipt.", {
24
+ limit: z.number().optional().describe("Maximum number of recent receipts to verify (default: all)"),
25
+ }, async (args) => {
26
+ const serverVid = serverIdManager.vaultysId;
27
+ if (!fs.existsSync(AUDIT_DIR)) {
28
+ return {
29
+ content: [{ type: "text", text: "No audit directory found. No tool calls have been recorded yet." }],
30
+ };
31
+ }
32
+ const files = fs.readdirSync(AUDIT_DIR)
33
+ .filter((f) => f.endsWith(".json"))
34
+ .sort();
35
+ if (files.length === 0) {
36
+ return {
37
+ content: [{ type: "text", text: "No audit receipts found. No tool calls have been recorded yet." }],
38
+ };
39
+ }
40
+ const limit = args.limit ?? files.length;
41
+ const toVerify = files.slice(-limit); // most recent N
42
+ let passed = 0;
43
+ let failed = 0;
44
+ let errors = 0;
45
+ const results = [];
46
+ for (const file of toVerify) {
47
+ const filePath = path.join(AUDIT_DIR, file);
48
+ let record;
49
+ try {
50
+ record = JSON.parse(fs.readFileSync(filePath, "utf-8"));
51
+ }
52
+ catch {
53
+ errors++;
54
+ results.push({
55
+ job_id: file.replace(".json", ""),
56
+ timestamp: "?",
57
+ tool: "?",
58
+ decision: "?",
59
+ verified: "error",
60
+ });
61
+ continue;
62
+ }
63
+ restoreSignature(record.receipt);
64
+ let verified = false;
65
+ try {
66
+ verified = ExecutionManager.verifyReceipt(record.receipt, serverVid);
67
+ }
68
+ catch {
69
+ verified = false;
70
+ }
71
+ if (verified)
72
+ passed++;
73
+ else
74
+ failed++;
75
+ results.push({
76
+ job_id: record.job_id,
77
+ timestamp: record.timestamp,
78
+ tool: record.tool,
79
+ decision: record.decision,
80
+ verified,
81
+ });
82
+ }
83
+ const summary = {
84
+ total: files.length,
85
+ verified_count: toVerify.length,
86
+ passed,
87
+ failed,
88
+ errors,
89
+ integrity: failed === 0 && errors === 0 ? "INTACT" : "COMPROMISED",
90
+ server_did: serverVid.did,
91
+ results,
92
+ };
93
+ return {
94
+ content: [{
95
+ type: "text",
96
+ text: JSON.stringify(summary, null, 2),
97
+ }],
98
+ };
99
+ });
100
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaultys/mcp-agent",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Policy-enforced MCP server powered by VaultysID — cryptographic authorization and audit trail for every AI tool call",
6
6
  "license": "MIT",
@@ -50,7 +50,7 @@
50
50
  "grant-policy": "tsx grant-policy.ts",
51
51
  "srp-grant": "tsx srp-grant-policy.ts",
52
52
  "audit": "tsx src/audit.ts",
53
- "test": "tsx test-e2e.ts",
53
+ "test": "tsx test/e2e.test.ts",
54
54
  "build": "tsc && chmod +x dist/bin/*.js"
55
55
  }
56
56
  }