@rel-time/mcp-server 1.2.11 → 1.2.12
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 +2 -1
- package/index.js +314 -36
- package/package.json +1 -1
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -40,7 +40,8 @@ Once paid via Lightning or Stripe (or if you pass an existing `rel_key_...` key)
|
|
|
40
40
|
|
|
41
41
|
| Tool Name | Requires Key? | What It Does |
|
|
42
42
|
| :--- | :---: | :--- |
|
|
43
|
-
| `reltime_anchor_file` | Yes | Computes the SHA-256 hash of a local file **on your machine** (0 bytes uploaded), supports `biometric: true` for **Biometric Anchors** (TouchID/FaceID/YubiKey), anchors via `POST /v1/anchor`, saves `reltime-stamp-<filename>.svg` and `reltime-doomsday-proof-<filename>.json`, and automatically outputs a clickable **Stamped Copy** (`reltime-stamped-<name>.pdf` or `.png`). |
|
|
43
|
+
| `reltime_anchor_file` | Yes | Computes the SHA-256 hash of a local file **on your machine** (0 bytes uploaded), supports `biometric: true` for **Biometric Anchors** (TouchID/FaceID/YubiKey), anchors via `POST /v1/anchor`, saves `reltime-stamp-<filename>.svg`, `reltime-certificate-<filename>.html`, and `reltime-doomsday-proof-<filename>.json`, and automatically outputs a clickable **Stamped Copy** (`reltime-stamped-<name>.pdf` or `.png`). |
|
|
44
|
+
| `reltime_anchor_folder` | Yes | **Bulk folder anchoring (10 to 5,000+ files in one call):** Hashes all files in a local folder 100% locally, supports `biometric: true` (Passkey) or Anonymous mode, automatically skips already-anchored files (safe to resume), and keeps your directory clean by storing per-file Doomsday Proofs inside `<folder>/_reltime_proofs/` plus a master `reltime-batch-manifest.json`. |
|
|
44
45
|
| `reltime_audit_trail` | Yes | Fetches the account's chronological anchor ledger (`GET /v1/account/history`), aggregates Bitcoin block settlements, VDF `T_index` ticks, and Corporate Hardware Passkey (`signer_public_key`) signatures, optionally verifies a local file or entire folder bit-for-bit (`verify_local_path`), and spins up a self-contained interactive HTML Audit Report (`reltime-audit-report-*.html`) in your browser. |
|
|
45
46
|
| `reltime_link_passkey` | **No** | Opens `https://rel-time.com/mcp-passkey` in the system browser so the user can touch TouchID / FaceID / YubiKey once, saving `{ public_key_hex, passkey_signature }` to `~/.reltime/passkey.json` for seamless Biometric Anchors. |
|
|
46
47
|
| `reltime_stamp_file` | **No** | Overlays the authentic 64-ray Sun-Stamp onto the bottom-right corner of any local PDF or Image (`.png`, `.jpg`, `.jpeg`, `.webp`, `.gif`) 100% locally. |
|
package/index.js
CHANGED
|
@@ -56,7 +56,7 @@ let LAST_INVOICE_PACK = null;
|
|
|
56
56
|
|
|
57
57
|
const SERVER_INFO = {
|
|
58
58
|
name: "rel-time-mcp-server",
|
|
59
|
-
version: "1.2.
|
|
59
|
+
version: "1.2.12",
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -1527,6 +1527,18 @@ function generateAuditReportHtml(audit) {
|
|
|
1527
1527
|
</html>`;
|
|
1528
1528
|
}
|
|
1529
1529
|
|
|
1530
|
+
function formatBytes(bytes) {
|
|
1531
|
+
if (bytes === undefined || bytes === null || Number.isNaN(Number(bytes))) {
|
|
1532
|
+
return "Zero-Knowledge (32-Byte Digest)";
|
|
1533
|
+
}
|
|
1534
|
+
const b = Number(bytes);
|
|
1535
|
+
if (b === 0) return "0 Bytes";
|
|
1536
|
+
const k = 1024;
|
|
1537
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
1538
|
+
const i = Math.min(sizes.length - 1, Math.floor(Math.log(b) / Math.log(k)));
|
|
1539
|
+
return `${parseFloat((b / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1530
1542
|
function inferMimeTypeFromFileName(fileName) {
|
|
1531
1543
|
if (!fileName || fileName === "Zero-Knowledge Hash Payload") {
|
|
1532
1544
|
return "application/octet-stream (Zero-Knowledge)";
|
|
@@ -2111,6 +2123,49 @@ const TOOLS = [
|
|
|
2111
2123
|
required: ["file_path"],
|
|
2112
2124
|
},
|
|
2113
2125
|
},
|
|
2126
|
+
{
|
|
2127
|
+
name: "reltime_anchor_folder",
|
|
2128
|
+
description:
|
|
2129
|
+
"Bulk zero-knowledge folder anchoring (10 to 5,000+ files in a single call): Hashes all files in a local folder 100% locally (0 file bytes uploaded), supports Biometric (Passkey) or Anonymous anchoring, skips any files that are already anchored (safe to resume), and keeps the user's folder clean by storing per-file Doomsday Proofs inside a single `_reltime_proofs/` subfolder plus a master `reltime-batch-manifest.json`.",
|
|
2130
|
+
inputSchema: {
|
|
2131
|
+
type: "object",
|
|
2132
|
+
properties: {
|
|
2133
|
+
folder_path: {
|
|
2134
|
+
type: "string",
|
|
2135
|
+
description: "Absolute path to the local directory to hash and anchor.",
|
|
2136
|
+
},
|
|
2137
|
+
recursive: {
|
|
2138
|
+
type: "boolean",
|
|
2139
|
+
description: "If true, recursively anchors files in subdirectories. Defaults to false (top-level files only).",
|
|
2140
|
+
},
|
|
2141
|
+
biometric: {
|
|
2142
|
+
type: "boolean",
|
|
2143
|
+
description:
|
|
2144
|
+
"If true, performs Biometric Anchors using your linked hardware Passkey (`~/.reltime/passkey.json`) across the entire folder without repeated TouchID prompts.",
|
|
2145
|
+
},
|
|
2146
|
+
anchor_mode: {
|
|
2147
|
+
type: "string",
|
|
2148
|
+
enum: ["standard", "temporal"],
|
|
2149
|
+
description: "Use 'standard' (default) or 'temporal' (VDF T_index sequential ordering for Superhighway & Autonomous Agents).",
|
|
2150
|
+
},
|
|
2151
|
+
artifact_mode: {
|
|
2152
|
+
type: "string",
|
|
2153
|
+
enum: ["proofs_subfolder", "manifest_only", "full"],
|
|
2154
|
+
description:
|
|
2155
|
+
"Controls local output files so bulk runs never clutter the folder: 'proofs_subfolder' (default) writes JSON proofs into `<folder>/_reltime_proofs/` + `reltime-batch-manifest.json`; 'manifest_only' writes only `reltime-batch-manifest.json`; 'full' also writes SVG Sun-Stamps and HTML certificates.",
|
|
2156
|
+
},
|
|
2157
|
+
concurrency: {
|
|
2158
|
+
type: "number",
|
|
2159
|
+
description: "Number of concurrent anchor requests (default: 5, max: 10).",
|
|
2160
|
+
},
|
|
2161
|
+
api_key: {
|
|
2162
|
+
type: "string",
|
|
2163
|
+
description: "Optional override for RELTIME_API_KEY.",
|
|
2164
|
+
},
|
|
2165
|
+
},
|
|
2166
|
+
required: ["folder_path"],
|
|
2167
|
+
},
|
|
2168
|
+
},
|
|
2114
2169
|
{
|
|
2115
2170
|
name: "reltime_link_passkey",
|
|
2116
2171
|
description:
|
|
@@ -2450,12 +2505,27 @@ async function executeTool(name, args = {}) {
|
|
|
2450
2505
|
const verifyUrl = `https://rel-time.com/verify?t=${lookupHash}`;
|
|
2451
2506
|
const stampEndpointUrl = `${API_BASE}/stamp/${lookupHash}`;
|
|
2452
2507
|
|
|
2453
|
-
|
|
2508
|
+
let svgContent = data.visual_fingerprint || "";
|
|
2509
|
+
const needsSvg = args.save_sun_stamp_svg !== false || args.save_stamped_copy !== false;
|
|
2510
|
+
if (!svgContent && needsSvg) {
|
|
2511
|
+
try {
|
|
2512
|
+
const stampRes = await fetch(stampEndpointUrl);
|
|
2513
|
+
if (stampRes.ok) {
|
|
2514
|
+
svgContent = await stampRes.text();
|
|
2515
|
+
}
|
|
2516
|
+
} catch (e) {
|
|
2517
|
+
// Ignore SVG fetch error if offline/rate-limited
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2454
2520
|
|
|
2455
2521
|
let savedSvgPath = null;
|
|
2456
|
-
if (args.save_sun_stamp_svg !== false) {
|
|
2457
|
-
|
|
2458
|
-
|
|
2522
|
+
if (args.save_sun_stamp_svg !== false && svgContent) {
|
|
2523
|
+
try {
|
|
2524
|
+
savedSvgPath = path.join(path.dirname(filePath), `reltime-stamp-${path.basename(filePath)}.svg`);
|
|
2525
|
+
fs.writeFileSync(savedSvgPath, svgContent, "utf8");
|
|
2526
|
+
} catch (e) {
|
|
2527
|
+
savedSvgPath = null;
|
|
2528
|
+
}
|
|
2459
2529
|
}
|
|
2460
2530
|
|
|
2461
2531
|
// Save initial Doomsday Proof JSON alongside the file
|
|
@@ -2489,40 +2559,48 @@ async function executeTool(name, args = {}) {
|
|
|
2489
2559
|
|
|
2490
2560
|
// 3. Automatically generate Stamped Copy (.PDF or .PNG) for PDFs and Images
|
|
2491
2561
|
let stampedCopyResult = null;
|
|
2492
|
-
if (args.save_stamped_copy !== false) {
|
|
2493
|
-
|
|
2562
|
+
if (args.save_stamped_copy !== false && svgContent) {
|
|
2563
|
+
try {
|
|
2564
|
+
stampedCopyResult = await stampLocalFileOptionA(filePath, svgContent, null, clientHash);
|
|
2565
|
+
} catch (e) {
|
|
2566
|
+
stampedCopyResult = { status: "skipped", error: e.message };
|
|
2567
|
+
}
|
|
2494
2568
|
}
|
|
2495
2569
|
|
|
2496
2570
|
// 4. Generate 4-Plate Sovereign Cryptographic Provenance Certificate HTML
|
|
2497
2571
|
let savedCertificateHtmlPath = null;
|
|
2498
2572
|
if (args.save_certificate_html !== false) {
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
path.
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2573
|
+
try {
|
|
2574
|
+
const certHtml = generateProvenanceCertificateHtml({
|
|
2575
|
+
fileName: path.basename(filePath),
|
|
2576
|
+
fileSize: formatBytes(fileBuffer.length),
|
|
2577
|
+
mimeType: inferMimeTypeFromFileName(path.basename(filePath)),
|
|
2578
|
+
originalFileHash,
|
|
2579
|
+
attestedHash: clientHash,
|
|
2580
|
+
signerPublicKey: passkeyCreds ? passkeyCreds.public_key_hex : null,
|
|
2581
|
+
anchorMode: data.anchor_mode || anchorMode,
|
|
2582
|
+
tIndex,
|
|
2583
|
+
vdfTicks: data.vdf_ticks || data.solar_ticks || 0,
|
|
2584
|
+
status: data.status || "pending_finality",
|
|
2585
|
+
blockHeight: data.settlement?.bitcoin_block_height || null,
|
|
2586
|
+
blockTimeUtc: data.settlement?.bitcoin_block_time
|
|
2587
|
+
? new Date(data.settlement.bitcoin_block_time * 1000).toISOString().replace("T", " ").slice(0, 19) + " UTC"
|
|
2588
|
+
: null,
|
|
2589
|
+
merkleProofCount: Array.isArray(data.settlement?.merkle_proof_path)
|
|
2590
|
+
? data.settlement.merkle_proof_path.length
|
|
2591
|
+
: null,
|
|
2592
|
+
txid: data.settlement?.bitcoin_txid || null,
|
|
2593
|
+
});
|
|
2594
|
+
savedCertificateHtmlPath = path.join(
|
|
2595
|
+
path.dirname(filePath),
|
|
2596
|
+
`reltime-certificate-${path.basename(filePath)}.html`
|
|
2597
|
+
);
|
|
2598
|
+
fs.writeFileSync(savedCertificateHtmlPath, certHtml, "utf8");
|
|
2599
|
+
if (args.open_certificate_in_browser) {
|
|
2600
|
+
openSystemBrowser(savedCertificateHtmlPath);
|
|
2601
|
+
}
|
|
2602
|
+
} catch (e) {
|
|
2603
|
+
savedCertificateHtmlPath = null;
|
|
2526
2604
|
}
|
|
2527
2605
|
}
|
|
2528
2606
|
|
|
@@ -2548,6 +2626,203 @@ async function executeTool(name, args = {}) {
|
|
|
2548
2626
|
};
|
|
2549
2627
|
}
|
|
2550
2628
|
|
|
2629
|
+
if (name === "reltime_anchor_folder") {
|
|
2630
|
+
if (!key) {
|
|
2631
|
+
return buildPackSelectionPrompt(
|
|
2632
|
+
"Before anchoring a folder of files, a Rel-Time API key is required. Ask the user which pack they want to provision first:"
|
|
2633
|
+
);
|
|
2634
|
+
}
|
|
2635
|
+
const folderPath = resolveLocalFilePath(args.folder_path);
|
|
2636
|
+
if (!fs.existsSync(folderPath) || !fs.statSync(folderPath).isDirectory()) {
|
|
2637
|
+
throw new Error(`Directory not found at path: ${folderPath}`);
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
const recursive = Boolean(args.recursive);
|
|
2641
|
+
const anchorMode = args.anchor_mode || "standard";
|
|
2642
|
+
const artifactMode = args.artifact_mode || "proofs_subfolder";
|
|
2643
|
+
const concurrency = Math.max(1, Math.min(10, Number(args.concurrency) || 5));
|
|
2644
|
+
|
|
2645
|
+
let passkeyCreds = null;
|
|
2646
|
+
if (args.biometric) {
|
|
2647
|
+
passkeyCreds = loadSavedPasskey();
|
|
2648
|
+
if (!passkeyCreds) {
|
|
2649
|
+
passkeyCreds = await launchBrowserPasskeyBridge();
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
const isReltimeGeneratedFile = (fname) => {
|
|
2654
|
+
const lower = fname.toLowerCase();
|
|
2655
|
+
return (
|
|
2656
|
+
fname.startsWith(".") ||
|
|
2657
|
+
lower.startsWith("reltime-stamp-") ||
|
|
2658
|
+
lower.startsWith("reltime-doomsday-proof-") ||
|
|
2659
|
+
lower.startsWith("reltime-certificate-") ||
|
|
2660
|
+
lower.startsWith("reltime-stamped-") ||
|
|
2661
|
+
lower.startsWith("reltime-audit-report-") ||
|
|
2662
|
+
lower === "reltime-batch-manifest.json"
|
|
2663
|
+
);
|
|
2664
|
+
};
|
|
2665
|
+
|
|
2666
|
+
const targetFiles = [];
|
|
2667
|
+
const walkDir = (dir) => {
|
|
2668
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
2669
|
+
for (const entry of entries) {
|
|
2670
|
+
if (entry.name.startsWith(".") || entry.name === "_reltime_proofs" || entry.name === "node_modules") {
|
|
2671
|
+
continue;
|
|
2672
|
+
}
|
|
2673
|
+
const fullPath = path.join(dir, entry.name);
|
|
2674
|
+
if (entry.isDirectory()) {
|
|
2675
|
+
if (recursive) walkDir(fullPath);
|
|
2676
|
+
} else if (entry.isFile() && !isReltimeGeneratedFile(entry.name)) {
|
|
2677
|
+
targetFiles.push(fullPath);
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
};
|
|
2681
|
+
walkDir(folderPath);
|
|
2682
|
+
|
|
2683
|
+
const proofsDir = path.join(folderPath, "_reltime_proofs");
|
|
2684
|
+
if (artifactMode === "proofs_subfolder" && !fs.existsSync(proofsDir)) {
|
|
2685
|
+
fs.mkdirSync(proofsDir, { recursive: true });
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
const manifestPath = path.join(folderPath, "reltime-batch-manifest.json");
|
|
2689
|
+
let existingManifest = { anchored_files: {} };
|
|
2690
|
+
if (fs.existsSync(manifestPath)) {
|
|
2691
|
+
try {
|
|
2692
|
+
existingManifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")) || { anchored_files: {} };
|
|
2693
|
+
if (!existingManifest.anchored_files) existingManifest.anchored_files = {};
|
|
2694
|
+
} catch (e) {
|
|
2695
|
+
existingManifest = { anchored_files: {} };
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
const results = [];
|
|
2700
|
+
const skipped = [];
|
|
2701
|
+
const errors = [];
|
|
2702
|
+
let outOfCredits = false;
|
|
2703
|
+
|
|
2704
|
+
const toProcess = [];
|
|
2705
|
+
for (const fPath of targetFiles) {
|
|
2706
|
+
const relPath = path.relative(folderPath, fPath);
|
|
2707
|
+
const baseName = path.basename(fPath);
|
|
2708
|
+
const sidecarProof = path.join(path.dirname(fPath), `reltime-doomsday-proof-${baseName}.json`);
|
|
2709
|
+
const subfolderProof = path.join(proofsDir, `reltime-doomsday-proof-${relPath.replace(/[\\/]/g, "__")}.json`);
|
|
2710
|
+
if (existingManifest.anchored_files[relPath] || fs.existsSync(sidecarProof) || fs.existsSync(subfolderProof)) {
|
|
2711
|
+
skipped.push(relPath);
|
|
2712
|
+
} else {
|
|
2713
|
+
toProcess.push({ fPath, relPath, baseName, subfolderProof });
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
let cursor = 0;
|
|
2718
|
+
const worker = async () => {
|
|
2719
|
+
while (cursor < toProcess.length && !outOfCredits) {
|
|
2720
|
+
const idx = cursor++;
|
|
2721
|
+
const item = toProcess[idx];
|
|
2722
|
+
if (!item) break;
|
|
2723
|
+
try {
|
|
2724
|
+
const buf = fs.readFileSync(item.fPath);
|
|
2725
|
+
const originalFileHash = crypto.createHash("sha256").update(buf).digest("hex");
|
|
2726
|
+
const clientHash =
|
|
2727
|
+
args.biometric && passkeyCreds
|
|
2728
|
+
? crypto.createHash("sha256").update(`${originalFileHash}${passkeyCreds.public_key_hex}`, "utf8").digest("hex")
|
|
2729
|
+
: originalFileHash;
|
|
2730
|
+
|
|
2731
|
+
const reqBody = {
|
|
2732
|
+
client_hash: clientHash,
|
|
2733
|
+
anchor_mode: anchorMode,
|
|
2734
|
+
};
|
|
2735
|
+
if (args.biometric && passkeyCreds) {
|
|
2736
|
+
reqBody.original_file_hash = originalFileHash;
|
|
2737
|
+
reqBody.passkey_signature = passkeyCreds.passkey_signature;
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2740
|
+
const res = await fetch(`${API_BASE}/anchor`, {
|
|
2741
|
+
method: "POST",
|
|
2742
|
+
headers: {
|
|
2743
|
+
"Content-Type": "application/json",
|
|
2744
|
+
Authorization: `Bearer ${key}`,
|
|
2745
|
+
},
|
|
2746
|
+
body: JSON.stringify(reqBody),
|
|
2747
|
+
});
|
|
2748
|
+
|
|
2749
|
+
if (res.status === 402) {
|
|
2750
|
+
outOfCredits = true;
|
|
2751
|
+
errors.push({ file: item.relPath, error: "Insufficient Hash Credits (HTTP 402)" });
|
|
2752
|
+
break;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
const data = await res.json();
|
|
2756
|
+
if (!res.ok) {
|
|
2757
|
+
errors.push({ file: item.relPath, error: `HTTP ${res.status}: ${JSON.stringify(data)}` });
|
|
2758
|
+
continue;
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
const tIndex = data.t_index || data.thermodynamic_proof;
|
|
2762
|
+
const lookupHash = (data.anchor_mode || anchorMode) === "temporal" ? tIndex : clientHash;
|
|
2763
|
+
const verifyUrl = `https://rel-time.com/verify?t=${lookupHash}`;
|
|
2764
|
+
const proofRecord = {
|
|
2765
|
+
protocol: "Rel-Time Sovereign Provenance Protocol",
|
|
2766
|
+
file_name: item.baseName,
|
|
2767
|
+
relative_path: item.relPath,
|
|
2768
|
+
identity_mode: args.biometric ? "BIOMETRIC_PASSKEY" : "ANONYMOUS",
|
|
2769
|
+
original_file_sha256_hash: originalFileHash,
|
|
2770
|
+
anchored_client_hash: clientHash,
|
|
2771
|
+
signer_public_key: passkeyCreds ? passkeyCreds.public_key_hex : null,
|
|
2772
|
+
t_index: tIndex,
|
|
2773
|
+
vdf_ticks: data.vdf_ticks || data.solar_ticks,
|
|
2774
|
+
anchor_mode: data.anchor_mode || anchorMode,
|
|
2775
|
+
status: data.status || "pending_finality",
|
|
2776
|
+
verify_url: verifyUrl,
|
|
2777
|
+
};
|
|
2778
|
+
|
|
2779
|
+
if (artifactMode === "proofs_subfolder") {
|
|
2780
|
+
fs.writeFileSync(item.subfolderProof, JSON.stringify(proofRecord, null, 2), "utf8");
|
|
2781
|
+
} else if (artifactMode === "full") {
|
|
2782
|
+
const sidecarPath = path.join(path.dirname(item.fPath), `reltime-doomsday-proof-${item.baseName}.json`);
|
|
2783
|
+
fs.writeFileSync(sidecarPath, JSON.stringify(proofRecord, null, 2), "utf8");
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
existingManifest.anchored_files[item.relPath] = proofRecord;
|
|
2787
|
+
results.push(proofRecord);
|
|
2788
|
+
} catch (err) {
|
|
2789
|
+
errors.push({ file: item.relPath, error: err.message });
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
};
|
|
2793
|
+
|
|
2794
|
+
const workers = Array.from({ length: Math.min(concurrency, Math.max(1, toProcess.length)) }, () => worker());
|
|
2795
|
+
await Promise.all(workers);
|
|
2796
|
+
|
|
2797
|
+
const manifestPayload = {
|
|
2798
|
+
protocol: "Rel-Time Sovereign Provenance Protocol — Batch Folder Manifest",
|
|
2799
|
+
folder_path: folderPath,
|
|
2800
|
+
updated_at: new Date().toISOString(),
|
|
2801
|
+
identity_mode: args.biometric ? "BIOMETRIC_PASSKEY" : "ANONYMOUS",
|
|
2802
|
+
signer_public_key: passkeyCreds ? passkeyCreds.public_key_hex : null,
|
|
2803
|
+
total_anchored_in_manifest: Object.keys(existingManifest.anchored_files).length,
|
|
2804
|
+
anchored_files: existingManifest.anchored_files,
|
|
2805
|
+
};
|
|
2806
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifestPayload, null, 2), "utf8");
|
|
2807
|
+
|
|
2808
|
+
return {
|
|
2809
|
+
status: outOfCredits ? "stopped_insufficient_credits" : "completed",
|
|
2810
|
+
folder_path: folderPath,
|
|
2811
|
+
total_files_found: targetFiles.length,
|
|
2812
|
+
newly_anchored_count: results.length,
|
|
2813
|
+
skipped_already_anchored_count: skipped.length,
|
|
2814
|
+
error_count: errors.length,
|
|
2815
|
+
identity_mode: args.biometric ? "BIOMETRIC_PASSKEY" : "ANONYMOUS",
|
|
2816
|
+
signer_public_key: passkeyCreds ? passkeyCreds.public_key_hex : null,
|
|
2817
|
+
artifact_mode: artifactMode,
|
|
2818
|
+
manifest_path: manifestPath,
|
|
2819
|
+
proofs_subfolder: artifactMode === "proofs_subfolder" ? proofsDir : null,
|
|
2820
|
+
errors: errors.slice(0, 20),
|
|
2821
|
+
next_step:
|
|
2822
|
+
"You can now run `reltime_audit_trail` with `verify_local_path` set to this folder to generate the full interactive HTML Cryptographic Audit Report.",
|
|
2823
|
+
};
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2551
2826
|
if (name === "reltime_stamp_file") {
|
|
2552
2827
|
const filePath = resolveLocalFilePath(args.file_path);
|
|
2553
2828
|
if (!fs.existsSync(filePath)) {
|
|
@@ -2813,7 +3088,7 @@ async function executeTool(name, args = {}) {
|
|
|
2813
3088
|
};
|
|
2814
3089
|
}
|
|
2815
3090
|
|
|
2816
|
-
const maxEntries = Math.min(
|
|
3091
|
+
const maxEntries = Math.min(5000, Math.max(1, Number(args.limit) || 2000));
|
|
2817
3092
|
const pageSize = Math.min(100, maxEntries);
|
|
2818
3093
|
const pagesToFetch = Math.ceil(maxEntries / pageSize);
|
|
2819
3094
|
let rawHistory = [];
|
|
@@ -2959,7 +3234,10 @@ async function executeTool(name, args = {}) {
|
|
|
2959
3234
|
item.startsWith("reltime-stamp-") ||
|
|
2960
3235
|
item.startsWith("reltime-doomsday-proof-") ||
|
|
2961
3236
|
item.startsWith("reltime-proof-") ||
|
|
2962
|
-
item.startsWith("reltime-
|
|
3237
|
+
item.startsWith("reltime-certificate-") ||
|
|
3238
|
+
item.startsWith("reltime-audit-report-") ||
|
|
3239
|
+
item === "reltime-batch-manifest.json" ||
|
|
3240
|
+
item === "_reltime_proofs"
|
|
2963
3241
|
) {
|
|
2964
3242
|
continue;
|
|
2965
3243
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rel-time/mcp-server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.12",
|
|
4
4
|
"mcpName": "io.github.relsun369-dev/rel-time",
|
|
5
5
|
"description": "Official Model Context Protocol (MCP) server for Rel-Time (rel-time.com) — Zero-Knowledge Bitcoin & VDF Provenance, Local File Hashing, and Sun-Stamp Generation for Claude, Cursor, Windsurf, and Antigravity.",
|
|
6
6
|
"main": "index.js",
|
package/server.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.relsun369-dev/rel-time",
|
|
4
4
|
"title": "Rel-Time Protocol (Bitcoin & VDF Provenance)",
|
|
5
5
|
"description": "Zero-knowledge Bitcoin Mainnet & VDF timestamping, Passkey signing, Sun-Stamps, and tamper audits.",
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"url": "https://github.com/relsun369-dev/reltime-mcp",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "1.2.
|
|
11
|
+
"version": "1.2.12",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
16
16
|
"identifier": "@rel-time/mcp-server",
|
|
17
|
-
"version": "1.2.
|
|
17
|
+
"version": "1.2.12",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
20
20
|
}
|