Execute Python code and manage Jupyter notebooks via mcp-server-jupyter (uvx)
mcp-server-jupyter gives agents full control over Jupyter notebooks: read cells (with or without outputs), add new cells, edit existing cells, and execute any cell against a real Python kernel. The kernel state persists across cells within a session, so imports and variables carry over. This is the only credential-free MCP server that gives agents actual Python code execution with output capture. 6 tools total: readnotebookwithoutputs, readnotebooksourceonly, readoutputofcell, executecell, addcell, editcell.
Recipe: Execute Python code and manage Jupyter notebooks via mcp-server-jupyter (uvx)
Spawn
uvx --from mcp-server-jupyter mcp-server-jupyter stdioTransport: stdio, NDJSON framing. Requires ipykernel (auto-installed by uvx as a dependency).
Server info
- Name:
Jupyter notebook manager - Version:
0.1.0 - Tools: 6 —
read_notebook_with_outputs,read_notebook_source_only,read_output_of_cell,execute_cell,add_cell,edit_cell
Prerequisite: a .ipynb file
The server operates on existing .ipynb files. Create one with standard nbformat 4 structure:
{
"cells": [
{"cell_type": "code", "id": "cell-1", "metadata": {},
"source": ["print('hello')"], "outputs": [], "execution_count": null}
],
"metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}},
"nbformat": 4, "nbformat_minor": 5
}Workflow: Read → Execute → Add → Execute → Read
Step 1: Read notebook source
{"name": "read_notebook_source_only", "arguments": {"notebook_path": "/tmp/test.ipynb"}}→ Returns cell IDs and source code:
Cell with ID: cell-1
import math
print(f'Pi = {math.pi:.10f}')
print(f'e = {math.e:.10f}')Step 2: Execute a cell
{"name": "execute_cell", "arguments": {"notebook_path": "/tmp/test.ipynb", "cell_id": "cell-1"}}→ Returns real Python output:
Pi = 3.1415926536
e = 2.7182818285Step 3: Add a new cell
{"name": "add_cell", "arguments": {
"notebook_path": "/tmp/test.ipynb",
"cell_type": "code",
"source": "data = [23, 45, 12, 67, 34, 89, 56, 78, 11, 42]\nmean = sum(data) / len(data)\nprint(f'Mean: {mean:.2f}')",
"position": 1
}}→ Cell with id 3e431ddc added successfully.
Step 4: Execute the new cell
{"name": "execute_cell", "arguments": {"notebook_path": "/tmp/test.ipynb", "cell_id": "3e431ddc"}}→ Returns computed output:
Data: [23, 45, 12, 67, 34, 89, 56, 78, 11, 42]
Mean: 45.70
Std Dev: 25.46
Min: 11, Max: 89, Range: 78
Sorted: [11, 12, 23, 34, 42, 45, 56, 67, 78, 89]Step 5: Read full notebook with outputs
{"name": "read_notebook_with_outputs", "arguments": {"notebook_path": "/tmp/test.ipynb"}}→ Returns all cells with their source AND captured outputs.
Key behaviors
- Kernel state persists: variables and imports from cell-1 are available in cell-2 (same kernel session).
- Cell IDs: use
read_notebook_source_onlyto discover cell IDs, then pass them toexecute_celloredit_cell. - Auto-generated IDs:
add_cellreturns the new cell's ID (e.g.,3e431ddc). - Edit then execute: use
edit_cellto modify source, thenexecute_cellto run the updated version.
Gotchas
- First execution is slow: the ipykernel takes 5-10s to start on first
execute_cell. Subsequent cells run in ~100ms. - TCP warning: stderr shows
Kernel is running over TCP without encryption— safe for local use, ignore it. - Notebook must exist: all tools require a valid
.ipynbfile path. The server doesn't create notebooks. - NDJSON framing: like other Python MCP servers, uses newline-delimited JSON, NOT Content-Length.
{ "server": "mcp-server-jupyter", "version": "0.1.0", "spawn": "uvx --from mcp-server-jupyter mcp-server-jupyter stdio", "transport": "stdio", "framing": "NDJSON", "tools": ["read_notebook_with_outputs", "read_notebook_source_only", "read_output_of_cell", "execute_cell", "add_cell", "edit_cell"], "trace": [ { "step": "initialize", "request": { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "pathfinder", "version": "1.0" } } }, "response": { "serverInfo": { "name": "Jupyter notebook manager", "version": "0.1.0" }, "protocolVersion": "2024-11-05" } }, { "step": "tools/list", "response": { "tools_count": 6, "tools": ["read_notebook_with_outputs", "read_notebook_source_only", "read_output_of_cell", "execute_cell", "add_cell", "edit_cell"] } }, { "step": "read_notebook_source_only", "request": { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "read_notebook_source_only", "arguments": { "notebook_path": "/tmp/pathfinder-test.ipynb" } } }, "response": { "content": [ { "type": "text", "text": "Cell with ID: cell-1" }, { "type": "text", "text": "import math print(f'Pi = {math.pi:.10f}') print(f'e = {math.e:.10f}')" } ], "isError": false } }, { "step": "execute_cell (cell-1)", "request": { "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "execute_cell", "arguments": { "notebook_path": "/tmp/pathfinder-test.ipynb", "cell_id": "cell-1" } } }, "response": { "content": [ { "type": "text", "text": "Pi = 3.1415926536 e = 2.7182818285 " } ], "isError": false } }, { "step": "add_cell (data analysis)", "request": { "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "add_cell", "arguments": { "notebook_path": "/tmp/pathfinder-test.ipynb", "cell_type": "code", "source": "data = [23, 45, 12, 67, 34, 89, 56, 78, 11, 42] mean = sum(data) / len(data) variance = sum((x - mean) ** 2 for x in data) / len(data) std_dev = variance ** 0.5 print(f'Data: {data}') print(f'Mean: {mean:.2f}') print(f'Std Dev: {std_dev:.2f}') print(f'Min: {min(data)}, Max: {max(data)}, Range: {max(data) - min(data)}') print(f'Sorted: {sorted(data)}')", "position": 1 } } }, "response": { "content": [ { "type": "text", "text": "Cell with id 3e431ddc added successfully." } ], "isError": false } }, { "step": "execute_cell (new cell 3e431ddc)", "request": { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "execute_cell", "arguments": { "notebook_path": "/tmp/pathfinder-test.ipynb", "cell_id": "3e431ddc" } } }, "response": { "content": [ { "type": "text", "text": "Data: [23, 45, 12, 67, 34, 89, 56, 78, 11, 42] Mean: 45.70 Std Dev: 25.46 Min: 11, Max: 89, Range: 78 Sorted: [11, 12, 23, 34, 42, 45, 56, 67, 78, 89] " } ], "isError": false } }, { "step": "read_notebook_with_outputs", "request": { "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "read_notebook_with_outputs", "arguments": { "notebook_path": "/tmp/pathfinder-test.ipynb" } } }, "response_summary": "Full notebook with 2 cells, each with source and captured output. Cell-1 output: Pi/e values. Cell-2 output: statistical analysis of data array.", "isError": false } ], "executed_at": "2026-06-13T12:25:00Z" }