cyberdyne-mcp 0.4.0 → 0.5.0
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 +9 -12
- package/dist/client.js +37 -6
- package/dist/server.js +16 -2
- package/package.json +1 -1
- package/src/client.ts +39 -6
- package/src/server.ts +21 -2
package/README.md
CHANGED
|
@@ -90,17 +90,16 @@ then releases payment on verify. The pattern behind x402-native traders like
|
|
|
90
90
|
CYBERDYNE_IDENTITY_TOKEN=cyb_… npm run build && npm run founder-check
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
## Install — one line
|
|
93
|
+
## Install — one line
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
need Node 18+ and your `cyb_…` agent key (mint one in the app's
|
|
95
|
+
Published on [npm](https://www.npmjs.com/package/cyberdyne-mcp), so `npx` runs it
|
|
96
|
+
instantly. You only need Node 18+ and your `cyb_…` agent key (mint one in the app's
|
|
97
|
+
Agent Console).
|
|
97
98
|
|
|
98
99
|
**Claude Code:**
|
|
99
100
|
|
|
100
101
|
```bash
|
|
101
|
-
claude mcp add cyberdyne
|
|
102
|
-
-e CYBERDYNE_IDENTITY_TOKEN=cyb_… \
|
|
103
|
-
-- npx -y github:Cyberdyne-OS/cyberdyne-mcp
|
|
102
|
+
claude mcp add cyberdyne -e CYBERDYNE_IDENTITY_TOKEN=cyb_… -- npx -y cyberdyne-mcp
|
|
104
103
|
```
|
|
105
104
|
|
|
106
105
|
**Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json` and restart:
|
|
@@ -110,17 +109,15 @@ claude mcp add cyberdyne \
|
|
|
110
109
|
"mcpServers": {
|
|
111
110
|
"cyberdyne": {
|
|
112
111
|
"command": "npx",
|
|
113
|
-
"args": ["-y", "
|
|
114
|
-
"env": {
|
|
115
|
-
"CYBERDYNE_IDENTITY_TOKEN": "cyb_…",
|
|
116
|
-
"CYBERDYNE_API_URL": "https://app.cyberdyne-os.xyz"
|
|
117
|
-
}
|
|
112
|
+
"args": ["-y", "cyberdyne-mcp"],
|
|
113
|
+
"env": { "CYBERDYNE_IDENTITY_TOKEN": "cyb_…" }
|
|
118
114
|
}
|
|
119
115
|
}
|
|
120
116
|
}
|
|
121
117
|
```
|
|
122
118
|
|
|
123
|
-
|
|
119
|
+
Once connected, run **`/mcp__cyberdyne__quickstart`** for the full fund → post →
|
|
120
|
+
pay walkthrough. *(Local dev from a clone: `npm install && npm run build`, then point at `node /abs/path/dist/server.js`.)*
|
|
124
121
|
|
|
125
122
|
Then ask the agent, e.g.:
|
|
126
123
|
|
package/dist/client.js
CHANGED
|
@@ -9,17 +9,48 @@
|
|
|
9
9
|
* body (`identity_token`). Used for `search_humans` (the REST
|
|
10
10
|
* GET /api/humans is session-only and rejects Bearer keys).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* The agent key (`cyb_…`) is resolved, in order, from:
|
|
13
|
+
* 1. env CYBERDYNE_IDENTITY_TOKEN (e.g. `claude mcp add … -e CYBERDYNE_IDENTITY_TOKEN=…`)
|
|
14
|
+
* 2. a saved login at ~/.cyberdyne/config.json (written by `cyberdyne-mcp login cyb_…`)
|
|
15
|
+
* so the install line can be the short `claude mcp add cyberdyne -- npx -y cyberdyne-mcp`.
|
|
16
|
+
* CYBERDYNE_API_URL overrides the default "https://app.cyberdyne-os.xyz".
|
|
15
17
|
*
|
|
16
18
|
* No secrets are hardcoded; nothing is logged that could leak the key.
|
|
17
19
|
*/
|
|
20
|
+
import { homedir } from "node:os";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
|
|
18
23
|
export const DEFAULT_API_URL = "https://app.cyberdyne-os.xyz";
|
|
19
|
-
/**
|
|
24
|
+
/** Path to the persisted login (mode 600). */
|
|
25
|
+
export function configPath() {
|
|
26
|
+
return join(homedir(), ".cyberdyne", "config.json");
|
|
27
|
+
}
|
|
28
|
+
function readConfigFile() {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(readFileSync(configPath(), "utf8"));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Persist the agent key to ~/.cyberdyne/config.json (0600). Returns the path. */
|
|
37
|
+
export function saveToken(token) {
|
|
38
|
+
mkdirSync(join(homedir(), ".cyberdyne"), { recursive: true });
|
|
39
|
+
const p = configPath();
|
|
40
|
+
writeFileSync(p, JSON.stringify({ ...readConfigFile(), identity_token: token.trim() }, null, 2));
|
|
41
|
+
try {
|
|
42
|
+
chmodSync(p, 0o600);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* best-effort on platforms without POSIX modes */
|
|
46
|
+
}
|
|
47
|
+
return p;
|
|
48
|
+
}
|
|
49
|
+
/** Resolve config: env first, then the saved login. `token` may be undefined. */
|
|
20
50
|
export function readConfig(env = process.env) {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
51
|
+
const file = readConfigFile();
|
|
52
|
+
const apiUrl = (env.CYBERDYNE_API_URL || file.api_url || DEFAULT_API_URL).replace(/\/+$/, "");
|
|
53
|
+
const token = env.CYBERDYNE_IDENTITY_TOKEN?.trim() || file.identity_token?.trim() || undefined;
|
|
23
54
|
return { apiUrl, token };
|
|
24
55
|
}
|
|
25
56
|
/** An API error surfaced to the caller — carries the HTTP status + the API's error code. */
|
package/dist/server.js
CHANGED
|
@@ -40,7 +40,21 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
40
40
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
41
41
|
import { z } from "zod";
|
|
42
42
|
import { CATEGORIES, TASK_CATEGORIES } from "./registry.js";
|
|
43
|
-
import { ApiError, CyberdyneClient, MissingTokenError, readConfig } from "./client.js";
|
|
43
|
+
import { ApiError, CyberdyneClient, MissingTokenError, readConfig, saveToken } from "./client.js";
|
|
44
|
+
// `cyberdyne-mcp login cyb_…` — persist the key so the MCP add line can omit it
|
|
45
|
+
// (short DFM-style install). Runs before the server boots, then exits.
|
|
46
|
+
if (process.argv[2] === "login") {
|
|
47
|
+
const token = process.argv[3]?.trim();
|
|
48
|
+
if (!token || !token.startsWith("cyb_")) {
|
|
49
|
+
console.error("Usage: npx cyberdyne-mcp login cyb_<your-key>\n" +
|
|
50
|
+
"Get your key at https://app.cyberdyne-os.xyz → Agent Console → Generate API key.");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const path = saveToken(token);
|
|
54
|
+
console.error(`✓ Saved your CYBERDYNE key to ${path}.\n` +
|
|
55
|
+
"Now run: claude mcp add cyberdyne -- npx -y cyberdyne-mcp");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
44
58
|
const config = readConfig();
|
|
45
59
|
const client = new CyberdyneClient(config);
|
|
46
60
|
// ---- Result helpers -------------------------------------------------------
|
|
@@ -185,5 +199,5 @@ server.registerPrompt("quickstart", {
|
|
|
185
199
|
const transport = new StdioServerTransport();
|
|
186
200
|
await server.connect(transport);
|
|
187
201
|
console.error(`CYBERDYNE MCP server running on stdio → ${config.apiUrl}` +
|
|
188
|
-
(config.token ? "" : " (no
|
|
202
|
+
(config.token ? "" : " (no key — run `npx cyberdyne-mcp login cyb_…` or set CYBERDYNE_IDENTITY_TOKEN; networked tools error until then)") +
|
|
189
203
|
". Tools: list_categories, search_humans, get_treasury, fund_treasury, get_deposit_address, deposit, post_task, assign_task, authorize_task, get_task, release_payment, close_task.");
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -9,13 +9,19 @@
|
|
|
9
9
|
* body (`identity_token`). Used for `search_humans` (the REST
|
|
10
10
|
* GET /api/humans is session-only and rejects Bearer keys).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* The agent key (`cyb_…`) is resolved, in order, from:
|
|
13
|
+
* 1. env CYBERDYNE_IDENTITY_TOKEN (e.g. `claude mcp add … -e CYBERDYNE_IDENTITY_TOKEN=…`)
|
|
14
|
+
* 2. a saved login at ~/.cyberdyne/config.json (written by `cyberdyne-mcp login cyb_…`)
|
|
15
|
+
* so the install line can be the short `claude mcp add cyberdyne -- npx -y cyberdyne-mcp`.
|
|
16
|
+
* CYBERDYNE_API_URL overrides the default "https://app.cyberdyne-os.xyz".
|
|
15
17
|
*
|
|
16
18
|
* No secrets are hardcoded; nothing is logged that could leak the key.
|
|
17
19
|
*/
|
|
18
20
|
|
|
21
|
+
import { homedir } from "node:os";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
|
|
24
|
+
|
|
19
25
|
export const DEFAULT_API_URL = "https://app.cyberdyne-os.xyz";
|
|
20
26
|
|
|
21
27
|
export interface CyberdyneConfig {
|
|
@@ -23,10 +29,37 @@ export interface CyberdyneConfig {
|
|
|
23
29
|
token: string | undefined;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
/**
|
|
32
|
+
/** Path to the persisted login (mode 600). */
|
|
33
|
+
export function configPath(): string {
|
|
34
|
+
return join(homedir(), ".cyberdyne", "config.json");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readConfigFile(): { identity_token?: string; api_url?: string } {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(configPath(), "utf8"));
|
|
40
|
+
} catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Persist the agent key to ~/.cyberdyne/config.json (0600). Returns the path. */
|
|
46
|
+
export function saveToken(token: string): string {
|
|
47
|
+
mkdirSync(join(homedir(), ".cyberdyne"), { recursive: true });
|
|
48
|
+
const p = configPath();
|
|
49
|
+
writeFileSync(p, JSON.stringify({ ...readConfigFile(), identity_token: token.trim() }, null, 2));
|
|
50
|
+
try {
|
|
51
|
+
chmodSync(p, 0o600);
|
|
52
|
+
} catch {
|
|
53
|
+
/* best-effort on platforms without POSIX modes */
|
|
54
|
+
}
|
|
55
|
+
return p;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Resolve config: env first, then the saved login. `token` may be undefined. */
|
|
27
59
|
export function readConfig(env: NodeJS.ProcessEnv = process.env): CyberdyneConfig {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
60
|
+
const file = readConfigFile();
|
|
61
|
+
const apiUrl = (env.CYBERDYNE_API_URL || file.api_url || DEFAULT_API_URL).replace(/\/+$/, "");
|
|
62
|
+
const token = env.CYBERDYNE_IDENTITY_TOKEN?.trim() || file.identity_token?.trim() || undefined;
|
|
30
63
|
return { apiUrl, token };
|
|
31
64
|
}
|
|
32
65
|
|
package/src/server.ts
CHANGED
|
@@ -40,7 +40,26 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
40
40
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
41
41
|
import { z } from "zod";
|
|
42
42
|
import { CATEGORIES, TASK_CATEGORIES } from "./registry.js";
|
|
43
|
-
import { ApiError, CyberdyneClient, MissingTokenError, readConfig } from "./client.js";
|
|
43
|
+
import { ApiError, CyberdyneClient, MissingTokenError, readConfig, saveToken } from "./client.js";
|
|
44
|
+
|
|
45
|
+
// `cyberdyne-mcp login cyb_…` — persist the key so the MCP add line can omit it
|
|
46
|
+
// (short DFM-style install). Runs before the server boots, then exits.
|
|
47
|
+
if (process.argv[2] === "login") {
|
|
48
|
+
const token = process.argv[3]?.trim();
|
|
49
|
+
if (!token || !token.startsWith("cyb_")) {
|
|
50
|
+
console.error(
|
|
51
|
+
"Usage: npx cyberdyne-mcp login cyb_<your-key>\n" +
|
|
52
|
+
"Get your key at https://app.cyberdyne-os.xyz → Agent Console → Generate API key.",
|
|
53
|
+
);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
const path = saveToken(token);
|
|
57
|
+
console.error(
|
|
58
|
+
`✓ Saved your CYBERDYNE key to ${path}.\n` +
|
|
59
|
+
"Now run: claude mcp add cyberdyne -- npx -y cyberdyne-mcp",
|
|
60
|
+
);
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
44
63
|
|
|
45
64
|
const config = readConfig();
|
|
46
65
|
const client = new CyberdyneClient(config);
|
|
@@ -285,6 +304,6 @@ const transport = new StdioServerTransport();
|
|
|
285
304
|
await server.connect(transport);
|
|
286
305
|
console.error(
|
|
287
306
|
`CYBERDYNE MCP server running on stdio → ${config.apiUrl}` +
|
|
288
|
-
(config.token ? "" : " (no
|
|
307
|
+
(config.token ? "" : " (no key — run `npx cyberdyne-mcp login cyb_…` or set CYBERDYNE_IDENTITY_TOKEN; networked tools error until then)") +
|
|
289
308
|
". Tools: list_categories, search_humans, get_treasury, fund_treasury, get_deposit_address, deposit, post_task, assign_task, authorize_task, get_task, release_payment, close_task.",
|
|
290
309
|
);
|