From ad07fcb86805c76f6b8be3dc956ca2276a09ceb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CBeeRad=E2=80=9D?= Date: Tue, 21 Apr 2026 09:24:31 +1000 Subject: [PATCH] feat: support one-command multi-client MCP setup - Allow comma-separated clients for setup, print-config, and install-rules - Add --install-rules to setup so MCP config and agent memory install together - Document the Claude Code plus Codex one-command demo path Generated with Claude Code --- README.md | 12 +++- apps/mcp-server-standalone/README.md | 5 +- apps/mcp-server-standalone/cli.js | 73 ++++++++++++++------ apps/mcp-server-standalone/package-lock.json | 4 +- apps/mcp-server-standalone/package.json | 2 +- docs/8_mcp.md | 9 ++- 6 files changed, 74 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 7c9221d..fdbd98b 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,12 @@ npx -y ra-h-mcp-server@latest setup --client cursor --yes npx -y ra-h-mcp-server@latest setup --client codex --yes ``` +Multiple clients can be installed in one pass. This is the best path if you use both Claude Code and Codex: + +```bash +npx -y ra-h-mcp-server@latest setup --client claude-code,codex --yes +``` + Notes: - `--yes` lets the installer write supported client config automatically. - Codex uses TOML config, so the installer writes `CODEX_HOME/config.toml` or `~/.codex/config.toml`. @@ -165,8 +171,10 @@ SQLITE_DB_PATH="$HOME/Desktop/ra-h_os-demo-data/rah.sqlite" npm run setup:local npm run dev npx -y ra-h-mcp-server@latest setup \ - --client claude-code \ + --client claude-code,codex \ --yes \ + --install-rules \ + --target "$HOME/Desktop/ra-h_os-demo" \ --db "$HOME/Desktop/ra-h_os-demo-data/rah.sqlite" ``` @@ -231,7 +239,7 @@ You are helping build a thoughtful graph of atomic units of context. Or install that guidance into the repo memory file: ```bash -npx -y ra-h-mcp-server@latest install-rules --client codex --target . --yes +npx -y ra-h-mcp-server@latest install-rules --client claude-code,codex --target . --yes ``` Available tools: diff --git a/apps/mcp-server-standalone/README.md b/apps/mcp-server-standalone/README.md index 4c8a16d..15384a6 100644 --- a/apps/mcp-server-standalone/README.md +++ b/apps/mcp-server-standalone/README.md @@ -15,12 +15,13 @@ Other useful commands: ```bash npx -y ra-h-mcp-server@latest setup --client cursor --yes npx -y ra-h-mcp-server@latest setup --client codex --yes +npx -y ra-h-mcp-server@latest setup --client claude-code,codex --yes --install-rules --target . npx -y ra-h-mcp-server@latest init-db npx -y ra-h-mcp-server@latest doctor npx -y ra-h-mcp-server@latest print-config --client claude-code ``` -`--yes` lets the installer write supported client config automatically. Codex uses TOML config, so the installer writes `CODEX_HOME/config.toml` or `~/.codex/config.toml`. +`--client` accepts a single client or comma-separated clients. `--yes` lets the installer write supported client config automatically. Codex uses TOML config, so the installer writes `CODEX_HOME/config.toml` or `~/.codex/config.toml`. Important contract: - `@latest` is the default user-facing install path @@ -96,7 +97,7 @@ Retrieve relevant RA-H context before substantive work, search before creating, Install or refresh that guidance without replacing the rest of the memory file: ```bash -npx -y ra-h-mcp-server@latest install-rules --client codex --target . --yes +npx -y ra-h-mcp-server@latest install-rules --client claude-code,codex --target . --yes ``` RA-H should still work well without this line. The MCP tools, server instructions, skills, and docs are meant to carry the core behavior on their own. diff --git a/apps/mcp-server-standalone/cli.js b/apps/mcp-server-standalone/cli.js index 8325e24..d89d0fc 100644 --- a/apps/mcp-server-standalone/cli.js +++ b/apps/mcp-server-standalone/cli.js @@ -34,18 +34,19 @@ function usage() { Usage: ra-h-mcp-server Start MCP stdio server - ra-h-mcp-server setup --client Configure MCP for an agent + ra-h-mcp-server setup --client Configure MCP for one or more agents ra-h-mcp-server doctor Verify package, DB, and schema ra-h-mcp-server init-db Create/verify the RA-H SQLite DB ra-h-mcp-server print-config --client ra-h-mcp-server install-rules --client [--target ] Options: - --client claude-code, claude-desktop, cursor, codex, opencode, vscode, windsurf, aider + --client claude-code, claude-desktop, cursor, codex, opencode, vscode, windsurf, aider --db Override DB path for this command --scope user or project (default: user) --pin current Use this package version instead of @latest in generated config --yes Write supported config files without prompting + --install-rules Also install RA-H graph behavior into each client's repo memory file --print-only Print config/rules without writing files --target Directory for project rule files `); @@ -59,6 +60,7 @@ function parseArgs(argv) { scope: 'user', pin: null, yes: false, + installRules: false, printOnly: false, target: null, }; @@ -69,12 +71,14 @@ function parseArgs(argv) { args.help = true; } else if (arg === '--yes' || arg === '-y') { args.yes = true; + } else if (arg === '--install-rules' || arg === '--rules') { + args.installRules = true; } else if (arg === '--print-only' || arg === '--dry-run') { args.printOnly = true; - } else if (['--client', '--db', '--scope', '--pin', '--target'].includes(arg)) { + } else if (['--client', '--clients', '--db', '--scope', '--pin', '--target'].includes(arg)) { const value = argv[i + 1]; if (!value || value.startsWith('--')) fail(`${arg} requires a value`); - args[arg.slice(2)] = value; + args[arg === '--clients' ? 'client' : arg.slice(2)] = value; i += 1; } else { args._.push(arg); @@ -337,12 +341,23 @@ function formatSnippet(snippet) { } function validateClient(client) { - if (!client) fail('Missing --client'); if (!SUPPORTED_CLIENTS.has(client)) { fail(`Unsupported client "${client}". Supported: ${Array.from(SUPPORTED_CLIENTS).join(', ')}`); } } +function resolveClients(rawClient) { + if (!rawClient) fail('Missing --client'); + const clients = rawClient + .split(',') + .map((client) => client.trim()) + .filter(Boolean); + + if (clients.length === 0) fail('Missing --client'); + clients.forEach(validateClient); + return [...new Set(clients)]; +} + function rulesSnippet() { return `## RA-H Graph Memory @@ -409,18 +424,20 @@ function commandDoctor(args) { } function commandPrintConfig(args) { - validateClient(args.client); + const clients = resolveClients(args.client); const dbPath = resolveDbPath(args); - const config = clientConfig(args.client, args, dbPath); - console.log(formatSnippet(config.snippet)); - if (config.note) log(config.note); - if (config.path) log(`Target path: ${config.path}`); + clients.forEach((client) => { + const config = clientConfig(client, args, dbPath); + if (clients.length > 1) log(`Config for ${client}:`); + console.log(formatSnippet(config.snippet)); + if (config.note) log(config.note); + if (config.path) log(`Target path: ${config.path}`); + }); } -function commandInstallRules(args) { - validateClient(args.client); +function installRulesForClient(client, args) { const content = rulesSnippet(); - const targetPath = rulesTarget(args.client, args.target); + const targetPath = rulesTarget(client, args.target); if (args.printOnly || !args.yes) { console.log(content); @@ -435,13 +452,13 @@ function commandInstallRules(args) { log(`Updated rules in ${targetPath}`); } -function commandSetup(args) { - validateClient(args.client); - const dbPath = resolveDbPath(args); - initDb(dbPath); - log(`Database ready at ${dbPath}`); +function commandInstallRules(args) { + resolveClients(args.client).forEach((client) => installRulesForClient(client, args)); +} - const config = clientConfig(args.client, args, dbPath); +function setupClient(client, args, dbPath) { + const config = clientConfig(client, args, dbPath); + log(`Configuring ${client}`); console.log(formatSnippet(config.snippet)); if (config.path) log(`MCP config target: ${config.path}`); if (config.note) log(config.note); @@ -460,9 +477,23 @@ function commandSetup(args) { log('Automatic config writing is not available for this client; copy the printed config.'); } - const rulePath = rulesTarget(args.client, args.target); + if (args.installRules) { + installRulesForClient(client, args); + return; + } + + const rulePath = rulesTarget(client, args.target); log(`Recommended rules target: ${rulePath}`); - log(`Install rules with: npx -y ${packageSpec(args)} install-rules --client ${args.client} --target --yes`); + log(`Install rules with: npx -y ${packageSpec(args)} install-rules --client ${client} --target --yes`); +} + +function commandSetup(args) { + const clients = resolveClients(args.client); + const dbPath = resolveDbPath(args); + initDb(dbPath); + log(`Database ready at ${dbPath}`); + + clients.forEach((client) => setupClient(client, args, dbPath)); commandDoctor(args); } diff --git a/apps/mcp-server-standalone/package-lock.json b/apps/mcp-server-standalone/package-lock.json index 9321e0f..7fda7ca 100644 --- a/apps/mcp-server-standalone/package-lock.json +++ b/apps/mcp-server-standalone/package-lock.json @@ -1,12 +1,12 @@ { "name": "ra-h-mcp-server", - "version": "3.2.2", + "version": "3.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ra-h-mcp-server", - "version": "3.2.2", + "version": "3.2.3", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", diff --git a/apps/mcp-server-standalone/package.json b/apps/mcp-server-standalone/package.json index 2752edc..09aedac 100644 --- a/apps/mcp-server-standalone/package.json +++ b/apps/mcp-server-standalone/package.json @@ -1,6 +1,6 @@ { "name": "ra-h-mcp-server", - "version": "3.2.2", + "version": "3.2.3", "description": "Connect Claude Code/Desktop to your RA-H knowledge base. Direct SQLite access to an existing RA-H database.", "main": "index.js", "bin": { diff --git a/docs/8_mcp.md b/docs/8_mcp.md index d9efb76..7410242 100644 --- a/docs/8_mcp.md +++ b/docs/8_mcp.md @@ -15,9 +15,10 @@ Other clients: ```bash npx -y ra-h-mcp-server@latest setup --client cursor --yes npx -y ra-h-mcp-server@latest setup --client codex --yes +npx -y ra-h-mcp-server@latest setup --client claude-code,codex --yes ``` -`--yes` lets the installer write supported client config automatically. Codex uses TOML config, so the installer writes `CODEX_HOME/config.toml` or `~/.codex/config.toml`. +`--client` accepts a single client or comma-separated clients. `--yes` lets the installer write supported client config automatically. Codex uses TOML config, so the installer writes `CODEX_HOME/config.toml` or `~/.codex/config.toml`. Verify the install: @@ -31,8 +32,10 @@ For demo isolation or a separate DB: ```bash npx -y ra-h-mcp-server@latest setup \ - --client claude-code \ + --client claude-code,codex \ --yes \ + --install-rules \ + --target "$HOME/Desktop/ra-h_os-demo" \ --db "$HOME/Desktop/ra-h_os-demo-data/rah.sqlite" ``` @@ -147,5 +150,5 @@ You are helping build a thoughtful graph of atomic units of context. The installer can add or refresh this section without replacing the rest of the memory file: ```bash -npx -y ra-h-mcp-server@latest install-rules --client codex --target . --yes +npx -y ra-h-mcp-server@latest install-rules --client claude-code,codex --target . --yes ```