-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
The MATLAB MCP Server is a Python-based Model Context Protocol (MCP) server that connects AI agents (Claude, Cursor, Copilot, etc.) to MATLAB installations. It enables agents to execute MATLAB code, discover toolboxes, generate interactive plots, manage async jobs, and expose custom functions—all through the MCP protocol.
MATLAB 2020b and later. The MATLAB Engine API for Python must be installed separately from your MATLAB installation.
- macOS: Fully supported (Intel and Apple Silicon with known engine pooling limits)
- Windows: Fully supported (via Python 3.10-3.12)
- Linux: Supported but less commonly tested
- Docker: Supported; MATLAB installation must be mounted as a volume
Any agent supporting the Model Context Protocol (MCP):
- Claude Desktop
- Claude Code
- Cursor (with MCP support)
- GitHub Copilot (with MCP support)
- Custom agents built with MCP SDKs
See the project repository for licence details.
No. The server requires a local MATLAB installation with the Engine API configured. It connects to real MATLAB engines via the matlab.engine Python module.
Not currently. The server connects to locally-installed MATLAB only.
PyPI: pip install matlab-mcp-python (or matlab-mcp for older versions). See Installation for details.
macOS:
cd /Applications/MATLAB_R2024a.app/extern/engines/python
pip install .Windows:
cd "C:\Program Files\MATLAB\R2024a\extern\engines\python"
pip install .Adjust the path for your MATLAB version. See Installation for platform-specific details.
| Feature | stdio | SSE |
|---|---|---|
| Users | Single | Multiple |
| Setup | Simple | More complex |
| Network | Local only | Remote (with proxy) |
| Sessions | One (default) | Per-user |
| Best for | Local development, testing | Shared servers, CI/CD |
Default: stdio. Change in config.yaml under server.transport.
See Configuration for full details.
Yes, with SSE transport. Start the server on a remote machine (or in Docker) and connect via HTTP. Always put it behind an authenticating reverse proxy for production. Set require_proxy_auth: true in config.
graph LR
A["Agent 1<br/>(Claude)"]
B["Agent 2<br/>(Cursor)"]
P["Reverse Proxy<br/>(nginx + auth)"]
S["MATLAB MCP<br/>Server<br/>(SSE)"]
M["MATLAB<br/>Engines"]
A -->|HTTP| P
B -->|HTTP| P
P -->|Trusted<br/>localhost| S
S -->|Engine API| M
See Configuration. The server reads config.yaml by default. You can also override settings with environment variables prefixed with MATLAB_MCP_, e.g.:
export MATLAB_MCP_POOL_MIN_ENGINES=2
export MATLAB_MCP_POOL_MAX_ENGINES=8
matlab-mcp-serverdocker-compose up -dThe docker-compose.yml mounts your MATLAB installation. See Installation for volume mounting details.
Create/edit ~/.config/claude.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"matlab": {
"command": "matlab-mcp-server",
"args": ["--transport", "stdio"]
}
}
}Restart Claude Desktop. See Installation for other agents.
Personal use → 1–2 engines
Small team (2–5) → 2–4 engines
Larger team → Scale based on concurrent users
macOS limit → ~4 engines (platform limitation)
Each engine consumes ~500MB–2GB of memory depending on loaded toolboxes.
Edit config.yaml:
pool:
min_engines: 1 # Always keep 1 warm
max_engines: 8 # Scale up to 8 under load
proactive_warmup_threshold: 0.8 # Start new engine at 80% utilization
scale_down_idle_timeout: 900 # Stop idle engines after 15 min
health_check_interval: 30 # Check engine health every 30sSee Configuration for all tuning options.
Requests queue (FIFO). If the pool hasn't reached max_engines, a new engine starts automatically. Requests wait in queue with a configurable queue_max_size (default 50).
- Lower
min_enginesandmax_engines - Reduce
max_sessions(SSE only) - Use
workspace_isolation: falseto skip fullclear allbetween sessions (less safe) - Disable toolboxes you don't need via
toolboxes.mode: include+ whitelist
- Increase
min_enginesto avoid startup latency - Lower
sync_timeoutif you're OK with more async jobs - Disable code checking:
execution.check_code_before_run: false(less safe) - Increase
startup_commandstime allowance if MATLAB takes time to load
Code completing within sync_timeout (default 30s) returns immediately. Longer code is auto-promoted to async:
sequenceDiagram
Agent->>Server: execute_code("long_task()")
Server->>MATLAB: eval(background=True)
par Wait for result
Server->>Server: Monitor for 30s
and
MATLAB->>MATLAB: Run long_task()
end
Note over Server: 30s timeout → async
Server->>Agent: {status: "running", job_id: "abc123"}
Agent->>Server: get_job_status("abc123")
Server->>Agent: {status: "running", progress: 45%}
Agent->>Server: get_job_result("abc123")
Server->>Agent: {status: "completed", output: "..."}
See Async Jobs for details on mcp_progress() and job management tools.
Use the mcp_progress() helper injected into the workspace:
for i = 1:1000000
do_work(i);
if mod(i, 100000) == 0
mcp_progress(__mcp_job_id__, i/1000000 * 100, sprintf('Trial %d/1000000', i));
end
endThe agent polls get_job_status() to see the progress message and percentage.
Yes. Define them in custom_tools.yaml:
tools:
- name: analyze_signal
function: signal.analysis.fft_peaks
description: Find dominant frequencies in a signal
parameters:
signal:
type: array
description: Input signal vector
n_peaks:
type: int
default: 5
description: Number of peaks to returnSee Custom Tools for full YAML format and type system.
Use the server in SSE mode:
- Start the server as a background service
- Point your CI/CD pipeline to the HTTP endpoint
- Submit jobs and poll for results
Example (pseudo-code):
import requests
response = requests.post(
"http://localhost:8765/rpc",
json={"jsonrpc": "2.0", "method": "execute_code", "params": {"code": "test"}}
)
job_id = response.json()["result"]["job_id"]
# Poll until done
while True:
status = requests.post(
"http://localhost:8765/rpc",
json={"jsonrpc": "2.0", "method": "get_job_status", "params": {"job_id": job_id}}
)
if status.json()["result"]["status"] == "completed":
break
time.sleep(1)Yes. Run the server in a Docker container with MATLAB mounted, then submit jobs via HTTP (SSE) or pipe commands via stdin (stdio). See Installation for Docker setup.
The server is framework-agnostic. It works with any tool that can speak MCP:
- Claude SDK (Python, TypeScript)
- Cursor (IDE integration)
- LangChain (with MCP adapter)
- Custom applications (via MCP client libraries)
-
Upload files: Use
upload_datatool (base64-encoded, max size configurable, default 100MB) -
Download results: Use
read_dataorread_imagetools to retrieve results - Avoid inline: Don't try to return multi-GB results inline; save to disk and read back
% Instead of returning huge matrix:
large_result = randn(100000, 100000);
save(fullfile(__mcp_temp_dir__, 'result.mat'), 'large_result');
disp('Saved to result.mat');
% Agent then calls:
% read_data('result.mat', 'raw')Yes, via the MCP client libraries:
from mcp_client import MCPClient
async with MCPClient("stdio", "matlab-mcp-server") as client:
result = await client.call_tool("execute_code", code="x = 1:10; plot(x, x.^2)")
print(result)For stdio: Local only, no network risk.
For SSE: Always use an authenticating reverse proxy:
- Put nginx/Apache in front with basic auth, OAuth, SAML, etc.
- Set
require_proxy_auth: truein config - Bind to
127.0.0.1if the proxy is on the same host - Use HTTPS/TLS in production
# Example nginx proxy
location / {
auth_basic "MATLAB MCP";
auth_basic_user_file /etc/nginx/htpasswd;
proxy_pass http://localhost:8765;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}No. The default blocklist prevents:
-
system(),unix(),dos() -
!shell escape -
eval(),feval(),evalc(),evalin(),assignin() -
perl(),python()
You can customize the blocklist in config.yaml:
security:
blocked_functions_enabled: true
blocked_functions:
- system
- eval
- my_dangerous_functionSee Security for details.
Yes. When workspace_isolation: true (default in SSE):
clear all
clear global
clear functions
fclose all
restoredefaultpathThis is run between sessions (but not between jobs in the same session). Each session gets its own temp directory.
security:
max_upload_size_mb: 100 # Default; set lower if neededEnable workspace_isolation and set an appropriate session_timeout:
sessions:
session_timeout: 3600 # 1 hour
workspace:
isolation: trueEach session starts fresh after the timeout.
- Verify MATLAB Engine API is installed:
python -c "import matlab.engine; print('OK')" - Check logs:
cat logs/server.log(path from config) - Ensure
config.yamlis valid YAML - Check environment variable overrides:
echo $MATLAB_MCP_*
-
macOS: You're hitting the ~4-engine limit. Set
max_engines: 4 -
Memory: Each engine uses ~500MB–2GB. Check
ps aux | grep MATLAB - License: Verify you have enough MATLAB licenses for your pool size
-
Health checks failing: Increase
health_check_interval(default 30s) to reduce noise
- Increase
sync_timeoutif jobs are auto-promoting unexpectedly - Check
get_job_status()for detailed state - Use
cancel_job()to forcefully stop stuck jobs - Review MATLAB output for infinite loops or deadlocks
Supported types: line, scatter, bar, histogram, surface, image. Custom graphics may fall back to static PNG. Check config:
output:
convert_figures_to_plotly: true
save_plot_png: trueTemporarily disable blocking (dev/testing only):
security:
blocked_functions_enabled: falseOr whitelist specific functions by removing them from the blocklist.
Adjust output length limits in config.yaml:
output:
max_text_length: 10000 # Increase from default 1000
save_truncated_results: true
result_dir: /path/to/results- Check reverse proxy logs
- Verify
require_proxy_authis set if using auth - Increase
queue_timeoutin config if requests take long - Use
--transport sse --host 0.0.0.0 --port 8765for explicit binding
pip install -e ".[dev]"
pytest tests/ -vTests use a mock MATLAB engine—no MATLAB installation needed.
- Implement in
src/matlab_mcp/tools/ - Register in
server.pywith@mcp.tool - Add tests in
tests/test_tools_*.py
See the existing tools for structure.
Open an issue or PR on GitHub. Contributions welcome!
See Architecture for system diagrams, component details, and data flow.