Architecture
System Overview
InstrMCP is designed as a bridge between Large Language Models and physics laboratory instruments. The architecture consists of several key components that work together to enable seamless interaction.
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Claude Desktop/ │◄──STDIO─┤ STDIO Proxy │◄───HTTP─┤ Jupyter MCP │
│ Claude Code/ │ │ (stdio_proxy.py)│ │ Server │
│ Codex │ └──────────────────┘ │ (mcp_server.py) │
└─────────────────┘ └─────────────────┘
│
├── QCodes Tools
├── Notebook Tools
├── Database Tools
└── MeasureIt Tools
Core Components
Jupyter MCP Server
The heart of InstrMCP is the FastMCP server that runs inside JupyterLab:
Location:
instrmcp/servers/jupyter_qcodes/mcp_server.pyFunction: Provides MCP tools and resources to connected clients
Integration: Runs as IPython extension within Jupyter kernel
Protocol: HTTP/SSE for communication
Key features: - Safe/unsafe mode switching - Optional feature management (database, MeasureIt) - Real-time instrument access - Notebook variable inspection - Active cell manipulation
STDIO Proxy
Bridges STDIO-based MCP clients to HTTP server:
Location:
instrmcp/tools/stdio_proxy.pyFunction: Converts STDIO MCP protocol to HTTP requests
Used by: Claude Desktop, Claude Code, Codex
Protocol: STDIO ↔ HTTP/SSE
The proxy handles: - Initialize/initialized handshake - Tool call forwarding - Response streaming - Session management
JupyterLab Extension
TypeScript extension for active cell bridging:
Location:
instrmcp/extensions/jupyterlab/Function: Provides real-time access to active cell
Protocol: Comm protocol (IPython kernel ↔ frontend)
Capabilities: - Get/update active cell content - Execute cells - Add/delete cells - Move cursor between cells - Patch cell content
QCodes Integration
Direct instrument access layer:
Location:
instrmcp/servers/jupyter_qcodes/tools.pyFunction: Read-only access to QCodes instruments
Features: - Parameter value reading - Instrument discovery - Hierarchical parameter access - Rate limiting and caching
Tool Categories
Notebook Tools (Safe)
Read-only notebook inspection:
list_variables- List notebook variables by typeget_variable_info- Detailed variable informationget_editing_cell- Current cell contentget_editing_cell_output- Last cell outputget_notebook_cells- Recent cell historymove_cursor- Change active cell selectionserver_status- Server state
QCodes Tools (Safe)
Instrument interaction:
instrument_info- Instrument details and parametersget_parameter_values- Read instrument parameters (batch supported)
Unsafe Tools
Cell manipulation (requires %mcp_unsafe):
execute_editing_cell- Run cell codeadd_new_cell- Insert new celldelete_editing_cell- Remove cellapply_patch- Partial cell editingdelete_cells_by_number- Bulk cell deletion
Database Tools (Optional)
QCodes database access (requires %mcp_option database):
list_experiments- List all experimentsget_dataset_info- Dataset metadata and parametersget_database_stats- Database health metrics
MeasureIt Tools (Optional)
Measurement status (requires %mcp_option measureit):
get_measureit_status- Check running sweeps
Resources
MCP resources provide context to LLMs:
QCodes Resources (Always available):
None. Use qcodes_instrument_info("*") to list instruments, then qcodes_instrument_info(name) for details.
Jupyter Resources (Always available):
notebook_cells- Complete notebook contents
Database Resources (Optional):
None. Use database_list_experiments and database_get_dataset_info for database metadata.
MeasureIt Resources (Optional):
measureit_sweep0d_template- Time-based monitoring patternsmeasureit_sweep1d_template- 1D sweep patternsmeasureit_sweep2d_template- 2D mapping patternsmeasureit_simulsweep_template- Simultaneous sweep patternsmeasureit_sweepqueue_template- Sequential workflow patternsmeasureit_common_patterns- Best practicesmeasureit_code_examples- Complete pattern library
Communication Flow
Client Initialization:
Claude Desktop starts launcher script
Launcher creates STDIO proxy
Proxy connects to HTTP server at
http://127.0.0.1:8123
MCP Handshake:
Client sends
initializerequestServer responds with capabilities and tool list
Client sends
initializednotification
Tool Invocation:
Client sends
tools/callrequestProxy forwards to HTTP server
Server executes tool in Jupyter kernel
Response returned through proxy to client
Active Cell Operations:
Tool requests active cell data
Python bridge sends comm message to frontend
TypeScript extension accesses JupyterLab API
Result sent back through comm protocol
Response delivered to MCP client
Safety Architecture
Safe Mode (Default):
Read-only instrument access
No code execution
No cell modification
Variable inspection only
Unsafe Mode (Explicit opt-in):
Code execution allowed
Cell manipulation enabled
Requires
%mcp_unsafemagic commandRequires server restart
Rate Limiting:
Instrument reads cached (5 seconds default)
Parameter batching supported
Prevents instrument overload
Error Handling:
All tool calls wrapped in try/except
Errors returned as JSON responses
No kernel crashes from tool failures
Extension Points
InstrMCP is designed to be extensible:
Custom Tools:
Add new tools in registrar modules:
registrars/qcodes_tools.py- QCodes-specific toolsregistrars/notebook_tools.py- Jupyter notebook toolsregistrars/database_tools.py- Database query toolsregistrars/measureit_tools.py- MeasureIt integration
Custom Resources:
Add resources in registrars/resources.py
Optional Features:
Create new optional features following the database/MeasureIt pattern:
Create registrar class
Add magic command handler
Implement tool/resource registration
Update
%mcp_optioncommand
Performance Considerations
Caching: Instrument parameters cached to reduce read frequency
Batch Operations: Multiple parameters read in single operation
Async Design: Non-blocking tool execution
Rate Limiting: Prevents excessive instrument queries
Lightweight Extension: Minimal JupyterLab frontend overhead