Skip to content
| Marketplace
Sign in
Visual Studio Code>Data Science>Jupyter MCP ServerNew to Visual Studio Code? Get it now.
Jupyter MCP Server

Jupyter MCP Server

Happypig375

|
150 installs
| (0) | Free
A notebook-specific MCP server for running, editing, creating, and managing Jupyter notebooks from MCP clients.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Jupyter MCP Server

Marketplace version Marketplace installs GitHub repository

A notebook-specific MCP server that runs inside VS Code. An external MCP client can inspect, edit, execute, create, export, and manage notebooks open in the VS Code windows the user is working in. It has no dependency on Copilot Chat or Cursor. Notebook document operations use VS Code's native API; kernel operations require the installed ms-toolsai.jupyter extension.

Install and connect

  1. Install Jupyter MCP Server (publisher Happypig375) from the Marketplace, or run code --install-extension Happypig375.vscode-jupyter-mcp-server.
  2. Check the $(notebook) MCP status item and copy its URL, or use the output channel. The default endpoint is http://127.0.0.1:51303/mcp.
  3. Configure the external client to use Streamable HTTP and that copied endpoint.

The tool contract below describes 0.4.0; see the changelog for earlier versions. After an upgrade, refresh or reconnect the client's MCP tool catalog if it still advertises old parameters. The connected server's tools/list response is authoritative.

How this project differs

The design is an in-extension broker over the user's live, shared in-memory NotebookDocument. Windows register as peers, duplicate URIs are disambiguated with short opaque notebookRef handles, and one broker port is taken over safely if its owner closes. The decisions below explain which documented ideas we adopted and which remain outside this project's boundary.

Design or workflow This project's decision, benefit, and tradeoff Relevant comparison
Shared live notebook document Adopted. Read and edit VS Code's current document, including unsaved changes. The agent and user share notebook state; the notebook must be open in VS Code. vscode-inmemory-notebook-mcp also supports live notebooks and external clients. mcp-jupyter-complete uses file edits and reloads; Datalayer supports standalone Jupyter Server workflows.
Window routing Implemented inside the extension host. One window owns the broker, peers can take over its port, and short refs distinguish the same URI in different windows. This avoids a separate daemon process. vscode-inmemory-notebook-mcp uses a daemon with per-window bridge workers.
Long-running execution Adopted for 0.4.0. run_cells returns an executionId; get_execution follows that same run after a wait budget expires or waitMs: 0 returns immediately. The operation-ID and polling pattern comes from vscode-inmemory-notebook-mcp.
Pushed output streaming Not implemented. Bounded polling serves request/response clients. Pushed events would add client notification support and event-history management that this workflow does not require. vscode-inmemory-notebook-mcp documents polling and streaming.
Cell locking Not implemented. The server checks explicit targets and execution freshness without imposing an edit-ownership policy on the user and agent. Locking would require a separate coordination policy. vscode-inmemory-notebook-mcp exposes cell-lock tools.
Per-run interruption Not implemented as an isolated cancellation tool. interrupt_kernels explicitly requests a kernel-wide interrupt; stopping observation of a run does not prove its code stopped. This server's interrupt implementation uses the notebook kernel command.
Provider startup and administration Generic Jupyter integration; no dedicated Colab adapter. Reuse registered controllers and normal provider setup. The checked Colab extension exposes no public connect/start API for an adapter to call. Dedicated provisioning, Drive, terminal, and resource-management tools are not implemented. Google Colab MCP bridges browser sessions; Colab CLI manages runtimes and files. The Colab VS Code guide documents its own setup and administration.

Whole-notebook reads, cell anchors, and export were inspired by vscode-inmemory-notebook-mcp; the execution-wait and output-capture pattern came from vscode-runtime-notebook-mcp.

Sources and repository documentation were checked on 2026-09-06. This is a bounded, documentation-scoped comparison; it does not claim competitor installation or behavioral testing.

Tools

Existing-notebook tools use notebookRef, or notebookRefs for a batch. Prefer the short ref from list_notebooks; a plain URI is also accepted when it identifies one open notebook. open_notebooks accepts file URIs in uris and an optional windowId; create_notebook accepts title and an optional windowId.

Cell references accept zero-based numeric indices or the string cell_id returned by a read. String references are matched as IDs first, so a native ID containing only digits (for example "40025805") remains an ID; send a JSON number to request an index. Numeric strings still fall back to indices when no exact ID matches. Prefer real cell IDs; an index:N fallback can change after insertion, deletion, or movement. Notebook refs remain valid across cell edits and resolve only against currently open notebooks.

Tool Category Description
create_notebook Create Create a workspace file or an untitled notebook in an empty window and open it
list_notebooks Read List grouped connected windows, including empty windows, with windowId, windowLabel, URI, and routable notebookRef
read_notebook Read Read an outline by default, or select source, outputs, or all; optionally target cellIds
search_cells Read Search cell source and output text with match locations
get_kernel_info Read Report observed active runtime fields and explicit unavailable reasons
get_execution Read Inspect a tracked executionId, or recover the notebook's latest run; optionally wait for its result
list_kernels Read List exact registered kernel/controller IDs; read-only
configure_kernel Manage Invoke Jupyter's provider configuration tool; normal picker/auth/consent UI may appear
edit_cells Write Insert, edit, delete, or exact-text replace cells; optional explicit rerun
move_cells Write Move cells while preserving content, outputs, and metadata
clear_cell_outputs Write Clear outputs and execution state
run_cells Execute Start a tracked, ordered run; waitMs bounds the caller's wait, and observation continues independently
select_kernel Manage Select an exact ID from list_kernels; no fallback or start
restart_kernels Manage Request notebook-kernel restarts; provider confirmation may be required
interrupt_kernels Manage Request kernel interrupts; completion cannot be confirmed
open_notebooks Manage Open file URIs, preserving an existing live model
save_notebooks Manage Persist file-backed notebooks, including remote execution state
upload_file / download_file File transfer Hashed transfer between hostPath and kernelPath; native Colab Contents transport for files above 4 MiB
export_notebook Manage Export as markdown, Python, or HTML

Editing cell metadata

edit_cells.edits[].metadata represents the cell's nbformat metadata, such as tags, jupyter.source_hidden, or presentation fields. Inserted cells store that map; edit and replace shallow-merge it with existing nbformat metadata. Omitting it preserves existing metadata. VS Code's native cell ID, attachments, and execution-count fields remain separate and are preserved. The saved .ipynb receives the supplied fields inside each cell's metadata object.

For insert, cellId is an anchor: a numeric index or stable ID inserts the new cell immediately after that cell. TOP inserts before the first cell and BOTTOM inserts after the last. This preserves the existing insertion behavior while making the position explicit.

This follows the ipynb extension's serializer and native cell envelope, checked on 2026-10-12. Standalone metadata regressions exercise serialized fields and reopening with a bounded serializer fixture. Setting NOTEBOOK_SERIALIZER_BUNDLE to an installed ipynb bundle additionally checks its pure conversion function without activating that extension; this is a serialization check, not a live editor/save integration test.

Reading without excess output

read_notebook returns notebook and cell metadata in every view. source adds source text, outputs adds saved output, and all adds both within the requested limits. Source slicing uses 1-based inclusive startLine and endLine; maxSourceChars defaults to 12,000 per cell, with 0 requesting unbounded source explicitly. Truncation is reported.

For outputs, outputMode selects summary, preferred text, or full textual representations. maxOutputChars bounds each cell's returned output. Binary images are summarized rather than decoded. Saved output can be stale after an edit; saving does not refresh it.

Jupyter and providers

The package declares ms-toolsai.jupyter as a dependency. Kernel-backed tools (list_kernels, configure_kernel, select_kernel, run_cells, restart/interrupt, and file transfer) are registered when that extension is present; presence does not guarantee every runtime API is available. get_kernel_info and get_execution remain exposed for read-only diagnostics.

list_kernels lists currently registered controllers, including those contributed by other extensions; it does not discover every dormant provider. configure_kernel explicitly delegates setup to Jupyter and may display a picker, authentication, or consent UI. select_kernel requires an exact listed ID. Inspection, listing, and file transfer do not start or select a kernel. File transfer requires the public API of an active idle Python kernel; see Microsoft's kernel execution and authorization sample.

Files above 4 MiB require Colab's registered filesystem provider, which uses Jupyter's Contents API. This is the same file service used by Upload to Colab and Colab's native download command. The provider buffers a whole file, so native transfers have a hard 64 MiB cap even if maxBytes is larger. Smaller files use 256 KiB kernel chunks unless colabFileUri explicitly selects the native service. Each chunk request carries its payload once as a base64 literal, zlib-compressed when that saves at least 10%. IPython keeps the source of every executed request in linecache for the kernel's lifetime, so each transfer request is tagged and removes earlier tagged sources; payload-bearing requests are not retained. A kernel object carries at most 64 MiB of chunk traffic; beyond that, transfers are refused before dispatch with guidance to use the native service or restart the kernel. Kernel-side exceptions are reported by class name only.

For native transfer, open a file from the existing runtime's Colab Contents view. Alternatively, Colab: Mount Server to Workspace is available when Colab's experimental colab.serverMounting setting is enabled. get_kernel_info then lists colabRootCandidates. A transfer creates a random nonce file in the selected kernel's /content and requires the candidate filesystem to read the same nonce before any payload is sent or retrieved. If multiple roots are exposed, supply colabFileUri explicitly; they are not probed in sequence. Alternatively, pass an exact colabFileUri, such as colab://<server-id>/content/data.bin, whose path must equal kernelPath. No runtime is started, selected or guessed. Missing or mismatched native routes fail without falling back to a large kernel transfer.

Uploads use the native service only for a random temporary file, then verify size/SHA-256 and atomically promote it in the original kernel. Downloads verify the returned bytes against an independent kernel-side hash before local promotion. No-overwrite remains the default. Kernel lookups/executions have a 60-second deadline, native payload steps two minutes, nonce reads fifteen seconds, and best-effort remote cleanup five seconds. Only one transfer may use a notebook or kernel at a time; each step rechecks the original active idle kernel. An observed restart invalidates the operation. Pending kernel executions or native payload requests quarantine that kernel until they settle. A timed-out read-only nonce probe does not quarantine the selected kernel, so a stale root cannot block a corrected explicit URI. The filesystem API cannot cancel in-flight I/O: a timeout, busy kernel or lost runtime may leave a random .part or nonce file, and unconfirmed promotion remains uncertain. MCP client cancellation is still not forwarded across window routing. See the transfer diagnosis and regression scope.

restart_kernels and interrupt_kernels request state changes through Jupyter's provider commands. restart_kernels refuses to dispatch when the public Jupyter API explicitly reports no active kernel; it never selects or starts a replacement. Provider command failures are returned as failures. After a command returns, the tool reports the current active-kernel observation and still does not claim completion, because a provider can display confirmation UI or acknowledge before the kernel state changes. Use get_kernel_info before run_cells to verify the intended runtime where available.

The optional Colab VS Code extension contributes controllers through Jupyter. On 2026-09-06, MCP server 0.3.0 with google.colab 0.9.3 passed live checks for targeted execution, nonadjacent output clearing, and a 524,425-byte upload/download round trip with matching SHA-256 hashes in an existing Colab Python session. Initial discovery used the normal Colab picker. This is evidence for that tested integration, not a claim that every Colab feature is MCP-integrated.

On 2026-10-14, Marketplace 0.4.3 with google.colab 0.9.7 passed a live 65,568,700-byte native upload/download round trip and a separate 62,572,000-byte upload. Hashes matched and the same Colab process remained responsive through subsequent notebook execution. See the validation record for timings, scope and remaining limits.

A bootstrap adapter was considered on the same date. The installed 0.9.3 command manifest has no connect/start command; current upstream activation returns no extension API, and Auto Connect is handled inside the Jupyter provider. The browser-focused Colab MCP server does not expose that VS Code provider.

Jupyter's public API lets an extension register its own server collection, but does not expose other extensions' provider instances. Its kernels.getKernel returns already-started kernels for open notebooks. The internal jupyter.kernel.selectJupyterServerKernel command accepts an extension ID, provider ID, and notebook, then invokes the normal server/kernel selector; it has no argument for choosing a server or provider action. The older addRemoteJupyterServer API is deprecated and rejects callers outside Codespaces. These routes do not provide unattended Colab bootstrap.

Providers can mark a sole setup command canBeAutoSelected, but the checked Colab provider does not use that option. A provider API for listing existing runtimes and connecting to an explicit runtime would justify an optional MCP adapter. Until such a route exists, initial Colab setup can still require user interaction; wrapping its picker would not remove that requirement.

Recommended flow

  1. Call list_notebooks and select a notebookRef.
  2. Read its outline, then request view: "source" for the cells needed. Edit cells and refresh indices or fallback anchors after structural changes.
  3. If a kernel must be chosen, list its registered controllers and select an exact ID. Configure the provider explicitly when necessary.
  4. Call run_cells. waitMs defaults to 1,000; zero returns immediately, and larger values can wait for long jobs. This is a request wait budget, not an execution time limit. A returned ID or dispatch status does not prove execution started.
  5. If the run is unfinished, call get_execution with that ID. Its waitMs defaults to zero and also supports long waits. A client may impose a shorter request timeout; neither that timeout nor an expired wait budget interrupts execution. Omit the ID to recover the latest tracked run after a lost response.
  6. Read results and save edits or export the notebook. Completed background runs persist file-backed outputs, including remote results; untitled notebooks are not force-saved.

Runs submit cells in order and stop after an observed failure. Only one tracked run is active per notebook, with at most 16 active runs per window and 256 cells per run. The registry retains at most 32 notebooks and eight runs per notebook; terminal records expire after one hour and can be evicted earlier at capacity. Active runs have no one-hour expiry. Returned execution output is capped at 12,000 characters per cell and 48,000 per receipt. run_cells includes output by default; get_execution includes it only with includeOutputs: true. Lookup requires an open notebook, and records do not survive an extension reload. saveBeforeExecute pre-saves dirty notebooks before edit, move, or run; use save_notebooks to persist subsequent edits.

Tracking observes cell identity, source, execution summaries, and restart/interrupt requests made through MCP. Restarts initiated outside those tools are detected only when VS Code exposes corresponding cell or lifecycle changes. An unavailable result means completion could not be confirmed; it does not establish that the kernel stopped.

Updating clients from 0.3.0

  • Replace inspect_notebooks, read_cells, and read_cell_outputs with the appropriate read_notebook view.
  • Replace run_cells.wait and timeoutMs with the single waitMs budget, then follow executionId with get_execution.
  • Replace file transfer's localPath with hostPath, which names a path on the VS Code extension host.

Obsolete keys and tools are rejected; refresh the client's tool catalog after upgrading.

Multi-window routing

All windows share the configured loopback HTTP URL. The first window binds the broker; others register private loopback peers. If the broker closes, a peer can take over the same port. A URI that is ambiguous across windows fails; use the listed ref. Multi-notebook operations are grouped by owner.

Configuration

Setting Default Description
jupyterMcp.enabled true Enable the server
jupyterMcp.transport http Streamable HTTP on loopback; stdio is scoped to the extension host and has no standalone Node launcher
jupyterMcp.port 51303 Shared machine-scoped broker port
jupyterMcp.saveBeforeExecute true Pre-save dirty notebooks before edit, move, or run

Development and testing

Install dependencies with npm ci, then run npm run typecheck and npm run compile. Press F5 to open an Extension Development Host.

npm test compiles the extension and runs the MCP boundary, Jupyter integration, broker, and kernel-file suites. npm run coverage merges their c8 coverage and enforces statements/lines >=75%, branches >=55%, and functions >=85%. The tests use shims without downloading VS Code; live provider checks are separate. CI runs on Ubuntu, Windows, and macOS.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft