From ec735fe42037a541c8ab62b10e2c70f7bef71f8c Mon Sep 17 00:00:00 2001 From: Albert DeFusco Date: Thu, 14 May 2026 10:58:15 -0400 Subject: [PATCH 1/3] anaconda api-key replacement in template --- src/anaconda_mcp/utils.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/anaconda_mcp/utils.py b/src/anaconda_mcp/utils.py index bd80da03..5d2ecbf2 100644 --- a/src/anaconda_mcp/utils.py +++ b/src/anaconda_mcp/utils.py @@ -7,21 +7,21 @@ def _render_config_template(config_path: str) -> str: - """Render config template by replacing {{PYTHON_EXECUTABLE}} with sys.executable. + """Render config template by replacing placeholders with runtime values. Creates a temporary rendered config file from the template. - Supports multiple ways to specify the Python executable: - 1. Environment variable: ANACONDA_MCP_PYTHON_EXECUTABLE - 2. sys.executable (default) + Placeholders: + {{PYTHON_EXECUTABLE}} - resolved from ANACONDA_MCP_PYTHON_EXECUTABLE or sys.executable + {{ANACONDA_TOKEN}} - resolved from anaconda-auth token (empty string if not authenticated) Returns the path to the rendered config file. """ + from anaconda_mcp.auth import get_auth_token config_file = Path(config_path) template_path = config_file.parent / f"{config_file.name}.template" - # If template exists, use it; otherwise use the config file itself source_path = template_path if template_path.exists() else config_file if not source_path.exists(): @@ -29,15 +29,15 @@ def _render_config_template(config_path: str) -> str: content = source_path.read_text() - # Determine which Python executable to use - # Priority: 1. Environment variable, 2. sys.executable python_executable = settings.PYTHON_EXECUTABLE or sys.executable - - # Replace the placeholder with the Python executable - # Escape backslashes for Windows paths python_path = python_executable.replace("\\", "\\\\") content = content.replace("{{PYTHON_EXECUTABLE}}", python_path) - content = content.replace('"python"', f'"{python_path}"') # Fallback for non-template + content = content.replace('"python"', f'"{python_path}"') + + anaconda_token = get_auth_token() + if anaconda_token is None: + raise RuntimeError("Not authenticated with Anaconda. Run 'anaconda-auth login' or sign in when prompted.") + content = content.replace("{{ANACONDA_TOKEN}}", anaconda_token) rendered_fd, rendered_path = tempfile.mkstemp(suffix=".toml", prefix="mcp_compose_") try: From 0080fd0170c7357c18e677d6fca25a8df02f5da2 Mon Sep 17 00:00:00 2001 From: Albert DeFusco Date: Thu, 14 May 2026 10:58:50 -0400 Subject: [PATCH 2/3] remove dependency on anon-usage --- src/anaconda_mcp/cli.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/anaconda_mcp/cli.py b/src/anaconda_mcp/cli.py index f857b27d..2c795da0 100644 --- a/src/anaconda_mcp/cli.py +++ b/src/anaconda_mcp/cli.py @@ -7,7 +7,6 @@ from pathlib import Path import click -from anaconda_anon_usage.tokens import client_token from mcp_compose.cli import ( compose_command as _compose, ) @@ -47,6 +46,17 @@ logger = logging.getLogger(__name__) +_AAU_TOKEN_PATH = Path.home() / ".conda" / "aau_token" + + +def _read_client_token() -> str: + try: + if _AAU_TOKEN_PATH.is_file(): + return _AAU_TOKEN_PATH.read_text().strip().split()[0] + except OSError: + pass + return "" + def _send_install_event(): try: @@ -117,7 +127,7 @@ def _handle_sigterm(signum, frame): snake_eyes = SnakeEyes() start_login(lambda x: x) active_user_params: dict[str, str] = {} - aau = client_token() + aau = _read_client_token() if aau: active_user_params["aau_client_id"] = aau snake_eyes.send( From d616712c8ddb745fdfc2c203332f43e5d2f65428 Mon Sep 17 00:00:00 2001 From: Albert DeFusco Date: Thu, 14 May 2026 11:10:47 -0400 Subject: [PATCH 3/3] switch to conda-mcp-lite --- pyproject.toml | 1 + src/anaconda_mcp/mcp_compose.toml | 30 +++++++++----------- src/anaconda_mcp/mcp_compose.toml.template | 32 ++++++++++------------ 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e348a48a..cdbd23e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ dependencies = [ "anaconda-cli-base>=0.8.1,<1.0.0", "click>=8.2.0,<9.0.0", "platformdirs>=4.0.0,<5", + "conda-mcp-lite", "rich>=13.0.0" ] diff --git a/src/anaconda_mcp/mcp_compose.toml b/src/anaconda_mcp/mcp_compose.toml index 3b921c63..09443163 100644 --- a/src/anaconda_mcp/mcp_compose.toml +++ b/src/anaconda_mcp/mcp_compose.toml @@ -39,21 +39,26 @@ domain = "anaconda.com" # ============================================================================ # ============================================================================ -# Proxied Streamable HTTP MCP Servers +# Proxied STDIO MCP Servers # ============================================================================ -[[servers.proxied.streamable-http]] +[[servers.proxied.stdio]] name = "conda" -url = "http://localhost:4041/mcp" +command = ["python", "-m", "conda_mcp_lite"] +restart_policy = "on-failure" +max_restarts = 3 + +# ============================================================================ +# Proxied Streamable HTTP MCP Servers (remote, no auto_start) +# ============================================================================ +[[servers.proxied.streamable-http]] +name = "search" +url = "https://stage.anaconda.com/api/search/mcp" timeout = 30 keep_alive = true reconnect_on_failure = true max_reconnect_attempts = 10 health_check_enabled = false mode = "proxy" -auto_start = true -command = ["python", "-m", "environments_mcp_server", "start", "--transport", "streamable-http", "--port", "4041"] -startup_delay = 3 - # ============================================================================ # Tool Manager Configuration @@ -74,13 +79,4 @@ version_suffix_format = "_v{version}" # REST API Configuration # ============================================================================ [api] -enabled = true -path_prefix = "/api/v1" -host = "0.0.0.0" -port = 8888 -cors_enabled = true -cors_origins = ["http://localhost:3000"] -cors_methods = ["GET", "POST", "PUT", "DELETE"] -docs_enabled = true -docs_path = "/docs" -openapi_path = "/openapi.json" +enabled = false diff --git a/src/anaconda_mcp/mcp_compose.toml.template b/src/anaconda_mcp/mcp_compose.toml.template index fe962835..06da60a8 100644 --- a/src/anaconda_mcp/mcp_compose.toml.template +++ b/src/anaconda_mcp/mcp_compose.toml.template @@ -43,21 +43,28 @@ domain = "anaconda.com" # ============================================================================ # ============================================================================ -# Proxied Streamable HTTP MCP Servers +# Proxied STDIO MCP Servers # ============================================================================ -[[servers.proxied.streamable-http]] +[[servers.proxied.stdio]] name = "conda" -url = "http://localhost:4041/mcp" +command = ["{{PYTHON_EXECUTABLE}}", "-m", "conda_mcp_lite"] +restart_policy = "on-failure" +max_restarts = 3 + +# ============================================================================ +# Proxied Streamable HTTP MCP Servers (remote, no auto_start) +# ============================================================================ +[[servers.proxied.streamable-http]] +name = "search" +url = "https://stage.anaconda.com/api/search/mcp" +auth_token = "{{ANACONDA_TOKEN}}" +auth_type = "bearer" timeout = 30 keep_alive = true reconnect_on_failure = true max_reconnect_attempts = 10 health_check_enabled = false mode = "proxy" -auto_start = true -command = ["{{PYTHON_EXECUTABLE}}", "-m", "environments_mcp_server", "start", "--transport", "streamable-http", "--port", "4041"] -startup_delay = 3 - # ============================================================================ # Tool Manager Configuration @@ -78,13 +85,4 @@ version_suffix_format = "_v{version}" # REST API Configuration # ============================================================================ [api] -enabled = true -path_prefix = "/api/v1" -host = "0.0.0.0" -port = 8888 -cors_enabled = true -cors_origins = ["http://localhost:3000"] -cors_methods = ["GET", "POST", "PUT", "DELETE"] -docs_enabled = true -docs_path = "/docs" -openapi_path = "/openapi.json" +enabled = false