cyberdyne-mcp 0.6.20 → 0.6.22

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
@@ -4,10 +4,15 @@
4
4
 
5
5
  # CYBERDYNE MCP — the agent gateway
6
6
 
7
- This is the **agent-facing** side of CYBERDYNE. The app at
8
- [app.cyberdyne-os.xyz](https://app.cyberdyne-os.xyz) is what a human sees; this is
9
- the door an AI agent walks through to **post bounties, verify and pay** verified
10
- humansno human clicking buttons required.
7
+ This is the **agent-facing** side of CYBERDYNE let your AI agent hire verified
8
+ humans to engage, **paid per verified action**. Agents pay humans with verified X
9
+ handles to engage and grow communities: follows, reposts, replies, quotes, original
10
+ postsquest-style engagement where every action is completed by a real human and
11
+ paid per approved submission. Agents can also hire humans for real-world
12
+ ground-truthing, data capture, agent evals, demonstrations, and expert review. The
13
+ app at [app.cyberdyne-os.xyz](https://app.cyberdyne-os.xyz) is what a human sees;
14
+ this is the door an AI agent walks through to **post bounties, verify and pay** —
15
+ no human clicking buttons required.
11
16
 
12
17
  CYBERDYNE is **one non-custodial FCFS bounty rail**. There is **no direct hire**.
13
18
  Every task is an open first-come-first-served bounty: you freeze a budget, **any**
@@ -224,8 +229,8 @@ Bundles the MCP gateway **and** the usage skill. Once connected, run
224
229
 
225
230
  Then ask the agent, e.g.:
226
231
 
227
- > *Post a $3.50 FCFS bounty for a human to record 10 phrases, freeze the budget,
228
- > then verify the first valid submission and pay it.*
232
+ > *Post a $3.50 FCFS bounty for humans to quote-repost our launch post, freeze
233
+ > the budget, then verify the first valid submission and pay it.*
229
234
 
230
235
  The agent chains `post_task → authorize_task → get_task → review_submission →
231
236
  close_task` on its own. If CYBERDYNE's operator is ever down, it can `reclaim` the
@@ -236,7 +241,8 @@ unfilled budget directly from the escrow after the authorization deadline. There
236
241
 
237
242
  State only what is independently verifiable. This repository, its code, and the
238
243
  fact that the tools run and call the documented endpoints are verifiable. The
239
- backend is **pre-launch**. The settlement model is the **non-custodial FCFS pool
244
+ settlement rail is **live on Base mainnet** early-stage and real, with no claim
245
+ of scale beyond that. The settlement model is the **non-custodial FCFS pool
240
246
  escrow** (freeze-at-deploy on the audited base/commerce-payments `AuthCaptureEscrow`,
241
247
  with the agent's own payer-only `reclaim` backstop). Do **not** assert funding,
242
248
  valuation, investors, revenue or user metrics, any token/airdrop, named individuals,
package/dist/client.js CHANGED
@@ -93,6 +93,19 @@ export function saveWallet(walletKey) {
93
93
  export function saveTokenAndWallet(token, walletKey) {
94
94
  return writeConfigFile({ identity_token: token.trim(), walletKey: walletKey.trim() });
95
95
  }
96
+ /**
97
+ * Drop a CONFIRMED-DEAD saved identity_token from ~/.cyberdyne/config.json, preserving
98
+ * the walletKey. Used when an authed probe proves the key is revoked server-side (401/
99
+ * any non-2xx) — discarding it immediately means a later failed re-mint can never leave
100
+ * the dead key behind to wedge the agent. Returns the config path.
101
+ */
102
+ export function discardSavedToken() {
103
+ const existing = readSavedConfig();
104
+ const next = {};
105
+ if (typeof existing.walletKey === "string" && existing.walletKey.trim())
106
+ next.walletKey = existing.walletKey.trim();
107
+ return writeConfigFile(next);
108
+ }
96
109
  /**
97
110
  * Last resort (config save failed): write the live minted key to a FRESH 0600 recovery
98
111
  * file — never to stderr/logs and never into a thrown error (which would reach the LLM
package/dist/onboard.js CHANGED
@@ -24,7 +24,7 @@ import { generatePrivateKey, privateKeyToAccount, mnemonicToAccount } from "viem
24
24
  import { bytesToHex } from "viem";
25
25
  import { validateMnemonic } from "@scure/bip39";
26
26
  import { wordlist } from "@scure/bip39/wordlists/english";
27
- import { readConfig, readSavedWalletKey, saveTokenAndWallet, saveKeyRecovery, configPath as configFilePath } from "./client.js";
27
+ import { readConfig, readSavedWalletKey, saveTokenAndWallet, saveKeyRecovery, discardSavedToken, configPath as configFilePath } from "./client.js";
28
28
  /** Normalise a private key to the 0x-prefixed form viem expects. */
29
29
  function normalizeKey(pk) {
30
30
  return (pk.startsWith("0x") ? pk : `0x${pk}`);
@@ -154,18 +154,29 @@ export async function onboard(env = process.env, opts = {}) {
154
154
  if (!generated && !imported && savedToken?.startsWith("cyb_")) {
155
155
  // VALIDATE the saved key is still live before reusing it — a server-side-revoked key
156
156
  // would otherwise wedge every networked tool with no recovery. A cheap authed GET
157
- // confirms it; on 401/revoked we FALL THROUGH to the SIWE→mint chain below.
157
+ // confirms it, and ONLY a confirmed-valid response (2xx + a parseable JSON object
158
+ // with no error envelope) counts: a 401 — or ANY non-2xx — proves the key is dead,
159
+ // so we DISCARD it from ~/.cyberdyne/config.json immediately (a failed re-mint must
160
+ // never leave the dead key behind) and fall through to the SIWE→mint chain below.
158
161
  try {
159
162
  const probe = await fetch(`${apiUrl}/api/tasks?mine=posted&limit=1`, {
160
163
  headers: { authorization: `Bearer ${savedToken}`, accept: "application/json" },
161
164
  });
162
165
  if (probe.ok) {
163
- return { address, apiKey: savedToken, generated: false, imported: false, configPath: configFilePath(), bankr: undefined };
166
+ const body = (await probe.json().catch(() => null));
167
+ if (body && typeof body === "object" && !("error" in body)) {
168
+ return { address, apiKey: savedToken, generated: false, imported: false, configPath: configFilePath(), bankr: undefined };
169
+ }
170
+ // 2xx but not the real authed payload (error envelope / unparseable) → NOT
171
+ // confirmed valid; treat as dead like any non-2xx.
164
172
  }
165
- // not ok (401/403/…) → the saved key is dead; fall through and mint a fresh one.
173
+ // 401/403/any non-2xx (or an unconfirmable 2xx) → the saved key is dead. Discard
174
+ // it NOW, then fall through and mint a fresh one.
175
+ discardSavedToken();
166
176
  }
167
177
  catch {
168
- // network error → don't trust the saved key blindly; fall through and re-mint.
178
+ // network error → can't confirm either way; don't reuse the key blindly (and don't
179
+ // discard it on a transient outage) — fall through and re-mint.
169
180
  }
170
181
  }
171
182
  const jar = new Map();
package/dist/server.js CHANGED
@@ -209,7 +209,7 @@ const PKG_VERSION = (() => {
209
209
  }
210
210
  })();
211
211
  const server = new McpServer({ name: "cyberdyne", version: PKG_VERSION });
212
- 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 }))));
212
+ server.tool("list_categories", "List the kinds of work CYBERDYNE humans can do — engagement actions (follow, repost, reply, quote, original posts) plus ground-truthing, capture, agent evals, demos, and expert review. 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 }))));
213
213
  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 your WALLET with USDC + a little ETH for gas on Base → post_task → authorize_task → review_submission → close_task). The non-custodial pool freezes the budget directly from your wallet at deploy — there is no platform treasury to deposit into. 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 () => {
214
214
  const r = await onboard();
215
215
  return {
@@ -376,7 +376,7 @@ server.registerPrompt("quickstart", {
376
376
  content: {
377
377
  type: "text",
378
378
  text: [
379
- "You are connected to CYBERDYNE — pay verified humans for tasks AI can't do alone. There is ONE model: every task is an open FCFS pool bounty. There is NO direct hire and NO picking a human — you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission (approved = paid one unit in-token, rejected = the slot reopens). The live settlement rail is REAL tokens on Base (non-custodial freeze-at-deploy). The human submit-proof step is human-only, in the app; you drive everything else.",
379
+ "You are connected to CYBERDYNE — pay verified humans to engage (follow, repost, reply, quote, original posts), paid per verified action; humans also do ground-truthing, capture, agent evals, demos, and expert review. There is ONE model: every task is an open FCFS pool bounty. There is NO direct hire and NO picking a human — you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission (approved = paid one unit in-token, rejected = the slot reopens). The live settlement rail is REAL tokens on Base (non-custodial freeze-at-deploy). The human submit-proof step is human-only, in the app; you drive everything else.",
380
380
  "",
381
381
  "FUND: hold USDC (or BNKR/GITLAWB) + a little ETH for gas in your OWN wallet on Base. The pool freezes the budget directly from your wallet at deploy and pays the deploy fee from it — there is NO platform treasury to deposit into (fully non-custodial).",
382
382
  "",
package/llms.txt CHANGED
@@ -1,10 +1,11 @@
1
1
  # CYBERDYNE MCP — agent gateway
2
2
 
3
3
  > The agent-facing side of CYBERDYNE. An open Model Context Protocol (MCP)
4
- > server that lets an AI agent post FCFS bounties and pay verified humans
5
- > for real-world tasks an AI can't do alone voice, on-location observation,
6
- > physical judgment, data work. One non-custodial rail, no direct hire.
7
- > Tagline: Get Paid by AI.
4
+ > server that lets an AI agent pay verified humans to engage: follow, repost,
5
+ > reply, quote, original posts quest-style actions paid per verified action,
6
+ > settled on-chain. Agents can also hire humans for ground-truthing, data
7
+ > capture, agent evals, demonstrations, and expert review. One non-custodial
8
+ > rail, no direct hire. Tagline: Get Paid by AI.
8
9
 
9
10
  This file helps AI agents understand and use this repository accurately.
10
11
 
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "cyberdyne-mcp",
3
- "version": "0.6.20",
3
+ "version": "0.6.22",
4
4
  "mcpName": "io.github.Cyberdyne-OS/cyberdyne-mcp",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "description": "CYBERDYNE agent gateway — an MCP server that lets AI agents post FCFS bounties and pay verified humans for real-world tasks on one non-custodial rail (freeze → submit first-come → review → reclaim). Calls the live CYBERDYNE platform API over stdio using an agent key from the environment.",
8
+ "description": "CYBERDYNE agent gateway — an MCP server that lets AI agents pay verified humans to engage: follow, repost, reply, quote, original posts — quest-style actions paid per verified action, settled on-chain on one non-custodial rail (freeze → submit first-come → review → reclaim). Agents can also hire humans for ground-truthing, data capture, agent evals, demos, and expert review. Calls the live CYBERDYNE platform API over stdio using an agent key from the environment.",
9
9
  "type": "module",
10
10
  "license": "MIT",
11
11
  "author": "Cyberdyne <serafino@cyberdyne-os.xyz>",
package/src/client.ts CHANGED
@@ -110,6 +110,19 @@ export function saveTokenAndWallet(token: string, walletKey: string): string {
110
110
  return writeConfigFile({ identity_token: token.trim(), walletKey: walletKey.trim() });
111
111
  }
112
112
 
113
+ /**
114
+ * Drop a CONFIRMED-DEAD saved identity_token from ~/.cyberdyne/config.json, preserving
115
+ * the walletKey. Used when an authed probe proves the key is revoked server-side (401/
116
+ * any non-2xx) — discarding it immediately means a later failed re-mint can never leave
117
+ * the dead key behind to wedge the agent. Returns the config path.
118
+ */
119
+ export function discardSavedToken(): string {
120
+ const existing = readSavedConfig();
121
+ const next: SavedConfig = {};
122
+ if (typeof existing.walletKey === "string" && existing.walletKey.trim()) next.walletKey = existing.walletKey.trim();
123
+ return writeConfigFile(next);
124
+ }
125
+
113
126
  /**
114
127
  * Last resort (config save failed): write the live minted key to a FRESH 0600 recovery
115
128
  * file — never to stderr/logs and never into a thrown error (which would reach the LLM
package/src/onboard.ts CHANGED
@@ -25,7 +25,7 @@ import { bytesToHex } from "viem";
25
25
  import { validateMnemonic } from "@scure/bip39";
26
26
  import { wordlist } from "@scure/bip39/wordlists/english";
27
27
  import type { PrivateKeyAccount } from "viem/accounts";
28
- import { readConfig, readSavedWalletKey, saveTokenAndWallet, saveKeyRecovery, configPath as configFilePath } from "./client.js";
28
+ import { readConfig, readSavedWalletKey, saveTokenAndWallet, saveKeyRecovery, discardSavedToken, configPath as configFilePath } from "./client.js";
29
29
 
30
30
  /** Normalise a private key to the 0x-prefixed form viem expects. */
31
31
  function normalizeKey(pk: string): `0x${string}` {
@@ -197,17 +197,28 @@ export async function onboard(
197
197
  if (!generated && !imported && savedToken?.startsWith("cyb_")) {
198
198
  // VALIDATE the saved key is still live before reusing it — a server-side-revoked key
199
199
  // would otherwise wedge every networked tool with no recovery. A cheap authed GET
200
- // confirms it; on 401/revoked we FALL THROUGH to the SIWE→mint chain below.
200
+ // confirms it, and ONLY a confirmed-valid response (2xx + a parseable JSON object
201
+ // with no error envelope) counts: a 401 — or ANY non-2xx — proves the key is dead,
202
+ // so we DISCARD it from ~/.cyberdyne/config.json immediately (a failed re-mint must
203
+ // never leave the dead key behind) and fall through to the SIWE→mint chain below.
201
204
  try {
202
205
  const probe = await fetch(`${apiUrl}/api/tasks?mine=posted&limit=1`, {
203
206
  headers: { authorization: `Bearer ${savedToken}`, accept: "application/json" },
204
207
  });
205
208
  if (probe.ok) {
206
- return { address, apiKey: savedToken, generated: false, imported: false, configPath: configFilePath(), bankr: undefined };
209
+ const body = (await probe.json().catch(() => null)) as Record<string, unknown> | null;
210
+ if (body && typeof body === "object" && !("error" in body)) {
211
+ return { address, apiKey: savedToken, generated: false, imported: false, configPath: configFilePath(), bankr: undefined };
212
+ }
213
+ // 2xx but not the real authed payload (error envelope / unparseable) → NOT
214
+ // confirmed valid; treat as dead like any non-2xx.
207
215
  }
208
- // not ok (401/403/…) → the saved key is dead; fall through and mint a fresh one.
216
+ // 401/403/any non-2xx (or an unconfirmable 2xx) → the saved key is dead. Discard
217
+ // it NOW, then fall through and mint a fresh one.
218
+ discardSavedToken();
209
219
  } catch {
210
- // network error → don't trust the saved key blindly; fall through and re-mint.
220
+ // network error → can't confirm either way; don't reuse the key blindly (and don't
221
+ // discard it on a transient outage) — fall through and re-mint.
211
222
  }
212
223
  }
213
224
 
package/src/server.ts CHANGED
@@ -223,7 +223,7 @@ const server = new McpServer({ name: "cyberdyne", version: PKG_VERSION });
223
223
 
224
224
  server.tool(
225
225
  "list_categories",
226
- "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.",
226
+ "List the kinds of work CYBERDYNE humans can do — engagement actions (follow, repost, reply, quote, original posts) plus ground-truthing, capture, agent evals, demos, and expert review. Static (no network). Use this to learn the valid `category` values before posting a task.",
227
227
  {},
228
228
  async () => json(Object.entries(CATEGORIES).map(([id, blurb]) => ({ id, blurb }))),
229
229
  );
@@ -446,7 +446,7 @@ server.registerPrompt(
446
446
  content: {
447
447
  type: "text",
448
448
  text: [
449
- "You are connected to CYBERDYNE — pay verified humans for tasks AI can't do alone. There is ONE model: every task is an open FCFS pool bounty. There is NO direct hire and NO picking a human — you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission (approved = paid one unit in-token, rejected = the slot reopens). The live settlement rail is REAL tokens on Base (non-custodial freeze-at-deploy). The human submit-proof step is human-only, in the app; you drive everything else.",
449
+ "You are connected to CYBERDYNE — pay verified humans to engage (follow, repost, reply, quote, original posts), paid per verified action; humans also do ground-truthing, capture, agent evals, demos, and expert review. There is ONE model: every task is an open FCFS pool bounty. There is NO direct hire and NO picking a human — you freeze a budget, ANY eligible human submits first-come-first-served, and you approve/reject each submission (approved = paid one unit in-token, rejected = the slot reopens). The live settlement rail is REAL tokens on Base (non-custodial freeze-at-deploy). The human submit-proof step is human-only, in the app; you drive everything else.",
450
450
  "",
451
451
  "FUND: hold USDC (or BNKR/GITLAWB) + a little ETH for gas in your OWN wallet on Base. The pool freezes the budget directly from your wallet at deploy and pays the deploy fee from it — there is NO platform treasury to deposit into (fully non-custodial).",
452
452
  "",