Skip to content

Troubleshooting

github-actions[bot] edited this page Mar 18, 2026 · 20 revisions

Troubleshooting

MATLAB Engine Connection Failures

Symptom: Engine start timeout, matlab.engine not found, or No suitable MATLAB found

Solutions:

  1. Verify MATLAB Engine API is installed:

    python -c "import matlab.engine; print('OK')"
  2. 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 .
  3. Check MATLAB version: Must be 2020b or later.

  4. 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"
  5. Increase engine start timeout: If MATLAB is slow to start:

    pool:
      engine_start_timeout: 300  # 5 minutes instead of default 120s
  6. Check system PATH: Ensure MATLAB executable is accessible:

    which matlab  # macOS/Linux
    where matlab  # Windows

Pool Startup Problems

Symptom: Server starts but engines fail to initialize, or min_engines not reached

Solutions:

  1. Check min_engines setting:

    pool:
      min_engines: 2  # default, reduced from max_engines if needed

    On macOS, max_engines is capped at 4 — ensure min_engines ≤ 4.

  2. Verify queue capacity:

    pool:
      queue_max_size: 50  # increase if jobs are rejected during startup
  3. Review engine start logs: Enable debug logging (see Debug Logging) and check ./logs/server.log for startup errors.

  4. 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
  5. Gradual warmup: If startup is slow, reduce min_engines and let the server scale up:

    pool:
      min_engines: 1
      max_engines: 10
      proactive_warmup_threshold: 0.8  # trigger scale-up at 80% utilization

Timeout Tuning

Symptom: Jobs timeout or hang unexpectedly

Solutions:

  1. 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.

  2. Set max execution time (hard limit per job):

    execution:
      max_execution_time: 86400  # default: 24 hours

    Jobs exceeding this limit are forcibly cancelled.

  3. SSE drain timeout (graceful shutdown wait):

    server:
      drain_timeout_seconds: 300  # wait 5 min for running jobs
  4. Scale-down idle timeout (when to shrink engine pool):

    pool:
      scale_down_idle_timeout: 900  # default: 15 min of idle time

Logging Configuration

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-mcp

Logs 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

Docker Networking

Symptom: Cannot connect to MATLAB MCP server in Docker from host, or Docker-internal networking issues

Solutions:

  1. 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)
  2. 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
  3. 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
  4. 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

  5. Network mode for macOS/Windows Docker Desktop: Use host network mode (Linux only), or rely on port mapping with 0.0.0.0.

Enable Debug Logging

Step-by-step:

  1. Create or edit config.yaml:

    server:
      log_level: "debug"
      log_file: "./logs/server.log"
  2. Or set environment variable before starting:

    export MATLAB_MCP_SERVER_LOG_LEVEL=debug
    matlab-mcp --transport stdio  # or sse
  3. Check the log file:

    tail -f ./logs/server.log
  4. 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
  5. For even more verbosity in development:

    • Review console stderr in stdio mode
    • Check dashboard logs via /api/errors endpoint (SSE mode)

"Max Engines Exceeded" on macOS

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 response

The server will automatically respect the platform constraint and issue a warning if you attempt to configure higher.

Connection Refused (SSE)

Symptom: Client can't connect to http://localhost:8765/sse

Solutions:

  1. Check the server is running:

    matlab-mcp --transport sse

    You should see: SSE server listening on http://0.0.0.0:8765

  2. 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
  3. Check host binding:

    • For local-only access: host: "127.0.0.1" (default is 0.0.0.0)
    • For remote access: host: "0.0.0.0"
  4. Check firewall: Ensure port 8765 (and 8766 for dashboard) are open:

    sudo ufw allow 8765  # Linux
    # macOS: System Preferences → Security & Privacy → Firewall
  5. Test connectivity:

    curl http://localhost:8765/sse

    Should respond with connection upgrade or error (not timeout).

Blocked Function Error

Symptom: BlockedFunctionError: Function 'system' is blocked

Explanation: The security validator blocks dangerous functions by default for shared/untrusted environments.

Solutions:

  1. 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
  2. Disable blocklist (only for trusted private servers):

    security:
      blocked_functions_enabled: false

    Or via environment:

    export MATLAB_MCP_SECURITY_BLOCKED_FUNCTIONS_ENABLED=false
  3. Remove specific functions from blocklist:

    security:
      blocked_functions:
        - "unix"
        - "dos"
        - "!"
        # Remove "system" from this list to allow it
  4. Default blocklist includes:

    • system, unix, dos, ! — shell execution
    • eval, feval, evalc, evalin, assignin — dynamic code
    • perl, python — external language execution

Job Stuck in "Running" State

Symptom: Job never completes, progress stops updating, or get_job_status returns "running" indefinitely

Solutions:

  1. 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
  2. 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
  3. 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
  4. 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).

  5. Review error log:

    tail -f ./logs/server.log | grep job_id

Plotly Conversion Failed

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:

  1. 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
  2. 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', ...);
  3. Static fallback: A PNG image is always generated even if Plotly conversion fails. Check list_files for .png output.

  4. Disable Plotly conversion: Fall back to static images only:

    output:
      plotly_conversion: false
      static_image_format: "png"  # png | jpg | svg
      static_image_dpi: 150

Large Result Truncated

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:

  1. 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
  2. Use file-based access: When result is truncated, agent can:

    • Call list_files to find the output file
    • Call read_data(filename, 'raw') for full access
    • Call read_script(filename) for text files
  3. 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

Code Quality Checking

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=true

The agent can manually call check_code() to get warnings before executing.

Session Isolation and Workspace Affinity

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 engine

Behavior:

  • 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')"

Clone this wiki locally