Add or update an MCP server in Claude's configuration. Args: file_spec: Path to the server file, optionally with :object suffix server_name: Name for the server in Claude's config with_editable: Optional directory to install in editable mode with_packages: Option
(
file_spec: str,
server_name: str,
*,
with_editable: Path | None = None,
with_packages: list[str] | None = None,
env_vars: dict[str, str] | None = None,
)
| 60 | |
| 61 | |
| 62 | def update_claude_config( |
| 63 | file_spec: str, |
| 64 | server_name: str, |
| 65 | *, |
| 66 | with_editable: Path | None = None, |
| 67 | with_packages: list[str] | None = None, |
| 68 | env_vars: dict[str, str] | None = None, |
| 69 | ) -> bool: |
| 70 | """Add or update an MCP server in Claude's configuration. |
| 71 | |
| 72 | Args: |
| 73 | file_spec: Path to the server file, optionally with :object suffix |
| 74 | server_name: Name for the server in Claude's config |
| 75 | with_editable: Optional directory to install in editable mode |
| 76 | with_packages: Optional list of additional packages to install |
| 77 | env_vars: Optional dictionary of environment variables. These are merged with |
| 78 | any existing variables, with new values taking precedence. |
| 79 | |
| 80 | Raises: |
| 81 | RuntimeError: If Claude Desktop's config directory is not found, indicating |
| 82 | Claude Desktop may not be installed or properly set up. |
| 83 | """ |
| 84 | config_dir = get_claude_config_path() |
| 85 | uv_path = get_uv_path() |
| 86 | if not config_dir: |
| 87 | raise RuntimeError( |
| 88 | "Claude Desktop config directory not found. Please ensure Claude Desktop" |
| 89 | " is installed and has been run at least once to initialize its config." |
| 90 | ) |
| 91 | |
| 92 | config_file = config_dir / "claude_desktop_config.json" |
| 93 | if not config_file.exists(): # pragma: lax no cover |
| 94 | try: |
| 95 | config_file.write_text("{}") |
| 96 | except Exception: |
| 97 | logger.exception( |
| 98 | "Failed to create Claude config file", |
| 99 | extra={ |
| 100 | "config_file": str(config_file), |
| 101 | }, |
| 102 | ) |
| 103 | return False |
| 104 | |
| 105 | try: |
| 106 | config = json.loads(config_file.read_text()) |
| 107 | if "mcpServers" not in config: |
| 108 | config["mcpServers"] = {} |
| 109 | |
| 110 | # Always preserve existing env vars and merge with new ones |
| 111 | if server_name in config["mcpServers"] and "env" in config["mcpServers"][server_name]: |
| 112 | existing_env = config["mcpServers"][server_name]["env"] |
| 113 | if env_vars: |
| 114 | # New vars take precedence over existing ones |
| 115 | env_vars = {**existing_env, **env_vars} |
| 116 | else: |
| 117 | env_vars = existing_env |
| 118 | |
| 119 | # Build uv run command |