-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
Symptom: Engine start timeout, matlab.engine not found, or No suitable MATLAB found
Solutions:
-
Verify MATLAB Engine API is installed:
python -c "import matlab.engine; print('OK')" -
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 2020b or later.
-
Set MATLAB root explicitly: If auto-detection fails:
pool: matlab_root: "/Applications/MATLAB_R2024a.app" # macOS # matlab_root: "C:\\Program Files\\MATLAB\\R2024a" # Windows
Or via environment variable:
export MATLAB_MCP_POOL_MATLAB_ROOT="/Applications/MATLAB_R2024a.app"
-
Increase engine start timeout: If MATLAB is slow to start:
pool: engine_start_timeout: 300 # 5 minutes instead of default 120s
-
Check system PATH: Ensure MATLAB executable is accessible:
which matlab # macOS/Linux where matlab # Windows
Symptom: Server starts but engines fail to initialize, or min_engines not reached
Solutions:
-
Check min_engines setting:
pool: min_engines: 2 # default, reduced from max_engines if needed
On macOS,
max_enginesis capped at 4 — ensuremin_engines ≤ 4. -
Verify queue capacity:
pool: queue_max_size: 50 # increase if jobs are rejected during startup
-
Review engine start logs: Enable debug logging (see Debug Logging) and check
./logs/server.logfor startup errors. -
Check system resources:
- Available memory (each MATLAB engine uses ~200-500MB)
- File descriptor limits:
ulimit -n(should be >1000) - On macOS: MATLAB has a limit of ~4 concurrent engines
-
Gradual warmup: If startup is slow, reduce
min_enginesand let the server scale up:pool: min_engines: 1 max_engines: 10 proactive_warmup_threshold: 0.8 # trigger scale-up at 80% utilization
Symptom: Jobs timeout or hang unexpectedly
Solutions:
-
Adjust sync timeout (time before promoting to async):
execution: sync_timeout: 30 # default: promote to async after 30s
For faster execution environments, reduce to 15s; for slower systems, increase to 60s.
-
Set max execution time (hard limit per job):
execution: max_execution_time: 86400 # default: 24 hours
Jobs exceeding this limit are forcibly cancelled.
-
SSE drain timeout (graceful shutdown wait):
server: drain_timeout_seconds: 300 # wait 5 min for running jobs
-
Scale-down idle timeout (when to shrink engine pool):
pool: scale_down_idle_timeout: 900 # default: 15 min of idle time
Enable debug logging:
server:
log_level: "debug" # debug | info | warning | error
log_file: "./logs/server.log"Or via environment variable:
export MATLAB_MCP_SERVER_LOG_LEVEL=debug
matlab-mcpLogs include:
- Engine lifecycle (start, health checks, shutdown)
- Job execution and progress
- Pool scaling decisions
- MATLAB code execution details
- Custom tool invocations
Log output locations:
- Stdout: All log levels (if not redirected)
- File:
./logs/server.log(created automatically if missing) - Dashboard: Recent errors accessible via monitoring API
Symptom: Cannot connect to MATLAB MCP server in Docker from host, or Docker-internal networking issues
Solutions:
-
Expose both ports:
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 --transport sse
- Port 8765: SSE transport
- Port 8766: Dashboard (monitoring)
-
Bind to 0.0.0.0 for remote access:
server: host: "0.0.0.0" # accessible from host machine port: 8765
Or via environment:
export MATLAB_MCP_SERVER_HOST=0.0.0.0 -
Mount MATLAB installation correctly:
docker run -v /path/to/MATLAB:/opt/matlab:ro \ -e MATLAB_MCP_POOL_MATLAB_ROOT=/opt/matlab \ matlab-mcp
Verify the mount exists inside container:
docker exec <container_id> ls -la /opt/matlab/bin/matlab
-
Docker Compose setup (edit
docker-compose.yml):services: matlab-mcp: image: matlab-mcp ports: - "8765:8765" - "8766:8766" volumes: - /path/to/MATLAB:/opt/matlab:ro environment: MATLAB_MCP_POOL_MATLAB_ROOT: /opt/matlab MATLAB_MCP_SERVER_HOST: 0.0.0.0 networks: - matlab-net networks: matlab-net:
Then:
docker compose up -
Network mode for macOS/Windows Docker Desktop: Use
hostnetwork mode (Linux only), or rely on port mapping with 0.0.0.0.
Step-by-step:
-
Create or edit
config.yaml:server: log_level: "debug" log_file: "./logs/server.log"
-
Or set environment variable before starting:
export MATLAB_MCP_SERVER_LOG_LEVEL=debug matlab-mcp --transport stdio # or sse
-
Check the log file:
tail -f ./logs/server.log
-
Debug output includes:
-
[DEBUG]Engine lifecycle events -
[DEBUG]Job queuing and execution steps -
[DEBUG]MATLAB code execution context -
[DEBUG]Pool scaling decisions -
[DEBUG]Custom tool parameter resolution
-
-
For even more verbosity in development:
- Review console stderr in stdio mode
- Check dashboard logs via
/api/errorsendpoint (SSE mode)
Symptom: Warning about max engines on macOS, or engine startup fails after ~4 instances
Explanation: MATLAB on macOS has a hard limit of approximately 4 concurrent engine instances. The server respects your configured max_engines but cannot exceed the platform limit.
Solution: Cap max_engines at 4 on macOS:
pool:
max_engines: 4
min_engines: 2 # keep some warm for faster responseThe server will automatically respect the platform constraint and issue a warning if you attempt to configure higher.
Symptom: Client can't connect to http://localhost:8765/sse
Solutions:
-
Check the server is running:
matlab-mcp --transport sse
You should see:
SSE server listening on http://0.0.0.0:8765 -
Check port is available:
lsof -i :8765 # macOS/Linux netstat -ano | findstr :8765 # Windows
If occupied, change in config:
server: port: 8766 # or another available port
-
Check host binding:
- For local-only access:
host: "127.0.0.1"(default is0.0.0.0) - For remote access:
host: "0.0.0.0"
- For local-only access:
-
Check firewall: Ensure port 8765 (and 8766 for dashboard) are open:
sudo ufw allow 8765 # Linux # macOS: System Preferences → Security & Privacy → Firewall
-
Test connectivity:
curl http://localhost:8765/sse
Should respond with connection upgrade or error (not timeout).
Symptom: BlockedFunctionError: Function 'system' is blocked
Explanation: The security validator blocks dangerous functions by default for shared/untrusted environments.
Solutions:
-
Use MATLAB-native alternatives instead of
system():- File operations:
dir,mkdir,copyfile,movefile,delete - Environment:
getenv,setenv - Process execution: Not recommended; use MATLAB functions instead
- File operations:
-
Disable blocklist (only for trusted private servers):
security: blocked_functions_enabled: false
Or via environment:
export MATLAB_MCP_SECURITY_BLOCKED_FUNCTIONS_ENABLED=false -
Remove specific functions from blocklist:
security: blocked_functions: - "unix" - "dos" - "!" # Remove "system" from this list to allow it
-
Default blocklist includes:
-
system,unix,dos,!— shell execution -
eval,feval,evalc,evalin,assignin— dynamic code -
perl,python— external language execution
-
Symptom: Job never completes, progress stops updating, or get_job_status returns "running" indefinitely
Solutions:
-
Cancel the job:
# Ask the agent to call cancel_job with the job ID # Or manually via API (SSE mode): curl -X POST http://localhost:8765/api/jobs/{job_id}/cancel
-
Check max execution time:
execution: max_execution_time: 86400 # 24h hard limit; jobs killed after this
Reduce if you want faster timeouts:
execution: max_execution_time: 3600 # 1 hour
-
Check MATLAB code for infinite loops: Add progress reporting to debug:
for i = 1:n % ... computation ... if mod(i, 100) == 0 mcp_progress(__mcp_job_id__, i/n*100, sprintf('Iteration %d/%d', i, n)); end end
-
Monitor engine health:
# Check pool status # Via API: curl http://localhost:8765/api/pool/status # Or ask agent to call: get_pool_status()
If an engine is stuck, it may be waiting on user input (which MCP code cannot provide).
-
Review error log:
tail -f ./logs/server.log | grep job_id
Symptom: No interactive plot returned, only text output or static PNG
Explanation: The Plotly converter (mcp_extract_props.m) supports common plot types. Complex or custom graphics may not convert.
Supported plot types: line, scatter, bar, area, histogram, surface, image, subplots, multiple axes
Solutions:
-
Check supported types:
- ✅ Line plots:
plot(),plot3() - ✅ Scatter:
scatter(),scatter3() - ✅ Bar:
bar(),barh() - ✅ Area:
area() - ✅ Histogram:
histogram(),hist() - ✅ Surface/mesh:
surface(),mesh(),surf() - ✅ Image:
imagesc(),imshow() - ✅ Subplots:
subplot(),tiledlayout() - ❌ Custom graphics objects, complex annotations
- ✅ Line plots:
-
Simplify the plot: Avoid:
- Multiple custom graphics overlays
- Complex legend positioning
- Custom renderer/opengl settings
% Good: simple line plot plot(x, y, 'LineWidth', 2); legend('Data'); xlabel('X'); title('My Plot'); % Difficult: custom text boxes, arrows, etc. annotation('textbox', ...);
-
Static fallback: A PNG image is always generated even if Plotly conversion fails. Check
list_filesfor.pngoutput. -
Disable Plotly conversion: Fall back to static images only:
output: plotly_conversion: false static_image_format: "png" # png | jpg | svg static_image_dpi: 150
Symptom: Output is cut off, saved to file instead of returned inline, or tables truncated
Explanation: Results exceeding configured thresholds are saved to file to prevent overwhelming clients.
Thresholds:
-
max_inline_text_length: 50000— text output (chars) -
large_result_threshold: 10000— tabular/matrix data (elements)
Solutions:
-
Increase limits (if clients can handle it):
output: max_inline_text_length: 100000 # 100k chars instead of 50k large_result_threshold: 50000 # 50k elements instead of 10k
-
Use file-based access: When result is truncated, agent can:
- Call
list_filesto find the output file - Call
read_data(filename, 'raw')for full access - Call
read_script(filename)for text files
- Call
-
Verify output format:
# Check what was saved curl http://localhost:8765/api/jobs/{job_id}/result # summary curl http://localhost:8765/api/jobs/{job_id}/files # saved files
Symptom: Code checker disabled or not running
Enable code checking:
code_checker:
enabled: true
auto_check_before_execute: false # set true to auto-check all code
severity_levels: ["error", "warning"]Or via environment:
export MATLAB_MCP_CODE_CHECKER_ENABLED=true
export MATLAB_MCP_CODE_CHECKER_AUTO_CHECK_BEFORE_EXECUTE=trueThe agent can manually call check_code() to get warnings before executing.
Symptom: Variables persist across jobs unexpectedly, or workspace is reset when it shouldn't be
Configuration:
execution:
workspace_isolation: true # reset workspace between jobs by default
engine_affinity: false # set true to pin session to single engineBehavior:
-
workspace_isolation: true— Fresh MATLAB workspace for each code execution (default, safe for multi-user) -
engine_affinity: true— Stick session to same engine, preserving variables across calls (useful for iterative development)
Set engine_affinity: true if the agent needs to build state across multiple calls:
execution:
engine_affinity: true
workspace:
startup_commands:
- "format long"
- "addpath('/shared/libs')"