@sheafhq/mcp-recorder 0.0.0-stage → 0.1.0
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 +101 -2
- package/dist/canonical.js +40 -0
- package/dist/canonical.js.map +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/envelope.js +138 -0
- package/dist/envelope.js.map +1 -0
- package/dist/proxy.js +97 -0
- package/dist/proxy.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -4
package/README.md
CHANGED
|
@@ -1,3 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @sheafhq/mcp-recorder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Transparent MCP (Model Context Protocol) proxy that captures every tool call an agent makes and emits signed, hash-chained, on-chain-anchored receipts to the [Sheaf](https://github.com/sheafhq/sheaf) recorder.
|
|
4
|
+
|
|
5
|
+
**Zero-code install.** Wrap any existing MCP server in Claude Desktop (or any MCP-aware client) with a one-line config change. No modifications to the wrapped server. No modifications to the agent.
|
|
6
|
+
|
|
7
|
+
Receipts are verifiable offline by any third party using [`@sheafhq/verify`](https://www.npmjs.com/package/@sheafhq/verify).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @sheafhq/mcp-recorder
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Claude Desktop setup
|
|
16
|
+
|
|
17
|
+
Edit `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/`; Windows: `%APPDATA%\Claude\`). Wrap the servers you want to audit:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"filesystem": {
|
|
23
|
+
"command": "sheaf-mcp-recorder",
|
|
24
|
+
"args": [
|
|
25
|
+
"--wrap",
|
|
26
|
+
"npx",
|
|
27
|
+
"-y",
|
|
28
|
+
"@modelcontextprotocol/server-filesystem",
|
|
29
|
+
"/Users/me/Documents"
|
|
30
|
+
],
|
|
31
|
+
"env": {
|
|
32
|
+
"SHEAF_CHAIN_ID": "claude-me-filesystem",
|
|
33
|
+
"SHEAF_ACTOR": "claude-desktop-me"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Restart Claude Desktop. Every `tools/call`, `resources/read`, and `sampling/createMessage` through this server now flows through Sheaf and gets a signed, chained receipt — with the tool arguments and the response hashed (never sent raw).
|
|
41
|
+
|
|
42
|
+
## How it works
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Claude (MCP client)
|
|
46
|
+
│ JSON-RPC over stdio
|
|
47
|
+
▼
|
|
48
|
+
┌──────────────────────────┐
|
|
49
|
+
│ sheaf-mcp-recorder │ ← this package. Transparent stdio proxy.
|
|
50
|
+
│ (zero-code wrapper) │
|
|
51
|
+
└───────────┬──────────────┘
|
|
52
|
+
│ JSON-RPC unchanged
|
|
53
|
+
▼
|
|
54
|
+
┌──────────────────────────┐
|
|
55
|
+
│ wrapped MCP server │ (filesystem, github, slack, …)
|
|
56
|
+
└───────────┬──────────────┘
|
|
57
|
+
│ JSON-RPC response
|
|
58
|
+
▼
|
|
59
|
+
(tap: build envelope, POST to Sheaf recorder)
|
|
60
|
+
│
|
|
61
|
+
▼
|
|
62
|
+
┌──────────────────────────┐
|
|
63
|
+
│ Sheaf recorder │ signs + chains + persists
|
|
64
|
+
│ sheaf-recorder.*.dev │ (anchored on-chain by Sheaf)
|
|
65
|
+
└──────────────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Fail-open design: if the recorder is unreachable, the agent's tool calls still work. Missed events are logged to stderr; the chain re-syncs on the next successful submission.
|
|
69
|
+
|
|
70
|
+
## Environment variables
|
|
71
|
+
|
|
72
|
+
| Var | Required | Default | Notes |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| `SHEAF_CHAIN_ID` | **yes** | — | Stable identifier for this agent/session's event chain |
|
|
75
|
+
| `SHEAF_ACTOR` | no | = `SHEAF_CHAIN_ID` | Written into every event's `actor` field |
|
|
76
|
+
| `SHEAF_RECORDER_URL` | no | `https://sheaf-recorder.goldencalf.workers.dev` | Point at your own instance if self-hosting |
|
|
77
|
+
| `SHEAF_CAPTURE_METHODS` | no | `tools/call,resources/read,sampling/createMessage` | Comma-separated JSON-RPC methods to intercept |
|
|
78
|
+
| `SHEAF_DEBUG` | no | — | `1` to log every event to stderr |
|
|
79
|
+
|
|
80
|
+
## What gets recorded
|
|
81
|
+
|
|
82
|
+
For every intercepted tool call, one hash-chained event containing:
|
|
83
|
+
|
|
84
|
+
- **intent** — short description (e.g. `invoke tool write_file`)
|
|
85
|
+
- **actor** — from `SHEAF_ACTOR`
|
|
86
|
+
- **tool** — e.g. `mcp://tool/write_file`
|
|
87
|
+
- **inputs_hash** — `sha256(canonicalize(params))` of the tool arguments (raw args are **not** sent to the recorder)
|
|
88
|
+
- **outputs_hash** — same for the response, or null on error
|
|
89
|
+
- **result** — `ok` / `error` / `timeout` / `cancelled`
|
|
90
|
+
- **ts** — ISO 8601 UTC timestamp
|
|
91
|
+
|
|
92
|
+
The envelope is hash-chained (`prev_hash` → previous envelope hash) so any tamper is detectable. The recorder co-signs with Ed25519 and anchors the Merkle root on Base L2 periodically.
|
|
93
|
+
|
|
94
|
+
## Verifying a receipt later
|
|
95
|
+
|
|
96
|
+
Any third party can verify a stored receipt using `@sheafhq/verify` — it reads the anchor transaction from Base and checks the Merkle inclusion + Ed25519 signature offline.
|
|
97
|
+
|
|
98
|
+
See the main [Sheaf ARCHITECTURE.md](https://github.com/sheafhq/sheaf/blob/main/ARCHITECTURE.md) for the full protocol.
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// RFC 8785 JCS — identical to packages/verify/src/canonical.ts.
|
|
2
|
+
export function canonicalize(value) {
|
|
3
|
+
if (value === null)
|
|
4
|
+
return "null";
|
|
5
|
+
if (typeof value === "boolean")
|
|
6
|
+
return value ? "true" : "false";
|
|
7
|
+
if (typeof value === "number") {
|
|
8
|
+
if (!Number.isFinite(value))
|
|
9
|
+
throw new Error("JCS: non-finite number");
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === "string")
|
|
13
|
+
return JSON.stringify(value);
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return "[" + value.map(canonicalize).join(",") + "]";
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "object") {
|
|
18
|
+
const obj = value;
|
|
19
|
+
const keys = Object.keys(obj).sort();
|
|
20
|
+
return ("{" +
|
|
21
|
+
keys
|
|
22
|
+
.map((k) => JSON.stringify(k) + ":" + canonicalize(obj[k]))
|
|
23
|
+
.join(",") +
|
|
24
|
+
"}");
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`JCS: unsupported value type: ${typeof value}`);
|
|
27
|
+
}
|
|
28
|
+
import { createHash } from "node:crypto";
|
|
29
|
+
export function sha256Hex(data) {
|
|
30
|
+
const h = createHash("sha256");
|
|
31
|
+
if (typeof data === "string")
|
|
32
|
+
h.update(data, "utf8");
|
|
33
|
+
else
|
|
34
|
+
h.update(data);
|
|
35
|
+
return h.digest("hex");
|
|
36
|
+
}
|
|
37
|
+
export function hashCanonical(value) {
|
|
38
|
+
return sha256Hex(canonicalize(value));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,OAAO,CACL,GAAG;YACH,IAAI;iBACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC1D,IAAI,CAAC,GAAG,CAAC;YACZ,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,KAAK,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,SAAS,CAAC,IAAkC;IAC1D,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;;QAChD,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpB,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// CLI entry for sheaf-mcp-recorder. Usage:
|
|
3
|
+
// sheaf-mcp-recorder --wrap <command> [args...]
|
|
4
|
+
//
|
|
5
|
+
// Environment variables:
|
|
6
|
+
// SHEAF_RECORDER_URL where to POST events (default: production)
|
|
7
|
+
// SHEAF_CHAIN_ID required. Stable per-session / per-agent identifier.
|
|
8
|
+
// SHEAF_ACTOR default: SHEAF_CHAIN_ID
|
|
9
|
+
// SHEAF_CAPTURE_METHODS comma-separated JSON-RPC methods to capture
|
|
10
|
+
// (default: tools/call,resources/read,sampling/createMessage)
|
|
11
|
+
// SHEAF_DEBUG=1 verbose stderr logging
|
|
12
|
+
import { runProxy } from "./proxy.js";
|
|
13
|
+
const argv = process.argv.slice(2);
|
|
14
|
+
function die(msg, code = 2) {
|
|
15
|
+
console.error(`sheaf-mcp-recorder: ${msg}`);
|
|
16
|
+
console.error("usage: sheaf-mcp-recorder --wrap <command> [args...]\n" +
|
|
17
|
+
" (set SHEAF_CHAIN_ID; see package README for all env vars)");
|
|
18
|
+
process.exit(code);
|
|
19
|
+
}
|
|
20
|
+
const wrapIdx = argv.indexOf("--wrap");
|
|
21
|
+
if (wrapIdx === -1)
|
|
22
|
+
die("missing --wrap flag");
|
|
23
|
+
if (wrapIdx === argv.length - 1)
|
|
24
|
+
die("no command after --wrap");
|
|
25
|
+
const command = argv[wrapIdx + 1];
|
|
26
|
+
const commandArgs = argv.slice(wrapIdx + 2);
|
|
27
|
+
const chainId = process.env.SHEAF_CHAIN_ID;
|
|
28
|
+
if (!chainId)
|
|
29
|
+
die("SHEAF_CHAIN_ID env var is required");
|
|
30
|
+
const cfg = {
|
|
31
|
+
recorderUrl: process.env.SHEAF_RECORDER_URL ??
|
|
32
|
+
"https://sheaf-recorder.goldencalf.workers.dev",
|
|
33
|
+
chainId,
|
|
34
|
+
actor: process.env.SHEAF_ACTOR ?? chainId,
|
|
35
|
+
captureMethods: new Set((process.env.SHEAF_CAPTURE_METHODS ??
|
|
36
|
+
"tools/call,resources/read,sampling/createMessage")
|
|
37
|
+
.split(",")
|
|
38
|
+
.map((s) => s.trim())
|
|
39
|
+
.filter(Boolean)),
|
|
40
|
+
logDebug: process.env.SHEAF_DEBUG === "1",
|
|
41
|
+
};
|
|
42
|
+
if (cfg.logDebug) {
|
|
43
|
+
console.error(`[arca] wrapping: ${command} ${commandArgs.join(" ")}`);
|
|
44
|
+
console.error(`[arca] recorder=${cfg.recorderUrl} chain=${cfg.chainId} actor=${cfg.actor} capture=[${[...cfg.captureMethods].join(",")}]`);
|
|
45
|
+
}
|
|
46
|
+
runProxy(cfg, command, commandArgs);
|
|
47
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,2CAA2C;AAC3C,kDAAkD;AAClD,EAAE;AACF,yBAAyB;AACzB,oEAAoE;AACpE,8EAA8E;AAC9E,iDAAiD;AACjD,uEAAuE;AACvE,oFAAoF;AACpF,gDAAgD;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,SAAS,GAAG,CAAC,GAAW,EAAE,IAAI,GAAG,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,KAAK,CACX,wDAAwD;QACtD,kEAAkE,CACrE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AACvC,IAAI,OAAO,KAAK,CAAC,CAAC;IAAE,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAC/C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC;IAAE,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAEhE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAE,CAAC;AACnC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;AAE5C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAC3C,IAAI,CAAC,OAAO;IAAE,GAAG,CAAC,oCAAoC,CAAC,CAAC;AAExD,MAAM,GAAG,GAAmB;IAC1B,WAAW,EACT,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAC9B,+CAA+C;IACjD,OAAO;IACP,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO;IACzC,cAAc,EAAE,IAAI,GAAG,CACrB,CACE,OAAO,CAAC,GAAG,CAAC,qBAAqB;QACjC,kDAAkD,CACnD;SACE,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB;IACD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG;CAC1C,CAAC;AAEF,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;IACjB,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,KAAK,CACX,mBAAmB,GAAG,CAAC,WAAW,UAAU,GAAG,CAAC,OAAO,UAAU,GAAG,CAAC,KAAK,aAAa,CAAC,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAC5H,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC"}
|
package/dist/envelope.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Build an event envelope + submit to the Sheaf recorder. Submission is a
|
|
2
|
+
// background best-effort operation: it must never block the MCP proxy pipeline,
|
|
3
|
+
// and a recorder outage must not break the agent's tool calls.
|
|
4
|
+
import { canonicalize, sha256Hex } from "./canonical.js";
|
|
5
|
+
export class RecorderClient {
|
|
6
|
+
cfg;
|
|
7
|
+
state;
|
|
8
|
+
queue = Promise.resolve();
|
|
9
|
+
constructor(cfg) {
|
|
10
|
+
this.cfg = cfg;
|
|
11
|
+
this.state = this.fetchInitialState();
|
|
12
|
+
}
|
|
13
|
+
debug(...args) {
|
|
14
|
+
if (this.cfg.logDebug)
|
|
15
|
+
console.error("[arca]", ...args);
|
|
16
|
+
}
|
|
17
|
+
async fetchInitialState() {
|
|
18
|
+
try {
|
|
19
|
+
const url = `${this.cfg.recorderUrl}/chains/${encodeURIComponent(this.cfg.chainId)}/head`;
|
|
20
|
+
const r = await fetch(url);
|
|
21
|
+
if (r.status === 404) {
|
|
22
|
+
this.debug(`chain ${this.cfg.chainId} is new; starting at seq=0`);
|
|
23
|
+
return { seq: 0, prev_hash: null };
|
|
24
|
+
}
|
|
25
|
+
if (!r.ok) {
|
|
26
|
+
this.debug(`recorder /head returned ${r.status}; assuming new chain`);
|
|
27
|
+
return { seq: 0, prev_hash: null };
|
|
28
|
+
}
|
|
29
|
+
const body = (await r.json());
|
|
30
|
+
this.debug(`chain ${this.cfg.chainId} head is seq=${body.head_seq}; resuming at seq=${body.head_seq + 1}`);
|
|
31
|
+
return { seq: body.head_seq + 1, prev_hash: body.head_hash };
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
this.debug(`could not reach recorder for initial head (${err.message}); starting at seq=0`);
|
|
35
|
+
return { seq: 0, prev_hash: null };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Queue an event submission. Returns immediately; does not block the caller. */
|
|
39
|
+
submit(call, response) {
|
|
40
|
+
this.queue = this.queue.then(() => this.submitInternal(call, response));
|
|
41
|
+
}
|
|
42
|
+
/** Wait for all queued submissions to finish. Call before process exit. */
|
|
43
|
+
async drain() {
|
|
44
|
+
await this.queue;
|
|
45
|
+
}
|
|
46
|
+
async submitInternal(call, response) {
|
|
47
|
+
try {
|
|
48
|
+
const state = await this.state;
|
|
49
|
+
let result = "ok";
|
|
50
|
+
let outputsHash = null;
|
|
51
|
+
if (!response)
|
|
52
|
+
result = "timeout";
|
|
53
|
+
else if (response.error)
|
|
54
|
+
result = "error";
|
|
55
|
+
else if (response.result !== undefined)
|
|
56
|
+
outputsHash = "sha256:" + sha256Hex(canonicalize(response.result));
|
|
57
|
+
const inputsHash = "sha256:" + sha256Hex(canonicalize(call.params));
|
|
58
|
+
const envelope = {
|
|
59
|
+
v: "arca/1",
|
|
60
|
+
event: {
|
|
61
|
+
intent: deriveIntent(call),
|
|
62
|
+
actor: this.cfg.actor,
|
|
63
|
+
authority: null,
|
|
64
|
+
tool: deriveToolName(call),
|
|
65
|
+
inputs_hash: inputsHash,
|
|
66
|
+
outputs_hash: outputsHash,
|
|
67
|
+
result,
|
|
68
|
+
ts: new Date().toISOString(),
|
|
69
|
+
},
|
|
70
|
+
chain: {
|
|
71
|
+
chain_id: this.cfg.chainId,
|
|
72
|
+
seq: state.seq,
|
|
73
|
+
prev_hash: state.prev_hash,
|
|
74
|
+
},
|
|
75
|
+
signatures: { actor: null },
|
|
76
|
+
};
|
|
77
|
+
const body = canonicalize(envelope);
|
|
78
|
+
const r = await fetch(`${this.cfg.recorderUrl}/events`, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: { "content-type": "application/json" },
|
|
81
|
+
body,
|
|
82
|
+
});
|
|
83
|
+
const receipt = (await r.json());
|
|
84
|
+
if (r.status === 201 && receipt.ok && typeof receipt.seq === "number") {
|
|
85
|
+
this.state = Promise.resolve({
|
|
86
|
+
seq: receipt.seq + 1,
|
|
87
|
+
prev_hash: receipt.envelope_hash ?? state.prev_hash,
|
|
88
|
+
});
|
|
89
|
+
this.debug(`recorded seq=${receipt.seq} for ${envelope.event.tool} → ${envelope.event.result}`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// 409 with head info means our local state drifted. Re-sync and give up
|
|
93
|
+
// this one submission (the proxy will keep working; recorder stays
|
|
94
|
+
// consistent).
|
|
95
|
+
if (r.status === 409 &&
|
|
96
|
+
typeof receipt.current_head_seq === "number" &&
|
|
97
|
+
typeof receipt.current_head_hash === "string") {
|
|
98
|
+
this.state = Promise.resolve({
|
|
99
|
+
seq: receipt.current_head_seq + 1,
|
|
100
|
+
prev_hash: receipt.current_head_hash,
|
|
101
|
+
});
|
|
102
|
+
this.debug(`resynced after 409: new seq=${receipt.current_head_seq + 1} (missed this submission)`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.debug(`submission failed (${r.status}): ${receipt.error ?? "unknown"}; event dropped`);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
this.debug(`submit threw: ${err.message}; event dropped`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function deriveToolName(call) {
|
|
113
|
+
const p = call.params;
|
|
114
|
+
switch (call.method) {
|
|
115
|
+
case "tools/call":
|
|
116
|
+
return `mcp://tool/${p?.name ?? "unknown"}`;
|
|
117
|
+
case "resources/read":
|
|
118
|
+
return `mcp://resource/${p?.uri ?? "unknown"}`;
|
|
119
|
+
case "sampling/createMessage":
|
|
120
|
+
return `mcp://sampling/createMessage`;
|
|
121
|
+
default:
|
|
122
|
+
return `mcp://method/${call.method}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function deriveIntent(call) {
|
|
126
|
+
const p = call.params;
|
|
127
|
+
switch (call.method) {
|
|
128
|
+
case "tools/call":
|
|
129
|
+
return `invoke tool ${p?.name ?? "unknown"}`;
|
|
130
|
+
case "resources/read":
|
|
131
|
+
return `read resource ${p?.uri ?? "unknown"}`;
|
|
132
|
+
case "sampling/createMessage":
|
|
133
|
+
return `sample LLM completion`;
|
|
134
|
+
default:
|
|
135
|
+
return call.method;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Stdio-mode MCP proxy. Spawn the wrapped server, relay JSON-RPC traffic
|
|
2
|
+
// bidirectionally. Tap tools/call, resources/read, sampling/createMessage.
|
|
3
|
+
// Fail open — any error in the recorder path must NOT disrupt the agent's
|
|
4
|
+
// tool calls.
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { createInterface } from "node:readline";
|
|
7
|
+
import { RecorderClient } from "./envelope.js";
|
|
8
|
+
export function runProxy(cfg, childCmd, childArgs) {
|
|
9
|
+
const recorder = new RecorderClient(cfg);
|
|
10
|
+
const pending = new Map();
|
|
11
|
+
const child = spawn(childCmd, childArgs, {
|
|
12
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
13
|
+
env: process.env,
|
|
14
|
+
});
|
|
15
|
+
child.on("exit", (code, signal) => {
|
|
16
|
+
if (cfg.logDebug)
|
|
17
|
+
console.error(`[arca] wrapped child exited code=${code} signal=${signal}; draining recorder queue`);
|
|
18
|
+
recorder
|
|
19
|
+
.drain()
|
|
20
|
+
.catch((err) => {
|
|
21
|
+
if (cfg.logDebug)
|
|
22
|
+
console.error(`[arca] drain error: ${err.message}`);
|
|
23
|
+
})
|
|
24
|
+
.finally(() => {
|
|
25
|
+
process.exit(code ?? 0);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
child.on("error", (err) => {
|
|
29
|
+
console.error(`[arca] failed to spawn wrapped child: ${err.message}`);
|
|
30
|
+
process.exit(127);
|
|
31
|
+
});
|
|
32
|
+
// Parent stdin → child stdin. Also tap each line as an outgoing request.
|
|
33
|
+
const parentIn = createInterface({ input: process.stdin });
|
|
34
|
+
parentIn.on("line", (line) => {
|
|
35
|
+
if (!line.trim())
|
|
36
|
+
return;
|
|
37
|
+
try {
|
|
38
|
+
const msg = JSON.parse(line);
|
|
39
|
+
if (msg &&
|
|
40
|
+
typeof msg === "object" &&
|
|
41
|
+
"method" in msg &&
|
|
42
|
+
"id" in msg &&
|
|
43
|
+
cfg.captureMethods.has(msg.method)) {
|
|
44
|
+
pending.set(msg.id, {
|
|
45
|
+
id: msg.id,
|
|
46
|
+
method: msg.method,
|
|
47
|
+
params: msg.params ?? {},
|
|
48
|
+
startedAt: Date.now(),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Not valid JSON — just pass through.
|
|
54
|
+
}
|
|
55
|
+
child.stdin.write(line + "\n");
|
|
56
|
+
});
|
|
57
|
+
parentIn.on("close", () => {
|
|
58
|
+
try {
|
|
59
|
+
child.stdin.end();
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
});
|
|
63
|
+
// Child stdout → parent stdout. Tap responses that match a pending request.
|
|
64
|
+
const childOut = createInterface({ input: child.stdout });
|
|
65
|
+
childOut.on("line", (line) => {
|
|
66
|
+
if (!line.trim()) {
|
|
67
|
+
process.stdout.write(line + "\n");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const msg = JSON.parse(line);
|
|
72
|
+
if (msg &&
|
|
73
|
+
typeof msg === "object" &&
|
|
74
|
+
"id" in msg &&
|
|
75
|
+
(msg.id || msg.id === 0) &&
|
|
76
|
+
pending.has(msg.id)) {
|
|
77
|
+
const call = pending.get(msg.id);
|
|
78
|
+
pending.delete(msg.id);
|
|
79
|
+
recorder.submit(call, { result: msg.result, error: msg.error });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Not valid JSON — pass through.
|
|
84
|
+
}
|
|
85
|
+
process.stdout.write(line + "\n");
|
|
86
|
+
});
|
|
87
|
+
// Forward signals so Ctrl-C etc. kills the child cleanly.
|
|
88
|
+
for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
89
|
+
process.on(sig, () => {
|
|
90
|
+
try {
|
|
91
|
+
child.kill(sig);
|
|
92
|
+
}
|
|
93
|
+
catch { }
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sheafhq/mcp-recorder",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Transparent MCP (Model Context Protocol) proxy that captures every tool call an agent makes and emits signed, hash-chained, on-chain-anchored receipts via the Sheaf recorder. Zero-code install via claude_desktop_config.json.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"sheaf-mcp-recorder": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": ["dist", "README.md"],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"sheaf",
|
|
17
|
+
"mcp",
|
|
18
|
+
"mcp-server",
|
|
19
|
+
"audit",
|
|
20
|
+
"attestation",
|
|
21
|
+
"agent",
|
|
22
|
+
"claude",
|
|
23
|
+
"interceptor",
|
|
24
|
+
"proxy",
|
|
25
|
+
"receipt",
|
|
26
|
+
"hash-chain"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/sheafhq/sheaf.git",
|
|
32
|
+
"directory": "packages/mcp-recorder"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/sheafhq/sheaf/tree/main/packages/mcp-recorder",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/sheafhq/sheaf/issues"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"typescript": "^5.6.0",
|
|
43
|
+
"@types/node": "^22.0.0"
|
|
44
|
+
}
|
|
45
|
+
}
|