Connect an agent to a sandboxed MCP Console session
Source:R/mcp-console.R
mcp_console_connection.RdStarts an MCP Console server
for one agent and connects to it. MCP Console runs R, Python and DuckDB SQL
in an OS sandbox and keeps their state for the conversation. Each connection
starts its own server. Register connection$tools() on the agent so that
the send tool goes through its permissions, hooks and limits.
Usage
mcp_console_connection(
agent,
command = Sys.getenv("DEPUTY_MCP_CONSOLE_BIN"),
args = character(),
env = NULL,
dependencies = c("deny", "allow"),
project_config = FALSE,
timeout = 60,
startup_timeout = 60
)Arguments
- agent
The agent that owns the connection. Its working directory becomes the Console workspace, where the server starts, the sandbox's workspace is rooted, and MCP Console reads its project configuration and writes recordings.
- command
Path to an
mcp-consoleexecutable, version 0.0.4. Defaults to theDEPUTY_MCP_CONSOLE_BINenvironment variable. Deputy doesn't install the executable or search for it.- args
Extra arguments for
mcp-console serve. Only--writable-root PATHand the overrides-c extends=:workspace,-c extends=:read-onlyand-c sandbox.network=restrictedare accepted. Anything else, including--no-sandbox, is an error.- env
Optional named character vector of environment variables for the server. The server inherits only a few variables (such as
HOME,PATHand theR_LIBSfamily), so set others here, for exampleUV_CACHE_DIRorXDG_CACHE_HOME. Without them, dependency installs write to caches underHOME.- dependencies
"deny"(the default) or"allow". MCP Console can install packages that code needs, and it does so outside its sandbox, with the server's permissions. With"deny", the connection errors if the server offers this, and calls that declarerequirementsare refused. See Details.- project_config
Set to
TRUEto start even though the workspace contains.agents/console/config.yaml. That file can widen the sandbox, so by default the connection refuses to start when it exists. Review the file before you opt in.- timeout
Maximum seconds for one MCP request.
- startup_timeout
Maximum seconds for the client and server to start.
Value
A McpConnection. Call its $close() method when the conversation
ends.
Details
Supported versions
Requires MCP Console 0.0.4 and mcptools 1.0.2 or 1.0.3. The connection
checks the version with command --version before starting the server.
After starting, it checks the arguments of send and the sandbox
description MCP Console adds to it, and closes the connection unless the
server uses its native sandbox with restricted networking (the default
policy, or the :workspace or :read-only profile).
Permissions
send runs code, so it is treated like a shell tool: in "standard" mode
the agent's permissions need bash = TRUE. The server declares no tool
annotations, so the cautious defaults also require web = TRUE.
"readonly" and "plan" modes always deny send. A call that declares
requirements also needs install_packages = TRUE and a connection created
with dependencies = "allow".
With dependencies = "allow", the server can also install packages on its
own, outside the sandbox, when code calls library() for a missing package
or imports a missing Python module. These installs can't be checked call by
call. MCP Console offers dependency installs when ir, uv or a recent
reticulate is available to it. The server's environment decides where they
are written.
Long-running calls
mcptools waits about 4 seconds for a reply, so each send waits at most
2.5 seconds: timeout_ms is capped at 2500, also when omitted. Longer work
keeps running: the call returns [running; poll with an empty send], and a
later send with no code collects the output. The tool description tells
the model this. Installs requested with requirements, restarts, and input
sent to a stopped worker have no time limit in MCP Console. If one takes
longer than the reply window, the connection closes with a
deputy_mcp_desynchronized error and the session is lost. That is why only
you can restart the session, with mcp_console_control(); the model's
send refuses it.
Closing and recordings
$close() asks MCP Console to shut down cleanly, then stops the process.
$cancel(), interrupting the agent during a call, and a lost reply stop the
server without asking; MCP Console's sandbox runner then stops its worker.
Processes that escape the runner are outside Deputy's control.
MCP Console records every call, result and plot, without redaction, under
.agents/console/sessions/<run-id>/ in the workspace. Version 0.0.4 can't
change that location or how long recordings are kept. The path is reported
in $status()$execution$recordings; deleting old recordings is up to you.
Examples
if (FALSE) { # \dontrun{
agent <- Agent$new(
chat = ellmer::chat("openai/gpt-6-luna"),
permissions = Permissions(bash = TRUE, web = TRUE)
)
console <- mcp_console_connection(agent, command = "/path/to/mcp-console")
agent$register_tools(console$tools())
# In a Shiny app: session$onSessionEnded(function() console$close())
console$close()
} # }