cyberdyne-mcp 0.6.4 → 0.6.5

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/dist/server.js CHANGED
@@ -9,7 +9,6 @@
9
9
  * list_categories — the static task taxonomy (no network)
10
10
  * search_humans — POST /api/a2a {search_humans} → capability index
11
11
  * get_treasury — GET /api/treasury → the agent's balance
12
- * fund_treasury — POST /api/treasury/fund → demo top-up (testnet only)
13
12
  * get_deposit_address — GET /api/treasury/deposit → where to send real USDC (live)
14
13
  * deposit — POST /api/treasury/deposit → credit treasury from a real USDC tx
15
14
  * withdraw_treasury — POST /api/treasury/withdraw → pull unspent treasury back to your wallet (live)
@@ -158,7 +157,7 @@ async function guard(fn) {
158
157
  }
159
158
  }
160
159
  // ---- Server ---------------------------------------------------------------
161
- const server = new McpServer({ name: "cyberdyne", version: "0.6.4" });
160
+ const server = new McpServer({ name: "cyberdyne", version: "0.6.5" });
162
161
  server.tool("list_categories", "List the kinds of real-world work CYBERDYNE humans can do. Static (no network). Use this to learn the valid `category` values before posting a task.", {}, async () => json(Object.entries(CATEGORIES).map(([id, blurb]) => ({ id, blurb }))));
163
162
  server.tool("onboard", "BOOTSTRAP (works WITHOUT an existing key — the one tool that self-onboards). Zero-browser: generates a fresh wallet if you don't have one, signs in to CYBERDYNE with it (SIWE), mints your `cyb_` agent API key, and saves both to ~/.cyberdyne/config.json (0600) so every other tool here authenticates automatically. No web dashboard, no env vars. Returns your wallet address, the cyb_ key (shown once), and the next steps (fund via get_deposit_address+deposit → post_task → authorize_task → review_submission → close_task). The same generated wallet auto-signs pool budgets. To bring your OWN wallet instead, use the CLI: `npx cyberdyne-mcp onboard --import <0xKEY | mnemonic>` (or --create for a fresh one). Idempotent-ish: re-running with a saved wallet reuses it and mints a fresh key.", {}, async () => guard(async () => {
164
163
  const r = await onboard();
@@ -183,17 +182,16 @@ server.tool("search_humans", "Find verified humans by capability via the live ca
183
182
  ...(min_reputation != null ? { min_reputation } : {}),
184
183
  ...(location ? { location } : {}),
185
184
  })));
186
- server.tool("get_treasury", "Get the agent's own treasury (the source of task rewards on the manual rail). Returns null if the agent has no treasury yet — call fund_treasury to create one.", {}, async () => guard(() => client.rest("GET", "/api/treasury")));
187
- server.tool("fund_treasury", "Demo top-up (TESTNET/DEMO ONLY): add USD to the treasury balance. DISABLED when the platform is live (returns 403 funding_disabled) — on the live rail fund with REAL USDC via get_deposit_address + deposit instead.", { amount_usd: z.number().positive().describe("USD to add to the treasury balance.") }, async ({ amount_usd }) => guard(() => client.rest("POST", "/api/treasury/fund", { body: { amount_usd } })));
185
+ server.tool("get_treasury", "Get the agent's own treasury residual on-chain balance available to cover deploy fees and to withdraw. Fund it with REAL USDC via get_deposit_address + deposit. Returns null if the agent has no treasury yet.", {}, async () => guard(() => client.rest("GET", "/api/treasury")));
188
186
  server.tool("get_deposit_address", "Get the on-chain address to fund your treasury with REAL USDC (live rail). Returns { deposit_address, chain_id, usdc_address, decimals }. Send USDC from your VERIFIED wallet to deposit_address on Base, then call `deposit` with the tx hash to credit your treasury.", {}, async () => guard(() => client.rest("GET", "/api/treasury/deposit")));
189
- server.tool("deposit", "Credit your treasury from a REAL on-chain USDC deposit (live rail; the real-money replacement for fund_treasury). First send USDC to the address from get_deposit_address (from your verified wallet), then call this with the transaction hash. The transfer is verified on-chain (to = platform wallet, from = your wallet) and credited exactly once — resubmitting the same tx never double-credits.", {
187
+ server.tool("deposit", "Credit your treasury from a REAL on-chain USDC deposit. First send USDC to the address from get_deposit_address (from your verified wallet), then call this with the transaction hash. The transfer is verified on-chain (to = platform wallet, from = your wallet) and credited exactly once — resubmitting the same tx never double-credits.", {
190
188
  tx_hash: z
191
189
  .string()
192
190
  .regex(/^0x[0-9a-fA-F]{64}$/)
193
191
  .describe("The Base tx hash of your USDC transfer to the deposit address."),
194
192
  }, async ({ tx_hash }) => guard(() => client.rest("POST", "/api/treasury/deposit", { body: { tx_hash } })));
195
193
  server.tool("withdraw_treasury", "Recover UNSPENT treasury to your wallet (live rail): pull USDC out of your treasury back to your own VERIFIED deposit wallet on Base — no browser. Available balance is your treasury balance net of any open escrow holds. Funds can ONLY go to your verified wallet (no destination param), so a leaked key can't redirect them. Returns { ok, tx_hash, amount_usd, to }. 400 insufficient_treasury if the balance can't cover it; 403 withdraws_disabled on the demo rail.", { amount_usd: z.number().positive().describe("USD to withdraw from your treasury to your verified wallet.") }, async ({ amount_usd }) => guard(() => client.rest("POST", "/api/treasury/withdraw", { body: { amount_usd } })));
196
- server.tool("post_task", "Open an FCFS pool bounty on the marketplace. There is NO direct hire and NO agent-picks-human — every task is an open bounty: you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission. Funds are NOT charged at post — the budget is frozen later at authorize_task. `reward_usd` is the total budget; `quantity` is how many identical units (humans) it pays — each unit holds reward_usd/quantity (each unit must be >= $0.01). Returns the created task (with its id). REAL-TOKEN POOL rail (USDC/BNKR on Base): the response also includes `authIntent` (the budget authorization to sign) and `deployFee` { usd, bps, recipient, token } (a SEPARATE non-refundable fee tx) — pass BOTH to authorize_task. TESTNET/non-real token (CYOS): no on-chain freeze; response is just { task } (treasury-checked, 402 insufficient_treasury if low).", {
194
+ server.tool("post_task", "Open an FCFS pool bounty on the marketplace. There is NO direct hire and NO agent-picks-human — every task is an open bounty: you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission. Funds are NOT charged at post — the budget is frozen later at authorize_task. `reward_usd` is the total budget; `quantity` is how many identical units (humans) it pays — each unit holds reward_usd/quantity (each unit must be >= $0.01). Returns the created task (with its id) plus `authIntent` (the budget authorization to sign) and `deployFee` { usd, bps, recipient, token } (a SEPARATE non-refundable fee tx) — pass BOTH to authorize_task. The non-custodial POOL escrow (USDC/BNKR/GITLAWB on Base) is the only settlement rail; a non-real token (CYOS) or non-live config has no rail and returns 422 settlement_unavailable.", {
197
195
  title: z.string().min(2).max(160).describe("Short task title."),
198
196
  category: z.enum(TASK_CATEGORIES),
199
197
  description: z.string().max(4000).optional().describe("What you need the human to do."),
@@ -205,7 +203,7 @@ server.tool("post_task", "Open an FCFS pool bounty on the marketplace. There is
205
203
  pay_token: z.enum(["USDC", "BNKR", "CYOS"]).optional().describe("Settlement token (default USDC)."),
206
204
  deadline_hours: z.number().int().positive().optional(),
207
205
  }, async (args) => guard(() => client.rest("POST", "/api/tasks", { body: args })));
208
- server.tool("authorize_task", "Freeze the bounty budget on-chain (the second step of the FCFS flow). REAL-TOKEN POOL rail: pass BOTH `auth_intent` (the authIntent from post_task) AND `deploy_fee` (the deployFee object from post_task) — with CYBERDYNE_EVM_PRIVATE_KEY set, the MCP signs the whole-budget authorization AND pays the separate 2.5% USDC / 5% other-token deploy fee tx from its wallet, then freezes the budget on the audited escrow; or pass a pre-signed `signed_payment` and a pre-paid `fee_tx_hash`. After this, any eligible human submits FCFS and you review_submission each. TESTNET/non-real (CYOS) rail: call with just { task_id } the prefunded treasury opens a logical hold, no signature. Idempotent once frozen.", {
206
+ server.tool("authorize_task", "Freeze the bounty budget on-chain (the second step of the FCFS flow). REAL-TOKEN POOL rail: pass BOTH `auth_intent` (the authIntent from post_task) AND `deploy_fee` (the deployFee object from post_task) — with CYBERDYNE_EVM_PRIVATE_KEY set, the MCP signs the whole-budget authorization AND pays the separate 2.5% USDC / 5% other-token deploy fee tx from its wallet, then freezes the budget on the audited escrow; or pass a pre-signed `signed_payment` and a pre-paid `fee_tx_hash`. After this, any eligible human submits FCFS and you review_submission each. The non-custodial POOL escrow is the only rail; a non-real token / non-live config returns 409 settlement_unavailable. Idempotent once frozen.", {
209
207
  task_id: z.string().uuid(),
210
208
  signed_payment: z.string().optional().describe("Pre-signed base64 auth-capture payload (external/Bankr signer)."),
211
209
  auth_intent: z.unknown().optional().describe("The authIntent from post_task — required for MCP wallet auto-signing."),
@@ -283,8 +281,7 @@ server.registerPrompt("quickstart", {
283
281
  "",
284
282
  "FUND (optional — the pool freezes from your wallet at deploy, but a treasury can cover fees):",
285
283
  "1. get_deposit_address -> the platform deposit address on Base.",
286
- "2. Send USDC to it FROM your own verified wallet, then deposit({ tx_hash }) -> credits your treasury (idempotent).",
287
- " (fund_treasury is demo/testnet only and is disabled on the live rail.) Check get_treasury anytime.",
284
+ "2. Send USDC to it FROM your own verified wallet, then deposit({ tx_hash }) -> credits your treasury (idempotent). Check get_treasury anytime.",
288
285
  "",
289
286
  "POST + PAY (the single FCFS flow):",
290
287
  "3. post_task({ title, category, reward_usd, quantity, duration_min, difficulty }) -> returns { task, authIntent, deployFee }. reward_usd is the TOTAL budget; quantity is how many humans it pays (each unit must be >= $0.01). authIntent is the whole-budget authorization; deployFee is a SEPARATE non-refundable fee tx (2.5% USDC / 5% other token).",
@@ -305,5 +302,5 @@ const transport = new StdioServerTransport();
305
302
  await server.connect(transport);
306
303
  console.error(`CYBERDYNE MCP server running on stdio → ${config.apiUrl}` +
307
304
  (config.token ? "" : " (no key — run `npx cyberdyne-mcp onboard` to self-generate a wallet + key, or `login cyb_…`, or set CYBERDYNE_IDENTITY_TOKEN; networked tools error until then)") +
308
- ". Tools (14): onboard, list_categories, search_humans, get_treasury, fund_treasury, get_deposit_address, deposit, withdraw_treasury, post_task, authorize_task, get_task, review_submission, close_task, reclaim." +
305
+ ". Tools (13): onboard, list_categories, search_humans, get_treasury, get_deposit_address, deposit, withdraw_treasury, post_task, authorize_task, get_task, review_submission, close_task, reclaim." +
309
306
  " CLI: onboard, login, treasury (alias balance/fees), post, tasks.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberdyne-mcp",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -45,9 +45,7 @@
45
45
  "build": "tsc",
46
46
  "prepublishOnly": "npm run build",
47
47
  "start": "node dist/server.js",
48
- "dev": "tsx src/server.ts",
49
- "smoke": "tsx src/smoke.ts",
50
- "founder-check": "tsx src/founder-check.ts"
48
+ "dev": "tsx src/server.ts"
51
49
  },
52
50
  "engines": {
53
51
  "node": ">=18"
package/src/server.ts CHANGED
@@ -9,7 +9,6 @@
9
9
  * list_categories — the static task taxonomy (no network)
10
10
  * search_humans — POST /api/a2a {search_humans} → capability index
11
11
  * get_treasury — GET /api/treasury → the agent's balance
12
- * fund_treasury — POST /api/treasury/fund → demo top-up (testnet only)
13
12
  * get_deposit_address — GET /api/treasury/deposit → where to send real USDC (live)
14
13
  * deposit — POST /api/treasury/deposit → credit treasury from a real USDC tx
15
14
  * withdraw_treasury — POST /api/treasury/withdraw → pull unspent treasury back to your wallet (live)
@@ -170,7 +169,7 @@ async function guard<T>(fn: () => Promise<T>) {
170
169
 
171
170
  // ---- Server ---------------------------------------------------------------
172
171
 
173
- const server = new McpServer({ name: "cyberdyne", version: "0.6.4" });
172
+ const server = new McpServer({ name: "cyberdyne", version: "0.6.5" });
174
173
 
175
174
  server.tool(
176
175
  "list_categories",
@@ -220,19 +219,11 @@ server.tool(
220
219
 
221
220
  server.tool(
222
221
  "get_treasury",
223
- "Get the agent's own treasury (the source of task rewards on the manual rail). Returns null if the agent has no treasury yet — call fund_treasury to create one.",
222
+ "Get the agent's own treasury residual on-chain balance available to cover deploy fees and to withdraw. Fund it with REAL USDC via get_deposit_address + deposit. Returns null if the agent has no treasury yet.",
224
223
  {},
225
224
  async () => guard(() => client.rest("GET", "/api/treasury")),
226
225
  );
227
226
 
228
- server.tool(
229
- "fund_treasury",
230
- "Demo top-up (TESTNET/DEMO ONLY): add USD to the treasury balance. DISABLED when the platform is live (returns 403 funding_disabled) — on the live rail fund with REAL USDC via get_deposit_address + deposit instead.",
231
- { amount_usd: z.number().positive().describe("USD to add to the treasury balance.") },
232
- async ({ amount_usd }) =>
233
- guard(() => client.rest("POST", "/api/treasury/fund", { body: { amount_usd } })),
234
- );
235
-
236
227
  server.tool(
237
228
  "get_deposit_address",
238
229
  "Get the on-chain address to fund your treasury with REAL USDC (live rail). Returns { deposit_address, chain_id, usdc_address, decimals }. Send USDC from your VERIFIED wallet to deposit_address on Base, then call `deposit` with the tx hash to credit your treasury.",
@@ -242,7 +233,7 @@ server.tool(
242
233
 
243
234
  server.tool(
244
235
  "deposit",
245
- "Credit your treasury from a REAL on-chain USDC deposit (live rail; the real-money replacement for fund_treasury). First send USDC to the address from get_deposit_address (from your verified wallet), then call this with the transaction hash. The transfer is verified on-chain (to = platform wallet, from = your wallet) and credited exactly once — resubmitting the same tx never double-credits.",
236
+ "Credit your treasury from a REAL on-chain USDC deposit. First send USDC to the address from get_deposit_address (from your verified wallet), then call this with the transaction hash. The transfer is verified on-chain (to = platform wallet, from = your wallet) and credited exactly once — resubmitting the same tx never double-credits.",
246
237
  {
247
238
  tx_hash: z
248
239
  .string()
@@ -263,7 +254,7 @@ server.tool(
263
254
 
264
255
  server.tool(
265
256
  "post_task",
266
- "Open an FCFS pool bounty on the marketplace. There is NO direct hire and NO agent-picks-human — every task is an open bounty: you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission. Funds are NOT charged at post — the budget is frozen later at authorize_task. `reward_usd` is the total budget; `quantity` is how many identical units (humans) it pays — each unit holds reward_usd/quantity (each unit must be >= $0.01). Returns the created task (with its id). REAL-TOKEN POOL rail (USDC/BNKR on Base): the response also includes `authIntent` (the budget authorization to sign) and `deployFee` { usd, bps, recipient, token } (a SEPARATE non-refundable fee tx) — pass BOTH to authorize_task. TESTNET/non-real token (CYOS): no on-chain freeze; response is just { task } (treasury-checked, 402 insufficient_treasury if low).",
257
+ "Open an FCFS pool bounty on the marketplace. There is NO direct hire and NO agent-picks-human — every task is an open bounty: you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission. Funds are NOT charged at post — the budget is frozen later at authorize_task. `reward_usd` is the total budget; `quantity` is how many identical units (humans) it pays — each unit holds reward_usd/quantity (each unit must be >= $0.01). Returns the created task (with its id) plus `authIntent` (the budget authorization to sign) and `deployFee` { usd, bps, recipient, token } (a SEPARATE non-refundable fee tx) — pass BOTH to authorize_task. The non-custodial POOL escrow (USDC/BNKR/GITLAWB on Base) is the only settlement rail; a non-real token (CYOS) or non-live config has no rail and returns 422 settlement_unavailable.",
267
258
  {
268
259
  title: z.string().min(2).max(160).describe("Short task title."),
269
260
  category: z.enum(TASK_CATEGORIES),
@@ -281,7 +272,7 @@ server.tool(
281
272
 
282
273
  server.tool(
283
274
  "authorize_task",
284
- "Freeze the bounty budget on-chain (the second step of the FCFS flow). REAL-TOKEN POOL rail: pass BOTH `auth_intent` (the authIntent from post_task) AND `deploy_fee` (the deployFee object from post_task) — with CYBERDYNE_EVM_PRIVATE_KEY set, the MCP signs the whole-budget authorization AND pays the separate 2.5% USDC / 5% other-token deploy fee tx from its wallet, then freezes the budget on the audited escrow; or pass a pre-signed `signed_payment` and a pre-paid `fee_tx_hash`. After this, any eligible human submits FCFS and you review_submission each. TESTNET/non-real (CYOS) rail: call with just { task_id } the prefunded treasury opens a logical hold, no signature. Idempotent once frozen.",
275
+ "Freeze the bounty budget on-chain (the second step of the FCFS flow). REAL-TOKEN POOL rail: pass BOTH `auth_intent` (the authIntent from post_task) AND `deploy_fee` (the deployFee object from post_task) — with CYBERDYNE_EVM_PRIVATE_KEY set, the MCP signs the whole-budget authorization AND pays the separate 2.5% USDC / 5% other-token deploy fee tx from its wallet, then freezes the budget on the audited escrow; or pass a pre-signed `signed_payment` and a pre-paid `fee_tx_hash`. After this, any eligible human submits FCFS and you review_submission each. The non-custodial POOL escrow is the only rail; a non-real token / non-live config returns 409 settlement_unavailable. Idempotent once frozen.",
285
276
  {
286
277
  task_id: z.string().uuid(),
287
278
  signed_payment: z.string().optional().describe("Pre-signed base64 auth-capture payload (external/Bankr signer)."),
@@ -405,8 +396,7 @@ server.registerPrompt(
405
396
  "",
406
397
  "FUND (optional — the pool freezes from your wallet at deploy, but a treasury can cover fees):",
407
398
  "1. get_deposit_address -> the platform deposit address on Base.",
408
- "2. Send USDC to it FROM your own verified wallet, then deposit({ tx_hash }) -> credits your treasury (idempotent).",
409
- " (fund_treasury is demo/testnet only and is disabled on the live rail.) Check get_treasury anytime.",
399
+ "2. Send USDC to it FROM your own verified wallet, then deposit({ tx_hash }) -> credits your treasury (idempotent). Check get_treasury anytime.",
410
400
  "",
411
401
  "POST + PAY (the single FCFS flow):",
412
402
  "3. post_task({ title, category, reward_usd, quantity, duration_min, difficulty }) -> returns { task, authIntent, deployFee }. reward_usd is the TOTAL budget; quantity is how many humans it pays (each unit must be >= $0.01). authIntent is the whole-budget authorization; deployFee is a SEPARATE non-refundable fee tx (2.5% USDC / 5% other token).",
@@ -431,6 +421,6 @@ await server.connect(transport);
431
421
  console.error(
432
422
  `CYBERDYNE MCP server running on stdio → ${config.apiUrl}` +
433
423
  (config.token ? "" : " (no key — run `npx cyberdyne-mcp onboard` to self-generate a wallet + key, or `login cyb_…`, or set CYBERDYNE_IDENTITY_TOKEN; networked tools error until then)") +
434
- ". Tools (14): onboard, list_categories, search_humans, get_treasury, fund_treasury, get_deposit_address, deposit, withdraw_treasury, post_task, authorize_task, get_task, review_submission, close_task, reclaim." +
424
+ ". Tools (13): onboard, list_categories, search_humans, get_treasury, get_deposit_address, deposit, withdraw_treasury, post_task, authorize_task, get_task, review_submission, close_task, reclaim." +
435
425
  " CLI: onboard, login, treasury (alias balance/fees), post, tasks.",
436
426
  );
@@ -1,91 +0,0 @@
1
- /**
2
- * Example: a trading agent hires a human for a founder liveness check before it buys.
3
- *
4
- * A trading agent can run every on-chain check itself — but it can't tell whether
5
- * a real person is behind a token. Fake / impersonated / deepfaked teams are the
6
- * #1 token scam, and defeating a deepfake on a live call is something only a human
7
- * can do. So before a risky buy, the agent hires a human through CYBERDYNE to
8
- * video-verify the founder, then settles on a passing verify. This is the pattern
9
- * behind e.g. Bankr (https://bankr.bot) and any x402 trader.
10
- *
11
- * This drives the LIVE platform. Requires CYBERDYNE_IDENTITY_TOKEN (a cyb_ key);
12
- * optionally CYBERDYNE_API_URL. No key is hardcoded — it no-ops without one.
13
- *
14
- * CYBERDYNE_API_URL=http://localhost:3000 CYBERDYNE_IDENTITY_TOKEN=cyb_… \
15
- * npm run build && npm run founder-check
16
- */
17
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
18
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
19
- const token = process.env.CYBERDYNE_IDENTITY_TOKEN;
20
- if (!token) {
21
- console.log("founder-check: no-op. Set CYBERDYNE_IDENTITY_TOKEN (a cyb_ key) and optionally " +
22
- "CYBERDYNE_API_URL to run this example against the live platform.");
23
- process.exit(0);
24
- }
25
- const transport = new StdioClientTransport({
26
- command: "node",
27
- args: ["dist/server.js"],
28
- env: { ...process.env },
29
- });
30
- const client = new Client({ name: "trading-agent", version: "0" });
31
- await client.connect(transport);
32
- const call = async (name, args = {}) => {
33
- const r = await client.callTool({ name, arguments: args });
34
- const data = JSON.parse(r.content[0].text);
35
- if (r.isError)
36
- throw new Error(`${name} → ${data.error}`);
37
- return data;
38
- };
39
- console.log("[agent] connected to CYBERDYNE over MCP\n");
40
- // 0. Make sure the agent treasury can cover the bounty (demo top-up).
41
- const t = await call("get_treasury");
42
- if (Number(t.treasury?.balance_usd ?? 0) < 50) {
43
- await call("fund_treasury", { amount_usd: 100 });
44
- }
45
- // 1. The agent can't verify a real human is behind the token — find one who can.
46
- const found = await call("search_humans", { skills: ["groundtruth"], min_reputation: 4.8 });
47
- const human = found.humans[0];
48
- console.log(`search_humans(groundtruth, min_rep 4.8) -> ${found.humans.length} match`);
49
- if (human)
50
- console.log(` hiring ${human.handle} ${human.location} rep ${human.reputation}\n`);
51
- // 2. Post the founder liveness check. Not charged until authorize.
52
- const posted = await call("post_task", {
53
- title: "Founder liveness check on $PEPE2",
54
- category: "groundtruth",
55
- description: "Get the claimed founder on a short video call and confirm they're a real, specific " +
56
- "person — not an impersonator or deepfake — matched to a known reference. Return verified / not + notes.",
57
- steps: [
58
- "Live video matches a known reference",
59
- "Passes liveness / deepfake probes => verified; otherwise not-verified + reasons",
60
- ],
61
- reward_usd: 50,
62
- duration_min: 30,
63
- difficulty: "hard",
64
- deadline_hours: 2,
65
- });
66
- const taskId = posted.task.id;
67
- console.log(`post_task -> ${taskId} reward $${posted.task.reward_usd}`);
68
- // (search_humans is discovery only — there is NO direct hire. The task is an open
69
- // FCFS pool bounty: ANY eligible human submits first-come-first-served.)
70
- void human;
71
- // 3. Authorize — freeze the budget (POOL: authIntent + deployFee; manual: just task_id).
72
- const authd = await call("authorize_task", {
73
- task_id: taskId,
74
- ...(posted.authIntent ? { auth_intent: posted.authIntent } : {}),
75
- ...(posted.deployFee ? { deploy_fee: posted.deployFee } : {}),
76
- });
77
- console.log(`authorize_task -> escrow ${authd.task?.escrow_status}`);
78
- // 4. Poll until the human's proof is in (they submit in the app — human-only).
79
- const got = await call("get_task", { task_id: taskId });
80
- console.log(`get_task -> ${got.task.status} submissions ${got.submissions.length}`);
81
- // 5. If the proof is in, verify it and capture one unit to the human.
82
- const pending = (got.submissions ?? []).find((s) => s.status === "pending");
83
- if (pending) {
84
- const settled = await call("review_submission", { submission_id: pending.id, approve: true, score: 5 });
85
- console.log(`review_submission -> captured ${JSON.stringify(settled).slice(0, 80)}`);
86
- console.log("\n[agent] has a human verification it could not produce itself, and the contributor is paid.");
87
- }
88
- else {
89
- console.log("\n[agent] bounty is live and the budget is frozen; humans submit proof in the app FCFS, then the agent reviews each.");
90
- }
91
- await client.close();
package/dist/smoke.js DELETED
@@ -1,90 +0,0 @@
1
- /**
2
- * Live smoke test: drive the MCP server against the REAL platform API like an
3
- * agent would. Not shipped.
4
- *
5
- * Requires both env vars to run for real:
6
- * CYBERDYNE_API_URL e.g. http://localhost:3000 or https://app.cyberdyne-os.xyz
7
- * CYBERDYNE_IDENTITY_TOKEN the agent's cyb_ key
8
- * If either is missing it no-ops with a clear message (no key is ever hardcoded).
9
- *
10
- * The server inherits this process's env over stdio, so the same creds drive it.
11
- */
12
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
13
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
14
- const apiUrl = process.env.CYBERDYNE_API_URL;
15
- const token = process.env.CYBERDYNE_IDENTITY_TOKEN;
16
- if (!token) {
17
- console.log("smoke: no-op. Set CYBERDYNE_IDENTITY_TOKEN (a cyb_ key) and optionally " +
18
- "CYBERDYNE_API_URL to run the live flow against the platform.\n" +
19
- " e.g. CYBERDYNE_API_URL=http://localhost:3000 CYBERDYNE_IDENTITY_TOKEN=cyb_… npm run smoke");
20
- process.exit(0);
21
- }
22
- const transport = new StdioClientTransport({
23
- command: "node",
24
- args: ["dist/server.js"],
25
- env: { ...process.env },
26
- });
27
- const client = new Client({ name: "smoke", version: "0" });
28
- await client.connect(transport);
29
- const call = async (name, args = {}) => {
30
- const r = await client.callTool({ name, arguments: args });
31
- const data = JSON.parse(r.content[0].text);
32
- if (r.isError)
33
- throw new Error(`${name} → ${data.error}`);
34
- return data;
35
- };
36
- console.log(`smoke → ${apiUrl ?? "https://app.cyberdyne-os.xyz"}`);
37
- console.log("tools:", (await client.listTools()).tools.map((t) => t.name).join(", "));
38
- // 1. Categories (static, no network).
39
- const cats = await call("list_categories");
40
- console.log(`list_categories → ${cats.length} categories`);
41
- // 2. Treasury — ensure it can cover a small task; top up if needed.
42
- let treasury = await call("get_treasury");
43
- const balance = Number(treasury.treasury?.balance_usd ?? 0);
44
- console.log(`get_treasury → balance $${balance}`);
45
- if (balance < 5) {
46
- treasury = await call("fund_treasury", { amount_usd: 25 });
47
- console.log(`fund_treasury → balance $${treasury.treasury?.balance_usd}`);
48
- }
49
- // 3. Discover a human via the live capability index.
50
- const found = await call("search_humans", { skills: ["capture"] });
51
- console.log(`search_humans(capture) → ${found.humans.length} match`);
52
- const human = found.humans[0];
53
- // (search_humans is for discovery only — there is NO direct hire/assign. Every task
54
- // is an open FCFS pool bounty: post a budget, humans submit, you review each.)
55
- void human;
56
- // 4. Post an FCFS pool bounty. reward_usd is the budget; not charged until authorize.
57
- const posted = await call("post_task", {
58
- title: "Read 10 phrases (smoke)",
59
- category: "capture",
60
- description: "Record 10 short phrases clearly in a quiet room.",
61
- reward_usd: 3.5,
62
- duration_min: 10,
63
- difficulty: "easy",
64
- });
65
- const taskId = posted.task.id;
66
- console.log(`post_task → ${taskId} (status ${posted.task.status})`);
67
- // 5. Authorize — freeze the budget (POOL: pass authIntent + deployFee; manual: just task_id).
68
- const authd = await call("authorize_task", {
69
- task_id: taskId,
70
- ...(posted.authIntent ? { auth_intent: posted.authIntent } : {}),
71
- ...(posted.deployFee ? { deploy_fee: posted.deployFee } : {}),
72
- });
73
- console.log(`authorize_task → escrow_status ${authd.task?.escrow_status}`);
74
- // 6. Poll the live task. The human submits proof in the app (human-only), so on a
75
- // fresh task there is typically no submission yet — that is expected here.
76
- const got = await call("get_task", { task_id: taskId });
77
- console.log(`get_task → status ${got.task.status}, submissions ${got.submissions.length}, claims ${got.claims.length}`);
78
- const pending = (got.submissions ?? []).find((s) => s.status === "pending");
79
- if (pending) {
80
- const settled = await call("review_submission", { submission_id: pending.id, approve: true, score: 5 });
81
- console.log(`review_submission → captured one unit ${JSON.stringify(settled).slice(0, 80)}`);
82
- }
83
- else {
84
- console.log("review_submission → skipped: no pending submission yet (a human submits proof in the app). " +
85
- "Closing the task to refund the unfilled budget.");
86
- const closed = await call("close_task", { task_id: taskId });
87
- console.log(`close_task → status ${closed.task?.status ?? "closed"}`);
88
- }
89
- await client.close();
90
- console.log("OK");
@@ -1,103 +0,0 @@
1
- /**
2
- * Example: a trading agent hires a human for a founder liveness check before it buys.
3
- *
4
- * A trading agent can run every on-chain check itself — but it can't tell whether
5
- * a real person is behind a token. Fake / impersonated / deepfaked teams are the
6
- * #1 token scam, and defeating a deepfake on a live call is something only a human
7
- * can do. So before a risky buy, the agent hires a human through CYBERDYNE to
8
- * video-verify the founder, then settles on a passing verify. This is the pattern
9
- * behind e.g. Bankr (https://bankr.bot) and any x402 trader.
10
- *
11
- * This drives the LIVE platform. Requires CYBERDYNE_IDENTITY_TOKEN (a cyb_ key);
12
- * optionally CYBERDYNE_API_URL. No key is hardcoded — it no-ops without one.
13
- *
14
- * CYBERDYNE_API_URL=http://localhost:3000 CYBERDYNE_IDENTITY_TOKEN=cyb_… \
15
- * npm run build && npm run founder-check
16
- */
17
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
18
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
19
-
20
- const token = process.env.CYBERDYNE_IDENTITY_TOKEN;
21
- if (!token) {
22
- console.log(
23
- "founder-check: no-op. Set CYBERDYNE_IDENTITY_TOKEN (a cyb_ key) and optionally " +
24
- "CYBERDYNE_API_URL to run this example against the live platform.",
25
- );
26
- process.exit(0);
27
- }
28
-
29
- const transport = new StdioClientTransport({
30
- command: "node",
31
- args: ["dist/server.js"],
32
- env: { ...process.env } as Record<string, string>,
33
- });
34
- const client = new Client({ name: "trading-agent", version: "0" });
35
- await client.connect(transport);
36
-
37
- const call = async (name: string, args: Record<string, unknown> = {}) => {
38
- const r: any = await client.callTool({ name, arguments: args });
39
- const data = JSON.parse(r.content[0].text);
40
- if (r.isError) throw new Error(`${name} → ${data.error}`);
41
- return data;
42
- };
43
-
44
- console.log("[agent] connected to CYBERDYNE over MCP\n");
45
-
46
- // 0. Make sure the agent treasury can cover the bounty (demo top-up).
47
- const t = await call("get_treasury");
48
- if (Number(t.treasury?.balance_usd ?? 0) < 50) {
49
- await call("fund_treasury", { amount_usd: 100 });
50
- }
51
-
52
- // 1. The agent can't verify a real human is behind the token — find one who can.
53
- const found = await call("search_humans", { skills: ["groundtruth"], min_reputation: 4.8 });
54
- const human = found.humans[0];
55
- console.log(`search_humans(groundtruth, min_rep 4.8) -> ${found.humans.length} match`);
56
- if (human) console.log(` hiring ${human.handle} ${human.location} rep ${human.reputation}\n`);
57
-
58
- // 2. Post the founder liveness check. Not charged until authorize.
59
- const posted = await call("post_task", {
60
- title: "Founder liveness check on $PEPE2",
61
- category: "groundtruth",
62
- description:
63
- "Get the claimed founder on a short video call and confirm they're a real, specific " +
64
- "person — not an impersonator or deepfake — matched to a known reference. Return verified / not + notes.",
65
- steps: [
66
- "Live video matches a known reference",
67
- "Passes liveness / deepfake probes => verified; otherwise not-verified + reasons",
68
- ],
69
- reward_usd: 50,
70
- duration_min: 30,
71
- difficulty: "hard",
72
- deadline_hours: 2,
73
- });
74
- const taskId = posted.task.id;
75
- console.log(`post_task -> ${taskId} reward $${posted.task.reward_usd}`);
76
-
77
- // (search_humans is discovery only — there is NO direct hire. The task is an open
78
- // FCFS pool bounty: ANY eligible human submits first-come-first-served.)
79
- void human;
80
-
81
- // 3. Authorize — freeze the budget (POOL: authIntent + deployFee; manual: just task_id).
82
- const authd = await call("authorize_task", {
83
- task_id: taskId,
84
- ...(posted.authIntent ? { auth_intent: posted.authIntent } : {}),
85
- ...(posted.deployFee ? { deploy_fee: posted.deployFee } : {}),
86
- });
87
- console.log(`authorize_task -> escrow ${authd.task?.escrow_status}`);
88
-
89
- // 4. Poll until the human's proof is in (they submit in the app — human-only).
90
- const got = await call("get_task", { task_id: taskId });
91
- console.log(`get_task -> ${got.task.status} submissions ${got.submissions.length}`);
92
-
93
- // 5. If the proof is in, verify it and capture one unit to the human.
94
- const pending = (got.submissions ?? []).find((s: any) => s.status === "pending");
95
- if (pending) {
96
- const settled = await call("review_submission", { submission_id: pending.id, approve: true, score: 5 });
97
- console.log(`review_submission -> captured ${JSON.stringify(settled).slice(0, 80)}`);
98
- console.log("\n[agent] has a human verification it could not produce itself, and the contributor is paid.");
99
- } else {
100
- console.log("\n[agent] bounty is live and the budget is frozen; humans submit proof in the app FCFS, then the agent reviews each.");
101
- }
102
-
103
- await client.close();
package/src/smoke.ts DELETED
@@ -1,108 +0,0 @@
1
- /**
2
- * Live smoke test: drive the MCP server against the REAL platform API like an
3
- * agent would. Not shipped.
4
- *
5
- * Requires both env vars to run for real:
6
- * CYBERDYNE_API_URL e.g. http://localhost:3000 or https://app.cyberdyne-os.xyz
7
- * CYBERDYNE_IDENTITY_TOKEN the agent's cyb_ key
8
- * If either is missing it no-ops with a clear message (no key is ever hardcoded).
9
- *
10
- * The server inherits this process's env over stdio, so the same creds drive it.
11
- */
12
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
13
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
14
-
15
- const apiUrl = process.env.CYBERDYNE_API_URL;
16
- const token = process.env.CYBERDYNE_IDENTITY_TOKEN;
17
-
18
- if (!token) {
19
- console.log(
20
- "smoke: no-op. Set CYBERDYNE_IDENTITY_TOKEN (a cyb_ key) and optionally " +
21
- "CYBERDYNE_API_URL to run the live flow against the platform.\n" +
22
- " e.g. CYBERDYNE_API_URL=http://localhost:3000 CYBERDYNE_IDENTITY_TOKEN=cyb_… npm run smoke",
23
- );
24
- process.exit(0);
25
- }
26
-
27
- const transport = new StdioClientTransport({
28
- command: "node",
29
- args: ["dist/server.js"],
30
- env: { ...process.env } as Record<string, string>,
31
- });
32
- const client = new Client({ name: "smoke", version: "0" });
33
- await client.connect(transport);
34
-
35
- const call = async (name: string, args: Record<string, unknown> = {}) => {
36
- const r: any = await client.callTool({ name, arguments: args });
37
- const data = JSON.parse(r.content[0].text);
38
- if (r.isError) throw new Error(`${name} → ${data.error}`);
39
- return data;
40
- };
41
-
42
- console.log(`smoke → ${apiUrl ?? "https://app.cyberdyne-os.xyz"}`);
43
- console.log("tools:", (await client.listTools()).tools.map((t) => t.name).join(", "));
44
-
45
- // 1. Categories (static, no network).
46
- const cats = await call("list_categories");
47
- console.log(`list_categories → ${cats.length} categories`);
48
-
49
- // 2. Treasury — ensure it can cover a small task; top up if needed.
50
- let treasury = await call("get_treasury");
51
- const balance = Number(treasury.treasury?.balance_usd ?? 0);
52
- console.log(`get_treasury → balance $${balance}`);
53
- if (balance < 5) {
54
- treasury = await call("fund_treasury", { amount_usd: 25 });
55
- console.log(`fund_treasury → balance $${treasury.treasury?.balance_usd}`);
56
- }
57
-
58
- // 3. Discover a human via the live capability index.
59
- const found = await call("search_humans", { skills: ["capture"] });
60
- console.log(`search_humans(capture) → ${found.humans.length} match`);
61
- const human = found.humans[0];
62
-
63
- // (search_humans is for discovery only — there is NO direct hire/assign. Every task
64
- // is an open FCFS pool bounty: post a budget, humans submit, you review each.)
65
- void human;
66
-
67
- // 4. Post an FCFS pool bounty. reward_usd is the budget; not charged until authorize.
68
- const posted = await call("post_task", {
69
- title: "Read 10 phrases (smoke)",
70
- category: "capture",
71
- description: "Record 10 short phrases clearly in a quiet room.",
72
- reward_usd: 3.5,
73
- duration_min: 10,
74
- difficulty: "easy",
75
- });
76
- const taskId = posted.task.id;
77
- console.log(`post_task → ${taskId} (status ${posted.task.status})`);
78
-
79
- // 5. Authorize — freeze the budget (POOL: pass authIntent + deployFee; manual: just task_id).
80
- const authd = await call("authorize_task", {
81
- task_id: taskId,
82
- ...(posted.authIntent ? { auth_intent: posted.authIntent } : {}),
83
- ...(posted.deployFee ? { deploy_fee: posted.deployFee } : {}),
84
- });
85
- console.log(`authorize_task → escrow_status ${authd.task?.escrow_status}`);
86
-
87
- // 6. Poll the live task. The human submits proof in the app (human-only), so on a
88
- // fresh task there is typically no submission yet — that is expected here.
89
- const got = await call("get_task", { task_id: taskId });
90
- console.log(
91
- `get_task → status ${got.task.status}, submissions ${got.submissions.length}, claims ${got.claims.length}`,
92
- );
93
-
94
- const pending = (got.submissions ?? []).find((s: any) => s.status === "pending");
95
- if (pending) {
96
- const settled = await call("review_submission", { submission_id: pending.id, approve: true, score: 5 });
97
- console.log(`review_submission → captured one unit ${JSON.stringify(settled).slice(0, 80)}`);
98
- } else {
99
- console.log(
100
- "review_submission → skipped: no pending submission yet (a human submits proof in the app). " +
101
- "Closing the task to refund the unfilled budget.",
102
- );
103
- const closed = await call("close_task", { task_id: taskId });
104
- console.log(`close_task → status ${closed.task?.status ?? "closed"}`);
105
- }
106
-
107
- await client.close();
108
- console.log("OK");