Jupyter Terminal
FreeNot checkedEnables an agent to run shell commands through a JupyterLab/JupyterHub-hosted terminal, using REST API and WebSocket via Selenium for session handling, when SSH
About
Enables an agent to run shell commands through a JupyterLab/JupyterHub-hosted terminal, using REST API and WebSocket via Selenium for session handling, when SSH is not available.
README
This MCP server lets an agent run commands through a JupyterLab/JupyterHub-hosted terminal when SSH is not available. Originally designed for man-in-the-loop debugging of NPU kernels on AMD's AUP Learning Cloud, it talks to a Jupyter Server terminal REST API and websocket endpoint using a Selenium WebDriver to keep a valid session and perform the requests. You need access to the JupyterLab machine from the system hosting the MCP server. You can also use this server without a browser, if you have a valid Jupyter token and the server is not behind Cloudflare or other login challenges.
[!WARNING] You must have permission from the system administrator to use the JupyterLab environment for research/development. Do not use this software to break rules or bypass security measures. The author is not responsible for any misuse of this software. Not affiliated with Jupyter or any other org. Always verify AI-generated commands before accepting and executing them.
Install
UV_CACHE_DIR=.uv-cache uv sync
Configure
Keep your token in environment variables or your agent's MCP config JSON.
export JUPYTER_URL="https://myjupyterserver.example.com/user/my-user/lab"
export JUPYTER_TOKEN="<your Jupyter token>" # only supported in non-browser mode
export JUPYTER_USERNAME="<your Jupyter username>"
Optional settings:
export JUPYTER_CONNECT_TIMEOUT="10"
export JUPYTER_VERIFY_TLS="true"
export JUPYTER_WEBSOCKET_RETRIES="3"
export JUPYTER_WEBSOCKET_RETRY_DELAY="1"
JUPYTER_URL may point at /lab; the server automatically converts it to the Jupyter API base URL.
The server opens the Lab URL, follows the Hub login/OAuth flow, and submits JUPYTER_USERNAME plus JUPYTER_TOKEN as the login credentials. If JUPYTER_USERNAME is omitted, it is derived from /user/<name>/ in JUPYTER_URL.
Websocket connection failures with transient statuses such as 503 Service Unavailable are retried. Before each retry, the server refreshes the JupyterHub session cookies.
In my experience, custom terminal names can sometimes remain listed after their websocket route has gone stale. Leaving JUPYTER_TERMINAL_NAME unset is usually more robust: the server reuses existing numeric terminals first, starting from the lowest name (1, then 2, and so on). If a selected terminal returns a 502/503/504 websocket handshake, the server tries the next existing numeric terminal before creating a fresh unnamed terminal.
Browser-backed mode does not require JUPYTER_TOKEN; the logged-in browser session supplies the cookies. Useful browser/socket settings:
export JUPYTER_MCP_SOCKET_HOST="127.0.0.1"
export JUPYTER_MCP_SOCKET_PORT="8765"
export CHROMEDRIVER="/path/to/chromedriver" # optional if chromedriver is already on PATH
export JUPYTER_CHROME_BINARY="/path/to/Google Chrome" # optional
export JUPYTER_CHROME_USER_DATA_DIR="/path/to/user-data-dir" # optional; reuse a Chrome user data dir
export JUPYTER_CHROME_PROFILE_DIRECTORY="Default" # optional; profile inside the user data dir
export JUPYTER_BROWSER_KEEP_OPEN="true" # optional; leave Chrome open when the daemon exits
Run
For a quick local config check:
UV_CACHE_DIR=.uv-cache uv run jupyter-terminal-mcp --check-config
For browser-backed mode, run the browser daemon in a regular terminal first:
export JUPYTER_URL="https://myjupyterserver.example.com/user/my-user/lab"
UV_CACHE_DIR=.uv-cache uv run jupyter-terminal-mcp --browser-server
Chrome opens. Complete any login procedure, Cloudflare challenge etc. manually, wait until JupyterLab is ready, then press Enter in the daemon terminal. The daemon listens for MCP JSON-RPC messages on 127.0.0.1:8765 by default.
Then configure MCP clients to launch the stdio socket proxy:
UV_CACHE_DIR=.uv-cache uv run jupyter-terminal-mcp --socket-client
Example browser-backed MCP configuration:
{
"mcpServers": {
"jupyter-terminal": {
"command": "uv",
"args": [
"--directory",
"~/Projects/jupyter-terminal-mcp",
"run",
"jupyter-terminal-mcp",
"--socket-client"
],
"env": {
"UV_CACHE_DIR": "~/Projects/jupyter-terminal-mcp/.uv-cache",
"JUPYTER_MCP_SOCKET_HOST": "127.0.0.1",
"JUPYTER_MCP_SOCKET_PORT": "8765"
}
}
}
}
In non-browser-backed mode, clients should launch:
UV_CACHE_DIR=.uv-cache uv run jupyter-terminal-mcp
Example non-browser-backed MCP configuration:
{
"mcpServers": {
"jupyter-terminal": {
"command": "uv",
"args": [
"--directory",
"~/Projects/jupyter-terminal-mcp",
"run",
"jupyter-terminal-mcp"
],
"env": {
"UV_CACHE_DIR": "~/Projects/jupyter-terminal-mcp/.uv-cache",
"JUPYTER_URL": "https://myjupyterserver.example.com/user/my-user/lab",
"JUPYTER_TOKEN": "<your Jupyter token>",
"JUPYTER_USERNAME": "my-user"
}
}
}
}
Tools
Your coding agent can then use the following tools:
| Tool | Description |
|---|---|
jupyter_terminal_run |
Run a shell command and return JSON with output, exit_code, terminal_name, timed_out, and elapsed time. |
jupyter_terminal_write |
Send raw text to the terminal for interactive prompts. |
jupyter_terminal_list |
List Jupyter terminals visible to the server. |
jupyter_terminal_run wraps each command with unique begin/end markers so the agent receives only the command's output and exit status. If a command times out, the server sends ^C to the terminal and returns the output collected so far.
[!WARNING] Make sure to gate access to
jupyter_terminal_runandjupyter_terminal_writeappropriately. These tools can be used to run arbitrary shell commands on the JupyterLab host, which is a security risk.
Install Jupyter Terminal in Claude Desktop, Claude Code & Cursor
unyly install jupyter-terminal-mcpInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add jupyter-terminal-mcp -- uvx --from git+https://github.com/TheManchineel/jupyter-terminal-mcp jupyter-terminal-mcpFAQ
Is Jupyter Terminal MCP free?
Yes, Jupyter Terminal MCP is free — one-click install via Unyly at no cost.
Does Jupyter Terminal need an API key?
No, Jupyter Terminal runs without API keys or environment variables.
Is Jupyter Terminal hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Jupyter Terminal in Claude Desktop, Claude Code or Cursor?
Open Jupyter Terminal on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Playwright
Browser automation, scraping, screenshots
by MicrosoftPuppeteer
Browser automation and web scraping.
by modelcontextprotocolopentabs-dev/opentabs
Plugin-based MCP server + Chrome extension that gives AI agents access to web applications through the user's authenticated browser session. 100+ plugins with a
by opentabs-devrobhunter/agentdeals
1,500+ developer infrastructure deals, free tiers, and startup programs across 54 categories. Search deals, compare vendors, plan stacks, and track pricing chan
by robhunterCompare Jupyter Terminal with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All browse MCPs
