mcpproxy

Note: mcpproxy is experimental software provided as-is, with no guarantees of security, stability, or fitness for any particular purpose. It has not undergone a security audit. Do not expose it to untrusted networks or use it to handle sensitive data in production.

mcpproxy is a Dockerized, config-driven MCP host that presents a single http://localhost:8888/mcp endpoint to any MCP-capable AI client. Every tool provider is a single YAML file: the YAML embeds the Python async def handler functions directly, declares the tool names, descriptions, and JSON Schema input schemas, and lists the environment variables the server should inject as secrets at call time. Alternatively, a provider can delegate entirely to an existing MCP npm package via an npx: block, with no Python code required. server.py loads all YAML files at startup, executes each code block or spawns the declared npx process, and registers every declared tool automatically — adding a new tool requires only a new YAML file, with no changes to the server.

A FastAPI frontend (port 8889) provides a browser-based interface for the full provider lifecycle. The Tools tab lists all loaded providers in a left panel; clicking a provider opens a form editor for its documentation, code, and per-tool fields, with buttons to add or remove tools, save the file, and restart the MCP server in place. A + New Provider wizard supports both Python code and npx package types; the wizard’s final step lists all required secrets and writes them to .env without leaving the browser. A 🔑 Secrets panel reads declared secrets.env entries from the selected provider, shows which variables are already set, and lets you fill in or update values interactively. A 🛠 Run Command panel runs any shell command inside the server environment and streams output live — particularly useful for npx providers that need one-time setup, such as npx playwright install chrome.

Secrets declared in a provider’s secrets.env block are injected from the environment at call time; their values are never part of the MCP tool schema and are never visible to the LLM. Docker Compose reads .env via env_file; the file is never baked into the image. The tools/ directory is similarly gitignored and must be mounted at runtime.

A pre-built image is published to the GitHub Container Registry on every push to main:

docker pull ghcr.io/billjr99/mcpproxy:latest
docker run -d --rm \
  -p 8888:8888 -p 8889:8889 \
  --env-file .env \
  -v "$(pwd)/tools":/app/tools \
  --name mcpproxy \
  ghcr.io/billjr99/mcpproxy:latest

The package is hosted on GitHub at:

mcpproxy

Quick Start

git clone https://github.com/BillJr99/mcpproxy
cd mcpproxy
./run_local.sh

run_local.sh generates .env.example from any existing tool YAMLs, prompts for missing secret values, creates a virtualenv, installs dependencies, and starts the server. The MCP endpoint is at http://localhost:8888/mcp and the web UI at http://localhost:8889.

Connecting AI Clients

mcpproxy works with any client that speaks the MCP HTTP transport. A few examples:

ClientConfiguration
Claude Codeclaude mcp add --transport http mcpproxy http://localhost:8888/mcp
Claude DesktopAdd {"url": "http://localhost:8888/mcp", "transport": "http"} to claude_desktop_config.json
CursorAdd a server entry in Settings → Features → MCP
ClineMCP Servers tab → Add MCP Server, transport HTTP/SSE
ContinueAdd an entry to .continue/config.json
OpenCodeAdd to opencode.json under mcp.servers
WindsurfSettings → Cascade → MCP
OllamaUse the included tests/ollama_agent.py bridge script

Provider YAML Reference

Each YAML file under tools/ follows this schema:

documentation: |           # optional; shown in the web UI
  Describe this provider.

code: |                    # Python source executed once at startup
  async def my_tool(context, arg1, arg2):
      return {"ok": True, "result": arg1}

# -- OR -- (mutually exclusive with code)
npx:
  command: npx @playwright/mcp@latest --headless --isolated

tools:
  - name: my_tool
    function: my_tool      # async function name from code block
    description: "..."
    input_schema:
      type: object
      properties:
        arg1: {type: string}
      required: [arg1]
    secrets:
      env:
        arg2: MY_SERVICE_API_KEY

Secrets are injected from the environment; they are never part of the tool schema.

Test Suite

pip install -r requirements.txt -r requirements-dev.txt
pytest tests/ -v

Unit tests cover server.py helpers and all frontend/app.py API endpoints. Additional shell scripts (tests/mcp_interactive.sh, tests/test_with_ollama.sh) and a Python agentic loop (tests/ollama_agent.py) support end-to-end validation against a running server.