97 lines
3.1 KiB
Python
97 lines
3.1 KiB
Python
|
|
#!/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 <config>` 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])} '<config>'")
|
||
|
|
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()
|