Skip to main content
Glama

MCP Server Code Execution Mode

by elusznik
GUIDE.mdβ€’14.3 kB
# User Guide A comprehensive guide to using the MCP Server Code Execution Mode bridge. ## Table of Contents - [Installation](#installation) - [Configuration](#configuration) - [MCP Server Setup](#mcp-server-setup) - [Usage Patterns](#usage-patterns) - [Advanced Topics](#advanced-topics) - [Troubleshooting](#troubleshooting) - [Best Practices](#best-practices) ## Installation ### Prerequisites #### 1. Container Runtime **Option A: Podman (Recommended)** ```bash # macOS brew install podman # Ubuntu/Debian sudo apt-get install podman # Verify podman --version ``` **Option B: Rootless Docker** ```bash # macOS brew install docker # Ubuntu/Debian sudo apt-get install docker.io # Add user to docker group sudo usermod -aG docker $USER newgrp docker ``` #### 2. Container Image ```bash # Pull image podman pull python:3.12-slim # Or with Docker docker pull python:3.12-slim # Verify podman images python:3.12-slim ``` ### Setup #### 1. Install Dependencies ```bash # Using pip pip install -r requirements.txt # Or using uv (recommended) uv sync ``` #### 2. Test Installation ```bash uv run python mcp_server_code_execution_mode.py ``` This starts the MCP server. If no errors occur, the installation is successful. #### 3. Register with MCP Client **Claude Code:** Create `~/.config/mcp/servers/mcp-server-code-execution-mode.json`: ```json { "mcpServers": { "mcp-server-code-execution-mode": { "command": "uv", "args": ["run", "python", "/absolute/path/to/mcp_server_code_execution_mode.py"], "env": { "MCP_BRIDGE_RUNTIME": "podman" } } } } ``` **For other MCP clients:** Add server to your client configuration: ```json { "mcpServers": { "mcp-server-code-execution-mode": { "command": "python3", "args": ["/path/to/mcp_server_code_execution_mode.py"] } } } ``` #### 4. Restart MCP Client Restart Claude Code or your MCP client to load the new server. ## Configuration ### Environment Variables Control bridge behavior with environment variables: #### Runtime Configuration ```bash # Force specific runtime export MCP_BRIDGE_RUNTIME=podman # or export MCP_BRIDGE_RUNTIME=docker # Custom container image export MCP_BRIDGE_IMAGE=python:3.11-slim # Default timeout (seconds) export MCP_BRIDGE_TIMEOUT=30 # Maximum allowed timeout export MCP_BRIDGE_MAX_TIMEOUT=120 ``` #### Resource Limits ```bash # Memory limit (format: number + unit) export MCP_BRIDGE_MEMORY=512m export MCP_BRIDGE_MEMORY=1g # Process limit export MCP_BRIDGE_PIDS=128 # CPU limit (can be decimal) export MCP_BRIDGE_CPUS=2.0 # Container user (UID:GID) export MCP_BRIDGE_CONTAINER_USER=1000:1000 ``` #### Advanced Options ```bash # Runtime idle timeout (seconds) # Podman machine auto-shutdown delay export MCP_BRIDGE_RUNTIME_IDLE_TIMEOUT=300 ``` ### Configuration File **Note:** The bridge currently does not support loading variables from a `.env` file. All configuration must be done via environment variables or container runtime settings. ## MCP Server Setup ### Automatic Discovery The bridge auto-discovers MCP servers from: 1. **Claude Code Config** - `~/.claude.json` - `~/Library/Application Support/Claude Code/claude_code_config.json` - `~/Library/Application Support/Claude/claude_code_config.json` *(early Claude Code builds)* - `~/Library/Application Support/Claude/claude_desktop_config.json` *(legacy Claude Desktop)* 2. **MCP Servers Directory** - `~/.config/mcp/servers/*.json` - `./mcp-servers/*.json` 3. **Local Config** - `./claude_code_config.json` - `./claude_desktop_config.json` *(legacy fallback)* ### Example: Filesystem Server ```bash # Create server config mkdir -p ~/.config/mcp/servers cat > ~/.config/mcp/servers/filesystem.json << 'EOF' { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], "env": {} } } } EOF ``` ### Example: PostgreSQL Server ```bash cat > ~/.config/mcp/servers/postgres.json << 'EOF' { "mcpServers": { "postgres": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://user:pass@localhost/mydb"], "env": {} } } } EOF ``` ### Example: Git Server ```bash cat > ~/.config/mcp/servers/git.json << 'EOF' { "mcpServers": { "git": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-git", "/path/to/repo"], "env": {} } } } EOF ``` ### Verifying Discovery The bridge logs discovered servers on startup: ``` 2024-01-01 12:00:00 - INFO - Loaded MCP servers: filesystem, postgres, git ``` ## Usage Patterns ### Response Format (TOON) The bridge wraps every tool response in a [Token-Oriented Object Notation](https://github.com/toon-format/toon) code block. TOON keeps the familiar JSON fields (status, stdout, stderr, etc.) but removes repeated keys and normalises arrays, typically saving 30–60% tokens for uniform tabular data. Lower token counts mean cheaper LLM calls and tighter prompts. If the encoder is unavailable the bridge automatically falls back to pretty-printed JSON, so integrations that expect bare JSON can still parse the payload without extra configuration. ### Basic Pattern: Direct Tool Use ```python # Call a single tool result = await mcp_filesystem.read_file(path='/tmp/data.txt') print(result) ``` ### Pattern: Chained Operations ```python # Chain multiple operations data = await mcp_server.read_data() processed = process(data) await mcp_server.write_data(data=processed) ``` ### Pattern: Data Pipeline ```python # Extract source_data = await mcp_source.fetch() # Transform cleaned = clean_data(source_data) # Load await mcp_destination.save(data=cleaned) # Report print(f"Processed {len(cleaned)} items") ``` ### Pattern: Batch Processing ```python # Get list items = await mcp_api.list_items() # Process in parallel tasks = [ mcp_api.process_item(id=item.id) for item in items ] # Wait for all results = await asyncio.gather(*tasks) ``` ### Pattern: Error Handling ```python try: result = await mcp_api.risky_operation() except Exception as e: print(f"Operation failed: {e}") # Fallback or retry logic ``` ### Pattern: Conditional Execution ```python # Check before acting status = await mcp_service.check_status() if status.ready: await mcp_service.execute() else: print("Service not ready") ``` ### Pattern: Multi-Server Workflow ```python # Get data from service A data = await mcp_service_a.fetch_data(query='xyz') # Process with service B processed = await mcp_service_b.process(data=data) # Save with service C await mcp_service_c.save(data=processed) # Notify with service D await mcp_service_d.notify(message='Done') ``` ### Pattern: Discover and Select Servers ```python from mcp import runtime # See everything the bridge knows about without loading schemas print("Discovered:", runtime.discovered_servers()) # Metadata for servers already loaded in this run print("Loaded metadata:", runtime.list_loaded_server_metadata()) # Ask the host to enumerate every available server (RPC call) available = await runtime.list_servers() print("Selectable via RPC:", available) # Peek at tool docs before deciding to use them loaded = runtime.list_loaded_server_metadata() if loaded: description = runtime.describe_server(loaded[0]["name"]) for tool in description["tools"]: print(tool["alias"], "β†’", tool.get("description", "")) ``` Typical output for the stub test server: ``` Discovered: ('stub',) Loaded metadata: ({'name': 'stub', 'alias': 'stub', 'tools': [{'name': 'echo', 'alias': 'echo', 'description': 'Echo the provided message', 'input_schema': {...}}]},) Selectable via RPC: ('stub',) ``` ## Advanced Topics ### Custom Timeout Per Call ```python # Set timeout for specific operation result = await mcp_slow_service.long_operation( timeout=60 # Override default 30s ) ``` ### Loading Specific Servers ```python # Only load necessary servers # When invoking run_python from your MCP client, specify the servers you need: # servers=['filesystem'] # Inside the sandboxed code you simply call the proxy: result = await mcp_filesystem.read_file(path='/tmp/test.txt') ``` ### Accessing Raw MCP Client ```python # Direct server access server = mcp_servers['filesystem'] result = await server.read_file(path='/tmp') ``` ### Loading Specific Servers **Note:** The `servers` parameter is only used when making the initial MCP tool call. The sandbox code sees only the proxies that were requested up front. ## Troubleshooting ### Container Runtime Not Found **Problem:** ``` Error: No container runtime found ``` **Solution:** 1. Install podman or docker 2. Verify: `podman --version` 3. Set explicit runtime: `export MCP_BRIDGE_RUNTIME=podman` ### Image Pull Failed **Problem:** ``` Error: Failed to pull image python:3.12-slim ``` **Solution:** ```bash # Manually pull podman pull python:3.12-slim # Or use different image export MCP_BRIDGE_IMAGE=python:3.11-slim ``` ### Gateway Servers Fail to Initialize **Problem:** ``` failed to connect: calling "initialize": EOF ``` **Solution:** 1. Authenticate the Docker daemon with every registry referenced in the gateway catalog (run `docker login` for Docker Hub and `ghcr.io` as needed). 2. Ensure required secrets (for example `github.personal_access_token` for `github-official`) are set via `docker mcp secret set <name>` or your gateway's secrets backend. 3. Replicate any expected environment variables or volume mounts defined in the catalog so each server can find its configuration data. 4. Re-run the bridge and inspect the gateway logs; if `list_tools` only returns `mcp-add`/`code-mode`, the external servers still are not starting. ### Permission Denied **Problem:** ``` Error: permission denied while trying to connect ``` **Solution:** ```bash # Add user to docker group sudo usermod -aG docker $USER newgrp docker # Or use podman (user namespaces) podman info # Verify user namespace ``` ### Timeout Errors **Problem:** ``` SandboxTimeout: Code exceeded timeout ``` **Solution:** ```bash # Increase timeout export MCP_BRIDGE_TIMEOUT=60 # Or per-call result = await mcp_operation(timeout=60) ``` ### Server Not Found **Problem:** ``` Error: MCP server 'xyz' is not loaded ``` **Solution:** 1. Verify server in config: `~/.config/mcp/servers/*.json` 2. Check bridge logs for discovery messages 3. Restart bridge after adding server 4. Explicitly request server: `servers=['xyz']` ### Network Issues (In Container) **Problem:** ``` Error: Network is unreachable ``` **Expected:** Containers have no network access by design. **Solution:** Access resources via MCP servers only. ### Out of Memory **Problem:** ``` Error: Memory limit exceeded ``` **Solution:** ```bash # Increase memory limit export MCP_BRIDGE_MEMORY=1g # Or optimize code # - Process data in chunks # - Use generators # - Clear references ``` ### Too Many Processes **Problem:** ``` Error: Cannot fork: Resource temporarily unavailable ``` **Solution:** ```bash # Increase PID limit export MCP_BRIDGE_PIDS=256 # Or reduce process count in code ``` ### Slow Performance **Problem:** Container startup is slow **Solutions:** 1. Keep podman machine running (avoid shutdown) 2. Use local image: `podman pull python:3.12-slim` 3. Consider caching strategies 4. Reuse containers (not currently supported) ## Best Practices ### 1. Resource Management ```python # GOOD: Process data in memory data = await mcp_api.get_data() processed = [item.transform() for item in data] # BAD: Write large files to disk await mcp_fs.write_file(path='/tmp/big.txt', data=huge_data) ``` ### 2. Error Handling ```python # GOOD: Handle errors gracefully try: result = await mcp_api.operation() except Exception as e: logger.error(f"Operation failed: {e}") return None # BAD: No error handling result = await mcp_api.operation() ``` ### 3. Batching ```python # GOOD: Batch requests results = await asyncio.gather( mcp_api.call1(), mcp_api.call2(), mcp_api.call3() ) # BAD: Sequential calls r1 = await mcp_api.call1() r2 = await mcp_api.call2() r3 = await mcp_api.call3() ``` ### 4. Timeouts ```python # GOOD: Set appropriate timeouts await mcp_fast_operation() # Uses default 30s await mcp_slow_operation(timeout=60) # Explicit 60s # BAD: Using default for all await mcp_slow_operation() # May timeout ``` ### 5. Code Organization ```python # GOOD: Modular code def process_user_data(user_id): data = await mcp_api.get_user(user_id) return transform_user_data(data) # Extract, transform, load data = extract() processed = transform(data) await load(processed) # BAD: Monolithic code result = await mcp_api.call1() result2 = await mcp_api.call2(result) result3 = await mcp_api.call3(result2) ``` ### 6. Security ```python # GOOD: Use MCP servers for sensitive operations await mcp_vault.get_secret('api_key') # BAD: Hardcode secrets API_KEY = "sk-1234567890abcdef" ``` ### 7. Idempotency ```python # GOOD: Idempotent operations await mcp_api.upsert_record(id='123', data=updated_data) # BAD: Non-idempotent await mcp_api.create_record(id='123', ...) await mcp_api.create_record(id='123', ...) # Duplicate ``` ### 8. Logging ```python # GOOD: Log operations logger.info(f"Processing {len(items)} items") result = await mcp_api.batch_process(items) logger.info(f"Completed: {result.count} processed") # BAD: Silent operations result = await mcp_api.batch_process(items) ``` ### 9. Data Size ```python # GOOD: Work with reasonable chunks for batch in chunk_large_list(large_list, size=100): await mcp_api.process_batch(batch) # BAD: Process everything at once await mcp_api.process_batch(huge_list) ``` ### 10. Cleanup ```python # Container auto-cleans up, but: # - Use temporary paths for files # - Let context managers handle cleanup # - Don't rely on persistent state # Each execution is stateless ``` ## Examples See [README.md](README.md#usage-examples) for more examples. ## Support For issues, questions, or contributions: - Check [STATUS.md](STATUS.md) for roadmap - Review [ARCHITECTURE.md](ARCHITECTURE.md) for technical details - See [HISTORY.md](HISTORY.md) for evolution

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/elusznik/mcp-server-code-execution-mode'

If you have feedback or need assistance with the MCP directory API, please join our Discord server