-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
The MATLAB MCP Server is a Python application that exposes MATLAB's computational engine to AI agents via the Model Context Protocol (MCP). It allows agents like Claude, Cursor, and GitHub Copilot to execute MATLAB code, discover toolboxes, generate interactive plots, and manage long-running jobs—all through a standardized protocol.
MATLAB R2020b and later. You must have a valid MATLAB installation with the Engine API for Python installed separately. The server connects to real MATLAB engines, not a simulator or online version.
Any agent supporting the Model Context Protocol: Claude Desktop, Claude Code, Cursor, GitHub Copilot (with MCP support), and custom agents built with the official MCP SDKs (Python, JavaScript, TypeScript, Go, Rust).
The project follows the license specified in the repository. Check the LICENSE file for details.
No. The server requires a locally-installed MATLAB with the Engine API. It does not work with MATLAB Online or cloud-only installations.
Yes:
pip install matlab-mcp-pythonYou must still install the MATLAB Engine API separately from your MATLAB installation directory. See Installation for platform-specific instructions.
Yes. The project includes a Dockerfile and docker-compose.yml. The Docker image does not include MATLAB—you must mount your own MATLAB installation as a volume. See Installation for Docker deployment steps.
cd /Applications/MATLAB_R2024a.app/extern/engines/python
pip install .Adjust the MATLAB version in the path. See Installation for Windows and Linux instructions.
Open Command Prompt (not PowerShell) and run:
cd C:\Program Files\MATLAB\R2024a\extern\engines\python
pip install .Alternatively, use the provided install.bat script which handles Python detection and virtual environment setup automatically.
cd /usr/local/MATLAB/R2024a/extern/engines/python
pip install .Path varies by MATLAB installation. Contact your system administrator if unsure.
- stdio: Standard input/output. Single user, no network. The agent launches the server process directly. Simplest setup.
- SSE: Server-Sent Events. Multi-user, over HTTP. Multiple agents can connect simultaneously. Requires a reverse proxy with authentication for production use.
Choose stdio for personal use or testing. Choose SSE for shared team servers.
See Configuration for setup details.
Yes, using SSE transport. Deploy the server on a remote machine and connect via HTTP. Always place it behind an authenticating reverse proxy (nginx, Caddy, Traefik) in production. Set security.require_proxy_auth: true in config.
See Security for hardening recommendations.
Add the server to your claude_desktop_config.json:
{
"mcpServers": {
"matlab": {
"command": "python",
"args": ["-m", "matlab_mcp"]
}
}
}See Installation for platform-specific config locations.
Similar to Claude Desktop. Add to Cursor's MCP configuration:
{
"mcpServers": {
"matlab": {
"command": "python",
"args": ["-m", "matlab_mcp"]
}
}
}Path varies by OS. Check Cursor's documentation for config file location.
- Personal use: 1–2 engines
- Small team (2–5 users): 2–4 engines
- Larger team: 4–10+ engines, depending on concurrency and your MATLAB license limit
Each engine is an independent MATLAB process consuming ~500MB–2GB of memory. On macOS, stability issues appear beyond ~4 engines in a single Python process.
No, but it will consume additional system memory. Each engine is a separate MATLAB process with its own memory footprint. Total memory = (base + engine count × per-engine overhead).
Monitor system resources and adjust max_engines if needed.
- Requests queue internally (up to
queue_max_size, default 50 requests) - If
current_engines < max_engines, a new engine is started proactively when pool utilization exceedsproactive_warmup_threshold(80% default) - Queued requests are served FIFO as engines become available
If the queue fills, subsequent requests are rejected with an error.
Typically 10–30 seconds, depending on your MATLAB installation and loaded toolboxes. Configure pool.engine_start_timeout (default 120s) to control the maximum wait time.
Yes:
-
execution.sync_timeout(30s default): Code finishing faster returns immediately. Longer code auto-promotes to async. -
output.plotly_conversion: Disable to skip Plotly conversion overhead (still generates static PNG). -
code_checker.auto_check_before_execute: Disable to skip linting overhead.
See Configuration for all tuning options.
Set server.log_level: debug in config or via environment variable:
MATLAB_MCP_SERVER_LOG_LEVEL=debug matlab-mcpLogs go to server.log_file (default ./logs/server.log). See Configuration for details.
Define them in custom_tools.yaml:
tools:
- name: "signal_analysis"
function: "analyze_signal"
description: "Analyze FFT and power spectrum"
parameters:
signal:
type: "array"
description: "Input signal"
sampling_rate:
type: "number"
description: "Sampling rate in Hz"
returns:
description: "Frequency and power arrays"The server automatically discovers and registers these as first-class MCP tools. See Custom Tools for a complete example.
Use the stdio transport and invoke the server from your CI script:
python -m matlab_mcp << 'EOF'
execute_code("x = randn(1000,1); mean(x)")
EOFOr use SSE transport with HTTP requests to a running server instance.
Yes. The server is a Python application, and you can import its components directly:
from matlab_mcp.jobs.executor import JobExecutor
result = await executor.execute(session_id="s1", code="2+2")See Architecture for the internal API structure.
Use the monitoring tools (if monitoring.enabled: true):
-
get_server_health— Overall health status, issues, uptime -
get_server_metrics— Pool utilization, jobs, sessions, errors, system stats -
HTTP dashboard — Browse to
http://localhost:8766for live charts and event logs
See MCP Tools Reference for details.
Yes. Use upload_data to write files to the session temp directory, then read_data or read_image to retrieve them. Example:
% In MATLAB code
save('results.mat', 'output_variable');Then retrieve via the agent:
read_data("results.mat", format="raw")
Code execution is hybrid:
- Submitted code starts in the background
- Server waits up to
sync_timeout(30s default) for completion - If done: returns result immediately (status="completed")
- If not done: promotes to async background job (status="pending"), returns
job_id
The agent polls get_job_status for progress and get_job_result for the final result.
See Async Jobs for detailed examples.
Use the mcp_progress() MATLAB helper in your code:
for trial = 1:1000000
% ... computation ...
if mod(trial, 10000) == 0
mcp_progress(__mcp_job_id__, trial/1000000*100, sprintf('Trial %d', trial));
end
endProgress is written to a temporary file and polled by agents via get_job_status. See Async Jobs for more examples.
Yes, use cancel_job(job_id). This terminates the background MATLAB execution and marks the job as cancelled.
Completed job results are retained for sessions.job_retention_seconds (default 86400 = 24 hours). Older jobs are automatically pruned. Session temp files are deleted when the session expires or is explicitly destroyed.
Yes! MATLAB figures are automatically converted to Plotly JSON, which renders as interactive charts in capable clients (Claude Code, Cursor). A static PNG is also generated as a fallback.
Disable Plotly conversion via output.plotly_conversion: false if needed.
- Line plots
- Scatter plots
- Bar charts
- Histograms
- 3D surfaces
- Image/heatmaps
- Subplots (multi-axes)
Complex custom graphics fall back to static PNG. See Examples for sample plots.
Yes. Set output.static_image_format to png, jpg, or svg. Adjust quality with output.static_image_dpi (default 150).
Plotly conversion is disabled for figures with > 10,000 data points (configurable output.large_result_threshold). Large plots fall back to static PNG or are truncated.
Write: Use upload_data to write files to the session temp directory.
Read:
-
read_script—.mMATLAB scripts (text) -
read_data—.mat,.csv,.json,.txt,.xlsxfiles -
read_image—.png,.jpg,.gifimages (inline rendering)
All files are isolated to the session's temp directory for security.
Default 100MB. Configure via security.max_upload_size_mb. Filenames are sanitized against path traversal attacks.
Use list_files to list all files in the current session's temp directory.
When the session expires (after sessions.session_timeout seconds of inactivity, default 1 hour) or when explicitly destroyed. Set execution.temp_cleanup_on_disconnect: true (default) to auto-cleanup.
For SSE transport:
- Always use HTTPS (via reverse proxy)
- Always require authentication (via reverse proxy)
- Set
security.require_proxy_auth: truein config - Bind to
127.0.0.1if the proxy is on the same machine
The server logs a warning at startup if SSE is enabled without require_proxy_auth: true.
See Security for hardening recommendations by deployment scenario.
| Function | Risk |
|---|---|
system(), unix(), dos()
|
Execute OS commands |
! |
Shell escape operator |
eval(), feval(), evalc(), evalin()
|
Execute code as string |
assignin() |
Modify caller/base workspace |
perl(), python()
|
Execute external scripts |
Blocked function names inside strings or comments are safe and won't trigger the blocklist. See Security for customization.
Yes:
security:
blocked_functions_enabled: true
blocked_functions:
- "system"
- "eval"
- "web" # Add or remove as neededSet blocked_functions_enabled: false to disable blocking entirely (not recommended for production).
Yes. When execution.workspace_isolation: true (default), each session gets a fresh MATLAB workspace:
clear all; clear global; clear functions; fclose all; restoredefaultpath;This prevents one user's variables or file handles from leaking to another.
Files are isolated to session-specific temp directories. Filenames are sanitized against path traversal (../../etc/passwd is rejected).
Check:
- MATLAB Engine API is installed:
python -c "import matlab.engine; print(matlab.engine.find_matlab())"should return available engines - MATLAB installation is valid:
matlab -nodesktop -batch "version"should run - Config file is valid YAML and paths are correct
- Python version is 3.10+ (check
python --version)
Enable debug logging to see detailed errors:
MATLAB_MCP_SERVER_LOG_LEVEL=debug matlab-mcpSee Troubleshooting for more help.
On macOS, check the engine start timeout:
pool:
engine_start_timeout: 180 # Increase from default 120Large MATLAB installations or older hardware may need more time to initialize.
Verify the function name matches exactly (case-sensitive) and is not inside a comment or string:
% This is SAFE:
disp('The system is working') % "system" is in a string
% system('cmd') % "system" is in a comment
% This is BLOCKED:
system('cmd') % Actual function callTo disable blocking temporarily for testing:
security:
blocked_functions_enabled: falseTry cancel_job(job_id) to terminate it. If it still doesn't clear, restart the server:
# Graceful shutdown (waits for jobs to finish)
kill -TERM <server_pid>
# Forced shutdown (immediate, may lose results)
kill -9 <server_pid>Check:
-
output.plotly_conversion: trueis set (default) - The plot is a supported type (see Plotting section above)
- The agent/UI supports Plotly JSON rendering
If stuck, disable Plotly conversion to use static PNG fallback:
output:
plotly_conversion: falseMemory is proportional to the number of active engines. Reduce pool.max_engines or enable pool.scale_down_idle_timeout to automatically shut down unused engines after idleness.
Check individual engine memory with ps aux | grep matlab.
graph TB
Agent["AI Agent<br/>(Claude, Cursor, etc.)"]
Transport["MCP Transport<br/>(stdio or SSE)"]
Server["FastMCP Server<br/>(fastmcp)"]
Tracker["Job Tracker<br/>(job history)"]
Executor["Job Executor<br/>(orchestration)"]
Pool["Engine Pool Manager<br/>(lifecycle & queueing)"]
EngineA["Engine A<br/>(MATLAB process)"]
EngineB["Engine B<br/>(MATLAB process)"]
Security["Security Validator<br/>(blocklist check)"]
Formatter["Result Formatter<br/>(output shaping)"]
Monitoring["Monitoring System<br/>(optional metrics)"]
Agent -->|MCP Protocol| Transport
Transport --> Server
Server --> Executor
Server --> Pool
Server --> Tracker
Server --> Security
Server --> Formatter
Server --> Monitoring
Executor -->|acquire/release| Pool
Pool --> EngineA
Pool --> EngineB
Tracker -->|create/query| Executor
Security -->|validate| Executor
Formatter -->|shape| Executor
Monitoring -->|collect metrics| Executor
See Architecture for detailed data flows.
- Agent submits code via
execute_codetool - Security validator checks for blocked functions
- Job is created and tracked
- Engine is acquired from pool
- Job context (ID, temp dir) is injected into MATLAB workspace
- Code executes in background
- If done within
sync_timeout: return result immediately - If timeout: promote to async, return
job_id
See Async Jobs for timeout and promotion details.
pip install -e ".[dev]"
pytest tests/ -vTests use a mock MATLAB engine (MockMatlabEngine)—no real MATLAB installation needed.
- Implement in
src/matlab_mcp/tools/ - Register in
src/matlab_mcp/server.pywith@mcp.tool - Add tests in
tests/ - Update MCP Tools Reference wiki page
Open an issue on GitHub with:
- Your MATLAB version
- Python version
- Exact error message and traceback
- Minimal code to reproduce
Yes! PRs are welcome. Please:
- Add tests for new functionality
- Run
pytestandruff checklocally - Update relevant wiki pages
- Follow existing code style
- Installation guide: Installation
- Configuration reference: Configuration
- All 20 built-in tools: MCP Tools Reference
- Custom tools (YAML): Custom Tools
- Code examples: Examples
- Async job details: Async Jobs
- System architecture: Architecture
- Security hardening: Security
- Troubleshooting: Troubleshooting
- GitHub repository: https://github.com/HanSur94/matlab-mcp-server-python