agenthub/src/mcp/install.ts
chahinebrini b004e9fbb4 feat(mcp): agenthub mcp install writes .mcp.json (auto-register)
One command, no hand-editing: `agenthub mcp install` writes/merges a project
.mcp.json (the standard config Claude Code and other .mcp.json-aware clients
auto-discover) with the hub URL filled in — so those agents register
automatically. Prints the global-config snippet for Codex/Kimi as fallback.
`--print` is a dry run. Bump 0.7.3 -> 0.7.4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 01:56:24 +02:00

74 lines
2.7 KiB
TypeScript

import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { findProjectRoot } from '../core/paths.js';
import { loadConfig } from '../core/config.js';
/**
* Register the AgentHub MCP server with as little friction as possible.
*
* Default: writes/merges a project `.mcp.json` — the standard config that Claude
* Code (and any `.mcp.json`-aware MCP client) auto-discovers, so those agents
* register with zero hand-editing. For CLIs that use a GLOBAL config instead
* (Codex / Kimi) it prints a ready-to-paste snippet. `--print` is a dry run.
*/
function resolveUrl(root: string): string {
let serverUrl = process.env.AGENTHUB_SERVER || undefined;
if (!serverUrl) {
try {
serverUrl = loadConfig(root).serverUrl;
} catch {
/* no project config */
}
}
return serverUrl ?? 'http://127.0.0.1:3377';
}
export function installMcp(cwd: string, opts: { print?: boolean } = {}): void {
const root = findProjectRoot(cwd) ?? cwd;
const url = resolveUrl(root);
const serverDef = { command: 'agenthub', args: ['mcp'], env: { AGENTHUB_SERVER: url } };
const out = (s = '') => process.stdout.write(s + '\n');
out();
out('AgentHub MCP — registration');
out('═══════════════════════════');
out(`Hub URL: ${url}`);
const mcpJsonPath = join(root, '.mcp.json');
if (opts.print) {
out('');
out(`Would write ${mcpJsonPath}:`);
out(JSON.stringify({ mcpServers: { agenthub: serverDef } }, null, 2));
} else {
let json: { mcpServers?: Record<string, unknown> } = { mcpServers: {} };
if (existsSync(mcpJsonPath)) {
try {
json = JSON.parse(readFileSync(mcpJsonPath, 'utf-8')) as typeof json;
} catch {
json = { mcpServers: {} };
}
}
if (!json.mcpServers) json.mcpServers = {};
json.mcpServers.agenthub = serverDef;
writeFileSync(mcpJsonPath, JSON.stringify(json, null, 2) + '\n', 'utf-8');
out('');
out(`✓ Wrote ${mcpJsonPath}`);
out(' → Claude Code (and any .mcp.json-aware client) opened here auto-registers it.');
}
out('');
out('For CLIs that use a GLOBAL config instead of project .mcp.json:');
out('');
out('── Codex (~/.codex/config.toml) ──');
out(' [mcp_servers.agenthub]');
out(' command = "agenthub"');
out(' args = ["mcp"]');
out(` env = { AGENTHUB_SERVER = "${url}" }`);
out('');
out('── Kimi (its MCP config) ──');
out(` stdio server — command: agenthub args: ["mcp"] env: AGENTHUB_SERVER=${url}`);
out('');
out('On Windows use the Mac LAN IP (e.g. http://192.168.178.30:3377). Requires agenthub >= 0.7.0.');
out('');
}