Complete guide for the Pluto Notebook MCP (Model Context Protocol) server.
- Quick Start
- What is MCP?
- Setup and Configuration
- Available Tools
- Usage Examples
- Architecture
- Commands
- Troubleshooting
Get started with the Pluto Notebook MCP server in 2 minutes!
The Pluto Notebook extension includes an HTTP-based MCP (Model Context Protocol) server that lets AI assistants like Claude Desktop and GitHub Copilot interact with your Julia Pluto notebooks.
Open any .jl file in VS Code. The extension will:
- ✅ Automatically start the Pluto server
- ✅ Automatically start the MCP HTTP server on port 3100
- ✅ Show status in "Pluto Server" output channel
Run this command in VS Code:
Pluto: Create MCP Config (Claude or Copilot)
Choose your tool:
- Claude Desktop → Creates
.mcp.json - GitHub Copilot → Creates
mcp.json
- Claude Desktop: Restart the app
- GitHub Copilot: Reload VS Code window (
Ctrl+Shift+P→ "Reload Window")
Ask your AI assistant:
List all open Pluto notebooks
or
Execute this code in my notebook: println("Hello from MCP!")
The MCP server provides the following capabilities to AI assistants:
- 📋 List notebooks - See all open notebooks
▶️ Execute code - Run Julia code without modifying notebook- 📝 Create cells - Add new cells with code
- ✏️ Edit cells - Update existing cell code
- 👀 Read cells - View cell code and output
- 🔍 Query status - Check server and notebook status
- Shared State: The extension and MCP clients share the same Pluto server connection and worker sessions
- No Duplicate Processes: Single Pluto server instance managed by the extension
- HTTP-based: More flexible than stdio, works with any HTTP client
- Health Monitoring: Built-in health check endpoint
The MCP server can be configured with the following settings:
{
"pluto-notebook.port": 1234, // Pluto server port
"pluto-notebook.mcpPort": 3100, // MCP HTTP server port
"pluto-notebook.autoStartMcpServer": true // Auto-start MCP server (default: true)
}By default, the MCP server starts automatically when the extension activates. To disable auto-start:
- Open VS Code settings
- Search for "Pluto Notebook"
- Uncheck "Auto Start Mcp Server"
Or add to your settings.json:
{
"pluto-notebook.autoStartMcpServer": false
}When auto-start is disabled, use Pluto: Start MCP Server command to start manually.
- SSE Stream:
http://localhost:3100/mcp(GET) - Messages:
http://localhost:3100/messages(POST) - Health Check:
http://localhost:3100/health(GET)
Create .mcp.json in your workspace root:
{
"mcpServers": {
"pluto-notebook": {
"url": "http://localhost:3100/mcp",
"type": "sse"
}
}
}Quick Setup:
- Run command:
Pluto: Create MCP Config (Claude or Copilot) - Select "Claude Desktop"
- File
.mcp.jsonis created in workspace root - Restart Claude Desktop to load the config
Create mcp.json in your workspace root:
{
"servers": {
"pluto-notebook": {
"url": "http://localhost:3100/mcp",
"type": "http"
}
},
"inputs": []
}Quick Setup:
- Run command:
Pluto: Create MCP Config (Claude or Copilot) - Select "GitHub Copilot"
- File
mcp.jsonis created/updated - Reload VS Code window (
Ctrl+Shift+P→ "Reload Window")
| Feature | Claude Desktop | GitHub Copilot |
|---|---|---|
| File | .mcp.json |
mcp.json |
| Location | Workspace root | Workspace root |
| Type | sse |
http |
| Restart | Restart app | Reload window |
| Purpose | MCP-specific | MCP-specific |
Both configs use the port from VS Code settings:
{
"pluto-notebook.mcpPort": 3100 // Default
}To change the port:
- Update setting:
pluto-notebook.mcpPort - Recreate config files
- Restart MCP server:
Pluto: Restart MCP Server
The MCP server exposes the following tools:
- learn_pluto_basics: Get comprehensive guide on Pluto.jl notebook structure and best practices
- start_pluto_server: Start the Pluto server
- connect_to_pluto_server: Connect to an existing Pluto server
- stop_pluto_server: Stop the Pluto server
- open_notebook: Open a Pluto notebook and create a worker session
- list_notebooks: Get a list of all open notebooks with their paths and IDs
- execute_cell: Execute an existing cell by ID
- create_cell: Create and execute a new cell
- edit_cell: Update the code of an existing cell
- read_cell: Read the code and output of a cell
- execute_code: Execute Julia code without creating a persistent cell (ephemeral)
- get_notebook_status: Get server and notebook status
Start the Pluto server on the configured port.
{
"name": "start_pluto_server",
"arguments": {
"port": 1234
}
}Connect to an already running Pluto server (useful if Julia is running externally).
{
"name": "connect_to_pluto_server",
"arguments": {
"port": 1234
}
}Stop the running Pluto server.
{
"name": "stop_pluto_server",
"arguments": {}
}Check if the Pluto server is running.
{
"name": "get_notebook_status",
"arguments": {}
}Response:
{
"server_running": true,
"message": "Pluto server is running"
}Get comprehensive guide on Pluto.jl notebook structure, reactivity, PlutoUI components, and best practices.
{
"name": "learn_pluto_basics",
"arguments": {}
}Response: Returns complete markdown documentation covering:
- Notebook file format and cell structure
- Reactive execution model and rules
- Complete PlutoUI component reference (Slider, TextField, NumberField, CheckBox, Select, Button, etc.)
- Combining markdown with interactive widgets
- Best practices and common patterns
Usage: AI assistants should call this tool first to understand how to properly create and modify Pluto notebooks.
Open a Pluto notebook and create a worker session.
{
"name": "open_notebook",
"arguments": {
"path": "/path/to/notebook.jl"
}
}Response:
{
"message": "Notebook opened: /path/to/notebook.jl\nNotebook ID: abc-123-def"
}Get a list of all currently open notebooks.
{
"name": "list_notebooks",
"arguments": {}
}Response:
{
"count": 2,
"notebooks": [
{
"path": "/path/to/notebook1.jl",
"notebookId": "abc-123-def"
},
{
"path": "/path/to/notebook2.jl",
"notebookId": "xyz-456-ghi"
}
]
}Create a new cell and execute it.
{
"name": "create_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"code": "x = 1 + 1",
"index": 0
}
}Response:
{
"cell_id": "abc-123",
"output": {
"body": "2",
"mime": "text/plain"
},
"runtime": 0.05,
"errored": false,
"message": "Cell created and executed successfully"
}Read the code and output of an existing cell.
{
"name": "read_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"cell_id": "abc-123"
}
}Response:
{
"cell_id": "abc-123",
"code": "x = 1 + 1",
"output": {
"body": "2",
"mime": "text/plain"
},
"runtime": 0.05,
"errored": false,
"running": false,
"queued": false
}Update the code of an existing cell.
{
"name": "edit_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"cell_id": "abc-123",
"code": "x = 2 + 2",
"run": true
}
}Response:
{
"cell_id": "abc-123",
"output": {
"body": "4",
"mime": "text/plain"
},
"runtime": 0.03,
"errored": false,
"message": "Cell updated and executed successfully"
}Execute an existing cell (runs current code in the cell).
{
"name": "execute_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"cell_id": "abc-123"
}
}Response:
{
"cell_id": "abc-123",
"output": {
"body": "4",
"mime": "text/plain"
},
"runtime": 0.03,
"errored": false
}Execute Julia code without creating a persistent cell (ephemeral execution).
This is useful for:
- Quick queries or evaluations
- Testing code snippets
- Inspecting variable values
- Running diagnostic commands
The code has access to all variables defined in the notebook, but doesn't modify the notebook structure.
{
"name": "execute_code",
"arguments": {
"path": "/path/to/notebook.jl",
"code": "println(\"x = $x\")"
}
}Response:
{
"output": {
"body": "x = 4",
"mime": "text/plain"
},
"runtime": 0.01,
"errored": false,
"message": "Code executed successfully (no cell created)"
}Important: The cell is created temporarily and deleted immediately after execution. It will not appear in the notebook file.
Try asking Claude or Copilot:
Basic Operations:
- "List all open notebooks"
- "Open the notebook at /path/to/analysis.jl"
- "What's the status of the Pluto server?"
Code Execution:
- "Execute: 2 + 2"
- "Run this code without saving: println(x)"
- "What's the value of variable x?"
Notebook Manipulation:
- "Create a cell that imports DataFrames"
- "Edit cell abc-123 to use Plots instead of StatsPlots"
- "Show me the output of cell xyz-789"
- Start server and open notebook:
{"name": "start_pluto_server", "arguments": {}}
{"name": "open_notebook", "arguments": {"path": "/path/to/analysis.jl"}}- Check what notebooks are open:
{ "name": "list_notebooks", "arguments": {} }- Execute quick queries without modifying notebook:
{
"name": "execute_code",
"arguments": {
"path": "/path/to/analysis.jl",
"code": "summary(dataframe)"
}
}- Create cells incrementally:
{
"name": "create_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"code": "using DataFrames",
"index": 0
}
}- Edit and refine:
{
"name": "edit_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"cell_id": "abc-123",
"code": "using DataFrames, Plots"
}
}- Test with ephemeral execution:
{
"name": "execute_code",
"arguments": {
"path": "/path/to/notebook.jl",
"code": "plot(1:10, rand(10))"
}
}- List all open notebooks:
{ "name": "list_notebooks", "arguments": {} }- Read specific cells:
{
"name": "read_cell",
"arguments": {
"path": "/path/to/notebook.jl",
"cell_id": "abc-123"
}
}- Query variable state without creating cells:
{
"name": "execute_code",
"arguments": {
"path": "/path/to/notebook.jl",
"code": "varinfo()"
}
}┌─────────────────────────────────────────────────────┐
│ VS Code Extension │
│ ┌────────────────┐ ┌──────────────────┐ │
│ │ Controller │───────▶│ PlutoManager │◀───┼───┐
│ │ Serializer │ │ (Shared) │ │ │
│ └────────────────┘ └──────────────────┘ │ │
│ │ │ │
│ ▼ │ │
│ ┌──────────────────┐ │ │
│ │ Pluto Server │ │ │
│ │ (Julia Process) │ │ │
│ └──────────────────┘ │ │
└─────────────────────────────────────────────────────┘ │
│
┌─────────────────────────────────────────────────────┐ │
│ MCP HTTP Server │ │
│ ┌────────────────────────────────────────────┐ │ │
│ │ HTTP/SSE Endpoints │ │ │
│ │ - GET /mcp (SSE stream) │ │ │
│ │ - POST /messages (JSON-RPC) │ │ │
│ │ - GET /health (health check) │ │ │
│ └────────────────────────────────────────────┘ │ │
│ │ │ │
└──────────────────────┼──────────────────────────────┘ │
│ │
└──────────────────────────────────┘
(Shared PlutoManager)
▲
│
┌────┴─────┐
│ Claude │
│ Desktop │
│ (MCP │
│ Client) │
└──────────┘
| Command | Description |
|---|---|
Pluto: Start Server |
Manually start Pluto server |
Pluto: Stop Server |
Stop Pluto server |
Pluto: Restart Server |
Restart Pluto server |
| Command | Description |
|---|---|
Pluto: Start MCP Server |
Manually start MCP HTTP server |
Pluto: Stop MCP Server |
Stop MCP HTTP server |
Pluto: Restart MCP Server |
Restart MCP HTTP server |
| Command | Description |
|---|---|
Pluto: Create MCP Config (Claude or Copilot) |
Create config file with interactive picker |
Pluto: Get MCP HTTP Server URL |
Get URL and config options |
The Pluto: Get MCP HTTP Server URL command provides actions:
- Copy URL - Copy MCP endpoint URL to clipboard
- Create Claude Config - Create
.mcp.json - Create Copilot Config - Create
mcp.json - Open Health Check - Open health endpoint in browser
Check the "Pluto Server" output channel in VS Code:
View → Output → Select "Pluto Server"
If auto-start is disabled:
- Check if auto-start is enabled:
pluto-notebook.autoStartMcpServer - Try starting manually:
Pluto: Start MCP Server - Check the "Pluto Server" output channel for errors
Change the port in settings:
{
"pluto-notebook.mcpPort": 3200 // Use different port
}Then:
- Restart the MCP server:
Pluto: Restart MCP Server - Recreate your config files
- Verify extension is active (open a
.jlfile) - Check health endpoint:
http://localhost:3100/health - Verify config file location:
- Claude Desktop config: Workspace root
- Name:
.mcp.json
- Restart Claude Desktop
Checklist:
- ✅
.mcp.jsonexists in workspace root - ✅ File has correct format (see above)
- ✅ Extension is active (open a
.jlfile) - ✅ MCP server is running
- ✅ Restarted Claude Desktop after creating config
- Verify config in
mcp.json(workspace root) - Reload VS Code window
- Check MCP support is enabled in Copilot settings
Checklist:
- ✅
mcp.jsonexists in workspace root - ✅ File has correct format (see above)
- ✅ Reloaded VS Code window
- ✅ GitHub Copilot MCP support is enabled
- ✅ Extension is active
Symptom: Command completes but no file appears
Solution:
- Check workspace is open
- Verify write permissions
- Check output in "Pluto Server" channel
The extension and MCP clients share the same PlutoManager. If you close a notebook in VS Code, it will also be closed for MCP clients.
Verify the MCP server is running:
curl http://localhost:3100/healthExpected response:
{
"status": "ok",
"plutoServerRunning": true,
"activeSessions": 0
}Check Config File Exists
Claude:
cat <workspace>/.mcp.jsonCopilot:
cat <workspace>/mcp.jsonCheck MCP Server Running
curl http://localhost:3100/healthAll tools return error information when something goes wrong:
{
"content": [
{
"type": "text",
"text": "Error: Pluto server is not running"
}
]
}Common errors:
"Pluto server is not running"- Start the server first"Notebook {path} is not open"- Open the notebook first"Cell {id} not found"- Invalid cell ID
💡 Pro Tips:
- Use
execute_codefor quick queries without modifying notebooks - The
list_notebookstool shows all open notebooks with their paths - MCP server shares state with the VS Code extension
- Changes via MCP are reflected immediately in VS Code
- Close notebooks in VS Code to free up MCP resources
🎯 Best Practices:
- Keep one notebook open at a time for focused work
- Use ephemeral execution for exploration
- Create persistent cells for important code
- Check health endpoint before debugging
- Use the command for config creation over manual editing
- Add
.mcp.jsonto.gitignoreif needed - Keep
mcpPortsetting consistent with config files - Test connection using health check
- Document the MCP port in project README for team sharing
- Open Pluto notebook project in VS Code
- Extension activates, MCP server starts on port 3100
- Run:
Pluto: Create MCP Config (Claude or Copilot) - Choose "Claude Desktop"
.mcp.jsoncreated and opened- Restart Claude Desktop
- Ask Claude: "List all open Pluto notebooks"
- Claude connects via MCP and responds!
- Claude Desktop: Uses
.mcp.jsonin workspace root - GitHub Copilot: Uses
mcp.jsonin workspace root - Interactive: Use command for easy setup
- Smart Merging: Preserves existing configurations
- Port Configurable: Via
pluto-notebook.mcpPortsetting - Shared State: Single PlutoManager instance for extension and MCP
- HTTP-based: Flexible SSE transport for real-time communication
If you encounter issues:
- Check the "Pluto Server" output channel
- Verify health endpoint responds
- Review configuration files
- Restart the extension/IDE
- File an issue with logs
Ready to go! 🚀
Open a .jl file, run Pluto: Create MCP Config, and start chatting with your AI assistant about your Pluto notebooks!