jupyter-rmcp (tmlksu/jupyter-rmcp) is an MCP server listed on the M8ven Trust Index. It scores 22 out of 100, grade F. It declares 31 tools. No publisher has claimed this listing.
A self-hosted MCP server providing Claude with an interactive Jupyter environment, including real kernels, persistent notebooks, and optional GPU offload to Google Colab.
Warning. Serious findings were identified. Review the full report before connecting. Grades reflect the full trust pyramid: code, verification depth, and reputation. New projects cap at C until adoption is earned.
How we verified
Verified is a snapshot. Live keeps it current, and builds your track record.
⚡ Connect GitHub → continuous verification on every pushwhy connect →Who stands behind it
tmlksu
Source: Glama
Claim it to get a verified publisher badge, a free copy of our full audit findings, and direct contact for any high-priority issues we find. Or connect your repo for our deepest verification, Live Monitored: read-only, revoke anytime. What we access →
Install from
The grade above is for the source repository. Registries can serve a different version, so we mark the ones we were not able to read.
These names and descriptions are the publisher's own, read from the source code. We print them as written. Our assessment is the findings above, not this list.
execute_codeRun ad-hoc Python in the kernel (stateful; variables persist across calls) and **append** it as a new cell to the bound notebook (if any). For iterating on an EXISTING cell without duplicating it, use execute_cell / edit_cell instead. On timeout the kernel is interrupted. Works for local and colab b…
get_jobPoll a background job started by execute_code(background=True): returns its `status` ("running_in_background" / "done" / "error" / "unknown") and a WINDOW of the stdout+stderr it has captured (unbuffered — live progress shows). Cheap, non-blocking; call repeatedly until status is no longer "running_…
list_kernelsList running kernels across all backends (local + registered Colab), with their backend, notebook binding, state, idle/age seconds, and pin status.
start_kernelStart a notebook kernel and return its kernel_id (use it with execute_code / add_cell / execute_cell). Work is saved to a notebook ON THE SERVER (viewable/editable in JupyterLab).
stop_kernelTerminate a kernel (and its session, if any) and free its resources. For a COLAB kernel this DESTROYS the VM — all /content files and pip installs on it are lost, and a later start_kernel gives a brand-new empty VM. To merely reset Python state while keeping the VM + files, use restart_kernel instea…
restart_kernelRestart a kernel, clearing all in-memory state (variables) but keeping the same id. For a COLAB kernel this restarts ONLY the Python process — the VM survives, so /content files, the HuggingFace/model cache and pip-installed packages persist; just the interpreter (and its module cache) is fresh. Use…
interrupt_kernelInterrupt a running kernel (raise KeyboardInterrupt) to stop a runaway execution. LOCAL kernels only — Colab has no interrupt.
colab_logReview a COLAB session's recent COMPLETED executions — each one's code AND the output it captured — WITHOUT re-running anything. Handy to retrieve a past cell's result or confirm what already ran on the VM. `limit` = how many recent executions to return. IMPORTANT: an execution is logged only when i…
pin_kernelPin/unpin a kernel to exempt it from the IDLE reaper (e.g. a long-lived notebook). Note: pinning does NOT exempt it from the absolute max-age hard cap (KERNEL_MAX_AGE_SEC) — nothing lives past that. Pin state persists across MCP restarts (kept in the kernel registry).
list_variablesList the user-defined variables currently held in the kernel (name/type/size).
list_backendsList available compute backends for start_kernel: `local` (the server's own Jupyter) and `colab` (official colab-cli, GPU on demand) if configured. Shows kind, reachability, and `exec_enabled` — false for `local` when the server runs colab-only, meaning it still stores/serves notebooks but refuses t…
notebook_revCurrent revision token of a notebook: {path, rev, cells}. `rev` is a content hash — pass it as `expected_rev` to an editing tool to guard against a concurrent external edit (e.g. a human in JupyterLab). Mutating tools also return the new rev.
list_cellsOverview of a notebook's cells (no full source): per cell {index, id, type, summary, num_lines, has_outputs, has_error}. `id` is stable across insert/delete/ move — prefer addressing later edits by `id`. Also returns the notebook `rev`.
read_cellsRead full source (+ a text summary of outputs) for specific cells, by `indices` OR `ids` (batch — one round-trip). Omit both to read all cells.
insert_cellsInsert several cells at once, contiguously BEFORE `index` (index == cell count appends). `cells` = list of {cell_type, source, summary?}. Prefer this over many single inserts. Returns {indices, ids, rev}.
insert_cellInsert one cell BEFORE `index` (index == cell count appends). For a block of cells prefer insert_cells. Returns {index, id, rev}.
patch_cellPREFERRED edit: replace a UNIQUE `old` substring with `new` in one cell (cheap — no full-source resend). Target by `cell_id` (stable, preferred) OR `index`. `old` must occur exactly once in the cell, else it errors (safer than a wrong guess). Does not touch outputs. Returns {index, id, rev}.
edit_cellReplace a cell's ENTIRE source (for small changes prefer patch_cell). Target by `cell_id` (preferred) OR `index`. `summary` sets metadata summary ("" clears). Does not execute or touch outputs. Returns {index, id, rev}.
delete_cellDelete a cell, addressed by `cell_id` (preferred) OR `index`. Returns {rev, remaining}.
move_cellMove a cell to `to_index` (final 0-based position). Address the moved cell by `from_id` (preferred) OR `from_index`. Returns {rev}.
execute_cellRun an EXISTING code cell in the kernel's bound notebook and update THAT cell's outputs in place (no duplicate). Target by `cell_id` (stable, preferred) OR `index`. Editing (patch_cell/edit_cell) is separate — this only runs a cell as-is.
create_notebookCreate a new notebook (.ipynb) under the work root, optionally seeded with `cells` (list of {cell_type, source, summary?}). To inspect/edit existing notebooks use list_cells / read_cells / patch_cell etc.
setup_kaggleMake Kaggle usable in this kernel (`!kaggle datasets download …`). For LOCAL kernels this is already configured (no-op). For a COLAB kernel it injects the server-side token into that Colab VM: the token is uploaded as a file and loaded into the VM env (`KAGGLE_API_TOKEN`) + `~/.kaggle/`, so it never…
setup_hfMake a HuggingFace token available in this kernel WITHOUT it appearing in exec/session history — needed for gated/private repos (`hf_hub_download`, `from_pretrained`). Same masked-injection design as setup_kaggle: for a COLAB kernel the token is uploaded as a file and loaded into the VM env (`HF_TOK…
upload_to_colabCopy a file from the server workspace (uploaded via JupyterLab / upload_file / fetch_to_workspace) ONTO the Colab VM for this kernel, so the notebook can open it there. `remote_path` defaults to /content/<basename>. Local kernels already see workspace files directly (no copy needed).
download_from_colabCopy a file FROM the Colab VM (e.g. a result/checkpoint the notebook produced) back into the server workspace so it persists and is visible in JupyterLab. `workspace_path` defaults to the remote basename at the work root. Colab kernels only.
list_notebooksList notebooks and subdirectories under `path` (relative to the work root). For ALL files (data, images, etc.) use list_files.
list_filesList EVERYTHING (files + folders) under `path` in the workspace — notebooks, uploaded data, images, etc. Files live on the server (persistent) and are visible to kernels (cwd is the work root) and in JupyterLab.
create_folderCreate a folder (and any missing parent folders) under the work root. Notebook/ file writes also auto-create parents, so you rarely need this explicitly.
upload_fileWrite a file into the workspace from base64 bytes (binary-safe; persists on the server, visible to kernels and JupyterLab). Auto-creates parent folders. For a human uploading from a phone/laptop, JupyterLab's Upload button is usually easier; use this when a client can provide the bytes (e.g. Claude …
fetch_to_workspaceDownload a URL to a file in the workspace, server-side (the server fetches it). Handy to bring in a test image/dataset by link when you can't upload from the device. Auto-creates parent folders; capped at 200 MB.
JUPYTER_TOKENand MCP_BEARER, then docker compose up -d --build.COLAB_ONLYKaggle on a laptop: =1 makes every kernel a Colab VM underGOOGLE_APPLICATION_CREDENTIALSKAGGLE_API_TOKENKaggle: set in .env (kaggle.com/settings/api →KAGGLE_USERNAMEKAGGLE_KEYHF_TOKENHUGGING_FACE_HUB_TOKENTool annotations
5/31 tools have annotations
Add readOnlyHint or destructiveHint annotations to every tool so hosts can warn users before invoking.
All four hints declared on every tool
31/31 tools missing one or more hints — execute_code (missing: readOnlyHint, destructiveHint, idempotentHint, openWorldHint); get_job (missing: destructiveHint, idempotentHint, openWorldHint); list_kernels (missing: readOnlyHint, destructiveHint, idempotentHint, openWorldHint), +28 more. OpenAI's directory rejects tools where any of the four hints are missing or non-boolean.
For every tool, set all four hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) to explicit true/false values that match the handler’s actual behaviour.
Tool annotations match behaviour
1 read-only tool performs write/delete/exec — colab_log (line 256: os.unlink(tmp.name))
Either remove the readOnlyHint:true annotation, or remove the write/delete call from the tool handler.
Destructive tools are labelled
5 tools perform destructive updates without destructiveHint — colab_log deletes at line 256 (os.unlink(tmp.name)); setup_kaggle deletes at line 50 ("p.unlink(missing_ok=True); print('kaggle configured (token)')\n"); setup_hf deletes at line 107 ("p.unlink(missing_ok=True); print('hf token configured')\n")
Add destructiveHint:true to any tool whose handler calls .delete(), .upsert(), .update(), unlink, rm, DELETE, DROP, REPLACE INTO, or any operation that overwrites existing data.
Descriptions match behaviour
1 tool describes read intent but its handler mutates — colab_log (line 256: os.unlink(tmp.name))
Rename the tool, rewrite the description, or move the side-effect into a separate clearly-named tool.
Tool inputs are validated
29/31 tool handlers declare input schemas (94%)
Declare an inputSchema with zod/joi/yup on every tool definition.
Tool handlers catch errors
Only 10/31 tool handlers wrap calls in try/catch (32%)
Wrap each tool handler body in try/catch and return a structured error response.
Tests exist
No test files found
Add tests that exercise each declared tool.
Tool description accuracy
colab_log: description implies read-only but handler writes/deletes/executes
Update tool descriptions to accurately reflect all capabilities — especially write, delete, or execute operations.
Claim the listing to review these findings one by one and send us a correction where you disagree, straight to the team. Claiming also means we tell you when the grade moves, and reach you first if we find anything urgent.
[](https://m8ven.ai/mcp/tmlksu/jupyter-rmcp)?variant=verified from the URL.Vetting this one by hand? Tool Check is an MCP that scores other MCPs. Add it once and ask Claude, ChatGPT, or any MCP client to grade a server, surface CVEs, check the publisher, and suggest safer alternatives — before you install.
https://m8ven.ai/api/mcp/tool-check