mcp-async-repl

mcp-async-repl

Async Python REPL + Shell execution for MCP. Provides persistent state, background jobs, interactive input() bridging, and crash isolation in a single server.

Category
Visit Server

README

mcp-async-repl

Async Python REPL + Shell execution for MCP. Persistent state, background jobs, and interactive input() bridging — in a single server.

The only MCP server that combines a crash-isolated persistent Python worker, true async shell execution, stdin interaction, and job lifecycle management in one package.

What makes this different

Every other Python REPL MCP server runs exec() in the server process and blocks on long-running code. This one doesn't.

  • Crash-isolated Python worker — runs in a separate subprocess with a JSON protocol over stdin/stdout. If your code segfaults, the MCP server stays alive.
  • True async from the start — both shell and Python execution return job IDs immediately if they take >2s. Poll with status tools. Never blocks the server.
  • input() bridging — user code can call input("prompt") and the server surfaces a waiting_input status. Feed text via send_python_input() to unblock it. No other REPL MCP has this.
  • Persistent state — variables survive across execute_python() calls until you restart the worker.
  • Shell + REPL in one server — async shell commands with stdin support alongside the persistent Python worker. No need for two separate MCP servers.
  • Auto venv via uv — creates and manages a .venv automatically. No Docker required.

Install

# Run directly with uvx (no install needed)
uvx mcp-async-repl

# Or install from PyPI
pip install mcp-async-repl

Configuration

Add to your MCP client config:

{
  "mcpServers": {
    "async-repl": {
      "command": "uvx",
      "args": ["mcp-async-repl"]
    }
  }
}

With a custom venv path:

{
  "mcpServers": {
    "async-repl": {
      "command": "uvx",
      "args": ["mcp-async-repl"],
      "env": {
        "REPL_VENV_DIR": "/path/to/your/venv"
      }
    }
  }
}

Claude Desktop

Add to claude_desktop_config.json:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Claude Code

claude mcp add async-repl uvx mcp-async-repl

Cursor

Add to .cursor/mcp.json or ~/.cursor/mcp.json.

Tools (9 total)

Python REPL

Tool Description
execute_python Execute code in a persistent worker. Returns immediately if >2s. Supports input().
send_python_input Feed text to a pending input() call in the worker.
check_python_status Poll status, stdout, stderr, and input prompts for the current job.
list_variables Inspect all variables in the persistent session.
restart_python_worker Kill and restart the worker. Clears all state.

Async Shell

Tool Description
execute_command_async Run any shell command in the background. Returns a job ID.
send_command_input Send stdin text to a running shell job (e.g. y\n, passwords).
check_job_status Poll status and output of a background shell job.

Package Management

Tool Description
install_package_async Install a pip package via uv in the background.

Example session

Full 8-step test run, executed by an LLM agent via Mux-Swarm:

> Test the Python REPL MCP by running these steps in order:
>
> 1. Execute: x = 42; print(f"x is {x}")
> 2. Execute: y = x * 2; print(f"y is {y}")
> 3. List variables
> 4. Execute: name = input("Enter your name: ")
> 5. Send python input: Jonathan
> 6. Execute: print(f"Hello {name}, x={x}")
> 7. Execute: import time; [print(f"tick {i}") for i in range(5) if not time.sleep(1)]
> 8. Restart the python worker, then list variables

── MuxAgent ────────────────────────────────────────────────────────────

## Step 1: Execute initial code with state and stdout
✅ Step 1 passed — State persisted, stdout captured: `x is 42`

## Step 2: Verify x persisted from step 1
✅ Step 2 passed — `x` persisted correctly: `y is 84`

## Step 3: List variables
✅ Step 3 passed — Variables `x` and `y` are present

## Step 4: Execute code with input() — should return waiting_input status
✅ Step 4 passed — Correctly returned `waiting_input` status with prompt: `'Enter your name: '`

## Step 5: Send python input to unblock
✅ Step 5 passed — Input delivered, status changed to `completed`

## Step 6: Verify name persisted alongside x and y
✅ Step 6 passed — All variables persisted: `Hello Jonathan, x=42`

## Step 7: Execute long-running code — should timeout to background
✅ Step 7a passed — Timed out to background as expected.
✅ Step 7b passed — Background job completed with all ticks: `tick 0` through `tick 4`

## Step 8: Restart python worker, then list variables
✅ Step 8 passed — Worker restarted, variables cleared (empty list returned)

───────────────────────────────────────────────────────────────────────

Summary: All Tests Passed ✅

| Step | Test                                      | Result                            |
|------|-------------------------------------------|-----------------------------------|
| 1    | State persistence + stdout capture        | ✅ `x is 42`                       |
| 2    | Variable persistence across calls         | ✅ `y is 84` (x=42 persisted)      |
| 3    | List variables                            | ✅ `x`, `y` found                  |
| 4    | input() returns waiting_input             | ✅ Status: `waiting_input`          |
| 5    | Send input unblocks                       | ✅ Status: `completed`              |
| 6    | All variables persist together            | ✅ `Hello Jonathan, x=42`           |
| 7    | Long-running → background + status check  | ✅ All ticks captured               |
| 8    | Restart clears state                      | ✅ Empty variable list              |

Architecture

┌─────────────────────────────────────────────────────┐
│                   MCP Server                        │
│               (mcp-async-repl)                      │
│                                                     │
│  ┌─────────────────┐    ┌────────────────────────┐  │
│  │  Shell Jobs      │    │  Python Worker Manager │  │
│  │                  │    │                        │  │
│  │  execute_command │    │  ┌──────────────────┐  │  │
│  │  send_input      │    │  │ Worker Subprocess│  │  │
│  │  check_status    │    │  │                  │  │  │
│  │                  │    │  │  Main Thread:    │  │  │
│  │  Each command    │    │  │   stdin loop     │  │  │
│  │  runs as an      │    │  │   (never blocks) │  │  │
│  │  async subprocess│    │  │                  │  │  │
│  │  with job ID     │    │  │  Exec Thread:    │  │  │
│  │                  │    │  │   runs exec()    │  │  │
│  │                  │    │  │   in daemon      │  │  │
│  │                  │    │  │   thread         │  │  │
│  │                  │    │  │                  │  │  │
│  │                  │    │  │  Input Queue:    │  │  │
│  │                  │    │  │   bridges input()│  │  │
│  │                  │    │  │   calls to host  │  │  │
│  └─────────────────┘    │  └──────────────────┘  │  │
│                          └────────────────────────┘  │
└─────────────────────────────────────────────────────┘

The Python worker runs in a separate subprocess communicating via JSON over stdin/stdout. Inside the worker:

  • Main thread reads commands from stdin and dispatches them. Never blocks.
  • Exec thread runs exec() in a daemon thread so input() calls don't starve the command loop.
  • Input queue bridges send_python_input() from the host to builtins.input() inside user code. When code calls input("prompt"), the worker emits an input_request message and blocks on the queue. The host pushes text onto the queue to unblock it.

This means:

  • Long-running code doesn't block the MCP server
  • input() works without a PTY
  • A crash in user code kills the worker, not the server
  • The worker can be restarted cleanly at any time

Environment variables

Variable Default Description
REPL_VENV_DIR .venv Path to the virtual environment. Created automatically via uv if it doesn't exist.

How it compares

Feature mcp-async-repl mcp-python (hdresearch) mcp-python-repl (soufiane-aazizi) mcp-background-job (dylan-gluck)
Persistent Python state
Async (non-blocking) execution
Background job polling
input() bridging
Shell command execution
Shell stdin interaction
Crash-isolated worker N/A
Variable introspection
Package install tool
Auto venv (no Docker)

Requirements

  • Python >= 3.10
  • uv (for venv creation and package installs)
  • mcp (FastMCP)

License

Apache License 2.0

Author

Jonathan Bankston (@jnotsknab)

Built for Mux-Swarm — a CLI-native multi-agent runtime.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured