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
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -34,18 +34,19 @@ function usage() {
|
||||
|
||||
Usage:
|
||||
ra-h-mcp-server Start MCP stdio server
|
||||
ra-h-mcp-server setup --client <name> Configure MCP for an agent
|
||||
ra-h-mcp-server setup --client <name> 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 <name>
|
||||
ra-h-mcp-server install-rules --client <name> [--target <path>]
|
||||
|
||||
Options:
|
||||
--client <name> claude-code, claude-desktop, cursor, codex, opencode, vscode, windsurf, aider
|
||||
--client <name[,name]> claude-code, claude-desktop, cursor, codex, opencode, vscode, windsurf, aider
|
||||
--db <path> Override DB path for this command
|
||||
--scope <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 <path> 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);
|
||||
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 <repo> --yes`);
|
||||
log(`Install rules with: npx -y ${packageSpec(args)} install-rules --client ${client} --target <repo> --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);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
+6
-3
@@ -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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user