ipython-mcp
This server exposes a persistent IPython namespace as an MCP tool server, letting agents execute Python, inspect and call live objects, manage the namespace, and register dynamic tools.
Execute Python: run expressions, statements, definitions, and multiline blocks in one persistent IPython shell; returns stdout, stderr, display data, final values, and structured errors.
Call functions: resolve a live callable by name and call it with JSON keyword arguments, returning a JSON-compatible result.
Discover and inspect: list visible callables with signatures/modules/docs, search namespace objects by name, and inspect one object's kind, type, signature, docs, and safe representation.
Manage the namespace: remove specific unprotected top-level names, reset user-created names while preserving runtime/configured bindings, and reload named modules.
Register/unregister dynamic tools: explicitly publish supported top-level synchronous callables as MCP tools with JSON schemas and fingerprints, and remove them idempotently.
Persistent state: variables, functions, classes, imports, and module state survive across calls until the server lifespan ends.
Bounded output: responses include truncation flags and omitted-character counts for stdout, stderr, results, tracebacks, and display data.
Profile support: the full profile exposes ten tools; a compact profile exposes only
executeandcall_functionwith minified JSON text replies.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ipython-mcpWrite and execute a Python function to check if a number is prime, then test it on 17."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ipython-mcp
ipython-mcp exposes one persistent, trusted local IPython namespace through
FastMCP. Variables, functions, classes, imports, module state, and explicitly
registered dynamic tools survive across calls until the server lifespan ends.
The FastMCP server owns one in-process IPython InteractiveShell on a dedicated
worker thread. Python execution, namespace operations and teardown are
serialized on that thread and awaited asynchronously. Tool discovery reads
published schema snapshots without waiting for active Python execution, so
tools/list and ping remain responsive during ordinary long-running work.
Live Python objects stay in the process; there is no runtime child process or
object-encoding protocol.
This is intentionally not a sandbox. User Python has the server process's permissions. Once a call starts executing Python it runs until it returns or raises. Cancellation cannot terminate running Python; namespace execution and teardown stay serialized until it finishes. Native extensions that hold the GIL can still block the process. Code that never returns requires restarting the trusted local server.
Install and run
From a source checkout:
uv sync --extra dev
uv run ipython-mcpFrom a built wheel:
uv build
uv tool install dist/ipython_mcp-0.1.0-py3-none-any.whl
ipython-mcpThe console entry point uses stdio. It writes no non-protocol data to stdout;
optional operational logs go to stderr and contain metadata only.
User code receives EOF on stdin (input() raises EOFError). Owner operations
isolate their standard streams from the transport; execute retains bounded
stdout/stderr in its response, while other operations discard direct output.
Register a source checkout with Codex (replace the path):
codex mcp add ipython -- \
uv run --directory /absolute/path/to/ipython-mcp ipython-mcpFor a wheel installed with uv tool install:
codex mcp add ipython -- ipython-mcpRelated MCP server: repl-mcp
Stable tool surface
The default full profile publishes ten stable tools. Registered callables are additional,
opt-in tools and are never published automatically.
listreturns visible callables with bounded signatures, modules, and docs.executeruns expressions, statements, definitions, and multiline blocks; it returns bounded stdout, stderr, display data, final values, and structured failures.call_functionresolves a live callable withouteval, binds a JSON object as keyword arguments, and returns a JSON-compatible value.searchfinds visible objects by exact or partial name with bounded metadata.reloadexplicitly reloads named modules and refreshes shell bindings.inspectreturns one object's kind, type, signature, module, docs, and safe representation with field-level truncation flags.removepartitions unique top-level names intoremoved,refused, andunknownwhile protecting IPython and configured module bindings.resetremoves unprotected user names, restores configured bindings, clears dynamic registrations, and preserves the monotonic execution count.register_toolexplicitly publishes one supported top-level synchronous callable with a deterministic JSON schema and fingerprint.unregister_toolidempotently removes requested dynamic registrations.
All ten paths use the same shell and registry. Live Python objects never cross a process boundary and response models contain no request, queue, worker, recovery, or epoch metadata.
Compact profile and reusable agent workflows
Set IPYTHON_MCP_PROFILE=compact and restart the server to expose only
execute and call_function. This profile omits output schemas and returns a
single minified JSON text block that Codex CLI can read. Empty protocol fields
are omitted; user values such as false, 0, null, empty containers, errors
and truncation indicators remain intact. Use full for discovery,
registration, cleanup and typed structuredContent.
The repo skill is discoverable through
.agents/skills/ipython-mcp; invoke $ipython-mcp in this repository or
reference its absolute path from another project. It teaches agents to load
data once, retain live objects, batch helper calls with artifact writing and
assertions, and return bounded summaries. Persist reusable helpers under the
active project's .ipython-mcp/snippets/ directory; the
example helper provides a bounded CSV
summary. Use absolute paths because the server's working directory can differ
from the agent's. Snippet files survive server restarts; live objects do not.
Measure with Codex CLI
With the project's .venv installed and Codex already signed in:
uv run --no-sync python scripts/codex_benchmark.py \
--output-dir /tmp/ipython-mcp-benchmark-new \
--models gpt-5.6-luna gpt-6-astra --repeats 1Use a fresh output directory for each experiment. The harness compares the
full profile without a skill against compact with the repo skill. Each case
reuses live rows across calls, saves a helper, then starts a fresh Codex/MCP
process to reuse that unchanged helper on another fixture. An independent
interpreter checks outputs and helper hashes. Prompts, invocation arguments,
raw events, actual token usage and correctness evidence are retained; a failed
case returns a nonzero exit status. --case MODEL/CONDITION selects one case
and --timeout bounds each CLI process.
The earlier measurements recorded 10.3% and 19.5% fewer total tokens with Luna and Astra on the pre-integration worker-process revision. They include skill-reading overhead and are historical evidence, not measurements of the current in-process runtime. The in-process CLI verification passed with both models, including unchanged helper reuse in a fresh session; its four compact-profile sessions consumed 284,054 total tokens including cached input. It does not provide a new full-profile comparison.
Optional startup task environment
A server can prepare one named uv environment before constructing IPython. The environment lives under an explicit workspace outside the project. It is created without system site packages using the same Python major/minor as the server, or safely reused only when its recorded Python and canonical requirements fingerprint match.
Both IPYTHON_MCP_ENVIRONMENT_WORKSPACE and
IPYTHON_MCP_ACTIVE_ENVIRONMENT are required to enable provisioning. When
both are omitted, uv is never called and the ordinary in-process startup path
is unchanged. Environment variables, trusted library paths, and preloads may
still be used without a uv environment.
Example:
codex mcp add ipython \
--env IPYTHON_MCP_ENVIRONMENT_WORKSPACE=/absolute/task-environments \
--env IPYTHON_MCP_ACTIVE_ENVIRONMENT=analytics-v1 \
--env 'IPYTHON_MCP_ENVIRONMENT_REQUIREMENTS=["polars==1.32.3"]' \
--env 'IPYTHON_MCP_ENVIRONMENT_VARIABLES={"TASK_MODE":"offline"}' \
--env IPYTHON_MCP_LIBRARY_PATHS=/absolute/agent-libraries \
--env IPYTHON_MCP_PRELOAD_MODULES=polars,my_agent_lib \
--env 'IPYTHON_MCP_MODULE_ALIASES={"polars":"pl","my_agent_lib":"lib"}' \
-- ipython-mcpEquivalent project-scoped Codex configuration:
[mcp_servers.ipython]
command = "ipython-mcp"
startup_timeout_sec = 310
[mcp_servers.ipython.env]
IPYTHON_MCP_ENVIRONMENT_WORKSPACE = "/absolute/task-environments"
IPYTHON_MCP_ACTIVE_ENVIRONMENT = "analytics-v1"
IPYTHON_MCP_ENVIRONMENT_REQUIREMENTS = '["polars==1.32.3"]'
IPYTHON_MCP_ENVIRONMENT_VARIABLES = '{"TASK_MODE":"offline"}'
IPYTHON_MCP_LIBRARY_PATHS = "/absolute/agent-libraries"
IPYTHON_MCP_PRELOAD_MODULES = "polars,my_agent_lib"
IPYTHON_MCP_MODULE_ALIASES = '{"polars":"pl","my_agent_lib":"lib"}'Startup order is fixed:
Validate the workspace, safe environment name, bounded PEP 508 requirements, variables, paths, module names, and aliases.
Create a temporary uv environment and atomically rename it into place, or verify an existing environment's metadata.
Prepend the selected site-packages, then apply configured variables and trusted library paths.
Import every preload and validate its unique, non-protected alias.
Construct the only
InteractiveShelland bind the preloaded modules.
The selected environment and all startup configuration are immutable for that server process. Change configuration by restarting the server. A different dependency set should use a new environment name; no environment create, switch, list, delete, or activate MCP tools exist.
Configuration, path, uv, dependency, preload, or binding failures abort the
lifespan before a shell is exposed. Temporary directories are removed, process
environment and sys.path changes are rolled back, and the project is not
modified. Diagnostics identify the failed phase, are bounded by
IPYTHON_MCP_MAX_TEXT_CHARS, redact configured variable values and URL
credentials, and are never persisted in the environment metadata.
Configuration reference
Environment variable | Meaning |
|
|
| Absolute workspace outside the project; configure with |
| Safe environment name ( |
| JSON array of bounded PEP 508 requirements; requires an active environment. |
| JSON object of environment-variable string values applied before preloads. |
| Positive finite timeout for each uv phase; default |
| Trusted library directories separated by the platform path separator. |
| Comma-separated modules imported before shell construction. |
| JSON object mapping configured preload modules to unique safe bindings. |
| Returned text and startup-diagnostic bound; default |
| Representation bound; default |
| Traceback bound; default |
| Retained collection/discovery items; default |
| Retained display payloads per execution; default |
| Nested JSON translation depth; default |
| Dynamic MCP tool-name bound; default |
| Dynamic description bound; default |
| Dynamic registration bound; default |
Output, namespace, and logging bounds
stdout and stderr use streaming prefix sinks whose retained memory is independent of produced output size. Exact omitted-character counts accompany their truncation flags. Display items are capped as they arrive. Results, representations, docs, signatures, filenames, error messages, and tracebacks use deterministic depth, item, and character bounds.
Names beginning with _, IPython bindings (In, Out, get_ipython,
exit, quit, and open), and configured preload aliases are protected from
remove, reset, and dynamic registration. reset restores configured
modules. Default logs contain tool name and outcome only—not code, arguments,
results, namespace values, environment-variable values, or traceback locals.
Dynamic tool contract
A backing name must be a non-protected top-level Python identifier. Dynamic
tool names start with an ASCII letter and contain only letters, digits, _, or
-. Stable-name, dynamic-name, and backing-symbol collisions are rejected.
Supported parameters use resolvable annotations composed from str, int,
float, bool, None, bounded containers, unions/optionals, and JSON-safe
Literal values. Positional-only parameters, variadics, unresolved or
unsupported annotations, non-JSON defaults, coroutine functions, generators,
and async/generator callable objects are rejected.
The schema fingerprint is SHA-256 over sorted compact input-schema JSON.
Body-only replacement with an identical schema stays callable through the
current live binding. A signature-affecting change makes the registration
stale until explicit re-registration. Delete/remove invalidate the affected
registration; reset clears the catalog. Catalog changes emit
notifications/tools/list_changed when the client supports it.
Migration from the F-004 runtime
F-005 is a deliberate breaking simplification. It removes the F-004
multiprocessing worker, controller, versioned IPC, pipes, reader/writer loops,
health probes, worker replacement, runtime epochs, stale-response handling,
process admission queue, queue limits, worker startup/interruption grace,
hard operation timeout recovery, worker shutdown logic, response runtime
metadata, and runtime_status tool.
Remove these obsolete settings from client configuration:
IPYTHON_MCP_OPERATION_TIMEOUT_SECONDSIPYTHON_MCP_INTERRUPTION_GRACE_SECONDSIPYTHON_MCP_WORKER_STARTUP_TIMEOUT_SECONDSIPYTHON_MCP_MAX_PENDING_OPERATIONSIPYTHON_MCP_QUEUE_WAIT_TIMEOUT_SECONDSIPYTHON_MCP_MAX_IPC_MESSAGE_BYTES
If callers relied on forced termination, queue overload responses, recovery epochs, or status polling, they must instead apply a client-side observation timeout and restart the entire trusted local server when code does not return. A client-side timeout does not imply that Python stopped.
Build-import-edit-reload workflow
Put a reusable module in a configured trusted library directory.
Preload it or import it with
execute.Discover functions with
listorsearchand call them withcall_function.Edit the module using normal file tools.
Call
reloadwith the explicit module name.
Verification
Repository-native checks are:
uv sync --extra dev
uv run pytest
uv run python scripts/release_matrix.py
uv buildThe tests cover the unconfigured startup path, direct same-process ownership, persistent state and dynamic tools, absence of runtime child processes and IPC modules, output bounds, startup variables/paths/preloads, uv reuse, conflicting pure-Python dependency versions across separate restarts, clean/redacted failures, stdio packaging flow, the non-preemptive cancellation contract, responsive discovery during execution, and compact output compatibility.
Available Tools
11 toolscall_functionC
Call a live callable by name with a JSON object of keyword arguments.
Inputs: name (required), arguments (required). Returns: ok, name, error, result, +3 more
executeA
Execute Python source in the persistent IPython namespace.
Inputs: code (required). Returns: ok, error, result, status, +6 more
inspectB
Inspect one live name with bounded metadata and explicit truncation flags.
Inputs: name (required). Returns: ok, kind, name, error, +8 more
listA
List callable functions currently available in the live namespace.
Inputs: no named parameters. Returns: error, runtime, functions, truncated
register_toolC
Explicitly publish one supported top-level synchronous live callable.
Inputs: name (required), tool_name, description. Returns: ok, error, runtime, registration
reloadB
Reload explicitly named imported modules and refresh their bindings.
Inputs: modules (required). Returns: error, results, runtime
removeC
Remove unprotected top-level names and report every requested partition.
Inputs: names (required). Returns: ok, error, refused, removed, +2 more
resetA
Remove user-created names while preserving runtime and configured bindings.
Inputs: no named parameters. Returns: ok, error, removed, runtime, +1 more
runtime_statusB
Report bounded out-of-band worker, queue, epoch, and recovery metadata.
Inputs: no named parameters. Returns: epoch, error, state, queue_depth, +4 more
searchA
Search visible live namespace objects by exact or partial name.
Inputs: query (required), exact, limit. Returns: error, results, runtime, truncated
unregister_toolA
Remove requested dynamic tool registrations without affecting stable tools.
Inputs: names (required). Returns: ok, error, runtime, unknown, +2 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
TDQS
Scored across 11 tools
Tools are mostly distinct, but `list`, `search`, and `inspect` all deal with namespace introspection and could be confused at a glance. `remove` vs `reset` also have overlapping deletion semantics, though descriptions clarify boundaries.
Naming uses a consistent snake_case imperative style (e.g., `execute`, `inspect`, `register_tool`). A few names like `runtime_status` are noun-like rather than verb_noun, but overall the pattern is predictable and readable.
11 tools is well within the ideal 3-15 range and each tool serves a clear purpose for managing a live IPython namespace. The count feels appropriate for the server's stated scope.
The toolset covers core operations: executing code, inspecting objects, managing namespace bindings, and runtime status. Minor gaps like fetching full history or handling asynchronous execution exist, but agents can work around them.
Maintenance
Related MCP Connectors
Hosted MCP runtime where your agent publishes its own tools by tool call and keeps working.
Hosted MCP memory and agent control plane for durable conversations, jobs, and operations.
- aXDeprecatedio.github.ax-platform
Agent-native collaboration network: orchestrate a team of long-running agents from any MCP client.
Your org's AI agents, tasks, runs, search, and brain files as MCP tools and resources.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides persistent IPython shell sessions per conversation with DataFrame-centric architecture, enabling stateful data analysis, CLI tool execution, and integration of external MCP servers within the same workspace context.23Apache 2.0
- AlicenseAqualityBmaintenanceA persistent Python REPL MCP server for AI agents with stateful execution, real timeouts, crash isolation, and an MCP bridge to call other tools in the project.13MIT
- AlicenseAqualityBmaintenanceEnables interactive Python execution with a persistent IPython kernel through MCP, retaining namespace state and providing structured output logs for agent and tool integrations.8Apache 2.0
- FlicenseNot gradedqualityDmaintenanceProvides a persistent Jupyter kernel for executing code, inspecting variables and dataframes, and checking SQL query plans, enabling agents to work with stateful Python sessions.-