Jupyter MCP Server

v2.2.1

Read, edit and run Jupyter notebooks over MCP. Cells are addressed by index within a notebook opened with use_notebook, and execution happens on the server, so a long computation keeps running after the session ends.

Connect

Add to your MCP client configuration:

{ "mcpServers": { "Jupyter MCP Server": { "command": "jupyter-mcp-server", "args": [ "--transport", "stdio", "--start-new-code-sandbox", "false" ] } } }
Protocol MCP 2025-11-25Transport stdioCapabilities tools, resources, prompts, logging

Tools

clear_cell_output

destructiveidempotent
TOOLclear_cell_output

Clear the outputs and execution count of a single code cell in the currently activated notebook, without deleting the cell itself.

Body

application/json
cell_indexinteger | nullnull

Index of the code cell to clear (0-based). Omit when passing cell_id.

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

cell_idstring | nullnull

Address the cell by its notebook cell id instead of its index. An index is a position, and a position stops being true the moment anyone inserts a cell above it; an id does not. Every result says which id it acted on, so read a cell once and address it by id afterwards. Given both, the id wins.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

clear_cell_output
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "clear_cell_output",
    "arguments": {
        "cell_index": null,
        "notebook_name": null,
        "cell_id": null
      }
  }
}
const result = await client.callTool("clear_cell_output", {
  "cell_index": null,
  "notebook_name": null,
  "cell_id": null
});
result = await session.call_tool("clear_cell_output", arguments={
  "cell_index": null,
  "notebook_name": null,
  "cell_id": null
})
Request Body
{
  "cell_index": null,
  "notebook_name": null,
  "cell_id": null
}
Response
{
  "kind": "string",
  "result": null
}

connect_to_jupyter

destructiveidempotent
TOOLconnect_to_jupyter

Connect to a Jupyter server dynamically with URL and token.

This tool allows you to connect to different Jupyter servers without needing to restart the MCP server or modify configuration files. Particularly useful when:

  • Working with multiple Jupyter servers with different ports/tokens
  • Jupyter server token changes dynamically
  • Need to switch between different Jupyter instances

Example usage:

Body

application/json
jupyter_urlstringrequired

Jupyter server URL to connect to (e.g., 'http://localhost:8888')

jupyter_tokenstring | nullnull

Jupyter server authentication token

document_providerstringjupyter

Which backend holds the notebook documents

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

connect_to_jupyter
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "connect_to_jupyter",
    "arguments": {
        "jupyter_url": "string",
        "jupyter_token": null,
        "document_provider": "jupyter"
      }
  }
}
const result = await client.callTool("connect_to_jupyter", {
  "jupyter_url": "string",
  "jupyter_token": null,
  "document_provider": "jupyter"
});
result = await session.call_tool("connect_to_jupyter", arguments={
  "jupyter_url": "string",
  "jupyter_token": null,
  "document_provider": "jupyter"
})
Request Body
{
  "jupyter_url": "string",
  "jupyter_token": null,
  "document_provider": "jupyter"
}
Response
{
  "kind": "string",
  "result": null
}

delete_cell

destructive
TOOLdelete_cell

Delete specific cells from the currently activated notebook and return the cell source of deleted cells (if include_source=True).

Body

application/json
cell_indicesArray<integer> | nullnull

List of cell indices to delete (0-based). Omit when passing cell_ids_to_delete.

include_sourcebooleantrue

Whether to include the source of deleted cells

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

cell_ids_to_deleteArray<string> | nullnull

Address the cells by their notebook cell ids instead of their indices. Safer for a multi-cell delete than indices, which shift as earlier cells go. Given both, the ids win; every id is checked before any cell is deleted, so a bad one fails the whole call rather than half-deleting the notebook.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

delete_cell
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "delete_cell",
    "arguments": {
        "cell_indices": null,
        "include_source": true,
        "notebook_name": null,
        "cell_ids_to_delete": null
      }
  }
}
const result = await client.callTool("delete_cell", {
  "cell_indices": null,
  "include_source": true,
  "notebook_name": null,
  "cell_ids_to_delete": null
});
result = await session.call_tool("delete_cell", arguments={
  "cell_indices": null,
  "include_source": true,
  "notebook_name": null,
  "cell_ids_to_delete": null
})
Request Body
{
  "cell_indices": null,
  "include_source": true,
  "notebook_name": null,
  "cell_ids_to_delete": null
}
Response
{
  "kind": "string",
  "result": null
}

edit_cell_source

destructive
TOOLedit_cell_source

Perform a surgical find-and-replace within a cell's source (like an editor's Edit tool). Finds old_string in the cell and replaces it with new_string. Matching is literal (not regex) and may span multiple lines. By default, old_string must appear exactly once; set replace_all=True for multiple occurrences. Returns a diff of the changes made.

Prefer this over overwrite_cell_source for small, targeted edits — it is safer because unchanged parts of the cell are left untouched. Use read_cell first to see the current source and construct an accurate old_string.

Body

application/json
cell_indexinteger | nullnull

Index of the cell to edit (0-based). Omit when passing cell_id.

old_stringstringrequired

Exact string to find in cell source

new_stringstringrequired

Replacement string

replace_allbooleanfalse

Replace all occurrences (default: first only)

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

cell_idstring | nullnull

Address the cell by its notebook cell id instead of its index. An index is a position, and a position stops being true the moment anyone inserts a cell above it; an id does not. Every result says which id it acted on, so read a cell once and address it by id afterwards. Given both, the id wins.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

edit_cell_source
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "edit_cell_source",
    "arguments": {
        "cell_index": null,
        "old_string": "string",
        "new_string": "string",
        "replace_all": false,
        "notebook_name": null,
        "cell_id": null
      }
  }
}
const result = await client.callTool("edit_cell_source", {
  "cell_index": null,
  "old_string": "string",
  "new_string": "string",
  "replace_all": false,
  "notebook_name": null,
  "cell_id": null
});
result = await session.call_tool("edit_cell_source", arguments={
  "cell_index": null,
  "old_string": "string",
  "new_string": "string",
  "replace_all": false,
  "notebook_name": null,
  "cell_id": null
})
Request Body
{
  "cell_index": null,
  "old_string": "string",
  "new_string": "string",
  "replace_all": false,
  "notebook_name": null,
  "cell_id": null
}
Response
{
  "kind": "string",
  "result": null
}

execute_cell

destructiveopen-world
TOOLexecute_cell

Execute a cell from the currently activated notebook with timeout and return it's outputs

Body

application/json
cell_indexinteger | nullnull

Index of the cell to execute (0-based). Omit when passing cell_id.

timeoutinteger0

Maximum seconds to wait for execution (0 = use config default)

streambooleantrue

Enable streaming progress (including time indicator) updates for long-running cells

progress_intervalinteger5

Seconds between progress updates (MCP keepalive + optional stream log)

cell_idstring | nullnull

Address the cell by its notebook cell id instead of its index. An index is a position, and a position stops being true the moment anyone inserts a cell above it; an id does not. Every result says which id it acted on, so read a cell once and address it by id afterwards. Given both, the id wins.

Returns

Cell or execution outputs, in order.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

outputsArray<any>

The outputs in order: text as text, an image as its own object.

countinteger0

How many outputs.

imagesinteger0

How many of them are images.

execute_cell
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "execute_cell",
    "arguments": {
        "cell_index": null,
        "timeout": 0,
        "stream": true,
        "progress_interval": 5,
        "cell_id": null
      }
  }
}
const result = await client.callTool("execute_cell", {
  "cell_index": null,
  "timeout": 0,
  "stream": true,
  "progress_interval": 5,
  "cell_id": null
});
result = await session.call_tool("execute_cell", arguments={
  "cell_index": null,
  "timeout": 0,
  "stream": true,
  "progress_interval": 5,
  "cell_id": null
})
Request Body
{
  "cell_index": null,
  "timeout": 0,
  "stream": true,
  "progress_interval": 5,
  "cell_id": null
}
Response
{
  "kind": "string",
  "result": null,
  "outputs": [],
  "count": 0,
  "images": 0
}

execute_code

destructiveopen-world
TOOLexecute_code

Execute code directly in a kernel (not saved to notebook).

If use_sandbox selected an active sandbox, this tool executes on that sandbox instead of a Jupyter kernel. This allows agents to switch between kernel-backed and sandbox-backed execution using the same execute_code API.

Targets the current activated notebook's kernel by default. Pass kernel_id to execute in a specific kernel directly — including raw kernels with no notebook attached.

Recommended to use in following cases:

  1. Execute Jupyter magic commands(e.g., %timeit, %pip install xxx)
  2. Performance profiling and debugging.
  3. View intermediate variable values(e.g., print(xxx), df.head())
  4. Temporary calculations and quick tests(e.g., np.mean(df['xxx']))
  5. Execute Shell commands in Jupyter server(e.g., !git xxx)

Under no circumstances should you use this tool to:

  1. Import new modules or perform variable assignments that affect subsequent Notebook execution
  2. Execute dangerous code that may harm the Jupyter server or the user's data without permission

Body

application/json
codestringrequired

Code to execute (supports magic commands with %, shell commands with !)

timeoutinteger30

Maximum seconds to wait for execution (0 = use config default)

kernel_idstring | nullnull

Target an existing kernel by ID (e.g. a raw kernel with no notebook). If omitted, uses the current notebook's kernel.

progress_intervalinteger5

Seconds between MCP progress keepalive updates during long-running execution

Returns

Cell or execution outputs, in order.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

outputsArray<any>

The outputs in order: text as text, an image as its own object.

countinteger0

How many outputs.

imagesinteger0

How many of them are images.

execute_code
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "execute_code",
    "arguments": {
        "code": "string",
        "timeout": 30,
        "kernel_id": null,
        "progress_interval": 5
      }
  }
}
const result = await client.callTool("execute_code", {
  "code": "string",
  "timeout": 30,
  "kernel_id": null,
  "progress_interval": 5
});
result = await session.call_tool("execute_code", arguments={
  "code": "string",
  "timeout": 30,
  "kernel_id": null,
  "progress_interval": 5
})
Request Body
{
  "code": "string",
  "timeout": 30,
  "kernel_id": null,
  "progress_interval": 5
}
Response
{
  "kind": "string",
  "result": null,
  "outputs": [],
  "count": 0,
  "images": 0
}

insert_cell

destructive
TOOLinsert_cell

Insert a cell to specified position from the currently activated notebook.

Body

application/json
cell_indexinteger>= -1required

Target index for insertion (0-based), use -1 to append at end

cell_typestringcodemarkdownrawrequired

Type of cell to insert

cell_sourcestringrequired

Source content for the cell

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

insert_cell
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "insert_cell",
    "arguments": {
        "cell_index": -1,
        "cell_type": "code",
        "cell_source": "string",
        "notebook_name": null
      }
  }
}
const result = await client.callTool("insert_cell", {
  "cell_index": -1,
  "cell_type": "code",
  "cell_source": "string",
  "notebook_name": null
});
result = await session.call_tool("insert_cell", arguments={
  "cell_index": -1,
  "cell_type": "code",
  "cell_source": "string",
  "notebook_name": null
})
Request Body
{
  "cell_index": -1,
  "cell_type": "code",
  "cell_source": "string",
  "notebook_name": null
}
Response
{
  "kind": "string",
  "result": null
}

insert_execute_code_cell

destructiveopen-world
TOOLinsert_execute_code_cell

Insert a cell at specified index from the currently activated notebook and then execute it with timeout and return it's outputs It is a shortcut tool for insert_cell and execute_cell tools, recommended to use if you want to insert a cell and execute it at the same time

Parameters

cell_indexinteger>= -1requiredargument

Index of the cell to insert and execute (0-based)

cell_sourcestringrequiredargument

Code source for the cell

timeoutinteger0argument

Maximum seconds to wait for execution (0 = use config default)

streambooleantrueargument

Enable streaming progress (including time indicator) updates for long-running cells

progress_intervalinteger5argument

Seconds between progress updates (MCP keepalive + optional stream log)

Returns

Cell or execution outputs, in order.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

outputsArray<any>

The outputs in order: text as text, an image as its own object.

countinteger0

How many outputs.

imagesinteger0

How many of them are images.

insert_execute_code_cell
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "insert_execute_code_cell",
    "arguments": {
        "cell_index": -1,
        "cell_source": "string",
        "timeout": 0,
        "stream": true,
        "progress_interval": 5
      }
  }
}
const result = await client.callTool("insert_execute_code_cell", {
  "cell_index": -1,
  "cell_source": "string",
  "timeout": 0,
  "stream": true,
  "progress_interval": 5
});
result = await session.call_tool("insert_execute_code_cell", arguments={
  "cell_index": -1,
  "cell_source": "string",
  "timeout": 0,
  "stream": true,
  "progress_interval": 5
})
Response
{
  "kind": "string",
  "result": null,
  "outputs": [],
  "count": 0,
  "images": 0
}

launch_sandbox

destructiveopen-world
TOOLlaunch_sandbox

Launch a code sandbox that can be used instead of Jupyter kernels.

After launch, call use_sandbox to make execute_code run on this sandbox (as an alternative to notebook-bound kernel execution). Works in both MCP_SERVER and JUPYTER_SERVER modes.

Body

application/json
sandbox_namestringrequired

Unique sandbox identifier used by list/use/terminate tools

variantstring | nullnull

Sandbox variant to launch. If omitted, defaults to configured SANDBOX_VARIANT when it is not jupyter-server; otherwise falls back to eval.

timeoutinteger>= 160

Default execution timeout in seconds for this sandbox

environmentstring | nullnull

Optional sandbox environment name (common for datalayer/modal variants). On the datalayer variant this is a platform environment by name, such as ai-agents-env, or an environment somebody built, written 'account/name' — the account being a person's handle or an organization's.

environment_versionstring | integer | nullnull

Which version of an 'account/name' environment to launch: its number, such as 3, or a version uid. Leave it unset to get the version its owner promoted, which is what you want unless you were asked for a particular one. Only the datalayer variant has versions; naming one for any other variant is refused rather than quietly ignored.

gpustring | nullnull

Optional GPU flavor / accelerator. Only coreweave, datalayer, daytona, kaggle and modal have a GPU; asking one of the others (e2b, cloudflare, docker, eval, google-colab, jupyter-server, monty) for a GPU is refused rather than quietly run on a CPU, so leave this unset for them. Examples: modal/datalayer T4, A10G, A100, H100; daytona H100, H200, RTX-4090; coreweave H100; kaggle NvidiaTeslaT4, NvidiaTeslaP100, or the aliases T4/P100.

server_urlstring | nullnull

Code Sandbox proxy URL when using the google-colab or kaggle variant

kernel_idstring | nullnull

Kernel ID when using the google-colab or kaggle variant

proxy_tokenstring | nullnull

Google Colab code sandbox proxy token when using google-colab variant

channels_urlstring | nullnull

Notebook session WebSocket channels URL to derive server_url/kernel_id (google-colab or kaggle variant)

tokenstring | nullnull

Kaggle API token for the kaggle variant (falls back to KAGGLE_API_TOKEN)

python_versionstring | nullnull

Modal Python version override (e.g. 3.12). Only used for modal variant.

snapshot_namestring | nullnull

Start from a saved snapshot instead of an empty sandbox, restoring the state it was taken in. Only the datalayer variant has snapshots; naming one for any other variant is refused rather than quietly started empty.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

launch_sandbox
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "launch_sandbox",
    "arguments": {
        "sandbox_name": "string",
        "variant": null,
        "timeout": 60,
        "environment": null,
        "environment_version": null,
        "gpu": null,
        "server_url": null,
        "kernel_id": null,
        "proxy_token": null,
        "channels_url": null,
        "token": null,
        "python_version": null,
        "snapshot_name": null
      }
  }
}
const result = await client.callTool("launch_sandbox", {
  "sandbox_name": "string",
  "variant": null,
  "timeout": 60,
  "environment": null,
  "environment_version": null,
  "gpu": null,
  "server_url": null,
  "kernel_id": null,
  "proxy_token": null,
  "channels_url": null,
  "token": null,
  "python_version": null,
  "snapshot_name": null
});
result = await session.call_tool("launch_sandbox", arguments={
  "sandbox_name": "string",
  "variant": null,
  "timeout": 60,
  "environment": null,
  "environment_version": null,
  "gpu": null,
  "server_url": null,
  "kernel_id": null,
  "proxy_token": null,
  "channels_url": null,
  "token": null,
  "python_version": null,
  "snapshot_name": null
})
Request Body
{
  "sandbox_name": "string",
  "variant": null,
  "timeout": 60,
  "environment": null,
  "environment_version": null,
  "gpu": null,
  "server_url": null,
  "kernel_id": null,
  "proxy_token": null,
  "channels_url": null,
  "token": null,
  "python_version": null,
  "snapshot_name": null
}
Response
{
  "kind": "string",
  "result": null
}

list_files

read-onlyidempotent
TOOLlist_files

List all files and directories recursively in the Jupyter server's file system. Used to explore the file system structure of the Jupyter server or to find specific files or directories.

Parameters

pathstringargument

The starting path to list from (empty string means root directory)

max_depthinteger[0, 3]1argument

Maximum depth to recurse into subdirectories

start_indexinteger>= 00argument

Starting index for pagination (0-based)

limitinteger>= 025argument

Maximum number of items to return (0 means no limit)

patternstringargument

Glob pattern to filter file paths

Returns

A listing that also comes back as rows keyed by its header.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

columnsArray<string>

The header, in order.

itemsArray<object>

One object per row, keyed by the header.

countinteger0

How many rows.

list_files
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "list_files",
    "arguments": {
        "path": "",
        "max_depth": 1,
        "start_index": 0,
        "limit": 25,
        "pattern": ""
      }
  }
}
const result = await client.callTool("list_files", {
  "path": "",
  "max_depth": 1,
  "start_index": 0,
  "limit": 25,
  "pattern": ""
});
result = await session.call_tool("list_files", arguments={
  "path": "",
  "max_depth": 1,
  "start_index": 0,
  "limit": 25,
  "pattern": ""
})
Response
{
  "kind": "string",
  "result": null,
  "columns": [
    "string"
  ],
  "items": [
    {}
  ],
  "count": 0
}

list_kernels

read-onlyidempotent
TOOLlist_kernels

List all available kernels in the Jupyter server.

This tool shows all running and available kernel sessions on the Jupyter server, including their IDs, names, states, connection information, and kernel specifications. Useful for monitoring kernel resources and identifying specific kernels for connection.

Returns

A listing that also comes back as rows keyed by its header.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

columnsArray<string>

The header, in order.

itemsArray<object>

One object per row, keyed by the header.

countinteger0

How many rows.

list_kernels
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "list_kernels",
    "arguments": {}
  }
}
const result = await client.callTool("list_kernels", {});
result = await session.call_tool("list_kernels", arguments={})
Response
{
  "kind": "string",
  "result": null,
  "columns": [
    "string"
  ],
  "items": [
    {}
  ],
  "count": 0
}

list_notebooks

read-onlyidempotent
TOOLlist_notebooks

List all notebooks that have been used via use_notebook tool

Returns

A listing that also comes back as rows keyed by its header.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

columnsArray<string>

The header, in order.

itemsArray<object>

One object per row, keyed by the header.

countinteger0

How many rows.

list_notebooks
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "list_notebooks",
    "arguments": {}
  }
}
const result = await client.callTool("list_notebooks", {});
result = await session.call_tool("list_notebooks", arguments={})
Response
{
  "kind": "string",
  "result": null,
  "columns": [
    "string"
  ],
  "items": [
    {}
  ],
  "count": 0
}

list_sandboxes

read-onlyidempotent
TOOLlist_sandboxes

List launched code sandboxes that can be used as alternatives to kernels.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

list_sandboxes
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "list_sandboxes",
    "arguments": {}
  }
}
const result = await client.callTool("list_sandboxes", {});
result = await session.call_tool("list_sandboxes", arguments={})
Response
{
  "kind": "string",
  "result": null
}

move_cell

destructive
TOOLmove_cell

Move a cell from source_index to target_index within the currently activated notebook.

The cell is removed from source_index and placed at target_index. Cells in between shift to fill the gap. The cell's type, source, and outputs are preserved. Example: in a notebook [A, B, C, D], move_cell(1, 3) produces [A, C, D, B].

Use this tool instead of manually deleting and re-inserting a cell — it is atomic and preserves cell metadata. Use read_notebook first to see cell indices if needed.

Body

application/json
source_indexinteger | nullnull

Index of the cell to move (0-based). Omit when passing source_cell_id.

target_indexinteger | nullnull

Destination index where the cell will end up (0-based). Omit when passing target_cell_id.

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

source_cell_idstring | nullnull

Address the cell to move by its id rather than its index.

target_cell_idstring | nullnull

Put the moved cell where this cell is now, addressed by id rather than by an index that the move itself will shift.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

move_cell
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "move_cell",
    "arguments": {
        "source_index": null,
        "target_index": null,
        "notebook_name": null,
        "source_cell_id": null,
        "target_cell_id": null
      }
  }
}
const result = await client.callTool("move_cell", {
  "source_index": null,
  "target_index": null,
  "notebook_name": null,
  "source_cell_id": null,
  "target_cell_id": null
});
result = await session.call_tool("move_cell", arguments={
  "source_index": null,
  "target_index": null,
  "notebook_name": null,
  "source_cell_id": null,
  "target_cell_id": null
})
Request Body
{
  "source_index": null,
  "target_index": null,
  "notebook_name": null,
  "source_cell_id": null,
  "target_cell_id": null
}
Response
{
  "kind": "string",
  "result": null
}

overwrite_cell_source

destructiveidempotent
TOOLoverwrite_cell_source

Replace the entire source of a cell in the currently activated notebook. Returns a diff showing the changes made.

Use this when rewriting a cell completely. For small, targeted changes, prefer edit_cell_source instead — it is safer for partial edits.

Body

application/json
cell_indexinteger | nullnull

Index of the cell to overwrite (0-based). Omit when passing cell_id.

cell_sourcestringrequired

New complete cell source

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

cell_idstring | nullnull

Address the cell by its notebook cell id instead of its index. An index is a position, and a position stops being true the moment anyone inserts a cell above it; an id does not. Every result says which id it acted on, so read a cell once and address it by id afterwards. Given both, the id wins.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

overwrite_cell_source
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "overwrite_cell_source",
    "arguments": {
        "cell_index": null,
        "cell_source": "string",
        "notebook_name": null,
        "cell_id": null
      }
  }
}
const result = await client.callTool("overwrite_cell_source", {
  "cell_index": null,
  "cell_source": "string",
  "notebook_name": null,
  "cell_id": null
});
result = await session.call_tool("overwrite_cell_source", arguments={
  "cell_index": null,
  "cell_source": "string",
  "notebook_name": null,
  "cell_id": null
})
Request Body
{
  "cell_index": null,
  "cell_source": "string",
  "notebook_name": null,
  "cell_id": null
}
Response
{
  "kind": "string",
  "result": null
}

read_cell

read-onlyidempotent
TOOLread_cell

Read a cell as readable text entries.

Includes metadata and source, plus optional formatted output text rather than raw nbformat objects.

Body

application/json
cell_indexinteger | nullnull

Index of the cell to read (0-based). Omit when passing cell_id.

include_outputsbooleantrue

Include outputs in the response (only for code cells)

notebook_namestring | nullnull

Target this specific connected notebook instead of the currently activated one. Use when multiple clients share this server, to avoid racing the shared 'current notebook' pointer. Omit to use the currently activated notebook.

cell_idstring | nullnull

Address the cell by its notebook cell id instead of its index. An index is a position, and a position stops being true the moment anyone inserts a cell above it; an id does not. Every result says which id it acted on, so read a cell once and address it by id afterwards. Given both, the id wins.

Returns

Cell or execution outputs, in order.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

outputsArray<any>

The outputs in order: text as text, an image as its own object.

countinteger0

How many outputs.

imagesinteger0

How many of them are images.

read_cell
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "read_cell",
    "arguments": {
        "cell_index": null,
        "include_outputs": true,
        "notebook_name": null,
        "cell_id": null
      }
  }
}
const result = await client.callTool("read_cell", {
  "cell_index": null,
  "include_outputs": true,
  "notebook_name": null,
  "cell_id": null
});
result = await session.call_tool("read_cell", arguments={
  "cell_index": null,
  "include_outputs": true,
  "notebook_name": null,
  "cell_id": null
})
Request Body
{
  "cell_index": null,
  "include_outputs": true,
  "notebook_name": null,
  "cell_id": null
}
Response
{
  "kind": "string",
  "result": null,
  "outputs": [],
  "count": 0,
  "images": 0
}

read_notebook

read-onlyidempotent
TOOLread_notebook

Read a notebook and return index, source content, type, execution count of each cell.

Using brief format to get a quick overview of the notebook structure and it's useful for locating specific cells for operations like delete or insert. Using detailed format to get detailed information of the notebook and it's useful for debugging and analysis.

It is recommended to use brief format with larger limit to get a overview of the notebook structure, then use detailed format with exact index and limit to get the detailed information of some specific cells.

Parameters

notebook_namestringrequiredargument

Notebook identifier to read

response_formatstringbriefdetailedbriefargument

Response format: 'brief' will return first line and lines number, 'detailed' will return full cell source

start_indexinteger>= 00argument

Starting index for pagination (0-based)

limitinteger>= 020argument

Maximum number of items to return (0 means no limit)

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

read_notebook
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "read_notebook",
    "arguments": {
        "notebook_name": "string",
        "response_format": "brief",
        "start_index": 0,
        "limit": 20
      }
  }
}
const result = await client.callTool("read_notebook", {
  "notebook_name": "string",
  "response_format": "brief",
  "start_index": 0,
  "limit": 20
});
result = await session.call_tool("read_notebook", arguments={
  "notebook_name": "string",
  "response_format": "brief",
  "start_index": 0,
  "limit": 20
})
Response
{
  "kind": "string",
  "result": null
}

restart_notebook

destructive
TOOLrestart_notebook

Restart the kernel for a specific notebook.

Parameters

notebook_namestringrequiredargument

Notebook identifier to restart

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

restart_notebook
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "restart_notebook",
    "arguments": {
        "notebook_name": "string"
      }
  }
}
const result = await client.callTool("restart_notebook", {
  "notebook_name": "string"
});
result = await session.call_tool("restart_notebook", arguments={
  "notebook_name": "string"
})
Response
{
  "kind": "string",
  "result": null
}

terminate_sandbox

destructiveidempotent
TOOLterminate_sandbox

Terminate a launched code sandbox.

Parameters

sandbox_namestringrequiredargument

Sandbox name to terminate and unregister

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

terminate_sandbox
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "terminate_sandbox",
    "arguments": {
        "sandbox_name": "string"
      }
  }
}
const result = await client.callTool("terminate_sandbox", {
  "sandbox_name": "string"
});
result = await session.call_tool("terminate_sandbox", arguments={
  "sandbox_name": "string"
})
Response
{
  "kind": "string",
  "result": null
}

unuse_notebook

destructiveidempotent
TOOLunuse_notebook

Unuse from a specific notebook and release its resources.

Parameters

notebook_namestringrequiredargument

Notebook identifier to disconnect

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

unuse_notebook
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "unuse_notebook",
    "arguments": {
        "notebook_name": "string"
      }
  }
}
const result = await client.callTool("unuse_notebook", {
  "notebook_name": "string"
});
result = await session.call_tool("unuse_notebook", arguments={
  "notebook_name": "string"
})
Response
{
  "kind": "string",
  "result": null
}

use_notebook

destructiveidempotent
TOOLuse_notebook

Use a notebook and activate it for following cell operations. All cell operations will be performed on the currently activated notebook. Activate new notebook will deactivate the previously activated notebook. Reactivate previously activated notebook using same notebook_name and notebook_path.

Parameters

notebook_namestringrequiredargument

Unique identifier for the notebook

notebook_pathstringrequiredargument

Path to the notebook file, relative to the Jupyter server root (e.g. 'notebook.ipynb')

modestringconnectcreateconnectargument

Notebook operation mode: 'connect' to connect to existing and activate it, 'create' to create new and activate it

kernel_idstringnullargument

Id of an existing kernel (or sandbox, for a non-Jupyter sandbox variant) to attach the notebook to. A new one is created if skipped.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

use_notebook
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "use_notebook",
    "arguments": {
        "notebook_name": "string",
        "notebook_path": "string",
        "mode": "connect",
        "kernel_id": null
      }
  }
}
const result = await client.callTool("use_notebook", {
  "notebook_name": "string",
  "notebook_path": "string",
  "mode": "connect",
  "kernel_id": null
});
result = await session.call_tool("use_notebook", arguments={
  "notebook_name": "string",
  "notebook_path": "string",
  "mode": "connect",
  "kernel_id": null
})
Response
{
  "kind": "string",
  "result": null
}

use_sandbox

destructiveidempotent
TOOLuse_sandbox

Select which launched sandbox execute_code should use instead of kernels.

Body

application/json
sandbox_namestring | nullnull

Sandbox name to activate for execute_code. Pass null/empty to disable sandbox routing and return to Jupyter kernels.

Returns

What every tool of this server answers with.

Declared so the shape is advertised rather than merely produced. A tool that returns structure without saying what it will return leaves a client nothing to validate against and the generated reference nothing to show — the call works and the contract is invisible, which is the worst of both.

Extra fields are allowed on purpose. A tool that already answers with a mapping keeps its own keys (see :func:_default_shape), and those are the interesting part of its answer; forbidding them would mean either flattening every tool into one shape or declaring nothing at all.

kindstringrequired

What this result is — 'cell.read', 'notebooks.list' and so on. Lets a client tell one answer from another without matching prose.

resultanynull

The answer itself: a message, the rows of a listing, or the outputs of an execution in order.

use_sandbox
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "use_sandbox",
    "arguments": {
        "sandbox_name": null
      }
  }
}
const result = await client.callTool("use_sandbox", {
  "sandbox_name": null
});
result = await session.call_tool("use_sandbox", arguments={
  "sandbox_name": null
})
Request Body
{
  "sandbox_name": null
}
Response
{
  "kind": "string",
  "result": null
}

Resources

capabilities_resource

RESOURCEcapabilities://

What this server can do, and where each answer came from.

A server does things a client cannot see and did not ask for — replacing a dead kernel with an empty one is the clearest case. Reading this is how a client finds out which of those are on, and an operator finds out why a capability is on, which is the first question asked when one surprises somebody.

A resource as well as a server/discover field, because a client may want to re-read it without re-discovering the server, and because a person can open a resource and look.

Returns

Returns MCP content array (text, image, or embedded resource).

capabilities_resource
{
  "jsonrpc": "2.0",
  "method": "resources/read",
  "params": {
    "uri": "capabilities://"
  }
}
const result = await client.readResource("capabilities://");
result = await session.read_resource("capabilities://")
Response
{
  "content": [
    {
      "type": "text",
      "text": "..."
    }
  ]
}

notebook

RESOURCEnotebook://{name}

A notebook in use, as nbformat JSON. Cells and outputs are resources of their own.

Parameters

namestringrequiredpath

Returns

Returns MCP content array (text, image, or embedded resource).

notebook
{
  "jsonrpc": "2.0",
  "method": "resources/read",
  "params": {
    "uri": "notebook://{name}"
  }
}
const result = await client.readResource("notebook://{name}");
result = await session.read_resource("notebook://{name}")
Response
{
  "content": [
    {
      "type": "text",
      "text": "..."
    }
  ]
}

notebook-cell

RESOURCEnotebook://{name}/cells/{cell_id}

One cell by its nbformat id, with its outputs listed rather than inlined.

Parameters

namestringrequiredpath
cell_idstringrequiredpath

Returns

Returns MCP content array (text, image, or embedded resource).

notebook-cell
{
  "jsonrpc": "2.0",
  "method": "resources/read",
  "params": {
    "uri": "notebook://{name}/cells/{cell_id}"
  }
}
const result = await client.readResource("notebook://{name}/cells/{cell_id}");
result = await session.read_resource("notebook://{name}/cells/{cell_id}")
Response
{
  "content": [
    {
      "type": "text",
      "text": "..."
    }
  ]
}

notebook-cell-output

RESOURCEnotebook://{name}/cells/{cell_id}/outputs/{index}

One output of one cell, with its own MIME type. Read it only if you need the bytes.

Parameters

namestringrequiredpath
cell_idstringrequiredpath
indexstringrequiredpath

Returns

Returns MCP content array (text, image, or embedded resource).

notebook-cell-output
{
  "jsonrpc": "2.0",
  "method": "resources/read",
  "params": {
    "uri": "notebook://{name}/cells/{cell_id}/outputs/{index}"
  }
}
const result = await client.readResource("notebook://{name}/cells/{cell_id}/outputs/{index}");
result = await session.read_resource("notebook://{name}/cells/{cell_id}/outputs/{index}")
Response
{
  "content": [
    {
      "type": "text",
      "text": "..."
    }
  ]
}

Prompts

jupyter_cite

PROMPTjupyter_cite

Like @ or # in Coding IDE or CLI, cite specific cells from specified notebook and insert them into the prompt.

Parameters

promptstringrequiredargument

User prompt for the cited cells

cell_indicesstringrequiredargument

Cell indices to cite (0-based),supporting flexible range format, e.g., '0,1,2', '0-2' or '0-2,4'

notebook_namestringargument

Name of the notebook to cite cells from, default (empty) to current activated notebook

Returns

Returns MCP content array (text, image, or embedded resource).

jupyter_cite
{
  "jsonrpc": "2.0",
  "method": "prompts/get",
  "params": {
    "name": "jupyter_cite",
    "arguments": {
        "prompt": "<prompt>",
        "cell_indices": "<cell_indices>",
        "notebook_name": "<notebook_name>"
      }
  }
}
const result = await client.getPrompt("jupyter_cite", {
  prompt: "<prompt>",
  cell_indices: "<cell_indices>",
  notebook_name: "<notebook_name>",
});
result = await session.get_prompt("jupyter_cite", arguments={
    "prompt": "<prompt>",
    "cell_indices": "<cell_indices>",
    "notebook_name": "<notebook_name>",
})
Response
{
  "content": [
    {
      "type": "text",
      "text": "..."
    }
  ]
}