af-jupyterlab-mcp
Allows users to create, inspect, list, and delete their own per-user JupyterLab servers, and query GPU availability and supported images.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@af-jupyterlab-mcpCreate a Jupyter server with 2 CPUs and a GPU"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
af-jupyterlab-mcp
MCP server that lets AF users create, inspect, and delete their own per-user JupyterLab servers on the UChicago ATLAS Analysis Facility Kubernetes cluster — the same notebooks af-portal deploys today, exposed as tools for LLMs.
Architecture
LLM <--MCP/HTTP--> af-jupyterlab-mcp <--k8s API--> notebook namespace (Pod/Service/Secret/Ingress)
^
| Authorization: Bearer <broker-issued JWT>
|
af-mcp-platform credential brokerThis repo ships two groups of tools: six that manage the Pod/Service/
Secret/Ingress quadruple for a notebook, ported from af-portal's
portal/jupyterlab.py and its four Jinja templates, and sixteen nb_* tools
that proxy calls into the Datalayer jupyter-mcp-server running inside the
notebook itself (4ea435f), so a session can drive code execution inside the
user's own notebook without the notebook token ever entering LLM context — see
maniaclab/af-mcp-platform#189.
Related MCP server: rucio-mcp
Project layout
src/af_jupyterlab_mcp/
├── cli.py # argparse: `af-jupyterlab-mcp serve` (HTTP only)
├── config.py # env-driven Settings: namespace, domain, image allowlist, quotas
├── server.py # FastMCP setup, lifespan (k8s client + broker verifier), tool registration
├── auth/
│ └── broker.py # extract_bearer(), get_broker_claims() -- broker-issued JWT verification
├── k8s/
│ ├── errors.py # GuardrailError, NameConflictError, NotFoundOrNotYoursError, ...
│ ├── guardrails.py # CPU/memory/duration range + image allowlist validation
│ ├── names.py # sanitize_k8s_pod_name, name availability, name generation
│ ├── templates.py # Jinja rendering of the four ported manifests
│ ├── notebooks.py # create/get/list/delete notebook (ported portal logic)
│ ├── gpu.py # get_gpu_availability (ported portal logic)
│ ├── proxy.py # call_notebook_tool -- MCP client that proxies into jupyter-mcp-server
│ └── templates/ # pod.yaml.j2, service.yaml.j2, secret.yaml.j2, ingress.yaml.j2
│ # (ported verbatim from af-portal/portal/templates/jupyterlab/)
└── tools/
├── _helpers.py # format_error(), append_next_actions(), format_notebook[_list]()
├── jupyterlab.py # the six CRD-management @mcp.tool() functions
└── nb_proxy.py # the sixteen nb_* jupyter-mcp-server proxy @mcp.tool() functionsTool surface
22 tools total. Every tool's MCP annotations declare its
read-only/mutating/destructive status (see CLAUDE.md's "Tool registration
pattern"); the column below mirrors that.
Notebook server management (k8s/notebooks.py, k8s/gpu.py)
Tool | Does | Kind |
| Create a per-user JupyterLab server (pod+service+secret+ingress) | mutating |
| List the caller's own JupyterLab servers | read-only |
| Get rich status for one of the caller's own JupyterLab servers | read-only |
| Delete one of the caller's own JupyterLab servers (all four objects) | destructive |
| Get cluster-wide GPU availability, optionally filtered by product | read-only |
| List the CPU and GPU images allowed by | read-only |
The owner of every server is always claims.unixname from the verified broker
JWT — no tool takes an owner/username argument.
Notebook content proxy (k8s/proxy.py, upstream: jupyter-mcp-server)
Every nb_* tool takes notebook_server_id first, verifies the caller owns
that pod, checks it is Ready, and forwards the call to the notebook's own
jupyter-mcp-server with the notebook token injected server-side (never
returned to the caller).
Tool | Does | Kind |
| List files on the notebook server's filesystem | read-only |
| List all running kernels on the notebook server | read-only |
| List notebooks open on the notebook server | read-only |
| Connect to or create a notebook on the notebook server | mutating |
| Disconnect from a notebook on the notebook server | mutating |
| Restart a notebook's kernel on the notebook server | destructive |
| Read a notebook's cells from the notebook server | read-only |
| Read a cell from the active notebook | read-only |
| Insert a cell at a given index in the active notebook | mutating |
| Overwrite the source of a cell in the active notebook | destructive |
| Edit part of a cell's source in the active notebook | mutating |
| Delete one or more cells from the active notebook | destructive |
| Move a cell to a different index in the active notebook | mutating |
| Execute a specific cell in the active notebook | destructive |
| Insert a code cell and immediately execute it | destructive |
| Execute arbitrary code in the notebook server's kernel | destructive |
The three code-execution tools (nb_execute_cell,
nb_insert_execute_code_cell, nb_execute_code) are marked destructive even
though "execute" isn't literally a delete: they can mutate anything the kernel
can reach, which is what the annotation communicates to a client.
nb_get_selected_cell and nb_run_all_cells are intentionally absent — they
require the jupyter-mcp-tools JupyterLab frontend extension, not installed in
the current notebook images.
Build and test commands
pixi run test # quick tests
pixi run lint # pre-commit + pylint
pixi run helm-lint # lint + smoke-render the Helm chartThis server cannot be deployed
Maintenance
Related MCP Connectors
Massed Compute MCP — GPU inventory, VM lifecycle, billing, SSH keys, and setup recipes.
GPU cloud platform — create, manage, and monitor instances, snapshots, SSH keys, and billing.
Read GPU instances, types, images, filesystems and firewall rules; launch and terminate instances.
On-demand GPU nodes for agents: create nodes, run commands, and submit jobs, billed by the minute.
Related MCP Servers
- FlicenseAqualityBmaintenanceAn MCP server that enables LLMs to execute Python code on GPU-accelerated compute nodes within SLURM-managed HPC environments. It bridges local clients to remote clusters by launching JupyterLab sessions via SLURM jobs to facilitate high-performance notebook-based computation.7-
- AlicenseNot gradedqualityCmaintenanceAn MCP server that exposes Rucio distributed data management operations as tools for LLMs. Designed for ATLAS physicists working with grid data on analysis facilities, but usable with any Rucio instance.125 PyPI6Apache 2.0
- AlicenseAqualityCmaintenanceEnables code execution in isolated Docker containers with persistent IPython, Node.js, or R kernels, supporting file import/export and cross-session transfers via MCP tools.6MIT
- AlicenseAqualityDmaintenanceAI-powered MCP server for connecting and managing Jupyter Notebooks. Enables interactive code execution, multi-notebook management, and multimodal output for data analysis, visualization, and machine learning.129MIT