jupyter-kernel-mcp
by qtalen
README.md
> **I share an in-depth data science and AI project practice every month. Visit and subscribe to https://www.dataleadsfuture.com**
>
# jupyter-mcp-kernel
An MCP (Model Context Protocol) server that connects **directly** to a Jupyter kernel via ZMQ — no JupyterLab or Notebook server required.
Enable your AI assistant to read, create, edit, execute, and manage Jupyter Notebooks as MCP tools.
---
## Architecture
```
┌──────────────┐ stdio ┌──────────────────┐ ZMQ ┌────────────────┐
│ AI Agent │ ◄────────────► │ jupyter-mcp- │ ◄──────────► │ Jupyter IPykernel │
│ (OpenCode) │ MCP tools │ kernel server │ │ (python3) │
└──────────────┘ └──────────────────┘ └────────────────┘
│
┌─────┴──────┐
│ .ipynb │
│ (on disk) │
└────────────┘
```
The server communicates with the kernel over ZMQ channels (iopub, shell, stdin, control) and persists notebook files to disk after every modification.
---
## Prerequisites
- Python ≥ 3.10
- `ipykernel` installed (so the kernel can start). If not sure:
```bash
python -m ipykernel install --user
```
- `uv` (recommended) or `pip`
---
## Installation
### Option A: Install from GitHub (recommended for end users)
```bash
uv tool install git+https://github.com/qtalen/jupyter-mcp-kernel.git
```
This makes the `jupyter-mcp-kernel` command available globally (managed by `uv`).
### Option B: Install from local source (for development)
```bash
git clone https://github.com/qtalen/jupyter-mcp-kernel.git
cd jupyter-mcp-kernel
uv tool install --path . jupyter-mcp-kernel
```
### Option C: Install via pip
```bash
pip install git+https://github.com/qtalen/jupyter-mcp-kernel.git
```
---
## Register with OpenCode
Add the following `mcp` entry to your project's `opencode.json`:
```json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"jupyter": {
"type": "local",
"command": ["jupyter-mcp-kernel", "--cell-timeout", "7200"],
"enabled": true,
"timeout": 7200000
}
}
}
```
Then restart OpenCode. The 8 MCP tools will appear automatically.
---
## Available Tools
All tools are registered as `@mcp.tool()` and are callable by your AI agent once the MCP server is connected.
### 1. `connect_to_jupyter`
| Item | Value |
|------|-------|
| **Description** | Start (or reuse) a Jupyter kernel. Must be called before any other operation. |
| **Parameters** | `kernel_name` (str, default `"python3"`) — the kernel spec name |
| **Returns** | `str` — confirmation message |
### 2. `use_notebook`
| Item | Value |
|------|-------|
| **Description** | Open an existing `.ipynb` file, or create a new one if it doesn't exist. Attaches the notebook to the current session. |
| **Parameters** | `path` (str) — file path; `kernel_name` (str, default `"python3"`) |
| **Returns** | `str` — path and cell count |
### 3. `read_notebook`
| Item | Value |
|------|-------|
| **Description** | List all cells. In simple mode, returns a TSV summary (index, type, preview, output count). In detailed mode, returns full source + outputs for every cell. |
| **Parameters** | `detailed` (bool, default `False`) |
| **Returns** | `list[TextContent | ImageContent]` — per-cell content, including embedded PNG images |
### 4. `read_cell`
| Item | Value |
|------|-------|
| **Description** | Read a single cell's source code and its outputs. |
| **Parameters** | `cell_index` (int, default `0`) |
| **Returns** | `list[TextContent | ImageContent]` — source + outputs (images are returned as inline base64 PNG) |
### 5. `insert_cell`
| Item | Value |
|------|-------|
| **Description** | Insert a new code or markdown cell at a specified index. |
| **Parameters** | `source` (str) — cell content; `index` (int, default `-1` = append); `cell_type` (str, `"code"` or `"markdown"`) |
| **Returns** | `str` — confirmation message |
### 6. `edit_cell_source`
| Item | Value |
|------|-------|
| **Description** | Find and replace text in an existing cell's source. Clears outputs. |
| **Parameters** | `cell_index` (int); `old_string` (str); `new_string` (str) |
| **Returns** | `str` — confirmation or error |
### 7. `delete_cell`
| Item | Value |
|------|-------|
| **Description** | Remove a cell by index. |
| **Parameters** | `cell_index` (int) |
| **Returns** | `str` — confirmation |
### 8. `execute_cell`
| Item | Value |
|------|-------|
| **Description** | Execute a code cell in the open notebook. Supports long execution with timeout and progress reporting. Results are saved back to the `.ipynb` file. |
| **Parameters** | `cell_index` (int); `timeout_seconds` (int or None, default: `--cell-timeout` CLI value); `progress_interval` (int, default `5`, set to `0` to disable progress) |
| **Returns** | `list[TextContent | ImageContent]` — stdout/stderr text, error tracebacks, images, and a final status message (`[COMPLETED in Xs]` / `[TIMEOUT after Xs]` / `[CANCELLED]`) |
### 9. `execute_code`
| Item | Value |
|------|-------|
| **Description** | Execute arbitrary Python code directly on the kernel (outside the notebook context). Useful for quick experiments or inspection. |
| **Parameters** | `code` (str); `timeout` (int, default `60`) |
| **Returns** | `list[TextContent | ImageContent]` — same output types as `execute_cell` |
---
## Typical Workflow
A typical AI-driven notebook session follows these steps:
```
connect_to_jupyter(kernel_name="python3")
→ "Kernel ready — python3"
use_notebook(path="notebooks/my_analysis.ipynb")
→ "Using notebook: C:/.../my_analysis.ipynb (0 cells)"
insert_cell(source="# My Analysis\n\n## Objective\n...", index=0, cell_type="markdown")
→ "Inserted markdown cell at index 0"
insert_cell(source="import pandas as pd\ndf = pd.read_csv('data.csv')", index=1)
→ "Inserted code cell at index 1"
execute_cell(cell_index=1)
→ [...] + "[COMPLETED in 2s]"
read_cell(cell_index=1)
→ Shows source + any output
edit_cell_source(cell_index=1, old_string="data.csv", new_string="data_v2.csv")
→ "Cell 1 updated: replaced 1 occurrence of 8 → 11 chars"
execute_cell(cell_index=1)
→ [...] + "[COMPLETED in 3s]"
delete_cell(cell_index=2)
→ "Deleted cell 2 (code)"
```
---
## CLI Options
```
jupyter-mcp-kernel [--cell-timeout SECONDS]
```
| Option | Default | Description |
|--------|---------|-------------|
| `--cell-timeout` | `7200` | Default execution timeout per cell (seconds). Can be overridden per-call via `execute_cell(timeout_seconds=...)`. |
---
## Troubleshooting
### Kernel fails to start
- Ensure `ipykernel` is installed: `python -m ipykernel install --user`
- Verify the kernel name. Run `jupyter kernelspec list` to see available kernels.
- Check for proxy issues. The server automatically adds `localhost,127.0.0.1` to `NO_PROXY`.
### No tools appear in OpenCode
- Confirm `jupyter-mcp-kernel` is on your PATH: `jupyter-mcp-kernel --help`
- Check `opencode.json` syntax and path.
- Restart OpenCode entirely after configuration changes.
### Cell execution hangs indefinitely
- The default timeout is 7200s (2h). Use `execute_cell(timeout_seconds=120)` for shorter tasks.
- The kernel may be stuck. Use `execute_cell(progress_interval=5)` to see progress updates.
- OpenCode can cancel execution via SIGINT → the server will interrupt the kernel.
### Windows-specific
- The server registers `SIGBREAK` (Ctrl+Break) for graceful shutdown on Windows.
- Paths with spaces are supported if quoted correctly in `opencode.json`.
---
## License
MIT
TDQS
B3.2/5.0
Scored across 9 tools
Disambiguation4/5
Tools have mostly distinct purposes, but 'execute_cell' and 'execute_code' could confuse agents due to similar names despite different contexts. Other tools are clearly separated.
Naming Consistency4/5
Most tools follow a verb_noun pattern (e.g., delete_cell, insert_cell), but 'connect_to_jupyter' and 'edit_cell_source' deviate slightly. Overall consistent.
Tool Count5/5
9 tools is well-scoped for a Jupyter kernel server, covering connection, notebook management, cell operations, and code execution without excess.
Completeness3/5
Covers core CRUD for cells and execution, but missing kernel management tools like restart or interrupt, and no explicit save/close functionality.
Maintenance
ActivityInactive
ResponsivenessNo issues