From a0d1c7fb6981b35b8c86d129e5d404d45bcec30f Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Wed, 15 Oct 2025 07:04:46 -0700 Subject: [PATCH] Remove obsolete claude.py with Windows path bug (#2101) --- src/fastmcp/cli/claude.py | 135 -------------------------------------- 1 file changed, 135 deletions(-) delete mode 100644 src/fastmcp/cli/claude.py diff --git a/src/fastmcp/cli/claude.py b/src/fastmcp/cli/claude.py deleted file mode 100644 index f2d425225..000000000 --- a/src/fastmcp/cli/claude.py +++ /dev/null @@ -1,135 +0,0 @@ -"""Claude app integration utilities.""" - -import json -import os -import sys -from pathlib import Path -from typing import Any - -from fastmcp.utilities.logging import get_logger -from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment - -logger = get_logger(__name__) - - -def get_claude_config_path() -> Path | None: - """Get the Claude config directory based on platform.""" - if sys.platform == "win32": - path = Path(Path.home(), "AppData", "Roaming", "Claude") - elif sys.platform == "darwin": - path = Path(Path.home(), "Library", "Application Support", "Claude") - elif sys.platform.startswith("linux"): - path = Path( - os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"), "Claude" - ) - else: - return None - - if path.exists(): - return path - return None - - -def update_claude_config( - file_spec: str, - server_name: str, - *, - with_editable: list[Path] | None = None, - with_packages: list[str] | None = None, - env_vars: dict[str, str] | None = None, -) -> bool: - """Add or update a FastMCP 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 list of directories to install in editable mode - with_packages: Optional list of additional packages to install - env_vars: Optional dictionary of environment variables. These are merged with - any existing variables, with new values taking precedence. - - Raises: - RuntimeError: If Claude Desktop's config directory is not found, indicating - Claude Desktop may not be installed or properly set up. - """ - config_dir = get_claude_config_path() - if not config_dir: - raise RuntimeError( - "Claude Desktop config directory not found. Please ensure Claude Desktop" - " is installed and has been run at least once to initialize its config." - ) - - config_file = config_dir / "claude_desktop_config.json" - if not config_file.exists(): - try: - config_file.write_text("{}") - except Exception as e: - logger.error( - "Failed to create Claude config file", - extra={ - "error": str(e), - "config_file": str(config_file), - }, - ) - return False - - try: - config = json.loads(config_file.read_text()) - if "mcpServers" not in config: - config["mcpServers"] = {} - - # Always preserve existing env vars and merge with new ones - if ( - server_name in config["mcpServers"] - and "env" in config["mcpServers"][server_name] - ): - existing_env = config["mcpServers"][server_name]["env"] - if env_vars: - # New vars take precedence over existing ones - env_vars = {**existing_env, **env_vars} - else: - env_vars = existing_env - - env_config = UVEnvironment( - dependencies=(with_packages or []) + ["fastmcp"], - editable=[str(p) for p in with_editable] if with_editable else None, - ) - - # Convert file path to absolute before adding to command - # Split off any :object suffix first - if ":" in file_spec: - file_path, server_object = file_spec.rsplit(":", 1) - file_spec = f"{Path(file_path).resolve()}:{server_object}" - else: - file_spec = str(Path(file_spec).resolve()) - - # Build the full command - full_command = env_config.build_command(["fastmcp", "run", file_spec]) - - # Extract command and args for the config - server_config: dict[str, Any] = { - "command": full_command[0], - "args": full_command[1:], - } - - # Add environment variables if specified - if env_vars: - server_config["env"] = env_vars - - config["mcpServers"][server_name] = server_config - - config_file.write_text(json.dumps(config, indent=2)) - logger.info( - f"Added server '{server_name}' to Claude config", - extra={"config_file": str(config_file)}, - ) - return True - except Exception as e: - logger.error( - "Failed to update Claude config", - extra={ - "error": str(e), - "config_file": str(config_file), - }, - ) - return False