mcp-pyrepl

aiamblichus/mcp-pyrepl

3.2

If you are the rightful owner of mcp-pyrepl and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

MCP PyREPL is a Model Context Protocol server that allows LLMs to interact with a Python code interpreter.

Tools
4
Resources
0
Prompts
0

MCP PyREPL

A Model Context Protocol (MCP) server that gives an LLM a way to interact with a Python code interpreter. Built on the FastMCP framework, this lightweight, self-contained server enables LLMs (like Claude) to execute Python code in a conversational manner, supporting branching execution paths and package installation on demand without relying on the full Jupyter stack.

Features

  • Conversational Code Execution: Support for branching execution paths that match the non-linear nature of chat conversations
  • Isolated Execution: Run Python code in isolated sessions with state preservation
  • Graph-Based Code Model: Code blocks are organized in a directed acyclic graph (DAG) rather than linear cells
  • Package Installation: Install Python packages on demand within isolated environments
  • Rich Output Support: Capture and display standard output, errors, and rich content (like plots)
  • Efficient Execution: Automatic detection of which code blocks need re-execution
  • Session Management: Create and reset sessions with unique identifiers
  • MCP Integration: Fully compatible with the Model Context Protocol framework

Prerequisites

  • Python 3.13+
  • uv package manager (required for dependency installation)
  • fastmcp CLI (installed automatically with dependencies)

Available Tools

The following MCP tools are provided:

  • create_repl(): Create a new REPL session with a dedicated isolated environment. Pre-installs base packages (numpy, pandas, matplotlib, scipy, scikit-learn, seaborn, plotly) and returns a session ID.
  • run_code(session_id, code, parent_cell_id): Execute code with optional branching from a previous code block. Returns execution results (stdout, stderr, display data, images) and the new cell ID.
  • install_packages(session_id, packages): Install Python packages in the session environment using uv package manager.
  • reset_repl(session_id): Reset a session, terminating the helper process and clearing the graph state.

Important Note: To display matplotlib figures, code must call display_figure(fig) rather than plt.show() or plt.savefig(). The display_figure() function is automatically available in each session's namespace.

Architecture

The system is built on FastMCP and designed around these core components:

  1. MCP Server (server.py): Defines MCP tools using FastMCP decorators and manages user sessions with progress updates for long-running operations
  2. Session Manager (session_manager.py): Manages multiple active sessions, handles creation, retrieval, resurrection from disk, reset, and destruction
  3. Session (session.py): Handles individual session lifecycle, code execution coordination, helper process management, and ZeroMQ communication
  4. Graph Manager (graph_manager.py): Manages code blocks as a directed acyclic graph with persistence and hash-based state tracking for efficient re-execution
  5. Helper Process (helper.py): A dedicated subprocess for each active session that runs within an isolated virtual environment, executing code via IPython and communicating via ZeroMQ IPC sockets
  6. Protocol (protocol.py): Defines the Pydantic-based communication protocol for server-helper communication
  7. Shell Config (shell.py): IPython shell configuration with custom PlotCapturingShell that captures rich display outputs

Each session maintains:

  • A dedicated directory with isolated virtual environment (managed by uv)
  • A graph structure of related code blocks that supports branching execution paths
  • Runtime state between code executions (variables, imports, etc.) preserved across executions
  • A hash-based verification system to detect state changes and optimize execution (only re-executes full paths when code has changed)
  • ZeroMQ IPC sockets for inter-process communication between server and helper processes

Development

  1. Clone the repository
  2. Install dependencies:
uv install
  1. Run the server:

Using FastMCP CLI (recommended):

# Development mode with MCP Inspector
make dev
# or
uv run fastmcp dev src/mcp_pyrepl/server.py

# Production mode (stdio transport)
make run
# or
uv run fastmcp run src/mcp_pyrepl/server.py

# HTTP transport
make run-http
# or
uv run python -m mcp_pyrepl.server --transport http --port 8484

Using the installed entrypoint:

uv run mcp-pyrepl
  1. Run tests:
make test
# or
uv run pytest
  1. Clean build artifacts:
make clean

Project Structure

src/mcp_pyrepl/
ā”œā”€ā”€ server.py         # Main MCP server implementation
ā”œā”€ā”€ session.py        # Session management and execution
ā”œā”€ā”€ session_manager.py # Manages multiple sessions
ā”œā”€ā”€ graph_manager.py  # Manages code block graph and persistence
ā”œā”€ā”€ helper.py         # Helper process for code execution
ā”œā”€ā”€ protocol.py       # Communication protocol definitions
└── shell.py          # IPython shell configuration

Usage Examples

Linear Code Execution

# Create a new session (base packages are pre-installed)
session_id = await create_repl()

# Install additional packages if needed
await install_packages(session_id, ["requests"])

# Run initial code (no parent)
result_1 = await run_code(
    session_id=session_id,
    code="import numpy as np\nimport matplotlib.pyplot as plt",
    parent_cell_id=None
)
cell_1 = result_1[-1].text  # Extract cell ID from response

# Run code that builds on the previous code
result_2 = await run_code(
    session_id=session_id,
    code="""x = np.linspace(0, 10, 100)
y = np.sin(x)""",
    parent_cell_id=cell_1
)
cell_2 = result_2[-1].text  # Extract cell ID from response

# Run a plotting cell that depends on the previous code
# Note: Use display_figure() instead of plt.show()
result_3 = await run_code(
    session_id=session_id,
    code="""fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title('Sine Wave')
display_figure(fig)""",
    parent_cell_id=cell_2
)

Branching Code Execution

# Create a branch from cell_2 with different analysis
result_3a = await run_code(
    session_id=session_id,
    code="""# Calculate some statistics
mean = np.mean(y)
std = np.std(y)
print(f"Mean: {mean}, Std Dev: {std}")""",
    parent_cell_id=cell_2
)
cell_3a = result_3a[-1].text  # Extract cell ID from response

# Create another branch with a different visualization
result_3b = await run_code(
    session_id=session_id,
    code="""# Create a different plot
fig, ax = plt.subplots()
ax.scatter(x, y)
ax.set_title('Sine Wave Scatter')
display_figure(fig)""",
    parent_cell_id=cell_2
)
cell_3b = result_3b[-1].text  # Extract cell ID from response

Resetting a Session

# Reset a session, clearing all state and terminating the helper process
await reset_repl(session_id)
# The helper process will be recreated automatically on next code execution

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.