From 921c1ec6ed06e99cf0294748a33ba4d18b8140a4 Mon Sep 17 00:00:00 2001 From: jackzhe Date: Sun, 17 May 2026 08:58:50 +0800 Subject: [PATCH 1/3] Add Codex MCP installer support --- README.md | 26 ++++++++++++++- package.json | 1 + src/index.ts | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 47298d2e..4e972d2f 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,19 @@ This detects your OS and writes to the correct Claude Desktop config file: Restart Claude Desktop after installing. +### Codex (CLI / IDE) + +```bash +npx @aibtc/mcp-server@latest --install --codex +``` + +This writes the AIBTC MCP server to Codex's shared config at `~/.codex/config.toml`. +Restart Codex, then run `codex mcp list` or use `/mcp` in the Codex TUI to verify +that `aibtc` is enabled. + ### Testnet Mode -Add `--testnet` to either command: +Add `--testnet` to any install command: ```bash # Claude Code on testnet @@ -55,6 +65,9 @@ npx @aibtc/mcp-server@latest --install --testnet # Claude Desktop on testnet npx @aibtc/mcp-server@latest --install --desktop --testnet + +# Codex on testnet +npx @aibtc/mcp-server@latest --install --codex --testnet ``` > **Why npx?** Using `npx @aibtc/mcp-server@latest` ensures you always get the newest version automatically. Global installs (`npm install -g`) won't auto-update. @@ -97,6 +110,17 @@ If you prefer to configure manually, add the following to your config file. > **Note:** Claude Desktop requires the `-y` flag in args so npx doesn't prompt for confirmation. +**Codex** (`~/.codex/config.toml`): + +```toml +[mcp_servers.aibtc] +command = "npx" +args = ["-y", "@aibtc/mcp-server@latest"] + +[mcp_servers.aibtc.env] +NETWORK = "mainnet" +``` + ## Giving Claude a Wallet When you first use @aibtc/mcp-server, Claude doesn't have a wallet. Here's the smooth onboarding flow: diff --git a/package.json b/package.json index ab2329ae..a8b5748d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "keywords": [ "claude", "claude-code", + "codex", "mcp", "model-context-protocol", "x402", diff --git a/src/index.ts b/src/index.ts index c04d6a19..65c56047 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,7 +16,7 @@ const require = createRequire(import.meta.url); const packageJson = require("../package.json"); // ============================================================================= -// AUTO-INSTALL FOR CLAUDE CODE AND CLAUDE DESKTOP +// AUTO-INSTALL FOR CLAUDE CODE, CLAUDE DESKTOP, AND CODEX // ============================================================================= function getClaudeDesktopConfigPath(): string { @@ -34,6 +34,57 @@ function getClaudeDesktopConfigPath(): string { } } +function getCodexConfigPath(): string { + return path.join(os.homedir(), ".codex", "config.toml"); +} + +function escapeTomlString(value: string): string { + return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); +} + +function removeTomlTable(content: string, tableName: string): string { + const target = `[${tableName}]`; + const lines = content.split(/\r?\n/); + const kept: string[] = []; + let skipping = false; + + for (const line of lines) { + const trimmed = line.trim(); + const startsTable = /^\[[^\]]+\]$/.test(trimmed); + + if (trimmed === target) { + skipping = true; + continue; + } + + if (skipping && startsTable) { + skipping = false; + } + + if (!skipping) { + kept.push(line); + } + } + + return kept.join("\n").trimEnd(); +} + +function upsertCodexConfig(content: string, network: string): string { + let next = removeTomlTable(content, "mcp_servers.aibtc"); + next = removeTomlTable(next, "mcp_servers.aibtc.env"); + + const block = [ + "[mcp_servers.aibtc]", + 'command = "npx"', + 'args = ["-y", "@aibtc/mcp-server@latest"]', + "", + "[mcp_servers.aibtc.env]", + `NETWORK = "${escapeTomlString(network)}"`, + ].join("\n"); + + return `${next}${next ? "\n\n" : ""}${block}\n`; +} + async function readJsonConfig(filePath: string): Promise> { try { const content = await fs.readFile(filePath, "utf8"); @@ -51,6 +102,20 @@ async function writeJsonConfig(filePath: string, config: Record await fs.writeFile(filePath, JSON.stringify(config, null, 2)); } +async function readTextConfig(filePath: string): Promise { + try { + return await fs.readFile(filePath, "utf8"); + } catch { + return ""; + } +} + +async function writeTextConfig(filePath: string, content: string): Promise { + const dir = path.dirname(filePath); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(filePath, content); +} + async function installToClaudeCode(): Promise { const claudeConfigPath = path.join(os.homedir(), ".claude.json"); const network = process.argv.includes("--testnet") ? "testnet" : "mainnet"; @@ -121,6 +186,29 @@ async function installToClaudeDesktop(): Promise { } } +async function installToCodex(): Promise { + const configPath = getCodexConfigPath(); + const network = process.argv.includes("--testnet") ? "testnet" : "mainnet"; + + console.log("šŸ”§ Installing @aibtc/mcp-server to Codex...\n"); + + const config = await readTextConfig(configPath); + await writeTextConfig(configPath, upsertCodexConfig(config, network)); + + console.log("āœ… Successfully installed!\n"); + console.log(` Config: ${configPath}`); + console.log(` Network: ${network}`); + console.log("\nšŸ“‹ Next steps:"); + console.log(" 1. Restart Codex or reload MCP configuration"); + console.log(" 2. Run `codex mcp list` or use `/mcp` in the Codex TUI to verify `aibtc` is enabled"); + console.log(" 3. Ask Codex: \"What's your wallet address?\""); + console.log(" 4. Codex will guide you through wallet setup\n"); + + if (network === "testnet") { + console.log("šŸ’” Tip: Get testnet STX at https://explorer.hiro.so/sandbox/faucet?chain=testnet\n"); + } +} + // ============================================================================= // YIELD HUNTER DAEMON // ============================================================================= @@ -151,7 +239,8 @@ if (process.argv[2] === "yield-hunter") { // Check for --install flag else if (process.argv.includes("--install") || process.argv.includes("install")) { const isDesktop = process.argv.includes("--desktop"); - const installFn = isDesktop ? installToClaudeDesktop : installToClaudeCode; + const isCodex = process.argv.includes("--codex"); + const installFn = isCodex ? installToCodex : isDesktop ? installToClaudeDesktop : installToClaudeCode; installFn() .then(() => process.exit(0)) .catch((error) => { From b18caf519b4d1caad22484beb3448b1e1bcd22cf Mon Sep 17 00:00:00 2001 From: jackzhe Date: Sun, 17 May 2026 09:27:07 +0800 Subject: [PATCH 2/3] Harden Codex config updates --- src/index.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index 65c56047..f8ce989f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,11 @@ function escapeTomlString(value: string): string { return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); } +function getTomlTableHeader(line: string): string | null { + const match = line.trim().match(/^(\[[^\]]+\])(?:\s*#.*)?$/); + return match?.[1] ?? null; +} + function removeTomlTable(content: string, tableName: string): string { const target = `[${tableName}]`; const lines = content.split(/\r?\n/); @@ -49,15 +54,14 @@ function removeTomlTable(content: string, tableName: string): string { let skipping = false; for (const line of lines) { - const trimmed = line.trim(); - const startsTable = /^\[[^\]]+\]$/.test(trimmed); + const tableHeader = getTomlTableHeader(line); - if (trimmed === target) { + if (tableHeader === target) { skipping = true; continue; } - if (skipping && startsTable) { + if (skipping && tableHeader) { skipping = false; } @@ -105,8 +109,11 @@ async function writeJsonConfig(filePath: string, config: Record async function readTextConfig(filePath: string): Promise { try { return await fs.readFile(filePath, "utf8"); - } catch { - return ""; + } catch (err: unknown) { + if ((err as NodeJS.ErrnoException).code === "ENOENT") { + return ""; + } + throw err; } } From 30ac179c6bdeffcf6e6ad6ff9d1102bdf524549a Mon Sep 17 00:00:00 2001 From: jackzhe Date: Sun, 17 May 2026 09:40:36 +0800 Subject: [PATCH 3/3] Preserve TOML array tables in Codex config --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index f8ce989f..2fce1eb3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -43,7 +43,7 @@ function escapeTomlString(value: string): string { } function getTomlTableHeader(line: string): string | null { - const match = line.trim().match(/^(\[[^\]]+\])(?:\s*#.*)?$/); + const match = line.trim().match(/^(\[\[?[^\]]+\]\]?)(?:\s*#.*)?$/); return match?.[1] ?? null; }