Skip to main content
Glama
TheManchineel

Jupyter Terminal MCP

Jupyter Terminal MCP

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

Related MCP server: Selenium MCP Server

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 tojupyter_terminal_run and jupyter_terminal_write appropriately. These tools can be used to run arbitrary shell commands on the JupyterLab host, which is a security risk.

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TheManchineel/jupyter-terminal-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server