Development
Set up MCP Jupyter for development and contribution.
Development Setup
1. Clone the Repository
mkdir ~/Development
cd ~/Development
git clone https://github.com/block/mcp-jupyter.git
cd mcp-jupyter
2. Create Development Environment
# Create virtual environment
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install in editable mode
uv pip install -e .
# Install development dependencies
uv pip install pytest pytest-asyncio ruff mypy
3. Run Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=mcp_jupyter
# Run specific test file
pytest tests/test_notebook.py
Using Development Version
With Goose
For development, use the local installation:
goose session --with-extension "uv run $(pwd)/.venv/bin/mcp-jupyter"
This allows you to make changes and test them immediately by restarting Goose.
With Other Clients
Update your MCP configuration to point to your local installation:
{
"mcpServers": {
"jupyter": {
"command": "/path/to/mcp-jupyter/.venv/bin/python",
"args": ["-m", "mcp_jupyter"],
"env": {
"PYTHONPATH": "/path/to/mcp-jupyter"
}
}
}
}
Project Structure
mcp-jupyter/
├── src/
│ └── mcp_jupyter/
│ ├── __init__.py
│ ├── __main__.py # Entry point
│ ├── server.py # MCP server implementation
│ ├── notebook.py # Notebook operations
│ ├── jupyter.py # Jupyter integration
│ ├── state.py # State management
│ └── utils.py # Utilities
├── tests/
│ ├── test_notebook.py
│ ├── test_integration.py
│ └── test_notebook_paths.py
├── demos/
│ ├── demo.ipynb
│ └── goose-demo.png
├── pyproject.toml
└── README.md
Making Changes
Code Style
We use ruff
for linting and formatting:
# Format code
ruff format .
# Check linting
ruff check .
# Fix linting issues
ruff check --fix .
Type Checking
Run mypy for type checking:
mypy src/mcp_jupyter
Testing Changes
- Unit Tests: Test individual functions
- Integration Tests: Test with real Jupyter server
- Manual Testing: Test with your MCP client
Example test:
def test_notebook_creation():
"""Test creating a new notebook."""
notebook_path = "test_notebook.ipynb"
cells = ["import pandas as pd", "print('Hello, World!')"]
create_new_notebook(notebook_path, cells, server_url, token)
assert check_notebook_exists(notebook_path, server_url, token)
Debugging
Enable Debug Logging
import logging
logging.basicConfig(level=logging.DEBUG)
Using VS Code
- Create
.vscode/launch.json
:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug MCP Jupyter",
"type": "python",
"request": "launch",
"module": "mcp_jupyter",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"TOKEN": "BLOCK"
}
}
]
}
- Set breakpoints in the code
- Run with F5
Common Issues
- Import errors: Ensure you're in the virtual environment
- Connection issues: Check Jupyter server is running
- State issues: Clear notebook state and restart kernel
Contributing
1. Fork and Branch
git checkout -b feature/your-feature-name
2. Make Changes
- Follow the code style
- Add tests for new features
- Update documentation
3. Test Thoroughly
# Run tests
pytest
# Check formatting
ruff format --check .
# Check types
mypy src/mcp_jupyter
4. Submit PR
- Push to your fork
- Create pull request
- Describe changes clearly
- Link any related issues
Architecture
Key Components
-
MCP Server (
server.py
)- Handles MCP protocol
- Manages tool registration
- Routes requests
-
Notebook Manager (
notebook.py
)- Creates/manages notebooks
- Handles kernel lifecycle
- Manages sessions
-
State Tracker (
state.py
)- Tracks notebook state
- Manages state consistency
- Provides decorators
-
Jupyter Client (
jupyter.py
)- Communicates with Jupyter
- Handles authentication
- Manages connections
Adding New Tools
To add a new MCP tool:
@mcp.tool()
def my_new_tool(param1: str, param2: int = 10) -> dict:
"""Tool description for MCP clients.
Args:
param1: Description of param1
param2: Description of param2
Returns:
dict: Result of the operation
"""
# Implementation
return {"result": "success"}