Skip to main content

MCP server for llm-nano-vm — run deterministic LLM programs via Model Context Protocol

Project description

nano-vm-mcp

CI PyPI Python License MCP

MCP server for llm-nano-vm — run deterministic LLM programs via the Model Context Protocol.

Tools

Tool Description
run_program Execute a Program dict → returns trace_id, status, step count, cost
get_trace Retrieve full Trace JSON by trace_id
list_programs List saved programs (id, name, created_at)
get_program Retrieve saved Program JSON by program_id
delete_program Delete a program and all its traces

Install

pip install nano-vm-mcp

For programs with llm steps, install the LiteLLM extra:

pip install 'nano-vm-mcp[litellm]'

Usage

stdio — Claude Desktop / local MCP client

nano-vm-mcp --transport stdio

claude_desktop_config.json:

{
  "mcpServers": {
    "nano-vm-mcp": {
      "command": "nano-vm-mcp",
      "args": ["--transport", "stdio"]
    }
  }
}

SSE — VPS / remote clients

NANO_VM_MCP_API_KEY=your-secret-token nano-vm-mcp --transport sse --port 8080

MCP client URL: http://<host>:8080/sse

With auth header: Authorization: Bearer your-secret-token

Docker Compose (VPS)

services:
  nano-vm-mcp:
    image: ghcr.io/ale007xd/nano-vm-mcp:latest
    ports:
      - "8080:8080"
    volumes:
      - ./data:/data
    environment:
      NANO_VM_MCP_DB: /data/nano_vm_mcp.db
      NANO_VM_MCP_PORT: 8080
      NANO_VM_MCP_API_KEY: your-secret-token
    command: ["nano-vm-mcp", "--transport", "sse"]

Configuration

Copy .env.example to .env:

cp .env.example .env
Variable Default Description
NANO_VM_MCP_DB nano_vm_mcp.db SQLite WAL database path
NANO_VM_MCP_HOST 0.0.0.0 SSE bind host
NANO_VM_MCP_PORT 8080 SSE bind port
NANO_VM_MCP_API_KEY (unset) Bearer token for SSE auth. If unset, all requests are allowed (warning logged)
NANO_VM_MCP_LLM_MODEL (unset) LiteLLM model string for llm steps (e.g. openrouter/meta-llama/llama-3.3-70b-instruct:free)

Endpoints

Path Auth Description
GET /health none Liveness probe — always returns {"status": "ok"}
GET /sse bearer SSE transport entry point
POST /messages bearer MCP message endpoint

Example: run a program

import asyncio
from mcp import ClientSession
from mcp.client.sse import sse_client

program = {
    "steps": [
        {"id": "s1", "type": "tool", "tool": "my_tool", "input": {"query": "hello"}}
    ]
}

async def main():
    headers = {"Authorization": "Bearer your-secret-token"}
    async with sse_client("http://localhost:8080/sse", headers=headers) as (r, w):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.call_tool("run_program", {"program": program, "save_as": "demo"})
            print(result.content[0].text)

asyncio.run(main())

Security

Condition expressions

run_program accepts a full Program dict — including condition steps with arbitrary expression strings. These are evaluated via eval() with __builtins__ cleared. This is a partial sandbox, not full isolation.

Rules for safe use:

  • Condition logic must be authored by you, not generated from untrusted input at runtime.
  • LLM output may appear as a value being tested ('yes' in '$decision'), never as the condition expression itself.
  • If you expose this MCP server to untrusted clients, validate or allowlist condition expressions before passing them to run_program.

Tool registry

ExecutionVM only calls tools that are explicitly registered in its tool registry. Unregistered tool names raise VMError — they are not silently executed.

nano-vm-mcp does not support registering custom tool functions in the server process. Programs with tool steps will raise VMError unless you run ExecutionVM directly with a populated tool registry. This is an intentional architectural constraint.

Avoid registering destructive or privileged tools (filesystem writes, shell exec, database mutations) without an explicit access control layer in your tool implementation.

SSE transport and auth

Set NANO_VM_MCP_API_KEY to enable bearer token authentication on the SSE transport. The comparison is timing-safe (secrets.compare_digest). If the variable is unset, a warning is logged to stderr and all requests are allowed — suitable for localhost only.

Do not expose the SSE endpoint to the public internet without NANO_VM_MCP_API_KEY set or behind a reverse proxy with auth (nginx, Cloudflare Access, VPN).


Roadmap

  • run_program, get_trace, list_programs, get_program, delete_program (v0.1.0)
  • stdio + SSE transports
  • SQLite WAL persistence
  • Bearer token auth for SSE — NANO_VM_MCP_API_KEY, timing-safe (v0.1.0)
  • /health liveness endpoint (unauthenticated)
  • Structured error responses + logging
  • plan_and_run — intent string → Planner → run (P7)
  • Docker image to GHCR

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

nano_vm_mcp-0.1.1.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

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

nano_vm_mcp-0.1.1-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file nano_vm_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: nano_vm_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nano_vm_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 02e03b66f125e30830f114e8629a8373e62c362bb8383007e27c89fcc53f8b5f
MD5 88aba61293c9b2dd98212b6649747d51
BLAKE2b-256 325349066a8364840d12b6e556e085a4f7a7adb81fc2d706c2bd679f51ddba37

See more details on using hashes here.

File details

Details for the file nano_vm_mcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: nano_vm_mcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nano_vm_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 01111423f1840b950a6edfef67edfd7e330d881f1944d5a287c86768347ed12b
MD5 1647f84d43a4583e8578abd04f80df6b
BLAKE2b-256 634c90701177eb379f570486cacba6da72a912a288010146e26cbcdbc4676d38

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