@otskit/mcp 0.1.5 → 0.1.6

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,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="docs/header.png" alt="OTSkit.ts MCP" width="480" />
2
+ <img src="https://raw.githubusercontent.com/OTSkit/OTSkit-MCP/master/docs/header.png" alt="OTSkit.ts MCP" width="480" />
3
3
  </p>
4
4
 
5
5
  # @otskit/mcp
@@ -8,6 +8,8 @@ OpenTimestamps MCP server — stamp, upgrade, and verify Bitcoin timestamps via
8
8
 
9
9
  Exposes a set of tools to any MCP-compatible agent so it can timestamp documents, monitor confirmation status, and verify proofs against the Bitcoin blockchain — all from a conversation.
10
10
 
11
+ > **Note on confirmation times:** After stamping, a proof is `pending` until Bitcoin confirms it. This typically takes **10–60 minutes** but can take **several hours** during network congestion. Use `ots-mcp watch` or `upgrade_timestamp` to monitor. A pending status is not an error.
12
+
11
13
  ## Install
12
14
 
13
15
  ```bash
@@ -38,7 +40,7 @@ Each command writes the MCP entry into the agent's config file, makes a `.bak` b
38
40
  | `ots-mcp backup [dest]` | Backup the SQLite database |
39
41
  | `ots-mcp setup <claude\|codex>` | Configure MCP for an agent |
40
42
 
41
- ## MCP tools exposed to Claude
43
+ ## MCP tools exposed to agents
42
44
 
43
45
  | Tool | Description |
44
46
  |---|---|
@@ -67,10 +69,6 @@ Create `~/.ots-mcp/config.json` to override defaults:
67
69
  ```json
68
70
  {
69
71
  "stamp_enabled": true,
70
- "preserve_enabled": true,
71
- "preserve_whitelist": ["/path/to/allowed/dir"],
72
- "preserve_max_bytes": 104857600,
73
- "preserve_max_files": 10000,
74
72
  "scheduler_interval_minutes": 30,
75
73
  "retry_max_attempts": 20,
76
74
  "calendar_timeout_ms": 10000,
@@ -54,6 +54,10 @@ function listStamps(db, params) {
54
54
  conds.push("created_at < ?");
55
55
  vals.push(cutoff);
56
56
  }
57
+ if (params.due_now) {
58
+ conds.push("(next_retry_at IS NULL OR next_retry_at <= ?)");
59
+ vals.push((/* @__PURE__ */ new Date()).toISOString());
60
+ }
57
61
  const where = conds.length ? `WHERE ${conds.join(" AND ")}` : "";
58
62
  const total = db.prepare(`SELECT COUNT(*) as n FROM stamps ${where}`).get(...vals).n;
59
63
  const items = db.prepare(
@@ -121,17 +125,23 @@ async function createTimestamp(input, db, config) {
121
125
  // src/tools/upgrade-timestamp.ts
122
126
  import { readFileSync } from "fs";
123
127
  import { OpenTimestampsClient as OpenTimestampsClient2, UpgradeError } from "@otskit/client";
124
- import { DetachedTimestampFile } from "@otskit/core";
128
+ import { DetachedTimestampFile, StreamDeserializationContext } from "@otskit/core";
129
+ function collectAttestations(ts) {
130
+ const atts = [...ts.attestations];
131
+ for (const branch of ts.branches) {
132
+ atts.push(...collectAttestations(branch.stamp));
133
+ }
134
+ return atts;
135
+ }
125
136
  function checkBitcoinConfirmation(bytes) {
126
137
  try {
127
- const proof = DetachedTimestampFile.deserialize(new Uint8Array(bytes));
128
- const attestations = proof.timestamp.getAttestations();
129
- const bitcoin = attestations.filter((a) => a.kind === "bitcoin");
130
- if (bitcoin.length > 0) {
131
- const block = Math.min(...bitcoin.map((a) => a.height));
132
- return { confirmed: true, block };
133
- }
134
- return { confirmed: false };
138
+ const ctx = new StreamDeserializationContext(new Uint8Array(bytes));
139
+ const dtf = DetachedTimestampFile.deserialize(ctx);
140
+ const attestations = collectAttestations(dtf.timestamp);
141
+ const bitcoinAtts = attestations.filter((a) => a.kind === "bitcoin");
142
+ if (bitcoinAtts.length === 0) return { confirmed: false };
143
+ const block = Math.min(...bitcoinAtts.map((a) => a.height));
144
+ return { confirmed: true, block };
135
145
  } catch {
136
146
  return { confirmed: false };
137
147
  }
@@ -237,7 +247,8 @@ function listPending(input, db, _config) {
237
247
  status: input.status ?? "pending",
238
248
  limit: Math.min(input.limit ?? 50, 200),
239
249
  offset: input.offset ?? 0,
240
- older_than_hours: input.older_than_hours
250
+ older_than_hours: input.older_than_hours,
251
+ due_now: input.due_now
241
252
  });
242
253
  }
243
254
 
@@ -3,7 +3,7 @@ import {
3
3
  listPending,
4
4
  upgradeTimestamp,
5
5
  verifyTimestamp
6
- } from "./chunk-55NLVWDQ.js";
6
+ } from "./chunk-VHQD7HZD.js";
7
7
  import {
8
8
  backupDb,
9
9
  getDb,
@@ -68,7 +68,7 @@ async function runCli(command, args) {
68
68
  break;
69
69
  }
70
70
  case "check-pending": {
71
- const { items } = listPending({ status: "pending", limit: 200 }, db, config);
71
+ const { items } = listPending({ status: "pending", limit: 200, due_now: true }, db, config);
72
72
  process.stderr.write(`Processing ${items.length} pending stamps...
73
73
  `);
74
74
  for (const record of items) {
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ Commands:
20
20
  }
21
21
  switch (command) {
22
22
  case "serve": {
23
- const { runServer } = await import("./server-Q7XYIZRY.js");
23
+ const { runServer } = await import("./server-D5YXBC55.js");
24
24
  await runServer();
25
25
  break;
26
26
  }
@@ -62,7 +62,7 @@ switch (command) {
62
62
  case "check-pending":
63
63
  case "backup":
64
64
  case "scheduler": {
65
- const { runCli } = await import("./cli-ZD2OP45N.js");
65
+ const { runCli } = await import("./cli-TF5PYS3T.js");
66
66
  await runCli(command, args);
67
67
  break;
68
68
  }
@@ -4,7 +4,7 @@ import {
4
4
  listPending,
5
5
  upgradeTimestamp,
6
6
  verifyTimestamp
7
- } from "./chunk-55NLVWDQ.js";
7
+ } from "./chunk-VHQD7HZD.js";
8
8
  import {
9
9
  getDb,
10
10
  loadConfig
@@ -31,15 +31,15 @@ function inspectTimestamp(input, db, _config) {
31
31
  } catch {
32
32
  return { error: "proof_missing", details: `Cannot read proof: ${record.proof_path}` };
33
33
  }
34
- let attestationCount = 0;
35
- let hasBitcoin = false;
34
+ let calendarAttestations = 0;
35
+ let bitcoinAttestations = 0;
36
36
  let bitcoinBlock = null;
37
37
  try {
38
38
  const proof = DetachedTimestampFile.deserialize(new Uint8Array(proofBytes));
39
39
  const attestations = proof.timestamp.getAttestations();
40
- attestationCount = attestations.length;
41
- hasBitcoin = attestations.some((a) => a.kind === "bitcoin");
42
- if (hasBitcoin) {
40
+ bitcoinAttestations = attestations.filter((a) => a.kind === "bitcoin").length;
41
+ calendarAttestations = attestations.filter((a) => a.kind !== "bitcoin").length;
42
+ if (bitcoinAttestations > 0) {
43
43
  const blocks = attestations.filter((a) => a.kind === "bitcoin").map((a) => a.height);
44
44
  bitcoinBlock = blocks.length > 0 ? Math.min(...blocks) : null;
45
45
  }
@@ -52,8 +52,9 @@ function inspectTimestamp(input, db, _config) {
52
52
  created_at: record.created_at,
53
53
  proof_path: record.proof_path,
54
54
  proof_size_bytes: proofSize,
55
- attestation_count: attestationCount,
56
- has_bitcoin_confirmation: hasBitcoin,
55
+ calendar_attestations: calendarAttestations,
56
+ bitcoin_attestations: bitcoinAttestations,
57
+ bitcoin_confirmed: bitcoinAttestations > 0,
57
58
  bitcoin_block: bitcoinBlock
58
59
  };
59
60
  }
@@ -119,7 +120,7 @@ var TOOL_DEFINITIONS = [
119
120
  },
120
121
  {
121
122
  name: "inspect_timestamp",
122
- description: "Shows the contents of a stored proof file without making any network calls. Useful for debugging: returns size, parsed attestations, and confirmation status from the proof itself.",
123
+ description: "Inspects a stored proof file without network calls. Returns calendar_attestations (promises from OTS servers, NOT Bitcoin confirmation) and bitcoin_attestations (actual Bitcoin blocks). A stamp is only truly confirmed when bitcoin_attestations > 0 and bitcoin_confirmed is true.",
123
124
  inputSchema: {
124
125
  type: "object",
125
126
  properties: { id: { type: "string", description: "UUID from the stamp record" } },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otskit/mcp",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "OpenTimestamps MCP server — stamp, upgrade, verify via AI agents",
5
5
  "type": "module",
6
6
  "engines": {
@@ -20,9 +20,9 @@
20
20
  "test:watch": "vitest"
21
21
  },
22
22
  "dependencies": {
23
- "@otskit/core": "^0.1.0",
24
- "@otskit/client": "^0.1.1",
25
23
  "@modelcontextprotocol/sdk": "^1.29.0",
24
+ "@otskit/client": "^0.1.1",
25
+ "@otskit/core": "^0.1.0",
26
26
  "better-sqlite3": "^12.10.0"
27
27
  },
28
28
  "pnpm": {
@@ -32,8 +32,15 @@
32
32
  ]
33
33
  },
34
34
  "devDependencies": {
35
+ "@semantic-release/changelog": "^6",
36
+ "@semantic-release/commit-analyzer": "^13.0.0",
37
+ "@semantic-release/git": "^10",
38
+ "@semantic-release/github": "^12.0.8",
39
+ "@semantic-release/npm": "^13.1.5",
40
+ "@semantic-release/release-notes-generator": "^14.0.0",
35
41
  "@types/better-sqlite3": "^7.6.13",
36
42
  "@types/node": "^22.0.0",
43
+ "semantic-release": "^25.0.3",
37
44
  "tsup": "^8.3.5",
38
45
  "typescript": "^5.6.3",
39
46
  "vitest": "^2.1.4"