Framework
- Jupyter
License
- OSI Approved :: BSD License
Programming Language
- Python
- Python :: 3
- Python :: 3.10
- Python :: 3.11
- Python :: 3.12
- Python :: 3.13
- Python :: 3.14
Jupyter Server MCP Extension
A configurable MCP (Model Context Protocol) server extension for Jupyter Server that allows dynamic registration of Python functions as tools accessible to MCP clients from a running Jupyter Server.
https://github.com/user-attachments/assets/aa779b1c-a443-48d7-b3eb-13f27a4333b3
Overview
This extension provides a simplified, trait-based approach to exposing Jupyter functionality through the MCP protocol. It can dynamically load and register tools from various Python packages, making them available to AI assistants and other MCP clients.
Key Features
- Simplified Architecture: Direct function registration without complex abstractions
- Configurable Tool Loading: Register tools via string specifications (
module:function) - Automatic Tool Discovery: Python packages can expose tools via entrypoints
- Jupyter Integration: Seamless integration with Jupyter Server extension system
- Streamable HTTP Transport: FastMCP-based HTTP server with proper MCP protocol support
- Traitlets Configuration: Full configuration support through Jupyter's traitlets system
Installation
Install jupyter-server-mcp into the same environment as Jupyter Server or JupyterLab.
pip
python -m pip install jupyter-server-mcp
conda / mamba / micromamba
conda install -c conda-forge jupyter-server-mcp
mamba install -c conda-forge jupyter-server-mcp
micromamba install -c conda-forge jupyter-server-mcp
pixi
In an existing Pixi workspace:
# If conda-forge is not already configured for the workspace
pixi project channel add conda-forge
pixi add jupyter-server-mcp
Quick Start
1. Basic Configuration
Create a jupyter_config.py file:
c = get_config()
# Basic MCP server settings
c.MCPExtensionApp.mcp_name = "My Jupyter MCP Server"
# Optional: override the default MCP port (3001).
# If 3001 is already in use, choose another fixed port and use the same
# port in your MCP client configuration below.
# c.MCPExtensionApp.mcp_port = 8080
# Register tools from existing packages
c.MCPExtensionApp.mcp_tools = [
# Standard library tools
"os:getcwd",
"json:dumps",
"time:time",
# Jupyter AI Tools - Notebook operations
"jupyter_ai_tools.toolkits.notebook:read_notebook",
"jupyter_ai_tools.toolkits.notebook:edit_cell",
# JupyterLab Commands Toolkit
"jupyterlab_commands_toolkit.tools:list_all_commands",
"jupyterlab_commands_toolkit.tools:execute_command",
]
2. Start Jupyter Server
jupyter lab --config=jupyter_config.py
The MCP server will start automatically on http://localhost:3001/mcp by default.
If the configured port is already in use, startup fails with a clear error instead
of silently choosing another port, because MCP clients need to be configured with
the actual endpoint URL.
Any trait can also be set directly on the command line, without a config file. For example, to override the port:
jupyter lab --MCPExtensionApp.mcp_port=8080
3. CLI MCP Client Configuration
By default, this extension exposes a FastMCP streamable HTTP endpoint at http://localhost:3001/mcp.
If you override the port via c.MCPExtensionApp.mcp_port or the --MCPExtensionApp.mcp_port=<port> CLI flag, replace 3001 in the examples below.
If a client asks for a transport type, choose HTTP or Streamable HTTP.
The list below is intentionally curated rather than exhaustive and focuses on terminal-based coding agents. For a broader, community-maintained directory of MCP-compatible clients, see the MCP client directory: https://modelcontextprotocol.io/clients.
OpenCode
Use opencode mcp add, or add the following to opencode.json or ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"jupyter-mcp": {
"type": "remote",
"url": "http://localhost:3001/mcp",
"enabled": true
}
}
}
Mistral Vibe
Add the following to ./.vibe/config.toml or ~/.vibe/config.toml:
[[mcp_servers]]
name = "jupyter-mcp"
transport = "streamable-http"
url = "http://localhost:3001/mcp"
Claude Code
Add the following to .mcp.json:
{
"mcpServers": {
"jupyter-mcp": {
"type": "http",
"url": "http://localhost:3001/mcp"
}
}
}
Or use the claude CLI:
claude mcp add --transport http jupyter-mcp http://localhost:3001/mcp
Codex
Use the codex CLI:
codex mcp add jupyter-mcp --url http://localhost:3001/mcp
Or add the following to ~/.codex/config.toml:
[mcp_servers.jupyter-mcp]
url = "http://localhost:3001/mcp"
Gemini CLI
Add the following to .gemini/settings.json:
{
"mcpServers": {
"jupyter-mcp": {
"httpUrl": "http://localhost:3001/mcp"
}
}
}
Copilot CLI
Use /mcp add in interactive mode, or add the following to ~/.copilot/mcp-config.json:
{
"mcpServers": {
"jupyter-mcp": {
"type": "http",
"url": "http://localhost:3001/mcp",
"tools": ["*"]
}
}
}
Architecture
Core Components
MCPServer (jupyter_server_mcp.mcp_server.MCPServer)
A simplified LoggingConfigurable class that manages FastMCP integration:
from jupyter_server_mcp.mcp_server import MCPServer
# Create server
server = MCPServer(name="My Server", port=8080)
# Register functions
def my_tool(message: str) -> str:
return f"Hello, {message}!"
server.register_tool(my_tool)
# Start server
await server.start_server()
Key Methods:
register_tool(func, name=None, description=None)- Register a Python functionregister_tools(tools)- Register multiple functions (list or dict)list_tools()- Get list of registered toolsstart_server(host=None)- Start the HTTP MCP server
MCPExtensionApp (jupyter_server_mcp.extension.MCPExtensionApp)
Jupyter Server extension that manages the MCP server lifecycle:
Configuration Traits:
mcp_name- Server name (default: "Jupyter MCP Server")mcp_port- Server port (default: 3001)mcp_tools- List of tools to register (format: "module:function")use_tool_discovery- Enable automatic tool discovery via entrypoints (default: True)
Tool Registration
Tools can be registered in two ways:
1. Manual Configuration
Specify tools directly in your Jupyter configuration using module:function format:
c.MCPExtensionApp.mcp_tools = [
"os:getcwd",
"jupyter_ai_tools.toolkits.notebook:read_notebook",
]
2. Automatic Discovery via Entrypoints
Python packages can expose tools automatically using the jupyter_server_mcp.tools entrypoint group.
In your package's pyproject.toml:
[project.entry-points."jupyter_server_mcp.tools"]
my_package_tools = "my_package.tools:TOOLS"
In my_package/tools.py:
# Option 1: Define as a list
TOOLS = [
"my_package.operations:create_file",
"my_package.operations:delete_file",
]
# Option 2: Define as a function
def get_tools():
return [
"my_package.operations:create_file",
"my_package.operations:delete_file",
]
Tools from entrypoints are discovered automatically when the extension starts. To disable automatic discovery:
c.MCPExtensionApp.use_tool_discovery = False
Configuration Examples
Minimal Setup
c = get_config()
# Optional: override the default port (3001)
# Use a fixed port that matches your MCP client configuration.
# c.MCPExtensionApp.mcp_port = 8080
Full Configuration
c = get_config()
# MCP Server Configuration
c.MCPExtensionApp.mcp_name = "Advanced Jupyter MCP Server"
c.MCPExtensionApp.mcp_port = 8080
c.MCPExtensionApp.mcp_tools = [
# File system operations (jupyter-ai-tools)
"jupyter_ai_tools.toolkits.file_system:read",
"jupyter_ai_tools.toolkits.file_system:write",
"jupyter_ai_tools.toolkits.file_system:edit",
"jupyter_ai_tools.toolkits.file_system:ls",
"jupyter_ai_tools.toolkits.file_system:glob",
# Notebook operations (jupyter-ai-tools)
"jupyter_ai_tools.toolkits.notebook:read_notebook",
"jupyter_ai_tools.toolkits.notebook:edit_cell",
"jupyter_ai_tools.toolkits.notebook:add_cell",
"jupyter_ai_tools.toolkits.notebook:delete_cell",
"jupyter_ai_tools.toolkits.notebook:create_notebook",
# Git operations (jupyter-ai-tools)
"jupyter_ai_tools.toolkits.git:git_status",
"jupyter_ai_tools.toolkits.git:git_add",
"jupyter_ai_tools.toolkits.git:git_commit",
"jupyter_ai_tools.toolkits.git:git_push",
# JupyterLab operations (jupyterlab-commands-toolkit)
"jupyterlab_commands_toolkit.tools:clear_all_outputs_in_notebook",
"jupyterlab_commands_toolkit.tools:open_document",
"jupyterlab_commands_toolkit.tools:open_markdown_file_in_preview_mode",
"jupyterlab_commands_toolkit.tools:show_diff_of_current_notebook",
# Utility functions
"os:getcwd",
"json:dumps",
"time:time",
"platform:system",
]
Running Tests
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run with coverage
pytest --cov=jupyter_server_mcp tests/
Project Structure
jupyter_server_mcp/
├── jupyter_server_mcp/
│ ├── __init__.py
│ ├── mcp_server.py # Core MCP server implementation
│ └── extension.py # Jupyter Server extension
├── tests/
│ ├── test_mcp_server.py # MCPServer tests
│ └── test_extension.py # Extension tests
├── demo/
│ ├── jupyter_config.py # Example configuration
│ └── *.py # Debug/diagnostic scripts
└── pyproject.toml # Package configuration
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
pytest tests/ - Submit a pull request