MCP server suite for quantum device physics laboratory's instrumentation control, enabling Large Language Models to interact directly with physics instruments and measurement systems through QCodes and JupyterLab.
Claude_1080P.mp4
- Full QCodes Integration: Built-in support for all QCodes instrument drivers
- Database Integration: Read-only access to QCodes databases with intelligent code generation
- MeasureIt Templates: Comprehensive measurement pattern library and code generation
- JupyterLab Native: Seamless integration with JupyterLab
- Dynamic Tool Creation: Create custom MCP tools at runtime using LLM-powered tool registration
- Safe mode: Read-only mode with optional unsafe execution
- CLI: Easy server management with
instrmcpcommand - MCP: Standard Model Context Protocol for LLM integration
- The MCP has been tested to work with Claude Desktop, Claude Code, and Codex CLI
From PyPI (Recommended):
pip install instrmcpThat's it! QCodes, JupyterLab, and all dependencies are automatically installed. The JupyterLab extension is automatically enabled (no Node.js or rebuild required).
From Source (For Development):
git clone https://github.com/caidish/instrMCP.git
cd instrMCP
pip install -e .
# Run setup to enable JupyterLab extension (only needed for editable install)
instrmcp-setup
# Set required environment variable for development
# For macOS/Linux:
export instrMCP_PATH="$(pwd)"
echo 'export instrMCP_PATH="'$(pwd)'"' >> ~/.zshrc # or ~/.bashrc
source ~/.zshrc
# For Windows (PowerShell):
$env:instrMCP_PATH = (Get-Location).Path
[System.Environment]::SetEnvironmentVariable('instrMCP_PATH', (Get-Location).Path, 'User')MeasureIt provides comprehensive measurement pattern templates for common physics experiments.
Installation:
pip install qmeasureImportant Notes:
- Import as
measureit(notqmeasure):import measureit - Python 3.8+ required
- For source installation or advanced configuration, see the MeasureIt GitHub repository
Enable in InstrMCP:
# In Jupyter notebook
%mcp_option add measureit
%mcp_restart# Start JupyterLab
jupyter labIn a Jupyter notebook cell:
# Load InstrMCP extension
%load_ext instrmcp.extensions
# Start MCP server
%mcp_start
# Check status
%mcp_status
# Enable unsafe mode (code execution)
%mcp_unsafe
# Enable optional features (restart required)
%mcp_option add measureit database
%mcp_restartinstrmcp config # Show configuration paths
instrmcp version # Show version
instrmcp metadata tokens # Count tokens in metadata descriptions
instrmcp --help # Show all commands- Architecture - Technical architecture, package structure, MCP tools and resources
- Troubleshooting - Common issues and solutions
- Development Guide - Development setup, testing, code quality, contributing
- Includes Threading Architecture & Qt Integration - How IPython kernel, Qt event loop, and MCP server thread interact; what cross-thread communication approaches work and don't work with MeasureIt
View current configuration:
instrmcp configInstrMCP provides seamless integration with Claude Desktop for AI-assisted laboratory instrumentation control.
- Run Automated Setup:
cd /path/to/your/instrMCP
./agentsetting/claudedesktopsetting/setup_claude.sh- Restart Claude Desktop completely and test with: "What MCP tools are available?"
Manual Setup Alternative:
# 1. Copy and edit configuration
cp agentsetting/claudedesktopsetting/claude_desktop_config.json ~/Library/Application\ Support/Claude/claude_desktop_config.json
# 2. Edit the copied file - replace placeholders with actual paths:
# /path/to/your/python3 → $(which python3)
# /path/to/your/instrMCP → $(pwd)See agentsetting/claudedesktopsetting/README.md for detailed setup instructions and troubleshooting.
Claude Code supports local MCP servers via STDIO. Use the provided launcher to connect:
# Add instrMCP as MCP Server
claude mcp add instrMCP --env instrMCP_PATH=$instrMCP_PATH \
--env PYTHONPATH=$instrMCP_PATH \
-- $instrMCP_PATH/venv/bin/python \
$instrMCP_PATH/agentsetting/claudedesktopsetting/claude_launcher.py
# Verify connection
/mcpPrerequisites:
- Ensure
instrMCP_PATHenvironment variable is set - Have a Jupyter server running with the instrMCP extension loaded
- MCP server started in Jupyter with
%mcp_start
Codex expects MCP servers over STDIO. Use the Codex launcher to proxy STDIO calls to your HTTP MCP server.
Configuration:
- command:
python - args:
["/path/to/your/instrMCP/agentsetting/codexsetting/codex_launcher.py"] - env:
JUPYTER_MCP_HOST=127.0.0.1JUPYTER_MCP_PORT=8123
Gemini CLI supports MCP servers over STDIO. Use the same launcher as Claude Desktop:
Configuration (~/.gemini/settings.json):
{
"mcpServers": {
"instrMCP": {
"command": "/path/to/your/python",
"args": ["/path/to/your/instrMCP/agentsetting/claudedesktopsetting/claude_launcher.py"],
"env": {
"instrMCP_PATH": "/path/to/your/instrMCP",
"PYTHONPATH": "/path/to/your/instrMCP"
},
"trust": true
}
}
}See agentsetting/geminisetting/README.md for detailed setup instructions.
The mcp_list_resources() tool helps LLMs discover and effectively use MCP resources:
Features:
- Comprehensive Resource Listing: All available MCP resources with URIs, descriptions, and use cases
- Context-Aware: Only shows resources based on enabled options (core, MeasureIt, database)
- Resources vs Tools Guidance: Educates LLMs on when to use read-only resources vs active tools
- Common Patterns: Examples like "Check available_instruments → Use qcodes_instrument_info"
- First-Use Recommendation: Use this tool FIRST to discover what context is available
Example Response:
{
"total_resources": 8,
"resources": [
{
"uri": "resource://available_instruments",
"name": "Available Instruments",
"use_when": "Need to know what instruments exist BEFORE calling qcodes_instrument_info",
"example": "Check this first to see instrument names..."
}
],
"guidance": {
"resources_vs_tools": {
"resources": "Provide READ-ONLY reference data, templates, and documentation",
"tools": "Perform ACTIVE operations like reading live values, executing code"
},
"when_to_use_resources": [
"Before using tools - check available_instruments first",
"For code templates - get MeasureIt examples",
"For configuration - check database_config"
]
}
}Cell modification tools now require user consent in unsafe mode:
Tools requiring consent:
notebook_update_editing_cell- Shows old/new content comparison before replacing entire cellnotebook_apply_patch- Shows visual diff dialog with exact changes
Features:
- Visual Diff Display: Red deletions, green additions, context lines
- Pattern Warning: Prominent alert if old_text not found in cell
- Change Statistics: Shows chars removed/added and delta
- Consent Workflow: "Decline" | "Allow" | "Always Allow" buttons
- Battle-Tested Diffing: Uses industry-standard
difflibrary (v8.0.2) from GitHub/GitLab
Example: When LLM calls notebook_apply_patch(old_text="x = 10", new_text="x = 20"), user sees:
- x = 10 ← Red background with strikethrough
+ x = 20 ← Green backgroundControl LLM context window consumption with line range selection:
Features:
- line_start / line_end parameters (default: lines 1-100)
- Automatic Bounds Clamping: Invalid ranges safely handled
- Truncation Metadata: Returns
total_lines,truncatedflag - Context Window Savings: Prevents large cells from consuming excessive tokens
Example:
# Get only first 50 lines of a large cell
get_editing_cell(line_start=1, line_end=50)
# Get lines 100-200 for focused analysis
get_editing_cell(line_start=100, line_end=200)Create custom MCP tools at runtime using LLM-powered tool registration:
# In Jupyter with instrMCP loaded in unsafe mode
# LLM can create tools dynamically using meta-tools:
dynamic_register_tool(
name="analyze_data",
source_code="def analyze_data(x): return x * 2",
capabilities=["cap:numpy", "cap:custom.analysis"], # Freeform labels
parameters=[{"name": "x", "type": "number", "description": "Input", "required": true}]
)Features:
- 6 Meta-Tools:
register,update,revoke,list,inspect,registry_stats - Consent UI: User approval required for tool registration/updates (shows full source code)
- Freeform Capability Labels: Tag tools with descriptive capabilities for discovery
- Persistent Registry: Tools saved to
~/.instrmcp/registry/and reloaded on server start - Audit Trail: All tool operations logged to
~/.instrmcp/audit/tool_audit.log - Auto JSON Correction: Optional LLM-powered JSON error fixing (opt-in via
%mcp_option auto_correct_json)
Capability Labels (v2.0.0): Capabilities are freeform documentation labels - NOT enforced security boundaries. Use any descriptive string:
- Suggested format:
cap:library.action(e.g.,cap:numpy.array,cap:qcodes.read) - Used for discovery, filtering, and transparency in consent UI
- No validation - flexibility for LLMs to describe tool dependencies
- Future: Enforcement layer planned for v3.0.0
See Dynamic Tools Quickstart for details.
- Unit tests: Comprehensive coverage of core functionality
- E2E tests: 166 Playwright tests (164 passed, 2 skipped) covering:
- Server lifecycle and mode switching
- Safe/unsafe/dangerous mode tools
- Security scanner pattern blocking
- Optional features (MeasureIt, Database, Dynamic Tools)
- Frontend widget and consent dialogs
- Zero linter errors on critical checks
- Code formatted with black
- CI/CD passing on all workflows
See tests/e2e/README.md for E2E test documentation.
- Capability Enforcement: Security boundaries based on capability taxonomy
- Support RedPitaya
- Support Raspberry Pi for outdated instruments
- Integrating lab wiki knowledge base for safety rails
- More LLM integration examples
MIT License - see LICENSE file.
We welcome contributions! See our Development Guide for details on:
- Setting up development environment
- Running tests
- Code quality standards
- Contribution guidelines