audit-ledger-mcp 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,302 +1,337 @@
1
- # audit-ledger-mcp
2
-
3
- **MCP server for the [AI Audit Ledger](https://github.com/shahidh68/audit-ledger).** Lets any AI agent — Claude Desktop, Cursor, LangGraph, custom — record decisions to a tamper-evident audit trail with one line of config.
4
-
5
- Built for teams shipping AI in regulated contexts: EU AI Act Article 12 logging, FCA SS1/23 model risk evidence, GDPR data minimisation. Personal data is hashed locally before any payload leaves the server — the ledger only ever sees fingerprints.
6
-
7
- [![npm](https://img.shields.io/npm/v/audit-ledger-mcp.svg)](https://www.npmjs.com/package/audit-ledger-mcp) [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE) [![MCP](https://img.shields.io/badge/MCP-compatible-7c3aed.svg)](https://modelcontextprotocol.io)
8
-
9
- **[Try the live dashboard →](https://d2pfirb2397ixy.cloudfront.net/?demo=1)**  ·  30 synthetic decisions written via this MCP server, queryable and verifiable.
10
-
11
- <p align="center">
12
- <img src="./demo.gif" alt="LangGraph agents using audit-ledger-mcp — triage, risk, and human-in-the-loop each calling record_decision" />
13
- </p>
14
-
15
- > A LangGraph workflow calls `record_decision` after each agent step. Three audit events written to the live ledger; every one independently verifiable.
16
-
17
- ---
18
-
19
- ## What it does
20
-
21
- Exposes three tools to any MCP-compatible agent:
22
-
23
- | Tool | What it does |
24
- |---|---|
25
- | `record_decision` | Log an AI decision. Hashes inputs locally, then writes through to the ledger. Returns an event ID. |
26
- | `verify_decision` | Cross-check a stored record against the immutable S3 Object Lock copy. Returns `integrity_verified: true/false`. |
27
- | `list_decisions` | Query recent decisions, optionally filtered by time window. Tenant-scoped by API key. |
28
-
29
- Each call ends up as a regulator-grade audit record in your deployed ledger — DynamoDB for query, S3 Object Lock COMPLIANCE mode for the immutable copy, 7-year retention by default.
30
-
31
- ---
32
-
33
- ## Quick start — zero configuration
34
-
35
- ```bash
36
- npx -y audit-ledger-mcp
37
- ```
38
-
39
- That's it. With no environment variables, the server boots into **sandbox mode** and writes records to a shared public tenant on a hosted ledger. You can try every tool — `record_decision`, `verify_decision`, `list_decisions` — without provisioning anything.
40
-
41
- When sandbox mode is active, you'll see a banner on stderr:
42
-
43
- ```
44
- [audit-ledger-mcp] ─────────────── SANDBOX MODE ───────────────
45
- [audit-ledger-mcp] No AUDIT_API_URL configured.
46
- [audit-ledger-mcp] Using the public sandbox at sandbox-public.
47
- [audit-ledger-mcp] View: https://d2pfirb2397ixy.cloudfront.net
48
- [audit-ledger-mcp] Do NOT write real personal data...
49
- ```
50
-
51
- ### Sandbox properties
52
-
53
- | | |
54
- |---|---|
55
- | **Hosted by** | github.com/shahidh68/audit-ledger (same AWS deployment) |
56
- | **Tenant** | `sandbox-public` (shared, public) |
57
- | **Rate limit** | 100 requests/minute per IP |
58
- | **Retention** | 7 years (records cannot be deleted) |
59
- | **Audience** | Tyre-kickers, integration tests, framework demos |
60
- | **NOT for** | Production data, customer PII, real compliance records |
61
-
62
- ### Wire it into Claude Desktop with zero config
63
-
64
- ```json
65
- {
66
- "mcpServers": {
67
- "audit-ledger-sandbox": {
68
- "command": "npx",
69
- "args": ["-y", "audit-ledger-mcp"]
70
- }
71
- }
72
- }
73
- ```
74
-
75
- Restart Claude Desktop. The three tools appear in the MCP menu immediately. Try asking Claude to "record this decision: should X be approved?" and watch a record land in the sandbox dashboard.
76
-
77
- ---
78
-
79
- ## Production install
80
-
81
- For real workloads, deploy your own audit ledger and point the MCP server at it:
82
-
83
- ```bash
84
- npm install -g audit-ledger-mcp
85
- ```
86
-
87
- Configure with **all three** env vars (any of them being set switches off sandbox mode):
88
-
89
- ```bash
90
- export AUDIT_API_URL="https://<api-id>.execute-api.<region>.amazonaws.com/prod"
91
- export AUDIT_WRITE_KEY="<your-tenant-write-key>"
92
- export AUDIT_READ_KEY="<your-tenant-read-key>"
93
-
94
- # Optional
95
- export AUDIT_TIMEOUT_MS=5000 # default 5000
96
- export AUDIT_RETRY_ATTEMPTS=3 # default 3
97
- ```
98
-
99
- The full template lives in [`.env.example`](./.env.example).
100
-
101
- ---
102
-
103
- ## Wire it into an agent
104
-
105
- ### Claude Desktop
106
-
107
- Edit your `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows: `%APPDATA%\Claude\claude_desktop_config.json`):
108
-
109
- ```json
110
- {
111
- "mcpServers": {
112
- "audit-ledger": {
113
- "command": "npx",
114
- "args": ["-y", "audit-ledger-mcp"],
115
- "env": {
116
- "AUDIT_API_URL": "https://<api-id>.execute-api.<region>.amazonaws.com/prod",
117
- "AUDIT_WRITE_KEY": "<your-tenant-write-key>",
118
- "AUDIT_READ_KEY": "<your-tenant-read-key>"
119
- }
120
- }
121
- }
122
- }
123
- ```
124
-
125
- Restart Claude Desktop. You'll see "audit-ledger" in the MCP tools menu. Ask Claude something like *"Record this decision: I declined the application because…"* and watch it call `record_decision` automatically.
126
-
127
- ### Cursor
128
-
129
- In Cursor settings → MCP → add server:
130
-
131
- ```json
132
- {
133
- "mcpServers": {
134
- "audit-ledger": {
135
- "command": "npx",
136
- "args": ["-y", "audit-ledger-mcp"],
137
- "env": {
138
- "AUDIT_API_URL": "https://<api-id>.execute-api.<region>.amazonaws.com/prod",
139
- "AUDIT_WRITE_KEY": "<your-tenant-write-key>",
140
- "AUDIT_READ_KEY": "<your-tenant-read-key>"
141
- }
142
- }
143
- }
144
- }
145
- ```
146
-
147
- ### LangGraph (Python)
148
-
149
- Using [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters):
150
-
151
- ```python
152
- from langchain_mcp_adapters.client import MultiServerMCPClient
153
- from langgraph.prebuilt import create_react_agent
154
- from langchain_anthropic import ChatAnthropic
155
- import os
156
-
157
- client = MultiServerMCPClient({
158
- "audit-ledger": {
159
- "command": "npx",
160
- "args": ["-y", "audit-ledger-mcp"],
161
- "transport": "stdio",
162
- "env": {
163
- "AUDIT_API_URL": os.environ["AUDIT_API_URL"],
164
- "AUDIT_WRITE_KEY": os.environ["AUDIT_WRITE_KEY"],
165
- "AUDIT_READ_KEY": os.environ["AUDIT_READ_KEY"],
166
- },
167
- }
168
- })
169
-
170
- tools = await client.get_tools()
171
- agent = create_react_agent(
172
- ChatAnthropic(model="claude-sonnet-4-7-20251022"),
173
- tools,
174
- )
175
-
176
- # The agent can now call record_decision, verify_decision, list_decisions
177
- result = await agent.ainvoke({
178
- "messages": [{"role": "user", "content": "Triage this loan application…"}]
179
- })
180
- ```
181
-
182
- ### Custom client (raw MCP)
183
-
184
- ```bash
185
- AUDIT_API_URL=... AUDIT_WRITE_KEY=... npx -y audit-ledger-mcp
186
- ```
187
-
188
- The server speaks MCP over stdio. Send `initialize`, `tools/list`, and `tools/call` requests per the [MCP specification](https://modelcontextprotocol.io/specification).
189
-
190
- ---
191
-
192
- ## How a `record_decision` call flows
193
-
194
- ```
195
- Agent audit-ledger-mcp AWS (your ledger)
196
- | | |
197
- |--- record_decision ----->| |
198
- | raw_user_input | (hash locally — no PII over |
199
- | raw_system_prompt | the wire from this point) |
200
- | decision_output | |
201
- | human_in_loop | |
202
- | |--- HTTPS POST /audit/events --->|
203
- | | {hashes + decision + |
204
- | | x-api-key} |
205
- | | |
206
- | |<--- 202 Accepted ---------------|
207
- | | { event_id, ... } |
208
- |<--- event_id ------------| |
209
- | recorded_at | |
210
- | note | |
211
- ```
212
-
213
- Storage on the AWS side happens asynchronously through SQS → Processor Lambda → DynamoDB + S3 Object Lock. See the [main repo's ARCHITECTURE.md](https://github.com/shahidh68/audit-ledger/blob/main/ARCHITECTURE.md) for the full path.
214
-
215
- ---
216
-
217
- ## Tool reference
218
-
219
- ### `record_decision`
220
-
221
- Record an AI decision to the ledger.
222
-
223
- | Parameter | Type | Required | Notes |
224
- |---|---|---|---|
225
- | `model_version` | string | Yes | e.g. `"claude-sonnet-4-7-20251022"` |
226
- | `raw_system_prompt` | string | Yes | Hashed locally |
227
- | `raw_user_input` | string | Yes | Hashed locally |
228
- | `ai_decision_output` | object | Yes | Stored verbatim — must not contain raw PII |
229
- | `human_in_loop` | boolean | Yes | Critical for EU AI Act Article 14 |
230
- | `event_id` | uuid v4 | No | Auto-generated if omitted |
231
- | `timestamp` | ISO 8601 | No | Defaults to now |
232
-
233
- ### `verify_decision`
234
-
235
- Tamper-check a stored record.
236
-
237
- | Parameter | Type | Required | Notes |
238
- |---|---|---|---|
239
- | `event_id` | uuid v4 | Yes | The ID of the record to verify |
240
-
241
- Returns the DynamoDB record, the S3 record, and `integrity_verified: true/false`.
242
-
243
- ### `list_decisions`
244
-
245
- List recent decisions for the calling tenant.
246
-
247
- | Parameter | Type | Required | Notes |
248
- |---|---|---|---|
249
- | `from` | ISO 8601 | No | Defaults to 7 days ago |
250
- | `to` | ISO 8601 | No | Defaults to now |
251
- | `limit` | integer 1–500 | No | Defaults to 100 |
252
-
253
- ---
254
-
255
- ## Security
256
-
257
- - **PII hashing happens in this process, not in the ledger.** SHA-256 over UTF-8. The ledger only ever stores hashes, the structured decision, and metadata.
258
- - **API keys are never logged.** They come from environment variables, are passed in the `x-api-key` header, and are never echoed back to the agent or written to disk.
259
- - **Two key namespaces.** Write keys cannot read; read keys cannot write. A leaked write key cannot exfiltrate data; a leaked read key cannot plant fake records.
260
- - **Errors are propagated with HTTP status passthrough.** Rate limit, invalid key, and validation errors surface to the agent so it can react appropriately rather than retry blindly.
261
-
262
- ---
263
-
264
- ## What this is not
265
-
266
- - **Not legal advice.** This is infrastructure that produces audit evidence. Whether that evidence satisfies any specific regulatory obligation is a question for your legal team.
267
- - **Not a substitute for a model risk audit.** It records what the AI did, not whether it was right.
268
- - **Not a bias or fairness testing tool.** It is the audit layer underneath whatever testing you already do.
269
-
270
- ---
271
-
272
- ## Development
273
-
274
- ```bash
275
- git clone https://github.com/shahidh68/audit-ledger-mcp.git
276
- cd audit-ledger-mcp
277
- npm install
278
- npm run build
279
- npm test
280
- ```
281
-
282
- The server is TypeScript on Node 20+, ESM, stdio transport, using `@modelcontextprotocol/sdk`.
283
-
284
- ---
285
-
286
- ## Related
287
-
288
- - **[shahidh68/audit-ledger](https://github.com/shahidh68/audit-ledger)** — the AWS infrastructure this server talks to. CDK stack, Python and Node SDKs, compliance dashboard, full architecture documentation.
289
-
290
- ---
291
-
292
- ## License
293
-
294
- Apache License 2.0 see [LICENSE](./LICENSE).
295
-
296
- The patent grant is intentional. Compliance infrastructure sits adjacent to enterprise legal review and the explicit grant matters there.
297
-
298
- ---
299
-
300
- ## Author
301
-
302
- Built by [Shahid](https://github.com/shahidh68). Available for Principal AI Engineering and Head of AI Engineering roles, and fractional advisory engagements, in UK regulated fintech.
1
+ # audit-ledger-mcp
2
+
3
+ **MCP server for the [AI Audit Ledger](https://github.com/shahidh68/audit-ledger).** Lets any AI agent — Claude Desktop, Cursor, LangGraph, custom — record decisions to a tamper-evident audit trail with one line of config.
4
+
5
+ Built for teams shipping AI in regulated contexts: EU AI Act Article 12 logging, FCA SS1/23 model risk evidence, GDPR data minimisation. Personal data is hashed locally before any payload leaves the server — the ledger only ever sees fingerprints.
6
+
7
+ [![npm](https://img.shields.io/npm/v/audit-ledger-mcp.svg)](https://www.npmjs.com/package/audit-ledger-mcp) [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE) [![MCP](https://img.shields.io/badge/MCP-compatible-7c3aed.svg)](https://modelcontextprotocol.io)
8
+
9
+ **[Try the live dashboard →](https://d2pfirb2397ixy.cloudfront.net/?demo=1)** &nbsp;&middot;&nbsp; 30 synthetic decisions written via this MCP server, queryable and verifiable.
10
+
11
+ <p align="center">
12
+ <img src="./demo.gif" alt="LangGraph agents using audit-ledger-mcp — triage, risk, and human-in-the-loop each calling record_decision" />
13
+ </p>
14
+
15
+ > A LangGraph workflow calls `record_decision` after each agent step. Three audit events written to the live ledger; every one independently verifiable.
16
+
17
+ ---
18
+
19
+ ## What it does
20
+
21
+ Exposes four tools to any MCP-compatible agent:
22
+
23
+ | Tool | What it does |
24
+ |---|---|
25
+ | `record_decision` | Log an AI decision. Hashes inputs locally, then writes through to the ledger. Returns an event ID. |
26
+ | `verify_decision` | Cross-check a stored record against the immutable S3 Object Lock copy. Returns `integrity_verified: true/false`. |
27
+ | `verify_completeness` | Detect deleted or missing records. Compares the ledger's per-tenant counter against the rows actually present and returns any sequence numbers that are gone. The answer to "can you prove the log is complete?" |
28
+ | `list_decisions` | Query recent decisions, optionally filtered by time window. Tenant-scoped by API key. |
29
+
30
+ Each call ends up as a regulator-grade audit record in your deployed ledger — DynamoDB for query, S3 Object Lock COMPLIANCE mode for the immutable copy, 7-year retention by default.
31
+
32
+ ---
33
+
34
+ ## Quick start — zero configuration
35
+
36
+ ```bash
37
+ npx -y audit-ledger-mcp
38
+ ```
39
+
40
+ That's it. With no environment variables, the server boots into **sandbox mode** and writes records to a shared public tenant on a hosted ledger. You can try every tool — `record_decision`, `verify_decision`, `verify_completeness`, `list_decisions` — without provisioning anything.
41
+
42
+ When sandbox mode is active, you'll see a banner on stderr:
43
+
44
+ ```
45
+ [audit-ledger-mcp] ─────────────── SANDBOX MODE ───────────────
46
+ [audit-ledger-mcp] No AUDIT_API_URL configured.
47
+ [audit-ledger-mcp] Using the public sandbox at sandbox-public.
48
+ [audit-ledger-mcp] View: https://d2pfirb2397ixy.cloudfront.net
49
+ [audit-ledger-mcp] Do NOT write real personal data...
50
+ ```
51
+
52
+ ### Sandbox properties
53
+
54
+ | | |
55
+ |---|---|
56
+ | **Hosted by** | github.com/shahidh68/audit-ledger (same AWS deployment) |
57
+ | **Tenant** | `sandbox-public` (shared, public) |
58
+ | **Rate limit** | 100 requests/minute per IP |
59
+ | **Retention** | 7 years (records cannot be deleted) |
60
+ | **Audience** | Tyre-kickers, integration tests, framework demos |
61
+ | **NOT for** | Production data, customer PII, real compliance records |
62
+
63
+ ### Wire it into Claude Desktop with zero config
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "audit-ledger-sandbox": {
69
+ "command": "npx",
70
+ "args": ["-y", "audit-ledger-mcp"]
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ Restart Claude Desktop. The four tools appear in the MCP menu immediately. Try asking Claude to "record this decision: should X be approved?" and watch a record land in the sandbox dashboard.
77
+
78
+ ---
79
+
80
+ ## Production install
81
+
82
+ For real workloads, deploy your own audit ledger and point the MCP server at it:
83
+
84
+ ```bash
85
+ npm install -g audit-ledger-mcp
86
+ ```
87
+
88
+ Configure with the API URL plus your tenant keys (any of them being set switches off sandbox mode). `AUDIT_HMAC_KEY` is technically optional for backwards compatibility but strongly recommended — see the note above the value below:
89
+
90
+ ```bash
91
+ export AUDIT_API_URL="https://<api-id>.execute-api.<region>.amazonaws.com/prod"
92
+ export AUDIT_WRITE_KEY="<your-tenant-write-key>"
93
+ export AUDIT_READ_KEY="<your-tenant-read-key>"
94
+
95
+ # Strongly recommended. Tenant-held secret used to HMAC PII and prompts
96
+ # locally before sending. Generate once, store next to AUDIT_WRITE_KEY:
97
+ # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
98
+ # If unset, the MCP falls back to plain SHA-256 and warns once (back-compat).
99
+ export AUDIT_HMAC_KEY="<your-tenant-hmac-secret>"
100
+
101
+ # Optional
102
+ export AUDIT_TIMEOUT_MS=5000 # default 5000
103
+ export AUDIT_RETRY_ATTEMPTS=3 # default 3
104
+ ```
105
+
106
+ The full template lives in [`.env.example`](./.env.example).
107
+
108
+ ---
109
+
110
+ ## Wire it into an agent
111
+
112
+ ### Claude Desktop
113
+
114
+ Edit your `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows: `%APPDATA%\Claude\claude_desktop_config.json`):
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ "audit-ledger": {
120
+ "command": "npx",
121
+ "args": ["-y", "audit-ledger-mcp"],
122
+ "env": {
123
+ "AUDIT_API_URL": "https://<api-id>.execute-api.<region>.amazonaws.com/prod",
124
+ "AUDIT_WRITE_KEY": "<your-tenant-write-key>",
125
+ "AUDIT_READ_KEY": "<your-tenant-read-key>",
126
+ "AUDIT_HMAC_KEY": "<your-tenant-hmac-secret>"
127
+ }
128
+ }
129
+ }
130
+ }
131
+ ```
132
+
133
+ `AUDIT_HMAC_KEY` is the tenant secret used to keyed-hash PII locally before any payload leaves the MCP server process. Generate it once with `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` and store the result in the `env` block above. The MCP never transmits this value, only reads it.
134
+
135
+ Restart Claude Desktop. You'll see "audit-ledger" in the MCP tools menu. Ask Claude something like *"Record this decision: I declined the application because…"* and watch it call `record_decision` automatically.
136
+
137
+ ### Cursor
138
+
139
+ In Cursor settings → MCP → add server:
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "audit-ledger": {
145
+ "command": "npx",
146
+ "args": ["-y", "audit-ledger-mcp"],
147
+ "env": {
148
+ "AUDIT_API_URL": "https://<api-id>.execute-api.<region>.amazonaws.com/prod",
149
+ "AUDIT_WRITE_KEY": "<your-tenant-write-key>",
150
+ "AUDIT_READ_KEY": "<your-tenant-read-key>",
151
+ "AUDIT_HMAC_KEY": "<your-tenant-hmac-secret>"
152
+ }
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### LangGraph (Python)
159
+
160
+ Using [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters):
161
+
162
+ ```python
163
+ from langchain_mcp_adapters.client import MultiServerMCPClient
164
+ from langgraph.prebuilt import create_react_agent
165
+ from langchain_anthropic import ChatAnthropic
166
+ import os
167
+
168
+ client = MultiServerMCPClient({
169
+ "audit-ledger": {
170
+ "command": "npx",
171
+ "args": ["-y", "audit-ledger-mcp"],
172
+ "transport": "stdio",
173
+ "env": {
174
+ "AUDIT_API_URL": os.environ["AUDIT_API_URL"],
175
+ "AUDIT_WRITE_KEY": os.environ["AUDIT_WRITE_KEY"],
176
+ "AUDIT_READ_KEY": os.environ["AUDIT_READ_KEY"],
177
+ "AUDIT_HMAC_KEY": os.environ["AUDIT_HMAC_KEY"],
178
+ },
179
+ }
180
+ })
181
+
182
+ tools = await client.get_tools()
183
+ agent = create_react_agent(
184
+ ChatAnthropic(model="claude-sonnet-4-7-20251022"),
185
+ tools,
186
+ )
187
+
188
+ # The agent can now call record_decision, verify_decision, verify_completeness, list_decisions
189
+ result = await agent.ainvoke({
190
+ "messages": [{"role": "user", "content": "Triage this loan application…"}]
191
+ })
192
+ ```
193
+
194
+ ### Custom client (raw MCP)
195
+
196
+ ```bash
197
+ AUDIT_API_URL=... AUDIT_WRITE_KEY=... AUDIT_READ_KEY=... AUDIT_HMAC_KEY=... npx -y audit-ledger-mcp
198
+ ```
199
+
200
+ The server speaks MCP over stdio. Send `initialize`, `tools/list`, and `tools/call` requests per the [MCP specification](https://modelcontextprotocol.io/specification).
201
+
202
+ ---
203
+
204
+ ## How a `record_decision` call flows
205
+
206
+ ```
207
+ Agent audit-ledger-mcp AWS (your ledger)
208
+ | | |
209
+ |--- record_decision ----->| |
210
+ | raw_user_input | (hash locally — no PII over |
211
+ | raw_system_prompt | the wire from this point) |
212
+ | decision_output | |
213
+ | human_in_loop | |
214
+ | |--- HTTPS POST /audit/events --->|
215
+ | | {hashes + decision + |
216
+ | | x-api-key} |
217
+ | | |
218
+ | |<--- 202 Accepted ---------------|
219
+ | | { event_id, ... } |
220
+ |<--- event_id ------------| |
221
+ | recorded_at | |
222
+ | note | |
223
+ ```
224
+
225
+ Storage on the AWS side happens asynchronously through SQS → Processor Lambda → DynamoDB + S3 Object Lock. See the [main repo's ARCHITECTURE.md](https://github.com/shahidh68/audit-ledger/blob/main/ARCHITECTURE.md) for the full path.
226
+
227
+ ---
228
+
229
+ ## Tool reference
230
+
231
+ ### `record_decision`
232
+
233
+ Record an AI decision to the ledger.
234
+
235
+ | Parameter | Type | Required | Notes |
236
+ |---|---|---|---|
237
+ | `model_version` | string | Yes | e.g. `"claude-sonnet-4-7-20251022"` |
238
+ | `raw_system_prompt` | string | Yes | Hashed locally |
239
+ | `raw_user_input` | string | Yes | Hashed locally |
240
+ | `ai_decision_output` | object | Yes | Stored verbatim — must not contain raw PII |
241
+ | `human_in_loop` | boolean | Yes | Critical for EU AI Act Article 14 |
242
+ | `event_id` | uuid v4 | No | Auto-generated if omitted |
243
+ | `timestamp` | ISO 8601 | No | Defaults to now |
244
+
245
+ ### `verify_decision`
246
+
247
+ Tamper-check a stored record.
248
+
249
+ | Parameter | Type | Required | Notes |
250
+ |---|---|---|---|
251
+ | `event_id` | uuid v4 | Yes | The ID of the record to verify |
252
+
253
+ Returns the DynamoDB record, the S3 record, and `integrity_verified: true/false`.
254
+
255
+ ### `verify_completeness`
256
+
257
+ Detect missing records. Sister tool to `verify_decision`: that one proves a record that exists has not been altered; this one proves no records have been deleted.
258
+
259
+ | Parameter | Type | Required | Notes |
260
+ |---|---|---|---|
261
+ | `from` | integer | No | Inclusive lower bound on sequence_no. Defaults to 1. |
262
+ | `to` | integer | No | Inclusive upper bound on sequence_no. Defaults to the tenant's current counter. |
263
+ | `tenant_id` | string | No | Required only with the admin read key; ignored otherwise. |
264
+
265
+ Returns the requested range, the expected vs found count, the list of missing sequence numbers, and a human-readable note.
266
+
267
+ ```json
268
+ {
269
+ "tenant_id": "acme-prod",
270
+ "range": { "from": 1, "to": 142 },
271
+ "expected_count": 142,
272
+ "found_count": 140,
273
+ "missing": [47, 91],
274
+ "note": "Found 2 missing sequence number(s) in range. Each gap represents a deleted, lost, or never-written record. Cross-check against burned_sequence log entries before treating as a deletion."
275
+ }
276
+ ```
277
+
278
+ ### `list_decisions`
279
+
280
+ List recent decisions for the calling tenant.
281
+
282
+ | Parameter | Type | Required | Notes |
283
+ |---|---|---|---|
284
+ | `from` | ISO 8601 | No | Defaults to 7 days ago |
285
+ | `to` | ISO 8601 | No | Defaults to now |
286
+ | `limit` | integer 1–500 | No | Defaults to 100 |
287
+
288
+ ---
289
+
290
+ ## Security
291
+
292
+ - **PII hashing happens in this process, not in the ledger.** HMAC-SHA256 over UTF-8, keyed off the `AUDIT_HMAC_KEY` you set in your environment. The key never leaves your process; only the 64-char hex digest is sent. Plain SHA-256 of low-entropy values (names, emails) is brute-forceable in seconds and under ICO/EDPB guidance still counts as personal data, which is why the keyed version is the default for new installs. For backwards compatibility, if `AUDIT_HMAC_KEY` is unset the MCP falls back to plain SHA-256 and logs a one-time deprecation warning on stderr; existing setups keep working unchanged.
293
+ - **API keys are never logged.** They come from environment variables, are passed in the `x-api-key` header, and are never echoed back to the agent or written to disk.
294
+ - **Two key namespaces.** Write keys cannot read; read keys cannot write. A leaked write key cannot exfiltrate data; a leaked read key cannot plant fake records.
295
+ - **Errors are propagated with HTTP status passthrough.** Rate limit, invalid key, and validation errors surface to the agent so it can react appropriately rather than retry blindly.
296
+
297
+ ---
298
+
299
+ ## What this is not
300
+
301
+ - **Not legal advice.** This is infrastructure that produces audit evidence. Whether that evidence satisfies any specific regulatory obligation is a question for your legal team.
302
+ - **Not a substitute for a model risk audit.** It records what the AI did, not whether it was right.
303
+ - **Not a bias or fairness testing tool.** It is the audit layer underneath whatever testing you already do.
304
+
305
+ ---
306
+
307
+ ## Development
308
+
309
+ ```bash
310
+ git clone https://github.com/shahidh68/audit-ledger-mcp.git
311
+ cd audit-ledger-mcp
312
+ npm install
313
+ npm run build
314
+ npm test
315
+ ```
316
+
317
+ The server is TypeScript on Node 20+, ESM, stdio transport, using `@modelcontextprotocol/sdk`.
318
+
319
+ ---
320
+
321
+ ## Related
322
+
323
+ - **[shahidh68/audit-ledger](https://github.com/shahidh68/audit-ledger)** — the AWS infrastructure this server talks to. CDK stack, Python and Node SDKs, compliance dashboard, full architecture documentation.
324
+
325
+ ---
326
+
327
+ ## License
328
+
329
+ Apache License 2.0 — see [LICENSE](./LICENSE).
330
+
331
+ The patent grant is intentional. Compliance infrastructure sits adjacent to enterprise legal review and the explicit grant matters there.
332
+
333
+ ---
334
+
335
+ ## Author
336
+
337
+ Built by [Shahid](https://github.com/shahidh68). Available for Principal AI Engineering and Head of AI Engineering roles, and fractional advisory engagements, in UK regulated fintech.
package/dist/client.d.ts CHANGED
@@ -29,10 +29,29 @@ export interface DecisionRecord {
29
29
  human_in_loop: boolean;
30
30
  }
31
31
  export interface TamperCheckResult {
32
+ /** Event ID echoed back by the API. */
33
+ event_id: string;
34
+ /** True when the DynamoDB and S3 copies of the record are byte-identical after canonical serialisation. */
32
35
  integrity_verified: boolean;
36
+ /** Human-readable explanation of the integrity result. */
37
+ integrity_note: string;
38
+ /** The record as currently held in DynamoDB. */
39
+ current_record: DecisionRecord;
40
+ /** The record as written to S3 Object Lock (the immutable archive). */
41
+ archived_record: DecisionRecord;
42
+ }
43
+ export interface CompletenessResult {
44
+ tenant_id: string;
45
+ range: {
46
+ from: number;
47
+ to: number;
48
+ };
49
+ expected_count: number;
50
+ found_count: number;
51
+ /** Sequence numbers issued by the ledger that are no longer present. */
52
+ missing: number[];
53
+ /** Human-readable summary. Distinguishes empty tenant, all-present, gaps. */
33
54
  note: string;
34
- dynamodb_record: DecisionRecord;
35
- s3_record: DecisionRecord;
36
55
  }
37
56
  export declare class AuditLedgerClient {
38
57
  private readonly apiUrl;
@@ -45,6 +64,12 @@ export declare class AuditLedgerClient {
45
64
  event_id: string;
46
65
  }>;
47
66
  verifyDecision(eventId: string): Promise<TamperCheckResult>;
67
+ verifyCompleteness(opts?: {
68
+ from?: number;
69
+ to?: number;
70
+ /** Required only when caller holds the admin read key; ignored otherwise. */
71
+ tenantId?: string;
72
+ }): Promise<CompletenessResult>;
48
73
  listDecisions(opts: {
49
74
  from?: string;
50
75
  to?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,MAAM,CAAC,EAAE,MAAM;aACf,IAAI,CAAC,EAAE,MAAM;gBAF7B,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,cAAc,CAAC;IAChC,SAAS,EAAE,cAAc,CAAC;CAC3B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,MAAM,EAAE,YAAY;IAQ1B,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAwBzF,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmB3D,aAAa,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA2BpF;;;OAGG;YACW,cAAc;CA0B7B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,MAAM,CAAC,EAAE,MAAM;aACf,IAAI,CAAC,EAAE,MAAM;gBAF7B,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,2GAA2G;IAC3G,kBAAkB,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,cAAc,EAAE,cAAc,CAAC;IAC/B,uEAAuE;IACvE,eAAe,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,MAAM,EAAE,YAAY;IAQ1B,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAwBzF,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmB3D,kBAAkB,CAAC,IAAI,GAAE;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,6EAA6E;QAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAuB9B,aAAa,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA2BpF;;;OAGG;YACW,cAAc;CA0B7B"}
package/dist/client.js CHANGED
@@ -62,6 +62,27 @@ export class AuditLedgerClient {
62
62
  }
63
63
  return (await res.json());
64
64
  }
65
+ async verifyCompleteness(opts = {}) {
66
+ if (!this.readKey) {
67
+ throw new AuditLedgerError("AUDIT_READ_KEY is not set — verify_completeness unavailable");
68
+ }
69
+ const params = new URLSearchParams();
70
+ if (typeof opts.from === "number")
71
+ params.set("from", String(opts.from));
72
+ if (typeof opts.to === "number")
73
+ params.set("to", String(opts.to));
74
+ if (opts.tenantId)
75
+ params.set("tenant_id", opts.tenantId);
76
+ const url = `${this.apiUrl}/audit/verify-completeness${params.toString() ? `?${params}` : ""}`;
77
+ const res = await this.fetchWithRetry(url, {
78
+ method: "GET",
79
+ headers: { "Accept": "application/json", "x-api-key": this.readKey },
80
+ });
81
+ if (res.status !== 200) {
82
+ throw new AuditLedgerError(`verify_completeness failed: HTTP ${res.status}`, res.status, await safeText(res));
83
+ }
84
+ return (await res.json());
85
+ }
65
86
  async listDecisions(opts) {
66
87
  if (!this.readKey) {
67
88
  throw new AuditLedgerError("AUDIT_READ_KEY is not set — list_decisions unavailable");
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/hashing.d.ts CHANGED
@@ -1,8 +1,21 @@
1
1
  /**
2
- * SHA-256 helpersmirror the hashing behaviour of the Python and Node SDKs
3
- * shipped in the main audit-ledger repo. PII is hashed locally before any
4
- * payload leaves the MCP server, so raw personal data never reaches the
5
- * audit ledger API.
2
+ * Local hashingraw PII never leaves the MCP server's process.
3
+ *
4
+ * By default this module uses HMAC-SHA256 keyed off the AUDIT_HMAC_KEY
5
+ * environment variable. Keyed hashing makes the output non-reversible by
6
+ * anyone who does not hold the key, which is what regulators (ICO / EDPB)
7
+ * expect when you describe a value as pseudonymised rather than identifiable.
8
+ *
9
+ * Backwards-compatible fallback:
10
+ * If AUDIT_HMAC_KEY is not set, the functions fall back to plain SHA-256
11
+ * so existing MCP installs do not break. A one-time stderr warning is
12
+ * emitted on first use to nudge operators to upgrade. The default will
13
+ * flip in a future major version.
14
+ *
15
+ * The key is your tenant's secret. Generate once and store it where you
16
+ * already store AUDIT_WRITE_KEY (env var, .env file, secrets manager):
17
+ * node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
18
+ * The key never leaves your environment and never reaches the ledger API.
6
19
  */
7
20
  /** SHA-256 hex digest of a UTF-8 string. Lowercased, 64 chars. */
8
21
  export declare function sha256(input: string): string;
@@ -11,6 +24,8 @@ export declare function sha256(input: string): string;
11
24
  * formatting-only changes do not produce a different hash — this matches
12
25
  * the behaviour of the SDKs in the main repo and keeps prompt-version
13
26
  * tracking stable across minor edits.
27
+ *
28
+ * Uses HMAC-SHA256 when AUDIT_HMAC_KEY is set, plain SHA-256 otherwise.
14
29
  */
15
30
  export declare function hashPrompt(rawPrompt: string): string;
16
31
  /**
@@ -18,6 +33,14 @@ export declare function hashPrompt(rawPrompt: string): string;
18
33
  * before sending. No normalisation — the input is hashed verbatim so any
19
34
  * change in the input produces a different hash, which is the right
20
35
  * behaviour for an audit trail of model inputs.
36
+ *
37
+ * Uses HMAC-SHA256 when AUDIT_HMAC_KEY is set, plain SHA-256 otherwise.
21
38
  */
22
39
  export declare function hashPii(rawInput: string): string;
40
+ /**
41
+ * Test-only hook. Resets the one-time warned flag so unit tests can assert
42
+ * the warning fires exactly once per process. Not part of the public API.
43
+ * @internal
44
+ */
45
+ export declare function _resetFallbackWarnedForTests(): void;
23
46
  //# sourceMappingURL=hashing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hashing.d.ts","sourceRoot":"","sources":["../src/hashing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhD"}
1
+ {"version":3,"file":"hashing.d.ts","sourceRoot":"","sources":["../src/hashing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA0BH,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}
package/dist/hashing.js CHANGED
@@ -1,10 +1,41 @@
1
1
  /**
2
- * SHA-256 helpersmirror the hashing behaviour of the Python and Node SDKs
3
- * shipped in the main audit-ledger repo. PII is hashed locally before any
4
- * payload leaves the MCP server, so raw personal data never reaches the
5
- * audit ledger API.
2
+ * Local hashingraw PII never leaves the MCP server's process.
3
+ *
4
+ * By default this module uses HMAC-SHA256 keyed off the AUDIT_HMAC_KEY
5
+ * environment variable. Keyed hashing makes the output non-reversible by
6
+ * anyone who does not hold the key, which is what regulators (ICO / EDPB)
7
+ * expect when you describe a value as pseudonymised rather than identifiable.
8
+ *
9
+ * Backwards-compatible fallback:
10
+ * If AUDIT_HMAC_KEY is not set, the functions fall back to plain SHA-256
11
+ * so existing MCP installs do not break. A one-time stderr warning is
12
+ * emitted on first use to nudge operators to upgrade. The default will
13
+ * flip in a future major version.
14
+ *
15
+ * The key is your tenant's secret. Generate once and store it where you
16
+ * already store AUDIT_WRITE_KEY (env var, .env file, secrets manager):
17
+ * node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
18
+ * The key never leaves your environment and never reaches the ledger API.
6
19
  */
7
- import { createHash } from "node:crypto";
20
+ import { createHash, createHmac } from "node:crypto";
21
+ let _fallbackWarned = false;
22
+ function getKey() {
23
+ const raw = (process.env.AUDIT_HMAC_KEY ?? "").trim();
24
+ return raw.length > 0 ? raw : null;
25
+ }
26
+ function warnFallbackOnce() {
27
+ if (_fallbackWarned)
28
+ return;
29
+ _fallbackWarned = true;
30
+ // stderr, not stdout — stdout is the MCP protocol channel and any extra
31
+ // bytes there will break the client. console.warn goes to stderr in Node.
32
+ console.warn("[audit-ledger-mcp] AUDIT_HMAC_KEY is not set; falling back to plain " +
33
+ "SHA-256 for PII hashing. Plain SHA-256 of low-entropy values (names, " +
34
+ "emails) is brute-forceable and should not be treated as anonymisation " +
35
+ "under ICO/EDPB guidance. Set AUDIT_HMAC_KEY to a 32+ byte secret to " +
36
+ "switch to keyed HMAC-SHA256. This fallback will be removed in a " +
37
+ "future major version.");
38
+ }
8
39
  /** SHA-256 hex digest of a UTF-8 string. Lowercased, 64 chars. */
9
40
  export function sha256(input) {
10
41
  return createHash("sha256").update(input, "utf8").digest("hex");
@@ -14,18 +45,40 @@ export function sha256(input) {
14
45
  * formatting-only changes do not produce a different hash — this matches
15
46
  * the behaviour of the SDKs in the main repo and keeps prompt-version
16
47
  * tracking stable across minor edits.
48
+ *
49
+ * Uses HMAC-SHA256 when AUDIT_HMAC_KEY is set, plain SHA-256 otherwise.
17
50
  */
18
51
  export function hashPrompt(rawPrompt) {
19
52
  const normalised = rawPrompt.replace(/\s+/g, " ").trim();
20
- return sha256(normalised);
53
+ const key = getKey();
54
+ if (key === null) {
55
+ warnFallbackOnce();
56
+ return createHash("sha256").update(normalised, "utf8").digest("hex");
57
+ }
58
+ return createHmac("sha256", key).update(normalised, "utf8").digest("hex");
21
59
  }
22
60
  /**
23
61
  * Hash raw user input (e.g. a CV, a transaction payload, a customer record)
24
62
  * before sending. No normalisation — the input is hashed verbatim so any
25
63
  * change in the input produces a different hash, which is the right
26
64
  * behaviour for an audit trail of model inputs.
65
+ *
66
+ * Uses HMAC-SHA256 when AUDIT_HMAC_KEY is set, plain SHA-256 otherwise.
27
67
  */
28
68
  export function hashPii(rawInput) {
29
- return sha256(rawInput);
69
+ const key = getKey();
70
+ if (key === null) {
71
+ warnFallbackOnce();
72
+ return createHash("sha256").update(rawInput, "utf8").digest("hex");
73
+ }
74
+ return createHmac("sha256", key).update(rawInput, "utf8").digest("hex");
75
+ }
76
+ /**
77
+ * Test-only hook. Resets the one-time warned flag so unit tests can assert
78
+ * the warning fires exactly once per process. Not part of the public API.
79
+ * @internal
80
+ */
81
+ export function _resetFallbackWarnedForTests() {
82
+ _fallbackWarned = false;
30
83
  }
31
84
  //# sourceMappingURL=hashing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hashing.js","sourceRoot":"","sources":["../src/hashing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,kEAAkE;AAClE,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"hashing.js","sourceRoot":"","sources":["../src/hashing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,SAAS,MAAM;IACb,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,SAAS,gBAAgB;IACvB,IAAI,eAAe;QAAE,OAAO;IAC5B,eAAe,GAAG,IAAI,CAAC;IACvB,wEAAwE;IACxE,0EAA0E;IAC1E,OAAO,CAAC,IAAI,CACV,sEAAsE;QACpE,uEAAuE;QACvE,wEAAwE;QACxE,sEAAsE;QACtE,kEAAkE;QAClE,uBAAuB,CAC1B,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,gBAAgB,EAAE,CAAC;QACnB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,gBAAgB,EAAE,CAAC;QACnB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B;IAC1C,eAAe,GAAG,KAAK,CAAC;AAC1B,CAAC"}
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import { AuditLedgerClient, AuditLedgerError } from "./client.js";
20
20
  import { SANDBOX_CONFIG, isSandboxMode, sandboxBanner } from "./sandbox.js";
21
21
  import { executeRecordDecision, recordDecisionToolDefinition, } from "./tools/record_decision.js";
22
22
  import { executeVerifyDecision, verifyDecisionToolDefinition, } from "./tools/verify_decision.js";
23
+ import { executeVerifyCompleteness, verifyCompletenessToolDefinition, } from "./tools/verify_completeness.js";
23
24
  import { executeListDecisions, listDecisionsToolDefinition, } from "./tools/list_decisions.js";
24
25
  // Read package.json at startup so PKG_NAME and PKG_VERSION cannot drift from
25
26
  // the published package version. dist/index.js lives one level below the
@@ -66,6 +67,7 @@ async function main() {
66
67
  tools: [
67
68
  recordDecisionToolDefinition,
68
69
  verifyDecisionToolDefinition,
70
+ verifyCompletenessToolDefinition,
69
71
  listDecisionsToolDefinition,
70
72
  ],
71
73
  }));
@@ -80,6 +82,9 @@ async function main() {
80
82
  case "verify_decision":
81
83
  result = await executeVerifyDecision(client, args);
82
84
  break;
85
+ case "verify_completeness":
86
+ result = await executeVerifyCompleteness(client, args);
87
+ break;
83
88
  case "list_decisions":
84
89
  result = await executeListDecisions(client, args);
85
90
  break;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * verify_completeness tool — detect missing audit records.
3
+ *
4
+ * Sister tool to verify_decision. verify_decision proves a record that exists
5
+ * matches its S3 copy (tampering check). verify_completeness proves no
6
+ * records have been deleted by comparing the tenant's monotonic sequence
7
+ * counter against the rows actually present in DynamoDB. A gap in the
8
+ * returned `missing` array represents a record that was deleted, lost during
9
+ * SQS redelivery, or otherwise never stored — combine with the processor's
10
+ * burned_sequence log entries to tell those apart.
11
+ */
12
+ import { z } from "zod";
13
+ import type { AuditLedgerClient, CompletenessResult } from "../client.js";
14
+ export declare const verifyCompletenessInputSchema: z.ZodObject<{
15
+ from: z.ZodOptional<z.ZodNumber>;
16
+ to: z.ZodOptional<z.ZodNumber>;
17
+ tenant_id: z.ZodOptional<z.ZodString>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ tenant_id?: string | undefined;
20
+ from?: number | undefined;
21
+ to?: number | undefined;
22
+ }, {
23
+ tenant_id?: string | undefined;
24
+ from?: number | undefined;
25
+ to?: number | undefined;
26
+ }>;
27
+ export type VerifyCompletenessInput = z.infer<typeof verifyCompletenessInputSchema>;
28
+ export declare const verifyCompletenessToolDefinition: {
29
+ readonly name: "verify_completeness";
30
+ readonly description: "Detect whether any audit records have been deleted or omitted for the caller's tenant. Each successfully stored decision receives a per-tenant monotonic sequence number. This tool compares the ledger's counter against the rows actually present in DynamoDB and returns any sequence numbers that are missing. Use this when a regulator or compliance team asks 'can you prove the log is complete?' — verify_decision only proves an existing record was not altered; this proves no record has disappeared.";
31
+ readonly inputSchema: {
32
+ readonly type: "object";
33
+ readonly properties: {
34
+ readonly from: {
35
+ readonly type: "integer";
36
+ readonly minimum: 1;
37
+ readonly description: string | undefined;
38
+ };
39
+ readonly to: {
40
+ readonly type: "integer";
41
+ readonly minimum: 1;
42
+ readonly description: string | undefined;
43
+ };
44
+ readonly tenant_id: {
45
+ readonly type: "string";
46
+ readonly description: string | undefined;
47
+ };
48
+ };
49
+ };
50
+ };
51
+ export declare function executeVerifyCompleteness(client: AuditLedgerClient, rawInput: unknown): Promise<CompletenessResult>;
52
+ //# sourceMappingURL=verify_completeness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify_completeness.d.ts","sourceRoot":"","sources":["../../src/tools/verify_completeness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE1E,eAAO,MAAM,6BAA6B;;;;;;;;;;;;EAqBxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;CAuBnC,CAAC;AAEX,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAO7B"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * verify_completeness tool — detect missing audit records.
3
+ *
4
+ * Sister tool to verify_decision. verify_decision proves a record that exists
5
+ * matches its S3 copy (tampering check). verify_completeness proves no
6
+ * records have been deleted by comparing the tenant's monotonic sequence
7
+ * counter against the rows actually present in DynamoDB. A gap in the
8
+ * returned `missing` array represents a record that was deleted, lost during
9
+ * SQS redelivery, or otherwise never stored — combine with the processor's
10
+ * burned_sequence log entries to tell those apart.
11
+ */
12
+ import { z } from "zod";
13
+ export const verifyCompletenessInputSchema = z.object({
14
+ from: z
15
+ .number()
16
+ .int()
17
+ .min(1)
18
+ .optional()
19
+ .describe("Inclusive lower bound on sequence_no. Defaults to 1."),
20
+ to: z
21
+ .number()
22
+ .int()
23
+ .min(1)
24
+ .optional()
25
+ .describe("Inclusive upper bound on sequence_no. Defaults to the tenant's current counter value."),
26
+ tenant_id: z
27
+ .string()
28
+ .optional()
29
+ .describe("Required only when calling with the admin read key. Ignored when called with a regular tenant read key — the tenant is inferred from the key."),
30
+ });
31
+ export const verifyCompletenessToolDefinition = {
32
+ name: "verify_completeness",
33
+ description: "Detect whether any audit records have been deleted or omitted for the caller's tenant. Each successfully stored decision receives a per-tenant monotonic sequence number. This tool compares the ledger's counter against the rows actually present in DynamoDB and returns any sequence numbers that are missing. Use this when a regulator or compliance team asks 'can you prove the log is complete?' — verify_decision only proves an existing record was not altered; this proves no record has disappeared.",
34
+ inputSchema: {
35
+ type: "object",
36
+ properties: {
37
+ from: {
38
+ type: "integer",
39
+ minimum: 1,
40
+ description: verifyCompletenessInputSchema.shape.from.description,
41
+ },
42
+ to: {
43
+ type: "integer",
44
+ minimum: 1,
45
+ description: verifyCompletenessInputSchema.shape.to.description,
46
+ },
47
+ tenant_id: {
48
+ type: "string",
49
+ description: verifyCompletenessInputSchema.shape.tenant_id.description,
50
+ },
51
+ },
52
+ },
53
+ };
54
+ export async function executeVerifyCompleteness(client, rawInput) {
55
+ const input = verifyCompletenessInputSchema.parse(rawInput ?? {});
56
+ return client.verifyCompleteness({
57
+ from: input.from,
58
+ to: input.to,
59
+ tenantId: input.tenant_id,
60
+ });
61
+ }
62
+ //# sourceMappingURL=verify_completeness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify_completeness.js","sourceRoot":"","sources":["../../src/tools/verify_completeness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC;IACpD,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CAAC,sDAAsD,CAAC;IACnE,EAAE,EAAE,CAAC;SACF,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CACP,uFAAuF,CACxF;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,+IAA+I,CAChJ;CACJ,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACT,ofAAof;IACtf,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,WAAW,EAAE,6BAA6B,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW;aAClE;YACD,EAAE,EAAE;gBACF,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,WAAW,EAAE,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW;aAChE;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,6BAA6B,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW;aACvE;SACF;KACF;CACO,CAAC;AAEX,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAyB,EACzB,QAAiB;IAEjB,MAAM,KAAK,GAAG,6BAA6B,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,kBAAkB,CAAC;QAC/B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,QAAQ,EAAE,KAAK,CAAC,SAAS;KAC1B,CAAC,CAAC;AACL,CAAC"}
@@ -32,8 +32,8 @@ export declare const verifyDecisionToolDefinition: {
32
32
  export declare function executeVerifyDecision(client: AuditLedgerClient, rawInput: unknown): Promise<{
33
33
  event_id: string;
34
34
  integrity_verified: boolean;
35
- note: string;
36
- dynamodb_record: unknown;
37
- s3_record: unknown;
35
+ integrity_note: string;
36
+ current_record: unknown;
37
+ archived_record: unknown;
38
38
  }>;
39
39
  //# sourceMappingURL=verify_decision.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify_decision.d.ts","sourceRoot":"","sources":["../../src/tools/verify_decision.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,eAAO,MAAM,yBAAyB;;;;;;EAKpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;CAW/B,CAAC;AAEX,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC,CAUD"}
1
+ {"version":3,"file":"verify_decision.d.ts","sourceRoot":"","sources":["../../src/tools/verify_decision.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,eAAO,MAAM,yBAAyB;;;;;;EAKpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;CAW/B,CAAC;AAEX,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC,CAUD"}
@@ -28,9 +28,9 @@ export async function executeVerifyDecision(client, rawInput) {
28
28
  return {
29
29
  event_id: input.event_id,
30
30
  integrity_verified: result.integrity_verified,
31
- note: result.note,
32
- dynamodb_record: result.dynamodb_record,
33
- s3_record: result.s3_record,
31
+ integrity_note: result.integrity_note,
32
+ current_record: result.current_record,
33
+ archived_record: result.archived_record,
34
34
  };
35
35
  }
36
36
  //# sourceMappingURL=verify_decision.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify_decision.js","sourceRoot":"","sources":["../../src/tools/verify_decision.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,IAAI,EAAE;SACN,QAAQ,CAAC,iDAAiD,CAAC;CAC/D,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,4VAA4V;IAC9V,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,yBAAyB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE;SAChH;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACvB;CACO,CAAC;AAEX,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAyB,EACzB,QAAiB;IAQjB,MAAM,KAAK,GAAG,yBAAyB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3D,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"verify_decision.js","sourceRoot":"","sources":["../../src/tools/verify_decision.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,IAAI,EAAE;SACN,QAAQ,CAAC,iDAAiD,CAAC;CAC/D,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,4VAA4V;IAC9V,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,yBAAyB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE;SAChH;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACvB;CACO,CAAC;AAEX,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAyB,EACzB,QAAiB;IAQjB,MAAM,KAAK,GAAG,yBAAyB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3D,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "audit-ledger-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "MCP server for AI Audit Ledger — record AI decisions to a tamper-evident ledger from any agent (Claude, Cursor, LangGraph, custom).",
5
5
  "mcpName": "io.github.shahidh68/audit-ledger-mcp",
6
6
  "type": "module",