Add envvar overrides for mcp app (#606)

Needed for deployed MCP servers so that the Engine can override port,
host, and transport.
This commit is contained in:
Eric Gustin 2025-10-07 12:43:59 -07:00 committed by GitHub
parent ab93356e7c
commit 805ad2d888
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 89 additions and 0 deletions

View file

@ -6,6 +6,7 @@ Provides a clean, minimal API for building MCP servers with lazy initialization.
from __future__ import annotations
import os
import sys
from pathlib import Path
from typing import Any, Callable, Literal, ParamSpec, TypeVar
@ -210,6 +211,8 @@ class MCPApp:
logger.info(f"Starting {self.name} v{self.version} with {len(self._catalog)} tools")
host, port, transport = MCPApp._get_configuration_overrides(host, port, transport)
if transport in ["http", "streamable-http", "streamable"]:
run_arcade_mcp(
catalog=self._catalog,
@ -232,6 +235,37 @@ class MCPApp:
else:
raise ServerError(f"Invalid transport: {transport}")
@staticmethod
def _get_configuration_overrides(
host: str, port: int, transport: TransportType
) -> tuple[str, int, TransportType]:
"""Get configuration overrides from environment variables."""
if envvar_transport := os.getenv("ARCADE_SERVER_TRANSPORT"):
transport = envvar_transport
logger.debug(
f"Using '{transport}' as transport from ARCADE_SERVER_TRANSPORT environment variable"
)
# host and port are only relevant for HTTP Streamable transport
if transport in ["http", "streamable-http", "streamable"]:
if envvar_host := os.getenv("ARCADE_SERVER_HOST"):
host = envvar_host
logger.debug(f"Using '{host}' as host from ARCADE_SERVER_HOST environment variable")
if envvar_port := os.getenv("ARCADE_SERVER_PORT"):
try:
port = int(envvar_port)
except ValueError:
logger.warning(
f"Invalid port: '{envvar_port}' from ARCADE_SERVER_PORT environment variable. Using default port {port}"
)
else:
logger.debug(
f"Using '{port}' as port from ARCADE_SERVER_PORT environment variable"
)
return host, port, transport
class _ToolsAPI:
"""Unified tools API for MCPApp (build-time and runtime)."""

View file

@ -179,3 +179,58 @@ class TestMCPApp:
# Test removing a resource at runtime
removed_resource = await mcp_app.resources.remove("file:///test.txt")
assert removed_resource.uri == "file:///test.txt"
def test_get_configuration_overrides(self, monkeypatch):
"""Test configuration overrides from environment variables."""
# Ensure environment variables are clear at the start
monkeypatch.delenv("ARCADE_SERVER_TRANSPORT", raising=False)
monkeypatch.delenv("ARCADE_SERVER_HOST", raising=False)
monkeypatch.delenv("ARCADE_SERVER_PORT", raising=False)
# Test default values (no environment variables)
host, port, transport = MCPApp._get_configuration_overrides("127.0.0.1", 8000, "http")
assert host == "127.0.0.1"
assert port == 8000
assert transport == "http"
# Test transport override
monkeypatch.setenv("ARCADE_SERVER_TRANSPORT", "stdio")
host, port, transport = MCPApp._get_configuration_overrides("127.0.0.1", 8000, "http")
assert transport == "stdio"
monkeypatch.delenv("ARCADE_SERVER_TRANSPORT")
# Test host override (only works with HTTP transport)
monkeypatch.setenv("ARCADE_SERVER_TRANSPORT", "http")
monkeypatch.setenv("ARCADE_SERVER_HOST", "192.168.1.1")
host, port, transport = MCPApp._get_configuration_overrides("127.0.0.1", 8000, "http")
assert host == "192.168.1.1"
assert transport == "http"
monkeypatch.delenv("ARCADE_SERVER_HOST")
monkeypatch.delenv("ARCADE_SERVER_TRANSPORT")
# Test port override (only works with HTTP transport)
monkeypatch.setenv("ARCADE_SERVER_PORT", "9000")
host, port, transport = MCPApp._get_configuration_overrides("127.0.0.1", 8000, "http")
assert port == 9000
monkeypatch.delenv("ARCADE_SERVER_PORT")
# Test invalid port value
monkeypatch.setenv("ARCADE_SERVER_TRANSPORT", "http")
monkeypatch.setenv("ARCADE_SERVER_PORT", "invalid_port")
host, port, transport = MCPApp._get_configuration_overrides("127.0.0.1", 8000, "http")
assert port == 8000 # Should keep the default value
monkeypatch.delenv("ARCADE_SERVER_PORT")
monkeypatch.delenv("ARCADE_SERVER_TRANSPORT")
# Test host/port with stdio transport
monkeypatch.setenv("ARCADE_SERVER_TRANSPORT", "stdio")
monkeypatch.setenv("ARCADE_SERVER_HOST", "192.168.1.1")
monkeypatch.setenv("ARCADE_SERVER_PORT", "9000")
host, port, transport = MCPApp._get_configuration_overrides("127.0.0.1", 8000, "http")
# For stdio, host and port are still returned but not used by the server
assert host == "127.0.0.1" # Host should remain unchanged for stdio transport
assert port == 8000 # Port should remain unchanged for stdio transport
assert transport == "stdio"
monkeypatch.delenv("ARCADE_SERVER_HOST")
monkeypatch.delenv("ARCADE_SERVER_PORT")
monkeypatch.delenv("ARCADE_SERVER_TRANSPORT")