-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
The MATLAB MCP Server is a Model Context Protocol (MCP) server that enables AI agents (Claude, Cursor, etc.) to execute MATLAB code, discover toolboxes, manage long-running jobs, and integrate with custom MATLAB libraries. It provides a secure, multi-user capable bridge between AI agents and MATLAB.
MATLAB R2022b and later. The MATLAB Engine API for Python must be installed from your MATLAB distribution.
Check the LICENSE file in the repository. The project is open-source and welcomes contributions.
-
Windows (10, 11) via
install.bator PyPI - macOS (Intel/Apple Silicon) via PyPI or Docker
- Linux via PyPI or Docker
Docker images are provided for simplified deployment without a local MATLAB installation (MATLAB must be mounted as a volume).
No. The server requires a local MATLAB installation with the Engine API available. It communicates with real MATLAB engines; there is no fallback simulator.
Any agent implementing the Model Context Protocol:
- Claude Desktop (with MCP plugin)
- Claude Code
- Cursor
- Custom agents built with MCP SDKs (Python, TypeScript, etc.)
On Windows:
cd "C:\Program Files\MATLAB\R2024a\extern\engines\python"
pip install .On macOS:
cd /Applications/MATLAB_R2024a.app/extern/engines/python
pip install .On Linux:
cd /usr/local/MATLAB/R2024a/extern/engines/python
pip install .Adjust the path for your MATLAB version. See Installation for details.
From PyPI:
pip install matlab-mcp-python
matlab-mcp --config config.yamlFrom source:
git clone https://github.com/HanSur94/matlab-mcp-server-python
cd matlab-mcp-server-python
pip install -e .
python -m matlab_mcp.server --config config.yamlDocker:
docker-compose upSee Installation for complete setup instructions including Docker.
graph LR
subgraph stdio["stdio (Single User)"]
Agent1["Agent"]
Server1["MCP Server"]
Agent1 -->|spawn process| Server1
Agent1 <-->|stdin/stdout| Server1
end
subgraph sse["SSE (Multi User)"]
Agent2["Agent 1"]
Agent3["Agent 2"]
RProxy["Reverse Proxy<br/>+ Auth"]
Server2["MCP Server"]
Agent2 -->|HTTP| RProxy
Agent3 -->|HTTP| RProxy
RProxy -->|localhost| Server2
Server2 -->|Server Sent<br/>Events| RProxy
end
- stdio: Single-user, no network setup. Agent launches the server process directly.
- SSE: Multi-user, requires HTTP setup. Server runs continuously; agents connect via HTTP. Always put behind an authenticating reverse proxy.
For personal use or local agent testing, choose stdio. For team deployments, choose SSE with a reverse proxy.
Yes, with SSE transport. Place the server behind a reverse proxy (nginx, Caddy) with authentication. Never expose it directly to the internet without auth. See Security and Installation.
Edit config.yaml and pass it to the server:
matlab-mcp --config /path/to/config.yamlConfiguration covers engine pool sizing, timeouts, security, output formatting, monitoring, and more. See Configuration for full reference.
Custom tools let you expose your own MATLAB functions as first-class MCP tools. Define them in custom_tools.yaml:
tools:
- name: "analyze_signal"
matlab_function: "signal_analysis.process"
description: "Analyze frequency content of a signal"
parameters:
signal_data:
type: "array"
description: "Input signal"
sample_rate:
type: "number"
description: "Sampling rate in Hz"
returns:
type: "object"
description: "Frequency spectrum"See Custom Tools for full syntax and examples.
graph LR
A["1-2 engines"] --> B["Personal use<br/>single agent"]
C["2-4 engines"] --> D["Small team<br/>2-5 concurrent users"]
E["4-8+ engines"] --> F["Larger team<br/>10+ concurrent users"]
G["macOS limit"] --> H["~4 engines max<br/>per Python process"]
style H fill:#ffcccc
- Personal: 1-2 engines
- Small team (2-5 users): 2-4 engines
- Larger deployments: Scale based on concurrent usage, respecting MATLAB license limits
- macOS: Stability issues above 4 engines due to MATLAB Engine API limitations
Typically 500MB–2GB per engine depending on:
- MATLAB version
- Loaded toolboxes (Simulink, Deep Learning, etc. add overhead)
- User code and data
A 4-engine pool might consume 2–8GB total.
Requests queue (configurable via queue_max_size, default 50). If the pool hasn't reached max_engines, new engines are started proactively up to the limit. Requests are served FIFO as engines become available.
-
Use async execution: Code exceeding
sync_timeout(default 30s) is automatically promoted. No extra configuration needed. -
Report progress: Call
mcp_progress(__mcp_job_id__, percentage, 'message')to send progress updates to the agent. -
Increase timeouts if needed:
max_execution_timecontrols the absolute limit (default 24 hours).
See Async Jobs for examples.
Yes, in config.yaml:
pool:
min_engines: 2 # Always keep running
max_engines: 10 # Absolute limit
scale_down_idle_timeout: 900 # Seconds before idle engine stops
proactive_warmup_threshold: 0.8 # Start new engine when utilization > 80%
health_check_interval: 60 # Health check frequency (seconds)See Configuration for all pool settings.
Add to claude_desktop_config.json:
{
"mcpServers": {
"matlab": {
"command": "python",
"args": ["-m", "matlab_mcp.server", "--config", "/path/to/config.yaml"]
}
}
}Restart Claude Desktop. MATLAB tools appear in the tool palette.
Similar to Claude Desktop. See Installation for details. Cursor supports MCP natively via similar config files.
Yes, if your GitHub runner has MATLAB installed:
- name: Run MATLAB via MCP
run: |
pip install matlab-mcp-python
matlab-mcp --config config.yaml &
# Connect your agent to the running serverHowever, GitHub-hosted runners do not include MATLAB. You would need a self-hosted runner with MATLAB pre-installed.
The docker-compose.yml provides a foundation. For Kubernetes:
- Build the Docker image with MATLAB mounted or pre-installed
- Create a Kubernetes Deployment
- Mount MATLAB as a hostPath or NFS volume
- Expose via a Service and Ingress with authentication
See Installation for Docker setup details before advancing to Kubernetes.
The server exposes:
-
HTTP
/healthendpoint — health status (healthy/degraded/unhealthy) -
HTTP
/metricsendpoint — live metrics snapshot (JSON) -
Web dashboard at
http://localhost:8766/dashboard— interactive charts, event logs
Enable monitoring in config.yaml:
monitoring:
enabled: true
dashboard_enabled: true
http_port: 8766 # Separate from main server portQuery tools via MCP: get_server_health, get_server_metrics, get_error_log.
See Architecture for the monitoring subsystem diagram.
You can call the server from within your CI pipeline. Use the SSE transport and hit the HTTP endpoints to fetch results:
import requests
import base64
# Upload a data file
with open("data.csv", "rb") as f:
content = base64.b64encode(f.read()).decode()
# Call via MCP (if agent integration) or direct HTTP if exposedSee Examples for integration patterns.
graph TB
Agent["AI Agent<br/>(Claude, Cursor, etc.)"]
MCP["MCP Server<br/>(FastMCP)"]
subgraph Tools["Tool Handlers"]
Core["execute_code<br/>check_code"]
Discovery["list_toolboxes<br/>list_functions"]
Files["upload_data<br/>read_script<br/>read_image"]
Jobs["get_job_status<br/>cancel_job"]
Custom["Custom Tools<br/>(user-defined)"]
end
Executor["JobExecutor"]
Tracker["JobTracker<br/>(async jobs)"]
Pool["EnginePoolManager<br/>(elastic scaling)"]
subgraph Engines["MATLAB Engines"]
E1["Engine 1"]
E2["Engine 2"]
EN["Engine N"]
end
Security["SecurityValidator<br/>(blocklist)"]
Formatter["ResultFormatter<br/>(Plotly convert)"]
Sessions["SessionManager<br/>(isolation)"]
Agent -->|MCP call| MCP
MCP --> Tools
Tools --> Security
Security --> Executor
Executor --> Tracker
Executor --> Pool
Pool --> Engines
Executor --> Formatter
Executor --> Sessions
Formatter -->|response| Agent
style Agent fill:#e1f5ff
style MCP fill:#fff3e0
style Engines fill:#f3e5f5
style Security fill:#ffebee
The architecture flows: Agent → MCP Server → Tool Handlers → Security Validator → JobExecutor → Engine Pool → MATLAB Engines → Result Formatter → Agent.
See Architecture for detailed component descriptions.
Symptoms: Requests fail with "Engine failed to start" message.
Causes:
- MATLAB not installed or MATLAB_ROOT not found
- MATLAB Engine API for Python not installed
- MATLAB license unavailable or locked
Solutions:
- Verify MATLAB installation:
matlab -r "quit" - Verify Engine API:
python -c "import matlab.engine; print('OK')" - Check MATLAB_ROOT environment variable
- Ensure MATLAB license is valid and available
See Troubleshooting for detailed verification steps.
Symptom: execute_code returns "blocked function" error for code that should be allowed.
Cause: The security validator may have a false positive if the blocklist is too strict.
Solution: Review the blocklist in your config.yaml. If you trust the code source, you can disable specific functions:
security:
blocked_functions_enabled: true
blocked_functions:
- "system"
- "unix"
- "dos"
# Remove "eval" if you need it for your use caseThe validator strips string literals and comments, so msg = "system() call" will NOT be blocked.
See Security for the smart scanning logic.
Symptom: A job never completes; get_job_status always shows "running".
Causes:
- Code has an infinite loop
- Code is waiting for user input (dialog,
input()) - Long-running code without progress reporting
Solutions:
-
Cancel the job:
cancel_job(job_id)stops the execution -
Increase timeouts: Adjust
max_execution_timein config if the job legitimately takes hours -
Add progress reporting: Use
mcp_progress()to confirm the job is progressing
See Async Jobs for progress reporting syntax.
Symptom: upload_data or read_image rejects a filename you believe is safe.
Cause: The security validator sanitizes filenames to prevent ../../etc/passwd style attacks.
Solution: Use simple, alphanumeric filenames with ., _, -:
- ✅
data_v1.csv,plot.png,my-file.m - ❌
../data.csv,file@2024.txt,folder/data.csv
Symptom: execute_code with a plot returns a static PNG instead of interactive Plotly JSON.
Causes:
- Unsupported plot type (custom graphics, uicontrols, etc.)
- Missing
mcp_extract_props.mMATLAB helper - Large plot with too many data points
Solution:
- Check that
plotly_conversion: truein config - Ensure MATLAB helpers are in the search path (automatic if installed from PyPI)
- Reduce plot complexity or switch to a supported plot type (line, scatter, bar, surface, histogram)
See Troubleshooting for Plotly debugging tips.
Symptom: On macOS, running > 4 concurrent MATLAB engines causes crashes or file descriptor errors.
Cause: MATLAB Engine API on macOS has known stability limits with multiple engines in a single Python process.
Solution: Limit max_engines to 4 or fewer in config.yaml:
pool:
max_engines: 4This is not a limitation of the MCP server itself, but of the underlying MATLAB Engine API. See Troubleshooting for workarounds.
pip install -e ".[dev]"
pytest tests/ -v
pytest tests/ --cov=src/matlab_mcp # With coverageTests use a mock MATLAB engine; no MATLAB installation needed. CI automatically runs tests on Python 3.10, 3.11, 3.12.
-
Implement the handler in
src/matlab_mcp/tools/(or extend an existing module):async def my_new_tool_impl(param: str) -> dict: """Docstring for MCP tool.""" return {"result": "value"}
-
Register in server.py:
@mcp.tool() async def my_new_tool(param: str) -> dict: return await my_new_tool_impl(param, ...)
-
Add tests in
tests/test_tools_*.py:@pytest.mark.asyncio async def test_my_new_tool(): result = await my_new_tool_impl("test") assert result["result"] == "value"
-
Document in MCP-Tools-Reference.
# Run with debug logging
MATLAB_MCP_LOG_LEVEL=debug python -m matlab_mcp.server --config config.yaml
# Or set in config.yaml
server:
log_level: debug
log_file: ./logs/debug.logLog files are written to log_file path. Watch the logs while the agent runs code to diagnose issues.
Yes! The project welcomes pull requests and issues on GitHub.
Before submitting:
- Run
pytestto ensure tests pass - Run
ruff checkfor linting - Add tests for new features
- Update MCP-Tools-Reference if adding tools
For more details, see:
- Installation — step-by-step setup
- Configuration — all config options
- MCP-Tools-Reference — tool reference
- Custom Tools — extend with your functions
- Async Jobs — long-running code patterns
- Security — security architecture
- Architecture — system design
- Troubleshooting — issue solutions