mcp-console
🚧 UNDER CONSTRUCTION 🚧
This project is not ready for use.
mcp-console is a ground-up rewrite of mcp-repl.
It applies the lessons learned from mcp-repl to a substantially different product---different enough that a new name makes sense.
MCP Console is being built as a persistent, sandboxed R, Python, and DuckDB SQL console for MCP agents. It gives an MCP client one live computational workspace instead of a sequence of disposable shell commands. An agent can submit complete R, Python, or SQL cells, keep state across calls, answer interactive prompts, inspect partial output, and switch languages as a task evolves.
The built-in worker embeds R. Python runs through reticulate, and SQL runs through a persistent DuckDB connection. R and Python can access one another's globals through reticulate, while DuckDB can query data frames in the R workspace directly. R plots made with the default device and open Matplotlib figures are returned as images, SQL results are returned as bounded previews, and long-running work can be polled or interrupted.
Install
MCP Console is currently distributed as native wheels for Apple Silicon and Intel macOS. Linux and Windows are not supported yet.
A working R installation is required.
Set R_HOME or make R discoverable on PATH.
The Python package installs r-lib-ir into the same uv tool environment; it supplies the ir command used to prepare R libraries.
The first server start may download and install the default R and Python requirements.
Run the published command without installing it persistently:
uvx mcp-console --help
uvx mcp-console serve
Or install it as a persistent uv tool:
uv tool install mcp-console
mcp-console --help
mcp-console serve
mcp-console serve communicates with its MCP client over standard input and output.
It waits for MCP protocol input rather than presenting an interactive terminal prompt.
What it is useful for
MCP Console is intended for iterative computational work: inspecting and transforming data, fitting models, running simulations, making plots, debugging code, and checking exact results.
An agent can load data once, build useful objects, inspect an intermediate result in another language, and continue without reconstructing its environment or passing every intermediate value through files and model context.
Working with the console
The MCP interface exposes one tool: send.
It runs one complete R, Python, or SQL cell, supplies interactive input, prepares additive requirements, applies an optional interrupt or restart, or collects pending output.
Code-bearing calls to send are sequential.
A control-only interrupt may overlap a pending send while that call resolves or prepares requirements, including for restart.
Requirements alone perform standalone preparation without starting an initial worker.
With a cell, requirements are its preconditions; without control, preparation precedes nonempty standard input and evaluation.
control = "interrupt" preserves in-memory state and orders signal delivery, same-call input, and a 100-millisecond grace period; when a cell follows, its requirements are then prepared before evaluation, and the cell is not run if the interrupted evaluation remains active.
control = "restart" resolves requirements before replacing the worker, then queues same-call input and runs an optional cell only in the replacement.
Polling and stdin remain code-free send calls.
Control, interrupt grace, and explicit requirement preparation do not consume the wait timeout, which starts after cell dispatch or attachment to an active evaluation.
R and Python global state and the in-memory DuckDB catalog remain available until the worker is restarted, replaced after failure, or the server exits.
Prepared requirements remain available across worker restarts, but in-memory language, database, debugger, and unread-input state does not.
Requirements declared on send are prepared before its cell runs and remain available to later cells.
Preparation makes packages and extensions available; it does not import, attach, or load them.
The built-in worker resolves missing plain R packages and managed Python imports on demand.
Use packages directly; declare an explicit Python requirement when exact distribution metadata is needed or automatic inference asks for it.
Successful package additions survive restart, while attached packages, imported modules, and other in-memory state do not.
Example workflow
An agent investigating measurements.csv could load the data and fit a model in one R cell submitted through send:
measurements <- readr::read_csv(
"measurements.csv",
show_col_types = FALSE
)
fit <- lm(response ~ temperature + group, data = measurements)
measurements$.residual <- residuals(fit)
It could then query the live R data frame with DuckDB SQL:
SELECT
"group",
count(*) AS n,
avg(abs(".residual")) AS mean_abs_residual
FROM measurements
GROUP BY "group"
ORDER BY mean_abs_residual DESC
And inspect or plot the same data from Python:
frame = r.measurements
import matplotlib.pyplot as plt
plt.scatter(frame["temperature"], frame[".residual"])
plt.axhline(0)
The data, model, Python imports, and DuckDB catalog remain available for later calls until the runtime is restarted or replaced.
Current status
The repository contains a working Rust MCP server, sandboxed worker relay, built-in mixed-language worker, host dependency resolvers, session recording, and public process-boundary transcript tests.
The registered MCP surface contains only send.
The core console and its initial PyPI distribution currently support only macOS. Linux and Windows support is not implemented. The project remains under active construction.
The server records a JSONL journal of tool calls and results together with image artifacts.
It projects each journal event into a Yamark-formatted, append-only transcript.md with syntax-highlighted R, Python, and SQL source, text results, and relative artifact links.
Alongside it, the server regenerates a Yamark-formatted transcript.qmd from incremental source and requirement state when submitted code or declared R or Python requirements change.
The QMD contains only submitted executable code cells and IR front matter with the built-in requirements and cumulative declarations.
With the PyPI package, run uvx --from r-lib-ir ir render transcript.qmd to execute those client-authored cells in order and export a fresh report using reticulate's default managed Python selection.
When ir is installed separately, ir render transcript.qmd is equivalent.
The projection is intended to reproduce the analysis represented by transcript.md, but it does not include recorded output or artifacts and does not yet reconstruct every runtime detail.
Human-facing tools for following and inspecting an agent's work remain future design.
Other current limitations include:
- there is one implicit session and no named-session management;
- cells run sequentially, while lifecycle control may overlap the operation it interrupts or replaces; and
- restart and worker replacement discard R, Python, DuckDB, debugger, and unread-input state.
Security boundary
Submitted R, Python, and SQL have shell-class capability inside the worker sandbox. The worker can read host files, but direct network access and regular-file writes outside its private temporary directory are denied. This is a process boundary, not a safe evaluator for untrusted code with access to sensitive readable files.
The server installs automatically inferred or explicitly declared R and Python packages and DuckDB extensions outside the worker sandbox with server permissions. Those operations may access the network and execute installation or build code, so only trusted requirements should be supplied. See Requirements and environments for the accepted inputs and trust model.
Session journals and the Markdown projection record submitted source, standard input, declared requirements, result text, and artifact paths without redaction.
Image bytes are stored in separate artifact files linked from those records.
The source-only Quarto document contains submitted code and declared R and Python requirements without redaction.
Rendering it executes that source outside the MCP Console worker sandbox with the permissions of the ir and Quarto processes.
Render only code you trust.
See Implemented architecture for recording and process placement.
Development
The implemented commands are:
mcp-console serve
mcp-console sandbox -- COMMAND [ARG]...
mcp-console --help
mcp-console help [COMMAND]
mcp-console --version
mcp-console serve communicates with its MCP client over standard input and output.
The standalone sandbox command is available for development, but it supervises only its direct child.
Use the MCP server for the supported worker-generation lifecycle.
Run development commands from the repository root:
scripts/format
scripts/check
scripts/test [BOUNDARY/SUITE[::CASE]]
scripts/test --list
scripts/test --update BOUNDARY/SUITE[::CASE]
scripts/format attempts each installed formatter and leaves failures visible while continuing with the remaining formatters.
scripts/check validates extracted runtime sources, checks Rust formatting and Clippy, runs Rust tests, and runs the complete transcript suite.
Documentation
The documentation index maps current documents by audience.
- Implemented architecture explains current process boundaries, ownership, lifecycle, recording, and artifacts.
- Built-in runtime describes user-visible R, Python, SQL, input, output, and graphics behavior.
- Requirements and environments describes dependency preparation and its trust boundary.
- Worker protocol and relay protocol define the exact transport contracts. Registered tool descriptions is a human-readable mirror of the current agent-facing wording.
- Transcript test guide explains selectors, normalization, and golden updates.
- The release guide describes PyPI setup, publication, verification, and recovery.
The project vision and other documents under design-sketches/ describe intended or exploratory future design, not the implemented system.
When current prose and implementation disagree, source and public acceptance tests are authoritative.
License
MCP Console is licensed under the MIT license.
Metadata
Release files for mcp-console 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_console-0.0.2-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| mcp_console-0.0.2-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 5.7 MB
Release files / mcp_console-0.0.2-py3-none-macosx_11_0_arm64.whl
| Download URL | mcp_console-0.0.2-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.8 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
717df2542802bd21f953e03c6f2a1564d0f5e6c99814462fb3d78dd2acbb2981
|
|
BLAKE2b-256 checksum How to use checksums |
596550e85f3a969ecc86dd90f96f23c6c487862d114063691ff85374f5f1127b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mcp_console-0.0.2-py3-none-macosx_10_12_x86_64.whl
| Download URL | mcp_console-0.0.2-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
2782707067fdd359acd4b77895149cb324d1958273b8092d21701953120780a6
|
|
BLAKE2b-256 checksum How to use checksums |
f30096202f6da65391421cb8c45db53063e4cbc3ef67b07a3023b444b8b4f95b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|