#!/usr/bin/env python3 """Register the ops-bridge MCP server at user scope in ~/.claude.json. Usage: python scripts/register_mcp.py [--dry-run] This script: 1. Reads the MCP server config from .mcp.json in the repo root. 2. Calls `claude mcp add-json -s user ops-bridge ` to register. 3. Patches the `cwd` field in ~/.claude.json (claude mcp add-json silently drops it). After running, all Claude Code sessions on this machine have access to the `ops-bridge` MCP tools — even when opened outside the ops-bridge repo directory. """ from __future__ import annotations import argparse import json import subprocess import sys from pathlib import Path REPO_ROOT = Path(__file__).parent.parent MCP_JSON = REPO_ROOT / ".mcp.json" CLAUDE_JSON = Path.home() / ".claude.json" SERVER_NAME = "ops-bridge" def load_server_config() -> dict: data = json.loads(MCP_JSON.read_text()) servers = data.get("mcpServers", {}) if SERVER_NAME not in servers: raise SystemExit(f"ERROR: '{SERVER_NAME}' not found in {MCP_JSON}") return servers[SERVER_NAME] def register(config: dict, dry_run: bool) -> None: config_json = json.dumps(config) cmd = ["claude", "mcp", "add-json", "-s", "user", SERVER_NAME, config_json] print(f"→ Running: {' '.join(cmd[:6])} ''") if not dry_run: result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"FAILED:\n{result.stderr}", file=sys.stderr) raise SystemExit(1) print(f" OK: {result.stdout.strip()}") def patch_cwd(cwd: str, dry_run: bool) -> None: """Patch the cwd field that claude mcp add-json silently drops.""" if not CLAUDE_JSON.exists(): print(f"WARNING: {CLAUDE_JSON} not found — skipping cwd patch") return data = json.loads(CLAUDE_JSON.read_text()) servers = data.setdefault("mcpServers", {}) if SERVER_NAME not in servers: print(f"WARNING: '{SERVER_NAME}' not found in {CLAUDE_JSON} after registration") return current_cwd = servers[SERVER_NAME].get("cwd") if current_cwd == cwd: print(f"→ cwd already correct: {cwd}") return servers[SERVER_NAME]["cwd"] = cwd print(f"→ Patching cwd: {cwd}") if not dry_run: CLAUDE_JSON.write_text(json.dumps(data, indent=2) + "\n") print(" OK") def main() -> None: parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--dry-run", action="store_true", help="Show what would be done without making changes") args = parser.parse_args() if args.dry_run: print("[DRY RUN] No changes will be made.\n") config = load_server_config() cwd = config.get("cwd", str(REPO_ROOT)) print(f"Registering ops-bridge MCP server from {MCP_JSON}") register(config, dry_run=args.dry_run) patch_cwd(cwd, dry_run=args.dry_run) if not args.dry_run: print("\nDone. Restart Claude Code for the changes to take effect.") else: print("\n[DRY RUN complete]") if __name__ == "__main__": main()