Fix stdio bugs (#608)
1. Updates `arcade configure claude --from-local` to create a valid json
config for claude desktop. NOTE: The `arcade configure` command needs
some re-work. It's fragile.
2. Fixes bug where stdio servers were sending logs to the wrong sink.
3. Disabled colorized logs for stdio.
4. Added missing dependency `httpx` for servers created with `arcade
new`
## Claude Desktop json configuration for stdio
Personally I like option 1 because the configuration looks the simplest
### Option 1:
Equivalent to `python server.py stdio`
```
{
"globalShortcut": "Alt+Ctrl+Space",
"mcpServers": {
"my_server": {
"command": "/path/to/my/mcp/server/directory/.venv/bin/python",
"args": [
"/path/to/my/mcp/server/directory/server.py",
"stdio"
]
}
}
}
```
### Option 2:
Equivalent to `uv run server.py stdio`
```
{
"mcpServers": {
"my_server": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/my/mcp/server/directory",
"python",
"server.py",
"stdio"
]
}
}
}
```
### Option 3:
Equivalent to `python -m arcade_mcp_server stdio --cwd ./`
```
{
"mcpServers": {
"my_server": {
"command": "/path/to/my/mcp/server/directory/.venv/bin/python",
"args": [
"-m",
"arcade_mcp_server",
"stdio",
"--cwd",
"/path/to/my/mcp/server/directory"
]
}
}
}
```
This commit is contained in:
parent
0cf1a8bd22
commit
b780e5b807
7 changed files with 48 additions and 18 deletions
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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>{level: <8}</level> | <green>{time:HH:mm:ss}</green> | <cyan>{name}:{line}</cyan> | <level>{message}</level>"
|
||||
else:
|
||||
format_str = "<level>{level: <8}</level> | <green>{time:HH:mm:ss}</green> | <level>{message}</level>"
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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" }]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue