@mikeargento/bitgraph-mcp 0.1.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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/__tests__/encoding.test.d.ts +2 -0
  4. package/dist/__tests__/encoding.test.d.ts.map +1 -0
  5. package/dist/__tests__/encoding.test.js +51 -0
  6. package/dist/__tests__/encoding.test.js.map +1 -0
  7. package/dist/__tests__/format.test.d.ts +2 -0
  8. package/dist/__tests__/format.test.d.ts.map +1 -0
  9. package/dist/__tests__/format.test.js +59 -0
  10. package/dist/__tests__/format.test.js.map +1 -0
  11. package/dist/__tests__/tools.test.d.ts +2 -0
  12. package/dist/__tests__/tools.test.d.ts.map +1 -0
  13. package/dist/__tests__/tools.test.js +304 -0
  14. package/dist/__tests__/tools.test.js.map +1 -0
  15. package/dist/api.d.ts +54 -0
  16. package/dist/api.d.ts.map +1 -0
  17. package/dist/api.js +144 -0
  18. package/dist/api.js.map +1 -0
  19. package/dist/encoding.d.ts +19 -0
  20. package/dist/encoding.d.ts.map +1 -0
  21. package/dist/encoding.js +64 -0
  22. package/dist/encoding.js.map +1 -0
  23. package/dist/format.d.ts +44 -0
  24. package/dist/format.d.ts.map +1 -0
  25. package/dist/format.js +164 -0
  26. package/dist/format.js.map +1 -0
  27. package/dist/index.d.ts +3 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +25 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/server.d.ts +11 -0
  32. package/dist/server.d.ts.map +1 -0
  33. package/dist/server.js +375 -0
  34. package/dist/server.js.map +1 -0
  35. package/dist/types.d.ts +88 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +3 -0
  38. package/dist/types.js.map +1 -0
  39. package/package.json +47 -0
  40. package/src/__tests__/encoding.test.ts +64 -0
  41. package/src/__tests__/format.test.ts +69 -0
  42. package/src/__tests__/tools.test.ts +334 -0
  43. package/src/api.ts +211 -0
  44. package/src/encoding.ts +72 -0
  45. package/src/format.ts +201 -0
  46. package/src/index.ts +30 -0
  47. package/src/server.ts +463 -0
  48. package/src/types.ts +74 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Mike Argento
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @mikeargento/bitgraph-mcp
2
+
3
+ MCP server for BitGraph. It gives any MCP client, Claude Code and Claude Desktop among them, the same three gestures the website has: take a BitGraph of a file, check whether bytes are on record, and fetch a proof.
4
+
5
+ BitGraph records a file's SHA-256 digest at a causal position in a forward-only ledger. Ethereum serves as a public clock, not a storage layer: the ledger periodically records the hash of a recent Ethereum block, and since a block's hash cannot be known before the block exists, the sequence is pinned to a public timeline. Nothing is ever written to Ethereum. This server hashes files locally; only the digest ever leaves the machine. File contents are never uploaded.
6
+
7
+ ```sh
8
+ claude mcp add bitgraph -- npx -y @mikeargento/bitgraph-mcp
9
+ ```
10
+
11
+ Tools:
12
+
13
+ - `bitgraph_record` records files at new causal positions. Files already on record are returned with their existing proof instead of being re-recorded; pass `again: true` to deliberately record the same bytes at a new position. Recordings are permanent.
14
+ - `bitgraph_check` reports whether files or digests are on record, with every causal position each one occupies. Read-only.
15
+ - `bitgraph_get_proof` fetches a proof by digest, BitGraph number, or file path, including the anchor window, the two Ethereum block times that bracket when it was BitGraphed. Read-only.
16
+
17
+ Configuration is by environment variable. `BITGRAPH_API_URL` overrides the endpoint (default `https://bitgraph.ing`). `BITGRAPH_API_KEY`, when set, is sent as a Bearer token on recordings.
18
+
19
+ Proofs are the bitgraph/1 schema and can be verified offline, without this server or any service, using `@mikeargento/bitgraph-verify`.
20
+
21
+ BitGraph itself lives at [bitgraph.ing](https://bitgraph.ing). The protocol, this package's source, and the rest of the documentation are in the main repository: [github.com/mikeargento/bitgraph](https://github.com/mikeargento/bitgraph).
22
+
23
+ ## License
24
+
25
+ MIT. Copyright (c) 2024-2026 Mike Argento. The BitGraph protocol is patent pending; this client is licensed for use, the protocol implementation it talks to is not.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=encoding.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/encoding.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ // Copyright (c) 2024-2026 Mike Argento. Licensed under the MIT License. See LICENSE.
2
+ import { test } from "node:test";
3
+ import { strict as assert } from "node:assert";
4
+ import { createHash } from "node:crypto";
5
+ import { writeFile, mkdtemp } from "node:fs/promises";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { fromUrlSafeB64, looksLikeDigest, mapConcurrent, sha256FileB64, toUrlSafeB64, } from "../encoding.js";
9
+ // A real 32-byte digest with + and / to exercise both substitutions.
10
+ const STANDARD = createHash("sha256").update("bitgraph").digest("base64");
11
+ test("url-safe round trip preserves the digest", () => {
12
+ const safe = toUrlSafeB64(STANDARD);
13
+ assert.ok(!safe.includes("+") && !safe.includes("/") && !safe.includes("="));
14
+ assert.equal(fromUrlSafeB64(safe), STANDARD);
15
+ });
16
+ test("fromUrlSafeB64 is a no-op on standard base64", () => {
17
+ assert.equal(fromUrlSafeB64(STANDARD), STANDARD);
18
+ });
19
+ test("looksLikeDigest accepts both forms, rejects junk", () => {
20
+ assert.ok(looksLikeDigest(STANDARD));
21
+ assert.ok(looksLikeDigest(toUrlSafeB64(STANDARD)));
22
+ assert.ok(!looksLikeDigest("not-a-digest"));
23
+ assert.ok(!looksLikeDigest(""));
24
+ assert.ok(!looksLikeDigest(Buffer.alloc(16).toString("base64"))); // 16 bytes, not 32
25
+ });
26
+ test("sha256FileB64 matches crypto over the same bytes", async () => {
27
+ const dir = await mkdtemp(join(tmpdir(), "bitgraph-mcp-"));
28
+ const file = join(dir, "sample.bin");
29
+ const bytes = Buffer.from("BitGraph proves causal ordering.\n");
30
+ await writeFile(file, bytes);
31
+ const expected = createHash("sha256").update(bytes).digest("base64");
32
+ assert.equal(await sha256FileB64(file), expected);
33
+ });
34
+ test("sha256FileB64 rejects directories and missing files", async () => {
35
+ await assert.rejects(() => sha256FileB64(tmpdir()), /Not a regular file/);
36
+ await assert.rejects(() => sha256FileB64(join(tmpdir(), "definitely-missing-9x7")));
37
+ });
38
+ test("mapConcurrent preserves order and honors the limit", async () => {
39
+ let inFlight = 0;
40
+ let peak = 0;
41
+ const out = await mapConcurrent([1, 2, 3, 4, 5, 6, 7, 8], 3, async (n) => {
42
+ inFlight += 1;
43
+ peak = Math.max(peak, inFlight);
44
+ await new Promise((r) => setTimeout(r, 5));
45
+ inFlight -= 1;
46
+ return n * 2;
47
+ });
48
+ assert.deepEqual(out, [2, 4, 6, 8, 10, 12, 14, 16]);
49
+ assert.ok(peak <= 3, `peak concurrency ${peak} exceeded 3`);
50
+ });
51
+ //# sourceMappingURL=encoding.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.test.js","sourceRoot":"","sources":["../../src/__tests__/encoding.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=format.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/format.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ // Copyright (c) 2024-2026 Mike Argento. Licensed under the MIT License. See LICENSE.
2
+ import { test } from "node:test";
3
+ import { strict as assert } from "node:assert";
4
+ import { createHash } from "node:crypto";
5
+ import { toUrlSafeB64 } from "../encoding.js";
6
+ import { capJson, proofUrl, renderProofMarkdown, renderRecordMarkdown } from "../format.js";
7
+ const DIGEST = createHash("sha256").update("bitgraph").digest("base64");
8
+ const EPOCH = createHash("sha256").update("epoch").digest("base64");
9
+ test("proofUrl pins a position with url-safe encodings", () => {
10
+ const url = proofUrl("https://bitgraph.ing", DIGEST, "42", EPOCH);
11
+ assert.ok(url.startsWith(`https://bitgraph.ing/proof/${encodeURIComponent(toUrlSafeB64(DIGEST))}`));
12
+ assert.ok(url.includes("counter=42"));
13
+ assert.ok(url.includes(`epoch=${encodeURIComponent(toUrlSafeB64(EPOCH))}`));
14
+ assert.ok(!url.includes("+") && !url.includes("=="), "no raw standard-b64 leaks into the URL");
15
+ });
16
+ test("proofUrl without a position has no query string", () => {
17
+ assert.ok(!proofUrl("https://bitgraph.ing", DIGEST).includes("?"));
18
+ });
19
+ test("record markdown mentions again=true only when something was already on record", () => {
20
+ const base = {
21
+ digest: toUrlSafeB64(DIGEST),
22
+ counter: "7",
23
+ epoch: toUrlSafeB64(EPOCH),
24
+ total_positions: 1,
25
+ proof_url: "https://bitgraph.ing/proof/x",
26
+ };
27
+ const fresh = renderRecordMarkdown([{ ...base, path: "/a", outcome: "recorded" }]);
28
+ assert.ok(!fresh.includes("again=true"));
29
+ const mixed = renderRecordMarkdown([
30
+ { ...base, path: "/a", outcome: "recorded" },
31
+ { ...base, path: "/b", outcome: "on record" },
32
+ ]);
33
+ assert.ok(mixed.includes("again=true"));
34
+ assert.ok(mixed.startsWith("1 recorded, 1 already on record."));
35
+ });
36
+ test("proof markdown states the window as between lower and upper", () => {
37
+ const detail = {
38
+ proofs: [{ proof: { artifact: { digestB64: DIGEST }, commit: { counter: "42", epochId: EPOCH } } }],
39
+ positions: [{ counter: "42", epoch: toUrlSafeB64(EPOCH), lowerTime: null, upperTime: null }],
40
+ causalWindow: {
41
+ anchorBefore: { blockTime: "2026-07-01T00:00:00.000Z", blockNumber: 100 },
42
+ anchorAfter: { blockTime: "2026-07-01T00:00:12.000Z", blockNumber: 101 },
43
+ },
44
+ };
45
+ const md = renderProofMarkdown(detail, "https://bitgraph.ing");
46
+ assert.ok(md.includes("BitGraphed between 2026-07-01T00:00:00.000Z (Ethereum block 100) and 2026-07-01T00:00:12.000Z (block 101)"), md);
47
+ assert.ok(md.includes("# BitGraph #42"));
48
+ });
49
+ test("capJson elides large attestation reports before truncating", () => {
50
+ const value = {
51
+ proof: { environment: { attestation: { reportB64: "A".repeat(40_000) } }, note: "keep me" },
52
+ };
53
+ const { text, truncated } = capJson(value);
54
+ assert.ok(truncated);
55
+ assert.ok(text.includes("elided 40000 base64 chars"));
56
+ assert.ok(text.includes("keep me"));
57
+ assert.ok(text.length <= 25_000 + 200);
58
+ });
59
+ //# sourceMappingURL=format.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.test.js","sourceRoot":"","sources":["../../src/__tests__/format.test.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAG5F,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACxE,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEpE,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC5D,MAAM,GAAG,GAAG,QAAQ,CAAC,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAClE,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,8BAA8B,kBAAkB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,kBAAkB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5E,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,wCAAwC,CAAC,CAAC;AACjG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iDAAiD,EAAE,GAAG,EAAE;IAC3D,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,+EAA+E,EAAE,GAAG,EAAE;IACzF,MAAM,IAAI,GAAG;QACX,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC;QAC5B,OAAO,EAAE,GAAG;QACZ,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC;QAC1B,eAAe,EAAE,CAAC;QAClB,SAAS,EAAE,8BAA8B;KAC1C,CAAC;IACF,MAAM,KAAK,GAAG,oBAAoB,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;IACnF,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,oBAAoB,CAAC;QACjC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE;QAC5C,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE;KAC9C,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACxC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,MAAM,MAAM,GAAwB;QAClC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACnG,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5F,YAAY,EAAE;YACZ,YAAY,EAAE,EAAE,SAAS,EAAE,0BAA0B,EAAE,WAAW,EAAE,GAAG,EAAE;YACzE,WAAW,EAAE,EAAE,SAAS,EAAE,0BAA0B,EAAE,WAAW,EAAE,GAAG,EAAE;SACzE;KACF,CAAC;IACF,MAAM,EAAE,GAAG,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAC/D,MAAM,CAAC,EAAE,CACP,EAAE,CAAC,QAAQ,CAAC,2GAA2G,CAAC,EACxH,EAAE,CACH,CAAC;IACF,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;IACtE,MAAM,KAAK,GAAG;QACZ,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAC5F,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,GAAG,GAAG,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tools.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tools.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,304 @@
1
+ // Copyright (c) 2024-2026 Mike Argento. Licensed under the MIT License. See LICENSE.
2
+ /**
3
+ * End-to-end tool tests: a real MCP client drives the real server over an
4
+ * in-memory transport, against a mock bitgraph.ing that asserts the exact
5
+ * wire shapes. No real ledger writes ever happen here.
6
+ */
7
+ import { test, before, after } from "node:test";
8
+ import { strict as assert } from "node:assert";
9
+ import { createHash } from "node:crypto";
10
+ import { createServer } from "node:http";
11
+ import { writeFile, mkdtemp } from "node:fs/promises";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
15
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
16
+ import { buildServer } from "../server.js";
17
+ import { toUrlSafeB64 } from "../encoding.js";
18
+ const requests = [];
19
+ let mock;
20
+ let fileA = "";
21
+ let fileB = "";
22
+ let fileC = "";
23
+ let digestA = ""; // standard b64 of fileA bytes
24
+ let digestB = "";
25
+ let commitMode = "ok";
26
+ const EPOCH = createHash("sha256").update("test-epoch").digest("base64");
27
+ let mintCounter = 100;
28
+ function proofFor(digestB64) {
29
+ mintCounter += 2; // slot consumes one position, commit lands on the next
30
+ return {
31
+ version: "bitgraph/1",
32
+ artifact: { hashAlg: "sha256", digestB64 },
33
+ commit: { counter: String(mintCounter), epochId: EPOCH },
34
+ signer: { publicKeyB64: "pk", signatureB64: "sig" },
35
+ environment: { enforcement: "measured-tee", measurement: "m" },
36
+ };
37
+ }
38
+ before(async () => {
39
+ const dir = await mkdtemp(join(tmpdir(), "bitgraph-mcp-e2e-"));
40
+ fileA = join(dir, "a.txt");
41
+ fileB = join(dir, "b.txt");
42
+ fileC = join(dir, "c.txt");
43
+ await writeFile(fileA, "alpha bytes");
44
+ await writeFile(fileB, "beta bytes");
45
+ await writeFile(fileC, "gamma bytes");
46
+ digestA = createHash("sha256").update("alpha bytes").digest("base64");
47
+ digestB = createHash("sha256").update("beta bytes").digest("base64");
48
+ mock = createServer((req, res) => {
49
+ const chunks = [];
50
+ req.on("data", (c) => chunks.push(c));
51
+ req.on("end", () => {
52
+ const raw = Buffer.concat(chunks).toString("utf8");
53
+ const body = raw.length > 0 ? JSON.parse(raw) : undefined;
54
+ const url = new URL(req.url ?? "/", "http://localhost");
55
+ requests.push({ method: req.method ?? "", path: url.pathname + url.search, headers: req.headers, body });
56
+ const send = (status, payload) => {
57
+ res.writeHead(status, { "Content-Type": "application/json" });
58
+ res.end(JSON.stringify(payload));
59
+ };
60
+ if (url.pathname === "/api/proofs/batch") {
61
+ // fileA is already on record (two positions); fileB is not.
62
+ const digests = body.digests;
63
+ const results = {};
64
+ for (const d of digests) {
65
+ if (d === toUrlSafeB64(digestA)) {
66
+ results[d] = {
67
+ proofs: [
68
+ { proof: { artifact: { digestB64: digestA }, commit: { counter: "10", epochId: EPOCH } } },
69
+ { proof: { artifact: { digestB64: digestA }, commit: { counter: "55", epochId: EPOCH } } },
70
+ ],
71
+ };
72
+ }
73
+ else {
74
+ results[d] = { proofs: [] };
75
+ }
76
+ }
77
+ send(200, { results });
78
+ }
79
+ else if (url.pathname === "/api/commit") {
80
+ if (commitMode === "429") {
81
+ res.writeHead(429, { "Content-Type": "application/json", "Retry-After": "30" });
82
+ res.end(JSON.stringify({ error: "Rate limit exceeded: per-client proof rate limit exceeded" }));
83
+ return;
84
+ }
85
+ const digests = body.digests;
86
+ if (commitMode === "short") {
87
+ send(200, digests.slice(1).map((d) => proofFor(d.digestB64)));
88
+ return;
89
+ }
90
+ send(200, digests.map((d) => proofFor(d.digestB64)));
91
+ }
92
+ else if (url.pathname.startsWith("/api/proofs/digest/")) {
93
+ const digest = decodeURIComponent(url.pathname.split("/").pop() ?? "");
94
+ if (digest === toUrlSafeB64(digestA)) {
95
+ send(200, {
96
+ proofs: [{ proof: { artifact: { digestB64: digestA }, commit: { counter: "10", epochId: EPOCH } } }],
97
+ positions: [
98
+ { counter: "10", epoch: toUrlSafeB64(EPOCH), lowerTime: "2026-07-01T00:00:00.000Z", upperTime: "2026-07-01T00:00:12.000Z" },
99
+ { counter: "55", epoch: toUrlSafeB64(EPOCH), lowerTime: null, upperTime: null },
100
+ ],
101
+ causalWindow: {
102
+ anchorBefore: { blockTime: "2026-07-01T00:00:00.000Z", blockNumber: 1 },
103
+ anchorAfter: { blockTime: "2026-07-01T00:00:12.000Z", blockNumber: 2 },
104
+ },
105
+ });
106
+ }
107
+ else {
108
+ send(200, { proofs: [] });
109
+ }
110
+ }
111
+ else if (url.pathname === "/api/search") {
112
+ const q = url.searchParams.get("q") ?? "";
113
+ if (q.replace(/[#,\s]/g, "") === "10") {
114
+ send(200, { found: true, digest: toUrlSafeB64(digestA), counter: "10" });
115
+ }
116
+ else {
117
+ send(200, { found: false });
118
+ }
119
+ }
120
+ else {
121
+ send(404, { error: "not found" });
122
+ }
123
+ });
124
+ });
125
+ await new Promise((resolve) => mock.listen(0, "127.0.0.1", resolve));
126
+ const address = mock.address();
127
+ if (address === null || typeof address === "string")
128
+ throw new Error("no port");
129
+ process.env["BITGRAPH_API_URL"] = `http://127.0.0.1:${address.port}`;
130
+ process.env["BITGRAPH_API_KEY"] = "test-key-123";
131
+ });
132
+ after(() => {
133
+ mock.close();
134
+ delete process.env["BITGRAPH_API_URL"];
135
+ delete process.env["BITGRAPH_API_KEY"];
136
+ });
137
+ async function connectedClient() {
138
+ const server = buildServer();
139
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
140
+ const client = new Client({ name: "test-client", version: "0.0.0" });
141
+ await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
142
+ return client;
143
+ }
144
+ test("lists the three tools", async () => {
145
+ const client = await connectedClient();
146
+ const tools = await client.listTools();
147
+ const names = tools.tools.map((t) => t.name).sort();
148
+ assert.deepEqual(names, ["bitgraph_check", "bitgraph_get_proof", "bitgraph_record"]);
149
+ });
150
+ test("record dedups on-record files and mints only fresh ones", async () => {
151
+ const client = await connectedClient();
152
+ requests.length = 0;
153
+ const result = await client.callTool({
154
+ name: "bitgraph_record",
155
+ arguments: { paths: [fileA, fileB] },
156
+ });
157
+ assert.ok(!result.isError, JSON.stringify(result.content));
158
+ const commit = requests.find((r) => r.path === "/api/commit");
159
+ if (!commit)
160
+ throw new Error("no commit request was sent");
161
+ const commitBody = commit.body;
162
+ assert.equal(commitBody.chainId, "bitgraph:main");
163
+ assert.deepEqual(commitBody.digests, [{ digestB64: digestB, hashAlg: "sha256" }], "only fileB minted, standard b64");
164
+ assert.equal(commit.headers["authorization"], "Bearer test-key-123", "api key forwarded");
165
+ const batch = requests.find((r) => r.path === "/api/proofs/batch");
166
+ if (!batch)
167
+ throw new Error("no batch check preceded the commit");
168
+ const batchBody = batch.body;
169
+ assert.ok(batchBody.digests.every((d) => !d.includes("+") && !d.includes("=")), "check uses url-safe digests");
170
+ const structured = result.structuredContent;
171
+ assert.equal(structured.summary.recorded, 1);
172
+ assert.equal(structured.summary.on_record, 1);
173
+ const a = structured.results.find((r) => r.path === fileA);
174
+ const b = structured.results.find((r) => r.path === fileB);
175
+ assert.equal(a?.outcome, "on record");
176
+ assert.equal(a?.counter, "10", "on-record outcome reports the EARLIEST position");
177
+ assert.equal(b?.outcome, "recorded");
178
+ });
179
+ test("record with again=true mints even on-record digests", async () => {
180
+ const client = await connectedClient();
181
+ requests.length = 0;
182
+ const result = await client.callTool({
183
+ name: "bitgraph_record",
184
+ arguments: { paths: [fileA], again: true },
185
+ });
186
+ assert.ok(!result.isError, JSON.stringify(result.content));
187
+ const commit = requests.find((r) => r.path === "/api/commit");
188
+ const commitBody = commit?.body;
189
+ assert.deepEqual(commitBody.digests.map((d) => d.digestB64), [digestA]);
190
+ const structured = result.structuredContent;
191
+ assert.equal(structured.results[0]?.outcome, "recorded");
192
+ assert.equal(structured.results[0]?.total_positions, 3, "two prior positions plus the new one");
193
+ });
194
+ test("check reports positions without ever committing", async () => {
195
+ const client = await connectedClient();
196
+ requests.length = 0;
197
+ const result = await client.callTool({
198
+ name: "bitgraph_check",
199
+ arguments: { paths: [fileB], digests: [toUrlSafeB64(digestA)] },
200
+ });
201
+ assert.ok(!result.isError, JSON.stringify(result.content));
202
+ assert.ok(!requests.some((r) => r.path === "/api/commit"), "check never commits");
203
+ const structured = result.structuredContent;
204
+ const a = structured.results.find((r) => r.input === toUrlSafeB64(digestA));
205
+ const b = structured.results.find((r) => r.input === fileB);
206
+ assert.equal(a?.on_record, true);
207
+ assert.equal(a?.positions.length, 2);
208
+ assert.equal(b?.on_record, false);
209
+ });
210
+ test("check rejects malformed digests with an actionable error", async () => {
211
+ const client = await connectedClient();
212
+ const result = await client.callTool({
213
+ name: "bitgraph_check",
214
+ arguments: { digests: ["zzz"] },
215
+ });
216
+ assert.ok(result.isError);
217
+ const text = result.content[0]?.text ?? "";
218
+ assert.ok(text.includes("not a base64 SHA-256 digest"));
219
+ });
220
+ test("get_proof by number resolves through search and renders the window", async () => {
221
+ const client = await connectedClient();
222
+ const result = await client.callTool({
223
+ name: "bitgraph_get_proof",
224
+ arguments: { number: "#10" },
225
+ });
226
+ assert.ok(!result.isError, JSON.stringify(result.content));
227
+ const text = result.content[0]?.text ?? "";
228
+ assert.ok(text.includes("# BitGraph #10"));
229
+ assert.ok(text.includes("BitGraphed between 2026-07-01T00:00:00.000Z"));
230
+ assert.ok(text.includes("Causal positions (2)"));
231
+ assert.ok(text.includes("/proof/"), "includes the proof page url");
232
+ });
233
+ test("get_proof for an unknown digest fails with guidance", async () => {
234
+ const client = await connectedClient();
235
+ const result = await client.callTool({
236
+ name: "bitgraph_get_proof",
237
+ arguments: { digest: toUrlSafeB64(digestB) },
238
+ });
239
+ assert.ok(result.isError);
240
+ const text = result.content[0]?.text ?? "";
241
+ assert.ok(text.includes("Not on record"));
242
+ });
243
+ test("get_proof requires exactly one selector", async () => {
244
+ const client = await connectedClient();
245
+ const result = await client.callTool({
246
+ name: "bitgraph_get_proof",
247
+ arguments: { digest: toUrlSafeB64(digestA), number: "10" },
248
+ });
249
+ assert.ok(result.isError);
250
+ });
251
+ test("commit failure labels unminted files as 'not recorded', never 'on record'", async () => {
252
+ const client = await connectedClient();
253
+ commitMode = "429";
254
+ try {
255
+ const result = await client.callTool({
256
+ name: "bitgraph_record",
257
+ arguments: { paths: [fileC] },
258
+ });
259
+ assert.ok(result.isError, "partial failure must be an error result");
260
+ const text = result.content[0]?.text ?? "";
261
+ assert.ok(text.includes("Retry after 30 seconds"), text);
262
+ assert.ok(text.includes("0 of 1"), text);
263
+ const structured = result.structuredContent;
264
+ assert.equal(structured.results[0]?.outcome, "not recorded");
265
+ assert.equal(structured.results[0]?.proof_url, null);
266
+ assert.equal(structured.summary.not_recorded, 1);
267
+ assert.equal(structured.summary.recorded, 0);
268
+ assert.equal(structured.summary.on_record, 0);
269
+ }
270
+ finally {
271
+ commitMode = "ok";
272
+ }
273
+ });
274
+ test("a 200 with fewer proofs than digests is treated as a partial failure", async () => {
275
+ const client = await connectedClient();
276
+ commitMode = "short";
277
+ try {
278
+ const result = await client.callTool({
279
+ name: "bitgraph_record",
280
+ arguments: { paths: [fileC] },
281
+ });
282
+ assert.ok(result.isError, "shortfall must not reach the success path");
283
+ const structured = result.structuredContent;
284
+ assert.equal(structured.results[0]?.outcome, "not recorded");
285
+ const text = result.content[0]?.text ?? "";
286
+ assert.ok(text.includes("fewer proofs than digests"), text);
287
+ }
288
+ finally {
289
+ commitMode = "ok";
290
+ }
291
+ });
292
+ test("record surfaces unreadable paths before any network call", async () => {
293
+ const client = await connectedClient();
294
+ requests.length = 0;
295
+ const result = await client.callTool({
296
+ name: "bitgraph_record",
297
+ arguments: { paths: [fileA, "/definitely/missing/file.bin"] },
298
+ });
299
+ assert.ok(result.isError);
300
+ assert.equal(requests.length, 0, "no API call happened; nothing was minted");
301
+ const text = result.content[0]?.text ?? "";
302
+ assert.ok(text.includes("nothing was recorded"));
303
+ });
304
+ //# sourceMappingURL=tools.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../src/__tests__/tools.test.ts"],"names":[],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @mikeargento/bitgraph-mcp: HTTP client for the hosted BitGraph API.
3
+ *
4
+ * All recording goes through the website's /api/commit proxy rather than the
5
+ * TEE directly: the proxy is what maintains the per-position by-digest index
6
+ * that makes every causal position of a file discoverable afterward.
7
+ */
8
+ import type { BatchCheckResponse, BitGraphProof, ProofDetailResponse, SearchResponse } from "./types.js";
9
+ export interface ApiConfig {
10
+ baseUrl: string;
11
+ apiKey?: string;
12
+ }
13
+ /** Read configuration from the environment at call time (testable via env). */
14
+ export declare function configFromEnv(): ApiConfig;
15
+ /** Matches the website client: 50 digests per commit request (~1s of TEE work each). */
16
+ export declare const COMMIT_CHUNK_SIZE = 50;
17
+ /** Matches the batch endpoint's MAX_DIGESTS. */
18
+ export declare const BATCH_CHECK_LIMIT = 500;
19
+ export declare class ApiError extends Error {
20
+ readonly status: number;
21
+ readonly retryAfterSec: number | null;
22
+ constructor(status: number, message: string, retryAfterSec?: number | null);
23
+ }
24
+ /**
25
+ * Look up which digests are on record. Input digests must be URL-safe base64;
26
+ * the response is keyed by the exact strings sent. Batches of up to 500.
27
+ */
28
+ export declare function batchCheck(config: ApiConfig, urlSafeDigests: readonly string[]): Promise<BatchCheckResponse>;
29
+ /**
30
+ * Record digests at new causal positions. Input digests must be STANDARD
31
+ * base64 (as stored in proofs). Commits sequentially in chunks of 50, matching
32
+ * the website client; the TEE serializes commits anyway.
33
+ *
34
+ * On a mid-batch failure the error carries how many proofs were already
35
+ * minted (those are permanent); the caller must report partial results
36
+ * honestly rather than pretending all-or-nothing.
37
+ */
38
+ export declare function commitDigests(config: ApiConfig, standardDigests: readonly string[], attribution?: {
39
+ name?: string | undefined;
40
+ title?: string | undefined;
41
+ message?: string | undefined;
42
+ }): Promise<BitGraphProof[]>;
43
+ /** A commit batch failed partway: `minted` proofs are already permanent. */
44
+ export declare class PartialCommitError extends Error {
45
+ readonly minted: BitGraphProof[];
46
+ readonly requested: number;
47
+ readonly cause2: unknown;
48
+ constructor(minted: BitGraphProof[], requested: number, cause: unknown);
49
+ }
50
+ /** Full detail for one digest: proof, all causal positions, anchor window. */
51
+ export declare function getProofDetail(config: ApiConfig, urlSafeDigest: string, counter?: string, urlSafeEpoch?: string): Promise<ProofDetailResponse>;
52
+ /** Resolve a BitGraph number (or digest string) to a digest via /api/search. */
53
+ export declare function search(config: ApiConfig, q: string): Promise<SearchResponse>;
54
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,IAAI,SAAS,CAIzC;AAED,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,gDAAgD;AAChD,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAKrC,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;gBAE1B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAE,MAAM,GAAG,IAAW;CAKjF;AA0DD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAc7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,eAAe,EAAE,SAAS,MAAM,EAAE,EAClC,WAAW,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACpG,OAAO,CAAC,aAAa,EAAE,CAAC,CAuB1B;AAED,4EAA4E;AAC5E,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,MAAM,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAYvE;AAED,8EAA8E;AAC9E,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAU9B;AAED,gFAAgF;AAChF,wBAAsB,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAMlF"}