cyberdyne-mcp 0.6.6 → 0.6.7
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/onboard.js +47 -10
- package/dist/server.js +4 -1
- package/package.json +1 -1
- package/src/onboard.ts +52 -11
- package/src/server.ts +4 -1
package/dist/onboard.js
CHANGED
|
@@ -180,17 +180,39 @@ export async function onboard(env = process.env, opts = {}) {
|
|
|
180
180
|
}
|
|
181
181
|
// 5. persist BOTH the token and the wallet key atomically (0600)
|
|
182
182
|
const configPath = saveTokenAndWallet(apiKey, privateKey);
|
|
183
|
-
|
|
183
|
+
// 6. (optional) auto-link Bankr — zero human interaction. If a bk_ key is supplied
|
|
184
|
+
// (opts or CYBERDYNE_BANKR_KEY), use it ONCE to connect the agent's Bankr project
|
|
185
|
+
// via the fresh cyb_ key. Best-effort: a failure never blocks onboarding, and the
|
|
186
|
+
// bk_ key is never stored (the backend uses it once and discards it).
|
|
187
|
+
let bankr;
|
|
188
|
+
const bankrKey = (opts.bankrKey ?? env.CYBERDYNE_BANKR_KEY ?? "").trim();
|
|
189
|
+
if (bankrKey.startsWith("bk_")) {
|
|
190
|
+
try {
|
|
191
|
+
const res = await fetch(`${apiUrl}/api/bankr/connect`, {
|
|
192
|
+
method: "POST",
|
|
193
|
+
headers: { "content-type": "application/json", accept: "application/json", authorization: `Bearer ${apiKey}` },
|
|
194
|
+
body: JSON.stringify({ bk_key: bankrKey }),
|
|
195
|
+
});
|
|
196
|
+
const j = (await res.json().catch(() => null));
|
|
197
|
+
bankr = res.ok && j?.ok
|
|
198
|
+
? { connected: true, project: j.project?.projectName ?? null, hint: j.hint }
|
|
199
|
+
: { connected: false, hint: j?.hint ?? `connect failed (${res.status})` };
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
bankr = { connected: false, hint: e instanceof Error ? e.message : "bankr connect error" };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return { address, apiKey, generated, imported, configPath, bankr };
|
|
184
206
|
}
|
|
185
207
|
/** The multi-line "next steps" block shared by the CLI + the MCP tool. */
|
|
186
208
|
export function nextStepsText() {
|
|
187
209
|
return [
|
|
188
210
|
"Next steps (no dashboard needed):",
|
|
189
|
-
" 1.
|
|
190
|
-
" 2. post_task({ title, category, reward_usd, quantity
|
|
211
|
+
" 1. Fund THIS wallet with USDC (or BNKR/GITLAWB) + a little ETH for gas on Base — the non-custodial pool freezes the budget directly from your wallet (there is no platform treasury).",
|
|
212
|
+
" 2. post_task({ title, category, reward_usd, quantity }) → returns the budget authorization + the deploy fee.",
|
|
191
213
|
" 3. authorize_task (sign budget + pay deploy fee + freeze) → humans submit FCFS → poll get_task.",
|
|
192
214
|
" 4. review_submission per pending submission (approve pays a unit; reject reopens it) → close_task refunds the rest.",
|
|
193
|
-
"The same wallet auto-signs pool budgets
|
|
215
|
+
"The same wallet auto-signs pool budgets. Trustless backstop: `reclaim` recovers an unfilled budget yourself after the deadline.",
|
|
194
216
|
].join("\n");
|
|
195
217
|
}
|
|
196
218
|
// ── CLI front-end for `onboard` (import / create / prompt) ───────────────────
|
|
@@ -201,11 +223,12 @@ export function nextStepsText() {
|
|
|
201
223
|
// --import (no value) read the secret from stdin (piped) or CYBERDYNE_IMPORT_KEY
|
|
202
224
|
// --create force a fresh wallet
|
|
203
225
|
// (none, interactive TTY) prompt: paste a key/mnemonic, or press enter to create
|
|
204
|
-
/** Tiny flag reader for the onboard args (
|
|
226
|
+
/** Tiny flag reader for the onboard args (`--import`, `--import=x`, `--create`, `--bankr`). */
|
|
205
227
|
function parseOnboardFlags(argv) {
|
|
206
228
|
let importFlag = false;
|
|
207
229
|
let importValue;
|
|
208
230
|
let create = false;
|
|
231
|
+
let bankrValue;
|
|
209
232
|
for (let i = 0; i < argv.length; i++) {
|
|
210
233
|
const tok = argv[i];
|
|
211
234
|
if (tok === "--create")
|
|
@@ -222,8 +245,18 @@ function parseOnboardFlags(argv) {
|
|
|
222
245
|
importFlag = true;
|
|
223
246
|
importValue = tok.slice("--import=".length);
|
|
224
247
|
}
|
|
248
|
+
else if (tok === "--bankr") {
|
|
249
|
+
const next = argv[i + 1];
|
|
250
|
+
if (next !== undefined && !next.startsWith("--")) {
|
|
251
|
+
bankrValue = next;
|
|
252
|
+
i++;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else if (tok.startsWith("--bankr=")) {
|
|
256
|
+
bankrValue = tok.slice("--bankr=".length);
|
|
257
|
+
}
|
|
225
258
|
}
|
|
226
|
-
return { importFlag, importValue, create };
|
|
259
|
+
return { importFlag, importValue, create, bankrValue };
|
|
227
260
|
}
|
|
228
261
|
/** Read a single line from stdin (used for the interactive import/create prompt). */
|
|
229
262
|
function promptLine(question) {
|
|
@@ -244,6 +277,8 @@ export const ONBOARD_USAGE = [
|
|
|
244
277
|
" CYBERDYNE_IMPORT_KEY=0x<key> npx cyberdyne-mcp onboard --import",
|
|
245
278
|
" (passing it as an argument leaves the secret in your shell history.)",
|
|
246
279
|
" --create generate a fresh wallet (default in a non-interactive / CI shell).",
|
|
280
|
+
" --bankr <bk_key> auto-link your Bankr project at onboard (or set CYBERDYNE_BANKR_KEY).",
|
|
281
|
+
" The bk_ key is used ONCE server-side and never stored.",
|
|
247
282
|
" (no flag, in a terminal) you'll be prompted: paste a key/mnemonic, or press enter to create.",
|
|
248
283
|
"",
|
|
249
284
|
"Either way: SIWE sign-in → mint your cyb_ key → save wallet + key to ~/.cyberdyne/config.json (0600).",
|
|
@@ -254,9 +289,11 @@ export const ONBOARD_USAGE = [
|
|
|
254
289
|
* piped stdin (with --import) → CYBERDYNE_IMPORT_KEY → --import <value> argv → TTY prompt.
|
|
255
290
|
*/
|
|
256
291
|
export async function onboardCli(argv, env = process.env) {
|
|
257
|
-
const { importFlag, importValue, create } = parseOnboardFlags(argv);
|
|
292
|
+
const { importFlag, importValue, create, bankrValue } = parseOnboardFlags(argv);
|
|
293
|
+
// Bankr auto-link key: --bankr <bk_…> (or env CYBERDYNE_BANKR_KEY, read inside onboard()).
|
|
294
|
+
const bankrKey = bankrValue?.trim() || undefined;
|
|
258
295
|
if (create)
|
|
259
|
-
return onboard(env, { forceCreate: true });
|
|
296
|
+
return onboard(env, { forceCreate: true, bankrKey });
|
|
260
297
|
// Determine the import secret, if the user asked to import.
|
|
261
298
|
let secret;
|
|
262
299
|
let fromArgv = false;
|
|
@@ -300,7 +337,7 @@ export async function onboardCli(argv, env = process.env) {
|
|
|
300
337
|
if (secret) {
|
|
301
338
|
// Validate early with a clear error before any network call.
|
|
302
339
|
privateKeyFromSecret(secret);
|
|
303
|
-
return onboard(env, { importSecret: secret });
|
|
340
|
+
return onboard(env, { importSecret: secret, bankrKey });
|
|
304
341
|
}
|
|
305
|
-
return onboard(env); // create / reuse-saved, as before
|
|
342
|
+
return onboard(env, { bankrKey }); // create / reuse-saved, as before
|
|
306
343
|
}
|
package/dist/server.js
CHANGED
|
@@ -70,6 +70,9 @@ if (process.argv[2] === "onboard") {
|
|
|
70
70
|
: r.imported
|
|
71
71
|
? `\n (your imported wallet private key was saved to ${r.configPath}; keep that file safe)`
|
|
72
72
|
: "") +
|
|
73
|
+
(r.bankr
|
|
74
|
+
? `\n Bankr : ${r.bankr.connected ? `connected${r.bankr.project ? ` · ${r.bankr.project}` : ""}` : "not connected"}${r.bankr.hint ? ` (${r.bankr.hint})` : ""}`
|
|
75
|
+
: "") +
|
|
73
76
|
`\n\n${nextStepsText()}` +
|
|
74
77
|
`\n\nThis MCP is already configured for this agent — networked tools will use the saved key.`);
|
|
75
78
|
process.exit(0);
|
|
@@ -148,7 +151,7 @@ async function guard(fn) {
|
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
// ---- Server ---------------------------------------------------------------
|
|
151
|
-
const server = new McpServer({ name: "cyberdyne", version: "0.6.
|
|
154
|
+
const server = new McpServer({ name: "cyberdyne", version: "0.6.7" });
|
|
152
155
|
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 }))));
|
|
153
156
|
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 () => {
|
|
154
157
|
const r = await onboard();
|
package/package.json
CHANGED
package/src/onboard.ts
CHANGED
|
@@ -137,6 +137,8 @@ export interface OnboardResult {
|
|
|
137
137
|
generated: boolean;
|
|
138
138
|
imported: boolean;
|
|
139
139
|
configPath: string;
|
|
140
|
+
/** Bankr auto-link outcome, when a bk_ key was supplied. Absent if none. */
|
|
141
|
+
bankr?: { connected: boolean; project?: string | null; hint?: string };
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
export interface OnboardOptions {
|
|
@@ -144,6 +146,10 @@ export interface OnboardOptions {
|
|
|
144
146
|
importSecret?: string;
|
|
145
147
|
/** Force a brand-new wallet even if env/config already has one (`onboard --create`). */
|
|
146
148
|
forceCreate?: boolean;
|
|
149
|
+
/** Optional Bankr `bk_` key: auto-link the agent's Bankr project at onboard, zero
|
|
150
|
+
* human interaction. Used ONCE to call POST /api/bankr/connect with the fresh cyb_
|
|
151
|
+
* key; never stored. Falls back to env CYBERDYNE_BANKR_KEY. */
|
|
152
|
+
bankrKey?: string;
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
/**
|
|
@@ -223,18 +229,40 @@ export async function onboard(
|
|
|
223
229
|
// 5. persist BOTH the token and the wallet key atomically (0600)
|
|
224
230
|
const configPath = saveTokenAndWallet(apiKey, privateKey);
|
|
225
231
|
|
|
226
|
-
|
|
232
|
+
// 6. (optional) auto-link Bankr — zero human interaction. If a bk_ key is supplied
|
|
233
|
+
// (opts or CYBERDYNE_BANKR_KEY), use it ONCE to connect the agent's Bankr project
|
|
234
|
+
// via the fresh cyb_ key. Best-effort: a failure never blocks onboarding, and the
|
|
235
|
+
// bk_ key is never stored (the backend uses it once and discards it).
|
|
236
|
+
let bankr: OnboardResult["bankr"];
|
|
237
|
+
const bankrKey = (opts.bankrKey ?? env.CYBERDYNE_BANKR_KEY ?? "").trim();
|
|
238
|
+
if (bankrKey.startsWith("bk_")) {
|
|
239
|
+
try {
|
|
240
|
+
const res = await fetch(`${apiUrl}/api/bankr/connect`, {
|
|
241
|
+
method: "POST",
|
|
242
|
+
headers: { "content-type": "application/json", accept: "application/json", authorization: `Bearer ${apiKey}` },
|
|
243
|
+
body: JSON.stringify({ bk_key: bankrKey }),
|
|
244
|
+
});
|
|
245
|
+
const j = (await res.json().catch(() => null)) as { ok?: boolean; project?: { projectName?: string } | null; hint?: string } | null;
|
|
246
|
+
bankr = res.ok && j?.ok
|
|
247
|
+
? { connected: true, project: j.project?.projectName ?? null, hint: j.hint }
|
|
248
|
+
: { connected: false, hint: j?.hint ?? `connect failed (${res.status})` };
|
|
249
|
+
} catch (e) {
|
|
250
|
+
bankr = { connected: false, hint: e instanceof Error ? e.message : "bankr connect error" };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { address, apiKey, generated, imported, configPath, bankr };
|
|
227
255
|
}
|
|
228
256
|
|
|
229
257
|
/** The multi-line "next steps" block shared by the CLI + the MCP tool. */
|
|
230
258
|
export function nextStepsText(): string {
|
|
231
259
|
return [
|
|
232
260
|
"Next steps (no dashboard needed):",
|
|
233
|
-
" 1.
|
|
234
|
-
" 2. post_task({ title, category, reward_usd, quantity
|
|
261
|
+
" 1. Fund THIS wallet with USDC (or BNKR/GITLAWB) + a little ETH for gas on Base — the non-custodial pool freezes the budget directly from your wallet (there is no platform treasury).",
|
|
262
|
+
" 2. post_task({ title, category, reward_usd, quantity }) → returns the budget authorization + the deploy fee.",
|
|
235
263
|
" 3. authorize_task (sign budget + pay deploy fee + freeze) → humans submit FCFS → poll get_task.",
|
|
236
264
|
" 4. review_submission per pending submission (approve pays a unit; reject reopens it) → close_task refunds the rest.",
|
|
237
|
-
"The same wallet auto-signs pool budgets
|
|
265
|
+
"The same wallet auto-signs pool budgets. Trustless backstop: `reclaim` recovers an unfilled budget yourself after the deadline.",
|
|
238
266
|
].join("\n");
|
|
239
267
|
}
|
|
240
268
|
|
|
@@ -247,11 +275,12 @@ export function nextStepsText(): string {
|
|
|
247
275
|
// --create force a fresh wallet
|
|
248
276
|
// (none, interactive TTY) prompt: paste a key/mnemonic, or press enter to create
|
|
249
277
|
|
|
250
|
-
/** Tiny flag reader for the onboard args (
|
|
251
|
-
function parseOnboardFlags(argv: string[]): { importFlag: boolean; importValue?: string; create: boolean } {
|
|
278
|
+
/** Tiny flag reader for the onboard args (`--import`, `--import=x`, `--create`, `--bankr`). */
|
|
279
|
+
function parseOnboardFlags(argv: string[]): { importFlag: boolean; importValue?: string; create: boolean; bankrValue?: string } {
|
|
252
280
|
let importFlag = false;
|
|
253
281
|
let importValue: string | undefined;
|
|
254
282
|
let create = false;
|
|
283
|
+
let bankrValue: string | undefined;
|
|
255
284
|
for (let i = 0; i < argv.length; i++) {
|
|
256
285
|
const tok = argv[i];
|
|
257
286
|
if (tok === "--create") create = true;
|
|
@@ -265,9 +294,17 @@ function parseOnboardFlags(argv: string[]): { importFlag: boolean; importValue?:
|
|
|
265
294
|
} else if (tok.startsWith("--import=")) {
|
|
266
295
|
importFlag = true;
|
|
267
296
|
importValue = tok.slice("--import=".length);
|
|
297
|
+
} else if (tok === "--bankr") {
|
|
298
|
+
const next = argv[i + 1];
|
|
299
|
+
if (next !== undefined && !next.startsWith("--")) {
|
|
300
|
+
bankrValue = next;
|
|
301
|
+
i++;
|
|
302
|
+
}
|
|
303
|
+
} else if (tok.startsWith("--bankr=")) {
|
|
304
|
+
bankrValue = tok.slice("--bankr=".length);
|
|
268
305
|
}
|
|
269
306
|
}
|
|
270
|
-
return { importFlag, importValue, create };
|
|
307
|
+
return { importFlag, importValue, create, bankrValue };
|
|
271
308
|
}
|
|
272
309
|
|
|
273
310
|
/** Read a single line from stdin (used for the interactive import/create prompt). */
|
|
@@ -290,6 +327,8 @@ export const ONBOARD_USAGE = [
|
|
|
290
327
|
" CYBERDYNE_IMPORT_KEY=0x<key> npx cyberdyne-mcp onboard --import",
|
|
291
328
|
" (passing it as an argument leaves the secret in your shell history.)",
|
|
292
329
|
" --create generate a fresh wallet (default in a non-interactive / CI shell).",
|
|
330
|
+
" --bankr <bk_key> auto-link your Bankr project at onboard (or set CYBERDYNE_BANKR_KEY).",
|
|
331
|
+
" The bk_ key is used ONCE server-side and never stored.",
|
|
293
332
|
" (no flag, in a terminal) you'll be prompted: paste a key/mnemonic, or press enter to create.",
|
|
294
333
|
"",
|
|
295
334
|
"Either way: SIWE sign-in → mint your cyb_ key → save wallet + key to ~/.cyberdyne/config.json (0600).",
|
|
@@ -301,9 +340,11 @@ export const ONBOARD_USAGE = [
|
|
|
301
340
|
* piped stdin (with --import) → CYBERDYNE_IMPORT_KEY → --import <value> argv → TTY prompt.
|
|
302
341
|
*/
|
|
303
342
|
export async function onboardCli(argv: string[], env: NodeJS.ProcessEnv = process.env): Promise<OnboardResult> {
|
|
304
|
-
const { importFlag, importValue, create } = parseOnboardFlags(argv);
|
|
343
|
+
const { importFlag, importValue, create, bankrValue } = parseOnboardFlags(argv);
|
|
344
|
+
// Bankr auto-link key: --bankr <bk_…> (or env CYBERDYNE_BANKR_KEY, read inside onboard()).
|
|
345
|
+
const bankrKey = bankrValue?.trim() || undefined;
|
|
305
346
|
|
|
306
|
-
if (create) return onboard(env, { forceCreate: true });
|
|
347
|
+
if (create) return onboard(env, { forceCreate: true, bankrKey });
|
|
307
348
|
|
|
308
349
|
// Determine the import secret, if the user asked to import.
|
|
309
350
|
let secret: string | undefined;
|
|
@@ -351,7 +392,7 @@ export async function onboardCli(argv: string[], env: NodeJS.ProcessEnv = proces
|
|
|
351
392
|
if (secret) {
|
|
352
393
|
// Validate early with a clear error before any network call.
|
|
353
394
|
privateKeyFromSecret(secret);
|
|
354
|
-
return onboard(env, { importSecret: secret });
|
|
395
|
+
return onboard(env, { importSecret: secret, bankrKey });
|
|
355
396
|
}
|
|
356
|
-
return onboard(env); // create / reuse-saved, as before
|
|
397
|
+
return onboard(env, { bankrKey }); // create / reuse-saved, as before
|
|
357
398
|
}
|
package/src/server.ts
CHANGED
|
@@ -72,6 +72,9 @@ if (process.argv[2] === "onboard") {
|
|
|
72
72
|
: r.imported
|
|
73
73
|
? `\n (your imported wallet private key was saved to ${r.configPath}; keep that file safe)`
|
|
74
74
|
: "") +
|
|
75
|
+
(r.bankr
|
|
76
|
+
? `\n Bankr : ${r.bankr.connected ? `connected${r.bankr.project ? ` · ${r.bankr.project}` : ""}` : "not connected"}${r.bankr.hint ? ` (${r.bankr.hint})` : ""}`
|
|
77
|
+
: "") +
|
|
75
78
|
`\n\n${nextStepsText()}` +
|
|
76
79
|
`\n\nThis MCP is already configured for this agent — networked tools will use the saved key.`,
|
|
77
80
|
);
|
|
@@ -160,7 +163,7 @@ async function guard<T>(fn: () => Promise<T>) {
|
|
|
160
163
|
|
|
161
164
|
// ---- Server ---------------------------------------------------------------
|
|
162
165
|
|
|
163
|
-
const server = new McpServer({ name: "cyberdyne", version: "0.6.
|
|
166
|
+
const server = new McpServer({ name: "cyberdyne", version: "0.6.7" });
|
|
164
167
|
|
|
165
168
|
server.tool(
|
|
166
169
|
"list_categories",
|