cascrow-mcp 1.0.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 (3) hide show
  1. package/DEMO_PROMPT.md +78 -0
  2. package/index.js +400 -0
  3. package/package.json +16 -0
package/DEMO_PROMPT.md ADDED
@@ -0,0 +1,78 @@
1
+ # Cascrow MCP Demo Prompt
2
+
3
+ Paste this into Claude Desktop to run the demo.
4
+
5
+ **Prerequisite:** Your `claude_desktop_config.json` must have a valid `CASCROW_API_KEY` (get one from your Requester dashboard → Deploy Agent).
6
+
7
+ ---
8
+
9
+ ## Short demo (90 sec YC video)
10
+
11
+ **PROMPT:**
12
+
13
+ ```
14
+ I need a landing page for my SaaS "TaskFlow". It needs:
15
+ 1. Hero section: headline + CTA
16
+ 2. Features section: 3 features
17
+
18
+ Use Cascrow to verify each milestone as I build it — create the contract first, then for each section: build it, submit proof, trigger AI verification.
19
+
20
+ Show me the contract link and confidence scores at the end.
21
+ ```
22
+
23
+ **Claude will:**
24
+ 1. `cascrow_create_contract` — 2 milestones, `amountUSD: 0` (verification-only, no MetaMask)
25
+ 2. Build HTML for milestone 1 → `cascrow_submit_proof` → `cascrow_verify` (4/5 YES)
26
+ 3. Build HTML for milestone 2 → `cascrow_submit_proof` → `cascrow_verify` (5/5 YES)
27
+ 4. Return contract URL + per-milestone confidence scores
28
+
29
+ **What you see in the browser:**
30
+ - `cascrow.com/contract/<id>` — milestones going PROOF_SUBMITTED → VERIFIED
31
+ - NFT certificate minted on XRP Ledger after final milestone
32
+
33
+ ---
34
+
35
+ ## Full demo (longer walkthrough)
36
+
37
+ **PROMPT:**
38
+
39
+ ```
40
+ I need a landing page for my SaaS product "TaskFlow" — a project management tool for remote teams.
41
+
42
+ The page needs:
43
+ 1. Hero section: headline "Get more done, together" + subheadline + CTA button "Start free trial"
44
+ 2. Features section: 3 features (Real-time collaboration, Smart deadlines, Team analytics)
45
+ 3. Pricing section: 3 tiers (Free $0, Pro $12/mo, Enterprise custom)
46
+
47
+ Use Cascrow to create a verification contract for these 3 milestones BEFORE you start building (amountUSD: 0 — verification only, no payment needed), then build the page (write the full HTML/CSS), submit proof for each milestone, and get Cascrow verification that everything was actually delivered.
48
+
49
+ At the end, show me:
50
+ - The complete HTML of the landing page
51
+ - The Cascrow contract link proving all milestones were verified
52
+ - The AI confidence score for each milestone
53
+ ```
54
+
55
+ **Claude will:**
56
+ 1. `cascrow_create_contract` — 3 milestones, `amountUSD: 0` (no escrow, no MetaMask)
57
+ 2. For each milestone:
58
+ - `cascrow_fund_milestone` — activate it (instant, no blockchain tx needed for $0)
59
+ - Build the actual HTML section
60
+ - `cascrow_submit_proof` — detailed proof of what was built
61
+ - `cascrow_verify` — 5 AI models vote, returns confidence score
62
+ 3. Deliver final HTML + Cascrow contract link
63
+
64
+ **What you see in the browser (`cascrow.com/contract/...`):**
65
+ - Contract created with 3 milestones
66
+ - Each milestone: FUNDED → PROOF_SUBMITTED → VERIFIED
67
+ - NFT certificate minted on XRP Ledger at the end
68
+
69
+ ---
70
+
71
+ ## Why `amountUSD: 0`?
72
+
73
+ Cascrow supports **verification-only mode** — agents can use the full 5-model AI verification pipeline without locking any funds. This is useful for:
74
+ - Autonomous agents that need trustless proof of work (no human holds funds)
75
+ - Demo recordings (no MetaMask popup interrupts the flow)
76
+ - Charging per-verification ($0.10/check) without requiring escrow setup
77
+
78
+ To use real escrow, just set `amountUSD` to the payment amount and the Requester funds via MetaMask.
package/index.js ADDED
@@ -0,0 +1,400 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cascrow MCP Server
4
+ * Gives Claude the ability to create contracts, fund milestones,
5
+ * submit proofs, and verify deliverables — all via the Cascrow API.
6
+ */
7
+
8
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
9
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10
+ import {
11
+ CallToolRequestSchema,
12
+ ListToolsRequestSchema,
13
+ } from "@modelcontextprotocol/sdk/types.js";
14
+
15
+ const BASE_URL = process.env.CASCROW_BASE_URL ?? "https://cascrow.com";
16
+ const API_KEY = process.env.CASCROW_API_KEY ?? "";
17
+
18
+ if (!API_KEY) {
19
+ process.stderr.write("ERROR: CASCROW_API_KEY is not set\n");
20
+ process.exit(1);
21
+ }
22
+
23
+ // ─── HTTP helpers ─────────────────────────────────────────────────────────────
24
+
25
+ async function apiPost(path, body) {
26
+ const res = await fetch(`${BASE_URL}${path}`, {
27
+ method: "POST",
28
+ headers: {
29
+ "Authorization": `Bearer ${API_KEY}`,
30
+ "Content-Type": "application/json",
31
+ },
32
+ body: JSON.stringify(body),
33
+ });
34
+ const data = await res.json();
35
+ if (!res.ok) {
36
+ throw new Error(data.error ?? `HTTP ${res.status}`);
37
+ }
38
+ return data;
39
+ }
40
+
41
+ async function apiGet(path) {
42
+ const res = await fetch(`${BASE_URL}${path}`, {
43
+ headers: { "Authorization": `Bearer ${API_KEY}` },
44
+ });
45
+ const data = await res.json();
46
+ if (!res.ok) {
47
+ throw new Error(data.error ?? `HTTP ${res.status}`);
48
+ }
49
+ return data;
50
+ }
51
+
52
+ async function uploadProof(milestoneId, filename, content) {
53
+ const blob = new Blob([content], { type: "text/plain" });
54
+ const form = new FormData();
55
+ form.append("file", blob, filename);
56
+ form.append("milestoneId", milestoneId);
57
+
58
+ const res = await fetch(`${BASE_URL}/api/proof/upload`, {
59
+ method: "POST",
60
+ headers: { "Authorization": `Bearer ${API_KEY}` },
61
+ body: form,
62
+ });
63
+ const data = await res.json();
64
+ if (!res.ok) {
65
+ throw new Error(data.error ?? `HTTP ${res.status}`);
66
+ }
67
+ return data;
68
+ }
69
+
70
+ async function streamVerify(proofId) {
71
+ const res = await fetch(`${BASE_URL}/api/verify`, {
72
+ method: "POST",
73
+ headers: {
74
+ "Authorization": `Bearer ${API_KEY}`,
75
+ "Content-Type": "application/json",
76
+ "Accept": "text/event-stream",
77
+ },
78
+ body: JSON.stringify({ proofId }),
79
+ });
80
+
81
+ if (!res.ok) {
82
+ const data = await res.json().catch(() => ({}));
83
+ throw new Error(data.error ?? `HTTP ${res.status}`);
84
+ }
85
+
86
+ const votes = [];
87
+ const reader = res.body.getReader();
88
+ const decoder = new TextDecoder();
89
+ let buffer = "";
90
+
91
+ while (true) {
92
+ const { done, value } = await reader.read();
93
+ if (done) break;
94
+ buffer += decoder.decode(value, { stream: true });
95
+
96
+ const lines = buffer.split("\n");
97
+ buffer = lines.pop() ?? "";
98
+
99
+ for (const line of lines) {
100
+ if (!line.startsWith("data:")) continue;
101
+ const raw = line.slice(5).trim();
102
+ if (!raw) continue;
103
+ try {
104
+ const msg = JSON.parse(raw);
105
+ if (msg.type === "model_vote") {
106
+ votes.push(msg);
107
+ // Log each vote to stderr so Claude Desktop can show live progress
108
+ const icon = msg.decision === "YES" ? "✅" : "❌";
109
+ process.stderr.write(`[cascrow] ${icon} ${msg.model}: ${msg.decision} (${msg.confidence}%)\n`);
110
+ } else if (msg.type === "complete") {
111
+ return { ...msg, votes };
112
+ } else if (msg.type === "error") {
113
+ throw new Error(msg.message);
114
+ }
115
+ } catch (e) {
116
+ if (e instanceof SyntaxError) continue;
117
+ throw e;
118
+ }
119
+ }
120
+ }
121
+ throw new Error("Stream ended without a complete event");
122
+ }
123
+
124
+ // ─── Tool definitions ─────────────────────────────────────────────────────────
125
+
126
+ const TOOLS = [
127
+ {
128
+ name: "cascrow_create_contract",
129
+ description:
130
+ "Create a Cascrow verification contract with one or more milestones. " +
131
+ "Each milestone defines a deliverable, its acceptance criteria, and a deadline. " +
132
+ "Returns contractId, milestoneIds, and a link to view the contract. " +
133
+ "Use this BEFORE starting any work so the user can see the plan.",
134
+ inputSchema: {
135
+ type: "object",
136
+ required: ["milestones"],
137
+ properties: {
138
+ milestones: {
139
+ type: "array",
140
+ minItems: 1,
141
+ description: "List of milestones to verify",
142
+ items: {
143
+ type: "object",
144
+ required: ["title", "description", "deadlineDays"],
145
+ properties: {
146
+ title: {
147
+ type: "string",
148
+ description: "Short milestone title, e.g. 'Hero section with CTA'",
149
+ },
150
+ description: {
151
+ type: "string",
152
+ description: "Detailed acceptance criteria — what exactly must be true for this milestone to pass AI verification",
153
+ },
154
+ deadlineDays: {
155
+ type: "number",
156
+ description: "Days from now until deadline (e.g. 7)",
157
+ },
158
+ },
159
+ },
160
+ },
161
+ },
162
+ },
163
+ },
164
+ {
165
+ name: "cascrow_fund_milestone",
166
+ description:
167
+ "Fund (activate) a milestone so it can receive proof. " +
168
+ "Call this after creating the contract and before submitting proof for a milestone.",
169
+ inputSchema: {
170
+ type: "object",
171
+ required: ["contractId"],
172
+ properties: {
173
+ contractId: { type: "string", description: "The contract ID returned by cascrow_create_contract" },
174
+ milestoneId: { type: "string", description: "Optional specific milestone ID. If omitted, funds the first available milestone." },
175
+ },
176
+ },
177
+ },
178
+ {
179
+ name: "cascrow_submit_proof",
180
+ description:
181
+ "Submit proof of completion for a milestone. " +
182
+ "Write a detailed, specific proof report describing exactly what was built, " +
183
+ "with verifiable evidence (URLs, metrics, specific implementation details). " +
184
+ "The more specific and verifiable the proof, the higher the AI confidence score.",
185
+ inputSchema: {
186
+ type: "object",
187
+ required: ["milestoneId", "proof"],
188
+ properties: {
189
+ milestoneId: { type: "string", description: "The milestone ID to submit proof for" },
190
+ proof: {
191
+ type: "string",
192
+ description: "Full proof report text. Include: what was built, specific technical details, live URLs, metrics, and how each acceptance criterion was met.",
193
+ },
194
+ filename: {
195
+ type: "string",
196
+ description: "Filename for the proof document (default: proof-report.txt)",
197
+ },
198
+ },
199
+ },
200
+ },
201
+ {
202
+ name: "cascrow_verify",
203
+ description:
204
+ "Trigger AI verification for a submitted proof and wait for the result. " +
205
+ "5 AI models vote in parallel (Claude, GPT-4o, Gemini, Mistral, Cerebras). " +
206
+ "Returns decision (YES/NO), confidence score, reasoning, and action taken. " +
207
+ "Call this after cascrow_submit_proof.",
208
+ inputSchema: {
209
+ type: "object",
210
+ required: ["proofId"],
211
+ properties: {
212
+ proofId: { type: "string", description: "The proof ID returned by cascrow_submit_proof" },
213
+ },
214
+ },
215
+ },
216
+ {
217
+ name: "cascrow_join_contract",
218
+ description:
219
+ "Join an existing contract as the Builder (the party that delivers the work). " +
220
+ "Use this when another agent or user has created a contract and shared an invite code with you. " +
221
+ "Once joined, the contract moves to AWAITING_ESCROW and you can receive proof submissions.",
222
+ inputSchema: {
223
+ type: "object",
224
+ required: ["inviteCode"],
225
+ properties: {
226
+ inviteCode: {
227
+ type: "string",
228
+ description: "The invite code or invite link token shared by the Requester agent.",
229
+ },
230
+ },
231
+ },
232
+ },
233
+ {
234
+ name: "cascrow_get_contract",
235
+ description: "Get the current status and details of a contract, including all milestones.",
236
+ inputSchema: {
237
+ type: "object",
238
+ required: ["contractId"],
239
+ properties: {
240
+ contractId: { type: "string" },
241
+ },
242
+ },
243
+ },
244
+ ];
245
+
246
+ // ─── Tool handlers ────────────────────────────────────────────────────────────
247
+
248
+ async function handleCreateContract({ milestones }) {
249
+ const deadline = (days) => {
250
+ const d = new Date();
251
+ d.setDate(d.getDate() + days);
252
+ return d.toISOString();
253
+ };
254
+
255
+ const payload = {
256
+ milestones: milestones.map((m) => ({
257
+ title: `${m.title} — ${m.description}`,
258
+ amountUSD: 0, // verification-only — $0.10 charged per verification trigger
259
+ cancelAfter: deadline(m.deadlineDays ?? 7),
260
+ })),
261
+ };
262
+
263
+ const data = await apiPost("/api/contracts", payload);
264
+ const contractUrl = `${BASE_URL}/contract/${data.contractId}`;
265
+
266
+ return {
267
+ contractId: data.contractId,
268
+ contractUrl,
269
+ milestoneCount: milestones.length,
270
+ message: `Contract created with ${milestones.length} milestone(s). View it here: ${contractUrl}`,
271
+ };
272
+ }
273
+
274
+ async function handleFundMilestone({ contractId, milestoneId }) {
275
+ const body = milestoneId ? { contractId, milestoneId } : { contractId };
276
+ const data = await apiPost("/api/agent/fund-milestone", body);
277
+ return {
278
+ milestoneId: data.milestoneId,
279
+ contractId: data.contractId,
280
+ status: data.status,
281
+ message: `Milestone funded and active. Ready to receive proof.`,
282
+ };
283
+ }
284
+
285
+ async function handleSubmitProof({ milestoneId, proof, filename }) {
286
+ const data = await uploadProof(
287
+ milestoneId,
288
+ filename ?? "proof-report.txt",
289
+ proof
290
+ );
291
+ return {
292
+ proofId: data.proofId,
293
+ message: `Proof submitted. Use cascrow_verify with proofId: ${data.proofId}`,
294
+ };
295
+ }
296
+
297
+ async function handleVerify({ proofId }) {
298
+ const result = await streamVerify(proofId);
299
+ const decision = result.decision ?? "?";
300
+ const confidence = result.confidence ?? 0;
301
+ const action = result.action ?? "?";
302
+ const reasoning = result.reasoning ?? "";
303
+ const votes = result.votes ?? [];
304
+
305
+ const passed = decision === "YES" && confidence >= 85;
306
+
307
+ const TOTAL_MODELS = 5;
308
+ const yesCount = votes.filter((v) => v.decision === "YES").length;
309
+ const failedCount = TOTAL_MODELS - votes.length;
310
+
311
+ const voteSummary = votes
312
+ .map((v) => ` ${v.decision === "YES" ? "✅" : "❌"} ${v.model}: ${v.decision} (${v.confidence}%)`)
313
+ .join("\n");
314
+ const failedNote = failedCount > 0 ? `\n ⚠️ ${failedCount} model(s) failed to respond` : "";
315
+ const voteHeader = votes.length > 0
316
+ ? `${yesCount}/${TOTAL_MODELS} models approved (${failedCount > 0 ? `${failedCount} failed` : "all responded"}):\n${voteSummary}${failedNote}\n\n`
317
+ : "";
318
+
319
+ return {
320
+ decision,
321
+ confidence,
322
+ action,
323
+ reasoning,
324
+ passed,
325
+ totalModels: TOTAL_MODELS,
326
+ modelsResponded: votes.length,
327
+ modelsFailed: failedCount,
328
+ txHash: result.txHash ?? null,
329
+ modelVotes: votes.map((v) => ({ model: v.model, decision: v.decision, confidence: v.confidence })),
330
+ message: passed
331
+ ? `✅ VERIFIED — Cascrow consensus confidence: ${confidence}%\n\n${voteHeader}${reasoning.slice(0, 300)}`
332
+ : `❌ NOT VERIFIED — Cascrow consensus confidence: ${confidence}%\n\n${voteHeader}${reasoning.slice(0, 300)}`,
333
+ };
334
+ }
335
+
336
+ async function handleJoinContract({ inviteCode }) {
337
+ const data = await apiPost("/api/contracts/join", { inviteCode });
338
+ return {
339
+ contractId: data.contractId,
340
+ message: `Joined contract as Builder. Contract is now AWAITING_ESCROW — ready to receive proof once funded.`,
341
+ };
342
+ }
343
+
344
+ async function handleGetContract({ contractId }) {
345
+ const data = await apiGet(`/api/contracts/${contractId}`);
346
+ return data;
347
+ }
348
+
349
+ // ─── MCP Server ───────────────────────────────────────────────────────────────
350
+
351
+ const server = new Server(
352
+ { name: "cascrow", version: "1.0.0" },
353
+ { capabilities: { tools: {} } }
354
+ );
355
+
356
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
357
+ tools: TOOLS,
358
+ }));
359
+
360
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
361
+ const { name, arguments: args } = request.params;
362
+
363
+ try {
364
+ let result;
365
+ switch (name) {
366
+ case "cascrow_create_contract":
367
+ result = await handleCreateContract(args);
368
+ break;
369
+ case "cascrow_fund_milestone":
370
+ result = await handleFundMilestone(args);
371
+ break;
372
+ case "cascrow_submit_proof":
373
+ result = await handleSubmitProof(args);
374
+ break;
375
+ case "cascrow_verify":
376
+ result = await handleVerify(args);
377
+ break;
378
+ case "cascrow_join_contract":
379
+ result = await handleJoinContract(args);
380
+ break;
381
+ case "cascrow_get_contract":
382
+ result = await handleGetContract(args);
383
+ break;
384
+ default:
385
+ throw new Error(`Unknown tool: ${name}`);
386
+ }
387
+
388
+ return {
389
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
390
+ };
391
+ } catch (err) {
392
+ return {
393
+ content: [{ type: "text", text: `Error: ${err.message}` }],
394
+ isError: true,
395
+ };
396
+ }
397
+ });
398
+
399
+ const transport = new StdioServerTransport();
400
+ await server.connect(transport);
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "cascrow-mcp",
3
+ "version": "1.0.1",
4
+ "description": "MCP server for Cascrow — agentic escrow and verification",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "cascrow-mcp": "./index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js"
12
+ },
13
+ "dependencies": {
14
+ "@modelcontextprotocol/sdk": "^1.0.0"
15
+ }
16
+ }