-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
Symptom: Engine start timeout, matlab.engine not found, or Failed to start MATLAB engine
Solutions:
-
Verify MATLAB Engine API is installed:
python -c "import matlab.engine; print('OK')"If this fails, install the Engine API:
cd /Applications/MATLAB_R2024a.app/extern/engines/python # macOS # cd "C:\Program Files\MATLAB\R2024a\extern\engines\python" # Windows pip install .
-
Check MATLAB version: Must be R2022b or later.
-
Verify MATLAB is on PATH or set
matlab_rootexplicitly:pool: matlab_root: "/Applications/MATLAB_R2024a.app" # macOS # matlab_root: "C:\\Program Files\\MATLAB\\R2024a" # Windows
-
Increase engine start timeout if MATLAB is slow to initialize:
pool: engine_start_timeout: 240 # increase from default 120 seconds
-
Check system resources: Ensure sufficient disk space and RAM. MATLAB engine startup requires ~500MB per instance.
-
Verify no MATLAB processes are hung: Kill stray MATLAB processes:
killall matlab # macOS/Linux taskkill /IM MATLAB.exe # Windows
Symptom: Pool fails to initialize, engines won't scale up, or queue_max_size exceeded
Solutions:
-
Check min/max engine configuration:
pool: min_engines: 2 # server starts this many at launch max_engines: 10 # capped at 4 on macOS by default
On macOS, MATLAB has a hard limit of ~4 concurrent engine instances. Set accordingly:
pool: max_engines: 4 # macOS limit
-
Increase queue size if jobs are rejected during high demand:
pool: queue_max_size: 100 # increase from default 50
-
Check proactive warmup threshold:
pool: proactive_warmup_threshold: 0.8 # triggers new engine when pool >80% busy
-
Monitor pool health: Call
get_pool_statusto see available/busy/max engines. If all engines are stuck "busy", check for hung jobs. -
Scale down idle engines:
pool: scale_down_idle_timeout: 900 # idle engines removed after 15 minutes
Symptom: Jobs timeout prematurely, or sync operations block for too long
Solutions:
-
Tune sync timeout (promotes long jobs to async automatically):
execution: sync_timeout: 30 # seconds before becoming async (default: 30)
Increase if you want more operations to complete synchronously:
execution: sync_timeout: 60 # allow up to 60 seconds for sync operations
-
Set absolute max execution time per job:
execution: max_execution_time: 86400 # 24 hours (hard limit)
-
Configure graceful shutdown drain timeout:
server: drain_timeout_seconds: 300 # wait up to 5 minutes for running jobs to finish
-
Session timeout for inactive sessions:
sessions: session_timeout: 3600 # cleanup after 1 hour of inactivity
-
Health check interval (detects hung engines):
pool: health_check_interval: 60 # ping engines every 60 seconds
Enable debug logging to troubleshoot issues:
-
In
config.yaml:server: log_level: "debug" # debug | info | warning | error log_file: "./logs/server.log"
-
Via environment variable:
export MATLAB_MCP_SERVER_LOG_LEVEL=debug matlab-mcp -
View logs:
tail -f ./logs/server.log # real-time log tail -
Structured logging includes:
- Engine lifecycle events (start, crash, recovery)
- Job execution (queue, start, progress, completion)
- Pool scaling decisions
- Security violations (blocked functions)
- Performance metrics
-
Log rotation: Logs are stored in
./logs/server.log. For production, configure external log aggregation.
Symptom: Docker container fails to connect to MATLAB, or port binding errors
Solutions:
-
Mount MATLAB correctly:
docker run -p 8765:8765 -p 8766:8766 \ -v /path/to/MATLAB:/opt/matlab:ro \ -e MATLAB_MCP_POOL_MATLAB_ROOT=/opt/matlab \ matlab-mcp
Verify the mount exists on your host:
ls /path/to/MATLAB/bin/matlab # should exist -
Check port bindings:
# SSE mode (multi-user) — port 8765 for MCP, 8766 for dashboard docker run -p 8765:8765 -p 8766:8766 ... # Verify port is accessible curl http://localhost:8765/sse
-
Use docker-compose for easier configuration:
version: '3' services: matlab-mcp: build: . ports: - "8765:8765" - "8766:8766" volumes: - /path/to/MATLAB:/opt/matlab:ro environment: MATLAB_MCP_POOL_MATLAB_ROOT: /opt/matlab MATLAB_MCP_SERVER_TRANSPORT: sse
Then:
docker compose up -
Debug container logs:
docker logs <container_id> # see startup errors docker exec <container_id> cat /logs/server.log # access log file
-
Network mode for advanced setups:
# Use host network (Linux only) docker run --network host ... -
MATLAB license in Docker: If using network licensing:
docker run -e MLM_LICENSE_FILE=<license_server> ...
Symptom: BlockedFunctionError: Function 'system' is blocked
Explanation: The security validator blocks dangerous functions by default to prevent code injection and unauthorized system access.
Solutions:
-
Use MATLAB-native alternatives (recommended):
- File operations:
dir,mkdir,copyfile,movefile,delete - Environment:
getenv,setenv - Shell execution: Use MATLAB functions instead of
system()
- File operations:
-
Remove specific functions from blocklist:
security: blocked_functions: - "system" - "unix" - "dos" - "!" - "eval" # Remove entries you trust
-
Disable blocklist entirely (not recommended for shared/untrusted servers):
security: blocked_functions_enabled: false
-
Default blocked functions:
system, unix, dos, !, eval, feval, evalc, evalin, assignin, perl, pythonThese are blocked because they allow shell command execution or dynamic code evaluation.
Symptom: Job never completes, progress stops updating, or workspace locks
Solutions:
-
Cancel the job:
Call cancel_job with the job IDOr via monitoring:
curl http://localhost:8766/health # see active jobs -
Check max execution time:
execution: max_execution_time: 86400 # 24h hard limit
Jobs are automatically terminated after this duration.
-
Add progress reporting to long jobs:
for i = 1:n % do work... if mod(i, 100) == 0 mcp_progress(__mcp_job_id__, i/n*100, sprintf('Iteration %d/%d', i, n)); end end
-
Check for infinite loops or blocking I/O:
- Infinite loops (
while truewithout exit condition) - Waiting for user input (
input(),pause()) - Blocking network/file operations
- Infinite loops (
-
Engine affinity may lock workspace: If
engine_affinity: true, the same engine is reused and job state persists. Check if previous job left workspace in bad state:execution: engine_affinity: false # disable to use fresh engine each time
-
Workspace isolation:
execution: workspace_isolation: true # clear workspace between jobs
Symptom: Output is cut off, saved to file instead of returned inline, or matrix data missing
Explanation: Results exceeding max_inline_text_length (50,000 chars) or large_result_threshold (10,000 elements) are automatically saved to file to avoid oversized responses.
Solutions:
-
Increase inline limits:
output: max_inline_text_length: 100000 # chars large_result_threshold: 50000 # elements for matrices/tables
-
Use
list_files+read_datato access full output:1. Call list_files to find the result file 2. Call read_data(filename, format: 'raw') to get full data -
Summarize large data in MATLAB:
large_matrix = randn(10000, 1000); % Return summary instead of full matrix summary = struct('size', size(large_matrix), 'mean', mean(large_matrix, 1), 'saved_to', 'data.mat'); disp(summary); save data.mat large_matrix
-
Check output format config:
output: static_image_format: "png" # png | jpg | svg thumbnail_enabled: true
Symptom: No interactive plot returned, only static PNG, or plot appears blank
Explanation: The Plotly converter (mcp_extract_props.m) supports common plot types. Complex multi-axis plots, custom graphics, or unsupported chart types may not convert.
Solutions:
-
Check supported types:
- line, scatter, bar, histogram, surface, image
- Subplots (
subplot,tiledlayout) - Multiple axes with legends
-
Simplify complex plots:
- Split multi-axis plots into separate figures
- Use standard MATLAB plotting functions (
plot,scatter,bar) - Avoid custom graphics objects
-
Verify Plotly conversion is enabled:
output: plotly_conversion: true # default: true
-
Static fallback is always available: Even if Plotly conversion fails, a PNG image is generated and returned.
-
Disable Plotly for static-only output:
output: plotly_conversion: false # use PNG only static_image_format: "png"
Symptom: Warning about max engines on macOS, server crashes with too many engines
Explanation: MATLAB on macOS has a hard limit of ~4 concurrent engine instances due to licensing constraints.
Solution: Cap max_engines on macOS:
pool:
max_engines: 4 # macOS limitSymptom: Client can't connect to http://localhost:8765/sse
Solutions:
-
Verify server is running in SSE mode:
matlab-mcp --transport sse # or in config.yaml: # server: # transport: "sse"
-
Check port configuration:
server: port: 8765 # default SSE port
-
Verify port is listening:
netstat -an | grep 8765 # macOS/Linux netstat -ano | findstr :8765 # Windows
-
Check host binding for remote access:
server: host: "0.0.0.0" # listen on all interfaces (remote) # or host: "127.0.0.1" # localhost only (local)
-
Firewall: Ensure port 8765 is open:
# macOS sudo lsof -i :8765 # Linux sudo ufw allow 8765
-
Check dashboard/monitoring port (8766):
curl http://localhost:8766/health # should return health JSON
To troubleshoot complex issues, enable debug logging:
-
Set log level to debug:
server: log_level: "debug" log_file: "./logs/server.log"
-
Or use environment variable:
export MATLAB_MCP_SERVER_LOG_LEVEL=debug matlab-mcp -
Watch logs in real-time:
tail -f ./logs/server.log
-
Debug log includes:
- Full request/response bodies for MCP tools
- MATLAB engine lifecycle (start, crash, recovery)
- Job queue operations
- Pool scaling decisions
- Security checks (blocked functions)
- Performance metrics
- Network events
-
For Docker, capture logs:
docker logs -f <container_id>
-
Performance profiling: Call
get_server_metricsto see detailed timing:{ "pool": {"total_engines": 10, "busy_engines": 3}, "jobs": {"total": 42, "running": 3, "completed": 39}, "sessions": {"active": 5}, "system": {"cpu_percent": 45.2, "memory_mb": 2048} } -
Health checks:
curl http://localhost:8766/health
Returns detailed health status (healthy/degraded/unhealthy) with issue detection.