Skip to main content

A Docker-powered MCP server framework — extend with drop-in kit files and connect to Claude Desktop, LM Studio, OpenWebUI, and more.

Project description

SimpleMCP V2

A Docker-powered MCP-compatible tool server you extend with drop-in kit files — no server code to touch, no venvs to manage. Drop a _kit.py file in, install it with one command, and it's live.

How it works

  • CLI (simplemcp): Manages the full lifecycle — install kits, start/stop/restart/rebuild the server, configure client integrations, manage the CDP browser broker.
  • Docker container: The server runs in an isolated container built from a bundled Dockerfile. On first simplemcp start, the image is built automatically. Use simplemcp rebuild --pull to pull the latest precompiled image from ghcr.io/dwhite-sys/simplemcp.
  • Kits (~/.simplemcp/kits/): Each kit is a plain Python file with @tool-decorated functions and four metadata fields. The container mounts this directory as a volume — kits are live without rebuilding.
  • bootstrap.py: Runs inside the container on every start. Clears __pycache__ so edits to kit files are always picked up fresh. AST-parses each kit's requirements list and installs anything missing via uv pip. Starts the socat CDP proxy (localhost:9222 → host.docker.internal:9222) for the Playwright kit. Execs the real server when done.
  • server.py: FastAPI server inside the container. Auto-discovers all kits at startup, and again on hot-reload. Speaks both SimpleMCP protocol and MCP JSON-RPC on the same port — no mode flag needed. Each kit also gets its own dedicated MCP port (base port + 1, +2, … per kit) for per-kit stdio shim connections.
  • utils/registry.py: The @tool decorator registers functions into a global dict. Type hints are scraped to build JSON Schema for each tool's input automatically.
  • stdio_shim.py: Thin bridge that translates MCP JSON-RPC from stdin to the already-running container's HTTP API. One shim process per kit entry in the client config, all sharing the same container.
  • Config (~/.simplemcp/config.json): Tracks installed kits, running port, container ID, and per-kit port assignments. Written and read exclusively by the CLI.
  • Kit configs (~/.simplemcp/kit_configs/<kit_stem>/config.json): Per-kit config values. Populated from the kit's config = {} dict on install (preserving any values the user has already set), volume-mounted into the container at runtime.

Kit anatomy

# my_kit.py
from utils import tool

kit_name        = "My Tools"
kit_description = "What this kit does."
requirements    = ["requests", "some-package"]
config          = {"MY_VAR": "default_value"}

@tool
def do_something(query: str, limit: int = 10):
    """
    Does something cool with a query.

    query: The search query to use.
    limit: Maximum number of results (default 10).

    Returns {"result": str, "count": int}.
    """
    my_var = os.getenv("MY_VAR", "default_value")
    return {"result": "stuff", "count": limit}
  • kit_name and kit_description are displayed by the protocol, simplemcp list, and client UIs.
  • requirements is AST-parsed by bootstrap.py — no import needed. Missing packages are installed on container start, or immediately into a live container on simplemcp install.
  • config is a dict of {"VAR_NAME": "default"} pairs. Values are stored in ~/.simplemcp/kit_configs/<kit_stem>/config.json, volume-mounted into the container, and available as environment variables. User-set values are preserved across reinstalls.
  • @tool is the only import required. Type hints are mandatory — they build the JSON Schema. Docstrings become the tool description shown to the model; write them for the model, not for humans.

Server protocol

One container, one port, both protocols always running. Each kit also gets its own dedicated MCP port for per-kit stdio connections.

SimpleMCP protocol

Endpoint Method Body Description
/list_kits GET All installed kit names and descriptions
/inspect_kit POST {"kit": "Name"} Kit metadata (name, description, tool count)
/list_tools_in_kit POST {"kit": "Name"} Full tool schemas for a kit
/inspect_tool POST {"tool": "fn_name"} Schema for a single tool
/run_tool POST {"tool": "fn_name", "arguments": {...}} Execute a tool, returns result directly
/reload_kit POST {"kit_stem": "my_kit"} Hot-reload a kit without restart

MCP protocol (JSON-RPC 2.0)

Endpoint Method Description
/mcp POST Handles initialize, tools/list, tools/call
/mcp GET SSE keepalive stream

The /mcp endpoint accepts an optional X-SimpleMCP-Kit header to scope tool listings and calls to a single kit — used automatically by the stdio shim.

Per-kit MCP ports

Each installed kit gets its own MCP port (e.g. kit 1 → 8468, kit 2 → 8469, …). The same /mcp endpoint is served on each port, pre-scoped to that kit. This is what simplemcp compat uses when writing client configs — each kit gets its own stdio shim pointed at its dedicated port.

stdio mode

simplemcp start stdio [kit_name] runs a shim process that bridges MCP JSON-RPC from stdin to the already-running container's per-kit MCP port. The container must already be running.

  • No per-connection container spawning — zero overhead per client connect
  • Multiple shim processes share the same container
  • Each shim targets a specific kit's dedicated port, so tool listings are automatically scoped
  • Omit kit_name to connect to the main port (all kits)

CLI reference

simplemcp install <path/to/kit.py>              Install or update a kit
simplemcp remove <kit_name>                     Remove a kit
simplemcp list                                  List installed kits and status

simplemcp start                                 Start the server (progress bar)
simplemcp start --verbose                       Start with full log output
simplemcp start stdio                           Start stdio shim (all kits)
simplemcp start stdio <kit_name>                Start stdio shim (single kit)
simplemcp stop                                  Stop the server
simplemcp restart                               Restart the server

simplemcp rebuild                               Build image locally and restart
simplemcp rebuild --pull                        Pull precompiled image from ghcr.io and restart
simplemcp rebuild --verbose                     Show full Docker build output

simplemcp compat claude                         Write kit entries to Claude Desktop config
simplemcp compat lmstudio                       Write kit entries to LM Studio config
simplemcp compat openwebui <url> <api_key>      Register kits with OpenWebUI

simplemcp config list <kit_name>                List config variables for a kit
simplemcp config get <kit_name> <var>           Get a config value
simplemcp config set <kit_name> <var> <val>     Set a config value
simplemcp config reset <kit_name> <var>         Reset a config value to its default

simplemcp browser start                         Start Chrome with CDP + the broker process
simplemcp browser stop                          Stop the Chrome CDP broker
simplemcp browser status                        Show broker and Chrome CDP status

Environment variables and kit config

Kits receive configuration through environment variables. There are two sources:

Host env forwarding — The host environment is filtered through an allowlist before being passed into the container. Only variables matching these suffixes are forwarded: _API_KEY, _TOKEN, _SECRET, _URL, _INSTANCE, _HOST, _PORT, _USER, _PASSWORD, _DB. Exact matches TZ, LANG, LC_ALL are also forwarded. Everything else (Windows paths, GPU vars, session vars, etc.) is blocked. Any localhost or 127.0.0.1 references in forwarded values are rewritten to host.docker.internal so kit code can reach host services from inside the container.

Kit config — The config = {"VAR": "default"} dict in a kit file is stored in ~/.simplemcp/kit_configs/<kit_stem>/config.json on install and volume-mounted into the container. Manage values with simplemcp config set/get/list/reset. These are available as environment variables inside the container and take precedence over host env forwarding.

Setup

pip install simplemcp-framework

Docker is the only other dependency. On Linux, simplemcp will attempt to install Docker automatically if missing and will fix docker group permissions with a single sudo call if needed.

simplemcp start

The Docker image builds automatically on first start (~2 minutes). Kit dependencies are installed into a persistent volume so subsequent starts are fast. To use the precompiled image instead:

simplemcp rebuild --pull

Adding a kit

simplemcp install my_kit.py

If the server is already running, the kit is hot-reloaded immediately — no restart needed. Running the same command again on an already-installed kit prints "Updated" and clears the stale bytecode for that kit.

Client integrations

Claude Desktop

simplemcp compat claude

Writes a mcpServers entry for each installed kit to claude_desktop_config.json (path is OS-aware). Each kit gets its own stdio entry pointed at its dedicated port. Removes stale entries for uninstalled kits. Restart Claude Desktop after.

Manual config example:

{
  "mcpServers": {
    "Web Kit V2": {
      "command": "simplemcp",
      "args": ["start", "stdio", "web_kit"]
    },
    "Gotify": {
      "command": "simplemcp",
      "args": ["start", "stdio", "gotify_kit"]
    }
  }
}

LM Studio

simplemcp compat lmstudio

Same format as Claude Desktop, written to ~/.lmstudio/mcp.json. Restart LM Studio after.

OpenWebUI

simplemcp compat openwebui https://your-instance:port sk-your-api-key

Hits POST /api/v1/configs/tool_servers directly — no manual UI steps. Existing non-SimpleMCP tool server entries are preserved. Generate an API key under your OpenWebUI profile → Settings → Account → API Keys (enable API keys in Admin Panel → Settings → General first).

Browser automation (Playwright kit)

The Playwright V2 kit connects to Chrome on your host via the Chrome DevTools Protocol (CDP). It doesn't launch its own browser — it drives the one you're already using.

simplemcp browser start

Launches Chrome with --remote-debugging-port=9222 and starts the broker process that the kit talks to. A socat proxy inside the container forwards localhost:9222 → host.docker.internal:9222 to work around Chrome's host header validation.

Available tools: browser_start, browser_stop, browser_list_tabs, browser_open_tab, browser_close_tab, browser_navigate, browser_get_text, browser_get_page, browser_click, browser_fill_and_submit, browser_screenshot, browser_evaluate.

Tabs are identified by their CDP target ID (a stable UUID assigned by Chrome). No manual tab registry — _context.pages is always the live source of truth.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

simplemcp_framework-2.1.2.tar.gz (44.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

simplemcp_framework-2.1.2-py3-none-any.whl (44.3 kB view details)

Uploaded Python 3

File details

Details for the file simplemcp_framework-2.1.2.tar.gz.

File metadata

  • Download URL: simplemcp_framework-2.1.2.tar.gz
  • Upload date:
  • Size: 44.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for simplemcp_framework-2.1.2.tar.gz
Algorithm Hash digest
SHA256 b8a245eae0c475a78dfcaf705506037bc1d0baa38f438ad96b530bd401cd5740
MD5 abecea018b0c15b190d61a7ce60f55e5
BLAKE2b-256 7fae3a0d465b74890152f8c7153adadad3b06bdcb1a3a09531e4bf567c3644c9

See more details on using hashes here.

File details

Details for the file simplemcp_framework-2.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for simplemcp_framework-2.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1c7700d05ccbb4898fd8561117921c5dc2fae78161d95aa61db9d2efc6b08714
MD5 08ab40a7280c0c823afa7b190cce4c62
BLAKE2b-256 1466b5b06ccc3fea727b077abd9c8476b68caca3c82c69881c14333a88a5e4a2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page