Skip to main content
Glama
universal-notebook-mcp

universal-notebook-mcp

by am-3

universal-notebook-mcp

Run Jupyter notebooks from any AI editor. Gives your AI assistant full access to read, edit, and execute .ipynb files with live kernel output — without needing to open JupyterLab.

Works in Antigravity, Cursor, Windsurf, Claude Desktop, Claude Code, and any MCP-compatible tool. Works on Windows, macOS, and Linux.


Quick start

1. Install Python 3.10+

Skip this step if you already have Python 3.10 or later (python --version to check).

Download from python.org and run the installer. Make sure to check "Add Python to PATH" during setup.

Or with winget:

winget install Python.Python.3.11
brew install python@3.11

Or download from python.org.

# Debian / Ubuntu
sudo apt install python3.11 python3.11-pip

# Fedora / RHEL
sudo dnf install python3.11

# Arch
sudo pacman -S python

2. Install the package

pip install universal-notebook-mcp

On macOS/Linux, if pip maps to Python 3.9, use pip3.11 instead. On Windows, pip from the Python 3.11 installer works directly.

Verify it installed:

nb-mcp --help

3. Add to your editor

Pick your editor below and paste the config. Replace the path with the folder that contains your notebooks.

⚠️ Use the real absolute path — MCP clients pass arguments as literal strings and do not expand editor variables like ${workspaceFolder}.

Windows paths: use forward slashes or escape backslashes: C:/Users/you/notebooks or C:\\Users\\you\\notebooks

Create .antigravity/mcp.json in your project folder:

{
  "mcpServers": {
    "notebook": {
      "command": "nb-mcp",
      "args": ["--workspace-root", "/absolute/path/to/notebooks"]
    }
  }
}

Or go to Settings → MCP Servers and add the same block.

~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project):

{
  "mcpServers": {
    "notebook": {
      "command": "nb-mcp",
      "args": ["--workspace-root", "/absolute/path/to/notebooks"]
    }
  }
}

~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "notebook": {
      "command": "nb-mcp",
      "args": ["--workspace-root", "/absolute/path/to/notebooks"]
    }
  }
}

Config file location:

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Linux: ~/.config/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "notebook": {
      "command": "nb-mcp",
      "args": ["--workspace-root", "/absolute/path/to/notebooks"]
    }
  }
}
claude mcp add notebook -- nb-mcp --workspace-root /absolute/path/to/notebooks

4. Reload your editor and go

Your AI can now work with notebooks. Try:

"List the cells in my notebook" "Run cell 3 and show me the output" "Fix the error in cell 5 and re-run it"


Related MCP server: JupyterMCP

What it can do

Tool

What it does

📖

notebook_list_cells

See all cells (type, tags, first line)

📖

notebook_read_cell

Read full source + saved outputs of a cell

📖

notebook_read_cell_output

Read just the outputs (stream, result, error)

📖

notebook_read_metadata

Read notebook metadata (kernel, language, etc.)

📖

notebook_list_stages

List all pipeline stage tags in the notebook

✏️

notebook_edit_cell

Edit a cell's source

✏️

notebook_insert_cell

Insert a new cell at any position

✏️

notebook_delete_cell

Delete a cell

✏️

notebook_edit_cell_metadata

Add or update cell tags and metadata

✏️

notebook_edit_metadata

Update notebook-level metadata

▶️

notebook_run_cell

Execute one cell and get its output

▶️

notebook_run_range

Execute a range of cells

▶️

notebook_run_all

Execute all cells

▶️

notebook_run_pipeline

Execute all cells tagged with a stage name

🔧

notebook_restart_kernel

Clear kernel state (variables, imports)

🔧

notebook_list_kernels

List all installed kernel environments

🔧

notebook_list_active_kernels

See which notebooks have a live kernel

Kernel state persists across calls — variables and imports from one cell are available in the next, just like a normal Jupyter session.

Edits are checkpointed — every edit creates a timestamped backup (.checkpoint_<timestamp>.ipynb) before writing, so you can always roll back.


Troubleshooting

nb-mcp: command not found (or 'nb-mcp' is not recognized on Windows)

The install directory isn't on your PATH. Find where pip installed it:

# macOS / Linux
python3 -m site --user-scripts   # or: which nb-mcp after activating your venv

# Windows (PowerShell)
python -c "import sys; print(sys.prefix + r'\Scripts')"

Then either use the full path in your MCP config:

"command": "C:\\Users\\you\\AppData\\Local\\Programs\\Python\\Python311\\Scripts\\nb-mcp.exe"

Or add the Scripts/bin directory to your PATH permanently.


ModuleNotFoundError when running a cell

The kernel doesn't have your packages installed. Register your environment:

pip install ipykernel
python -m ipykernel install --user --name myenv --display-name "My Env"

Then restart the kernel via notebook_restart_kernel or ask your AI to switch kernels.

List available kernels:

jupyter kernelspec list

Windows: path format in MCP config

Both of these work:

"C:/Users/you/notebooks"       ✓ forward slashes
"C:\\Users\\you\\notebooks"    ✓ escaped backslashes

Avoid raw backslashes — they break JSON:

"C:\Users\you\notebooks"       ✗ invalid JSON

git clone https://github.com/your-org/universal-notebook-mcp.git
cd universal-notebook-mcp

# macOS / Linux
pip3.11 install -e ".[dev]"

# Windows (PowerShell)
python -m pip install -e ".[dev]"

Run the tests:

python -m pytest                          # all tests
python -m pytest -m "not integration"     # unit tests only (no kernel needed)
python -m pytest -m integration -v        # integration tests (needs ipykernel)

Or use make targets on macOS/Linux:

make test        # unit only
make test-all    # unit + integration
make coverage    # coverage report
make lint        # ruff linter

Project layout:

src/universal_notebook_mcp/
  server.py           ← MCP tool surface (17 tools, FastMCP, stdio)
  notebook_adapter.py ← nbformat cell CRUD + checkpoint backups
  kernel_session.py   ← jupyter_client async kernel lifecycle
  notebook_runner.py  ← cell execution + output capture

tests/
  conftest.py         ← shared fixtures (mocked kernel, workspace)
  fixtures/           ← simple.ipynb, pipeline.ipynb, error.ipynb
  test_*.py           ← 125 tests (116 unit + 9 integration)

Security

All notebook paths are sandboxed to --workspace-root. Paths that escape it (e.g. ../secret.ipynb) or that aren't .ipynb files are rejected with an error.

License

MIT

Available Tools

17 tools
notebook_delete_cellA

Delete the cell at the given index.

A timestamped backup is written first unless checkpoint=false.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. cell_index: Zero-based index of the cell to delete. checkpoint: Write a backup before deleting (default: true).

Inputs: cell_index (required), notebook_path (required), checkpoint. Returns: result

notebook_edit_cellA

Replace the source of a cell.

A timestamped .checkpoint_*.ipynb backup is written before the change unless checkpoint=false.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. cell_index: Zero-based index of the cell to edit. source: New source code or markdown text. checkpoint: Write a backup before editing (default: true).

Inputs: source (required), cell_index (required), notebook_path (required), checkpoint. Returns: result

notebook_edit_cell_metadataA

Merge a JSON object into a cell's metadata.

Useful for adding or removing pipeline stage tags: updates = '{"tags": ["preprocess"]}'

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. cell_index: Zero-based index of the target cell. updates: JSON string with metadata keys to merge in. checkpoint: Write a backup before editing (default: true).

Inputs: updates (required), cell_index (required), notebook_path (required), checkpoint. Returns: result

notebook_edit_metadataA

Merge a JSON object into the top-level notebook metadata.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. updates: JSON string with top-level metadata keys to merge in. checkpoint: Write a backup before editing (default: true).

Inputs: updates (required), notebook_path (required), checkpoint. Returns: result

notebook_insert_cellA

Insert a new cell at the given position.

Cells at index and above are shifted down. To append after the last cell, pass index equal to the total number of cells.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. index: Position to insert at (0 = before first cell). source: Source code or text for the new cell. cell_type: 'code', 'markdown', or 'raw' (default: 'code'). checkpoint: Write a backup before editing (default: true).

Inputs: index (required), source (required), notebook_path (required), cell_type, +1 more. Returns: result

notebook_list_active_kernelsA

List notebooks that currently have a running kernel in this session.

Returns the absolute resolved paths of notebooks with live kernels.

Inputs: no named parameters. Returns: result

notebook_list_cellsA

List every cell in a notebook with its index, type, tags, and first line.

Call this first to understand the structure before reading or editing specific cells.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root.

Inputs: notebook_path (required). Returns: result

notebook_list_kernelsA

List every Jupyter kernel spec installed on this machine.

Returns a dict of {kernel_name: display_name}. Use the kernel_name value as the kernel_name argument to execution tools.

If you get ModuleNotFoundError when running a cell, the kernel may not have your packages installed. Install the current virtualenv as a kernel: python -m ipykernel install --user --name myenv

Inputs: no named parameters. Returns: result

notebook_list_stagesA

List every pipeline stage tag present across the notebook's cells.

Pipeline stages are cell tags set in JupyterLab via View → Cell Toolbar → Tags (e.g. 'preprocess', 'train', 'evaluate'). Use notebook_run_pipeline to execute all cells in a named stage.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root.

Inputs: notebook_path (required). Returns: result

notebook_read_cellA

Read the full source, type, tags, and saved outputs of a single cell.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. cell_index: Zero-based index of the cell (use notebook_list_cells to find it).

Inputs: cell_index (required), notebook_path (required). Returns: result

notebook_read_cell_outputA

Read the saved outputs of a code cell from the last time it was run.

Returns stream text, execute_result data, display_data, or error tracebacks. Note: outputs are empty until the cell has been executed at least once.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. cell_index: Zero-based index of a code cell.

Inputs: cell_index (required), notebook_path (required). Returns: result

notebook_read_metadataA

Read the top-level notebook metadata (kernelspec, language_info, etc.).

Args: notebook_path: Path to the .ipynb file, relative to the workspace root.

Inputs: notebook_path (required). Returns: result

notebook_restart_kernelA

Restart the kernel for a notebook, clearing all variables and imports.

The kernel process stays alive — only its state is reset, so subsequent run_cell calls start from a clean slate without the startup overhead of a fresh kernel.

Args: notebook_path: Path to the .ipynb file whose kernel should be restarted.

Inputs: notebook_path (required). Returns: result

notebook_run_allA

Execute every cell in the notebook in order and return all outputs.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. kernel_name: Kernel to use (default: 'python3'). timeout: Per-cell timeout in seconds (default: 60). stop_on_error: Stop at first failing cell (default: true). save_outputs: Write outputs back to the .ipynb file (default: true).

Inputs: notebook_path (required), timeout, kernel_name, save_outputs, +1 more. Returns: result

notebook_run_cellA

Execute a single code cell and return its outputs.

Kernel state (variables, imports) is preserved between calls on the same notebook, so cells can depend on earlier ones.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. cell_index: Zero-based index of the cell to run. kernel_name: Kernel to use (e.g. 'python3', 'myenv'). Defaults to 'python3'. Run notebook_list_kernels to see options. timeout: Seconds to wait for the cell to finish (default: 60). save_outputs: Write outputs back to the .ipynb file (default: true).

Inputs: cell_index (required), notebook_path (required), timeout, kernel_name, +1 more. Returns: result

notebook_run_pipelineA

Run all cells tagged with a pipeline stage, in notebook order.

Pipeline stage tags are set per-cell in JupyterLab: View → Cell Toolbar → Tags (add e.g. 'preprocess', 'train', 'evaluate')

Use notebook_list_stages to see what stages exist in a notebook.

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. stage: Tag name of the stage to run (e.g. 'preprocess'). kernel_name: Kernel to use (default: 'python3'). timeout: Per-cell timeout in seconds (default: 60). stop_on_error: Stop at first failing cell (default: true). save_outputs: Write outputs back to the .ipynb file (default: true).

Inputs: stage (required), notebook_path (required), timeout, kernel_name, +2 more. Returns: result

notebook_run_rangeA

Execute cells from start to end (inclusive) and return all outputs.

Execution stops at the first error by default (stop_on_error=true).

Args: notebook_path: Path to the .ipynb file, relative to the workspace root. start: First cell index to run (inclusive). end: Last cell index to run (inclusive). kernel_name: Kernel to use (default: 'python3'). timeout: Per-cell timeout in seconds (default: 60). stop_on_error: Stop at first failing cell (default: true). save_outputs: Write outputs back to the .ipynb file (default: true).

Inputs: end (required), start (required), notebook_path (required), timeout, +3 more. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 17 tools

    Disambiguation5/5

    Each tool targets a distinct operation on notebooks, cells, metadata, or kernels. There is no overlap, and descriptions clearly differentiate purposes (e.g., list_cells vs read_cell, run_all vs run_pipeline).

    Naming Consistency5/5

    All tools follow the `notebook_verb_noun` pattern consistently. Verbs like delete, edit, insert, list, read, restart, run are used uniformly, making it easy to predict tool behavior from its name.

    Tool Count5/5

    With 17 tools, the set covers cell manipulation, metadata editing, execution modes, and kernel management without being excessive. Each tool serves a clear purpose, and the count is well-suited to the domain.

    Completeness4/5

    Core workflows like CRUD for cells, multiple execution modes, and kernel management are covered. However, missing notebook creation (e.g., `notebook_create`) and explicit save/export operations are minor gaps that agents may need to work around.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers