diff --git a/libs/arcade-cli/arcade_cli/configure.py b/libs/arcade-cli/arcade_cli/configure.py index 5c8627e0..8aa728c7 100644 --- a/libs/arcade-cli/arcade_cli/configure.py +++ b/libs/arcade-cli/arcade_cli/configure.py @@ -56,6 +56,26 @@ def configure_claude_local(server_name: str, port: int = 8000, path: Path | None config_path = path or get_claude_config_path() config_path.parent.mkdir(parents=True, exist_ok=True) + # Assume server.py is the entry point for the server + server_file = Path.cwd() / "server.py" + + # Find the Python interpreter in the virtual environment + venv_python = None + # Check for .venv first (uv default) + if (Path.cwd() / ".venv").exists(): + system = platform.system() + if system == "Windows": + venv_python = Path.cwd() / ".venv" / "Scripts" / "python.exe" + else: + venv_python = Path.cwd() / ".venv" / "bin" / "python" + + # Fall back to system python if no venv found + if not venv_python or not venv_python.exists(): + console.print("[yellow]Warning: No .venv found, using system python[/yellow]") + import sys + + venv_python = Path(sys.executable) + # Load existing config or create new one config = {} if config_path.exists(): @@ -66,10 +86,10 @@ def configure_claude_local(server_name: str, port: int = 8000, path: Path | None if "mcpServers" not in config: config["mcpServers"] = {} + # Claude Desktop uses stdio transport config["mcpServers"][server_name] = { - "command": "python", - "args": ["-m", "arcade_mcp_server", "stream"], - "url": f"http://localhost:{port}/mcp", + "command": str(venv_python), + "args": [str(server_file), "stdio"], } # Write updated config @@ -82,7 +102,8 @@ def configure_claude_local(server_name: str, port: int = 8000, path: Path | None ) config_file_path = config_path.as_posix().replace(" ", "\\ ") console.print(f" MCP client config file: {config_file_path}", style="dim") - console.print(f" MCP Server URL: http://localhost:{port}/mcp", style="dim") + console.print(f" Server file: {server_file}", style="dim") + console.print(f" Python interpreter: {venv_python}", style="dim") console.print(" Restart Claude Desktop for changes to take effect.", style="yellow") diff --git a/libs/arcade-cli/arcade_cli/new.py b/libs/arcade-cli/arcade_cli/new.py index d4c67fd7..6da5be90 100644 --- a/libs/arcade-cli/arcade_cli/new.py +++ b/libs/arcade-cli/arcade_cli/new.py @@ -19,14 +19,14 @@ try: ARCADE_MCP_MAX_VERSION = str(int(ARCADE_MCP_MIN_VERSION.split(".")[0]) + 1) + ".0.0" except Exception as e: console.print(f"[red]Failed to get arcade-mcp version: {e}[/red]") - ARCADE_MCP_MIN_VERSION = "1.0.0" # Default version if unable to fetch + ARCADE_MCP_MIN_VERSION = "1.1.0" # Default version if unable to fetch ARCADE_MCP_MAX_VERSION = "2.0.0" ARCADE_TDK_MIN_VERSION = "3.0.0" ARCADE_TDK_MAX_VERSION = "4.0.0" ARCADE_SERVE_MIN_VERSION = "3.0.0" ARCADE_SERVE_MAX_VERSION = "4.0.0" -ARCADE_MCP_SERVER_MIN_VERSION = "1.0.1" +ARCADE_MCP_SERVER_MIN_VERSION = "1.1.1" ARCADE_MCP_SERVER_MAX_VERSION = "2.0.0" diff --git a/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/pyproject.toml b/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/pyproject.toml index 5501a074..59411b62 100644 --- a/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/pyproject.toml +++ b/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/pyproject.toml @@ -9,6 +9,7 @@ description = "MCP Server created with Arcade.dev" requires-python = ">=3.10" dependencies = [ "arcade-mcp-server>={{ arcade_mcp_server_min_version }},<{{ arcade_mcp_server_max_version }}", + "httpx>=0.28.0,<1.0.0", ] [project.optional-dependencies] diff --git a/libs/arcade-mcp-server/arcade_mcp_server/__main__.py b/libs/arcade-mcp-server/arcade_mcp_server/__main__.py index 36b01693..ca9af2d4 100644 --- a/libs/arcade-mcp-server/arcade_mcp_server/__main__.py +++ b/libs/arcade-mcp-server/arcade_mcp_server/__main__.py @@ -54,7 +54,7 @@ def setup_logging(level: str = "INFO", stdio_mode: bool = False) -> None: # Remove existing handlers logger.remove() - # Configure output destination + # In stdio mode, use stderr (stdout is reserved for JSON-RPC) sink = sys.stderr if stdio_mode else sys.stdout # Add handler with appropriate format @@ -69,7 +69,7 @@ def setup_logging(level: str = "INFO", stdio_mode: bool = False) -> None: sink, format=format_str, level=level, - colorize=True, + colorize=(not stdio_mode), diagnose=(level == "DEBUG"), ) diff --git a/libs/arcade-mcp-server/arcade_mcp_server/mcp_app.py b/libs/arcade-mcp-server/arcade_mcp_server/mcp_app.py index bad6d94a..7e77d027 100644 --- a/libs/arcade-mcp-server/arcade_mcp_server/mcp_app.py +++ b/libs/arcade-mcp-server/arcade_mcp_server/mcp_app.py @@ -103,7 +103,8 @@ class MCPApp: self.server: MCPServer | None = None self._load_env() - self._setup_logging() + if not logger._core.handlers: # type: ignore[attr-defined] + self._setup_logging(transport == "stdio") # Properties (exposed below initializer) @property @@ -128,17 +129,21 @@ class MCPApp: load_dotenv(env_path, override=False) logger.info(f"Loaded environment from {env_path}") - def _setup_logging(self) -> None: + def _setup_logging(self, stdio_mode: bool = False) -> None: logger.remove() + + # In stdio mode, use stderr (stdout is reserved for JSON-RPC) + sink = sys.stderr if stdio_mode else sys.stdout + if self.log_level == "DEBUG": format_str = "{level: <8} | {time:HH:mm:ss} | {name}:{line} | {message}" else: format_str = "{level: <8} | {time:HH:mm:ss} | {message}" logger.add( - sys.stdout, + sink, format=format_str, level=self.log_level, - colorize=True, + colorize=(not stdio_mode), diagnose=(self.log_level == "DEBUG"), ) @@ -209,10 +214,13 @@ class MCPApp: logger.error("No tools added to the server. Use @app.tool decorator or app.add_tool().") sys.exit(1) - logger.info(f"Starting {self.name} v{self.version} with {len(self._catalog)} tools") - host, port, transport = MCPApp._get_configuration_overrides(host, port, transport) + # Since the transport could have changed since __init__, we need to setup logging again + self._setup_logging(transport == "stdio") + + logger.info(f"Starting {self.name} v{self.version} with {len(self._catalog)} tools") + if transport in ["http", "streamable-http", "streamable"]: run_arcade_mcp( catalog=self._catalog, diff --git a/libs/arcade-mcp-server/pyproject.toml b/libs/arcade-mcp-server/pyproject.toml index d6b06349..1b897056 100644 --- a/libs/arcade-mcp-server/pyproject.toml +++ b/libs/arcade-mcp-server/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "arcade-mcp-server" -version = "1.1.0" +version = "1.1.1" description = "Model Context Protocol (MCP) server framework for Arcade.dev" readme = "README.md" authors = [{ name = "Arcade.dev" }] diff --git a/pyproject.toml b/pyproject.toml index 287ff2ec..e128247f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "arcade-mcp" -version = "1.0.2" +version = "1.1.0" description = "Arcade.dev - Tool Calling platform for Agents" readme = "README.md" license = {file = "LICENSE"} @@ -21,7 +21,7 @@ requires-python = ">=3.10" dependencies = [ # CLI dependencies - "arcade-mcp-server>=1.1.0,<2.0.0", + "arcade-mcp-server>=1.1.1,<2.0.0", "arcade-core>=3.0.0,<4.0.0", "typer==0.10.0", "rich==13.9.4", @@ -42,7 +42,7 @@ all = [ "pytz>=2024.1", "python-dateutil>=2.8.2", # mcp - "arcade-mcp-server>=1.1.0,<2.0.0", + "arcade-mcp-server>=1.1.1,<2.0.0", # serve "arcade-serve>=3.0.0,<4.0.0", # tdk