Skip to content

Troubleshooting

github-actions[bot] edited this page Mar 22, 2026 · 20 revisions
# Troubleshooting

## MATLAB Engine Connection Failures

**Symptom:** `Engine start timeout`, `matlab.engine not found`, or `Failed to start MATLAB engine`

**Solutions:**

1. **Verify MATLAB Engine API is installed:**
   ```bash
   python -c "import matlab.engine; print('OK')"
  1. 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 .
  2. Check MATLAB version: Must be R2022b or later.

  3. Check PATH and MATLAB root: MATLAB must be on your system PATH, or set matlab_root explicitly in config:

    pool:
      matlab_root: "/Applications/MATLAB_R2024a.app"
      # or on Windows:
      # matlab_root: "C:\\Program Files\\MATLAB\\R2024a"
  4. Increase engine startup timeout: If MATLAB is slow to start on your system:

    pool:
      engine_start_timeout: 300  # 5 minutes (default 120 seconds)
  5. Check engine health: Use the health check tool to diagnose engine issues:

    # Call get_server_health to see detailed engine diagnostics
  6. Enable debug logging (see section below) to see exactly where the connection fails.

Pool Startup Problems

Symptom: Server starts but engines fail to initialize, or pool never reaches min_engines

Solutions:

  1. Check minimum engines setting:

    pool:
      min_engines: 2  # default
      max_engines: 10

    Ensure min_engines ≤ max_engines.

  2. Check queue size: If many jobs are queued immediately, increase:

    pool:
      queue_max_size: 50  # default
  3. Monitor pool startup: Call get_pool_status after starting the server to see:

    • Available engines
    • Busy engines
    • Engines being started
    • Queue length
  4. Verify workspace isolation:

    execution:
      workspace_isolation: true  # each session gets its own workspace
  5. Check for startup command errors: If workspace.startup_commands have syntax errors, engines may fail to initialize:

    workspace:
      startup_commands:
        - "format long"
        - "warning('off', 'MATLAB:mir_warning_maybe_uninitialized_temporary')"

"Max engines exceeded" on macOS

Symptom: Warning about max engines on macOS, or engines fail to start beyond ~4

Explanation: MATLAB on macOS has a hard limit of ~4 concurrent engine instances due to licensing constraints.

Solution: Cap max_engines at 4 on macOS:

pool:
  max_engines: 4

Timeout Tuning

Sync-to-Async Promotion Timeout

Symptom: Fast operations are being promoted to async jobs unnecessarily

Tuning:

execution:
  sync_timeout: 30  # seconds before promoting to async (default 30)

Increase this if your network is slow or MATLAB operations commonly take 20-30 seconds:

execution:
  sync_timeout: 60  # wait up to 60 seconds for sync response

Engine Startup Timeout

Symptom: Engine start timeout errors, or slow MATLAB startup

Tuning:

pool:
  engine_start_timeout: 120  # seconds (default 120)

Increase on slow systems or with large startup_commands:

pool:
  engine_start_timeout: 300  # 5 minutes for heavily customized MATLAB

Health Check Interval

Symptom: Dead engines not detected promptly

Tuning:

pool:
  health_check_interval: 60  # seconds between pings (default 60)

Decrease for faster failure detection:

pool:
  health_check_interval: 30

Scale-Down Timeout

Symptom: Idle engines staying alive too long

Tuning:

pool:
  scale_down_idle_timeout: 900  # seconds (default 15 minutes)

Decrease to free resources faster:

pool:
  scale_down_idle_timeout: 300  # 5 minutes

Session Timeout

Symptom: Sessions being cleaned up while agent is still using them

Tuning:

sessions:
  session_timeout: 3600  # seconds of inactivity (default 1 hour)

Increase for long-running interactive sessions:

sessions:
  session_timeout: 86400  # 24 hours

Job Retention

Symptom: Completed job results disappearing too quickly

Tuning:

sessions:
  job_retention_seconds: 86400  # how long to keep metadata (default 24h)

Increase to retain results longer:

sessions:
  job_retention_seconds: 604800  # 7 days

Maximum Execution Time

Symptom: Long-running jobs killed unexpectedly

Tuning:

execution:
  max_execution_time: 86400  # seconds (default 24 hours)

Increase for very long simulations:

execution:
  max_execution_time: 604800  # 7 days

Logging Configuration

Enable Debug Logging

Debug logging shows detailed server activity, MATLAB communication, and error traces.

In config.yaml:

server:
  log_level: "debug"
  log_file: "./logs/server.log"

Via environment variable:

export MATLAB_MCP_SERVER_LOG_LEVEL=debug
matlab-mcp

Check the log file:

tail -f ./logs/server.log

Log Levels

Level Use Case
debug Detailed MATLAB communication, pool state changes, every API call — very verbose
info Normal operation, job starts/completions, pool scaling events
warning Recoverable issues, blocklist violations, conversion failures
error Engine crashes, code execution failures, critical issues

Rotate Logs

The server doesn't rotate logs automatically. For long-running servers, manage log size:

# On Linux/macOS
tail -f ./logs/server.log | tee -a ./logs/archived.log > /dev/null &

# Or use logrotate (Linux)
cat > /etc/logrotate.d/matlab-mcp << EOF
./logs/server.log {
    daily
    rotate 7
    compress
    delaycompress
}
EOF

Log Output Structure

Logs include timestamps, levels, and module names:

2024-01-15 10:23:45,123 - matlab_mcp.pool - DEBUG - Engine-1 health check: OK
2024-01-15 10:24:12,456 - matlab_mcp.executor - INFO - Job j_abc123 completed in 15.2s
2024-01-15 10:25:33,789 - matlab_mcp.security - WARNING - Blocked function 'system' attempted

Docker Networking

Port Mapping

By default, the SSE transport runs on ports 8765 (MCP) and 8766 (HTTP dashboard).

Expose ports for docker run:

docker run -p 8765:8765 -p 8766:8766 matlab-mcp

Or in docker-compose.yml:

services:
  matlab-mcp:
    ports:
      - "8765:8765"
      - "8766:8766"

Host Binding

For local-only access (docker host only):

docker run -p 127.0.0.1:8765:8765 matlab-mcp

For remote access (external clients):

docker run -p 0.0.0.0:8765:8765 matlab-mcp

Or in config.yaml inside the container:

server:
  host: "0.0.0.0"  # bind to all interfaces
  port: 8765

MATLAB Path in Docker

Mount your MATLAB installation to a known path:

docker run -v /path/to/MATLAB:/opt/matlab:ro \
  -e MATLAB_MCP_POOL_MATLAB_ROOT=/opt/matlab \
  matlab-mcp

Or mount your config.yaml:

docker run -v /path/to/config.yaml:/app/config.yaml \
  matlab-mcp

Docker Network Issues

Symptom: Client can't connect to http://localhost:8765 from outside the container

Solutions:

  1. Use container IP instead of localhost:

    docker inspect <container-id> | grep IPAddress
    # Connect to that IP address
  2. Use host network mode (Linux only):

    docker run --network host matlab-mcp
  3. Check firewall: Ensure ports 8765/8766 are open on your host.

  4. Use docker-compose with named services:

    services:
      matlab:
        image: matlab-mcp
        ports:
          - "8765:8765"

    Then connect to matlab:8765 from other containers.

MATLAB License in Docker

If using floating license servers, ensure MATLAB can reach the license server from inside the container:

# Pass through network
docker run --network bridge \
  -e MLM_LICENSE_FILE=port@licenseserver.local \
  matlab-mcp

Or mount your license file:

docker run -v /path/to/license.dat:/opt/matlab/licenses/license.dat:ro \
  matlab-mcp

Connection Refused (SSE)

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

Solutions:

  1. Check the server is running:

    matlab-mcp --transport sse

    Look for output like: Starting SSE server on http://0.0.0.0:8765

  2. Check port availability:

    # macOS/Linux
    lsof -i :8765
    
    # Windows
    netstat -ano | findstr :8765

    If the port is in use, either kill the process or change the port in config.yaml:

    server:
      port: 8767  # use a different port
  3. Check host binding: By default, the server binds to 0.0.0.0 (all interfaces). For local-only access:

    server:
      host: "127.0.0.1"

    For remote access:

      host: "0.0.0.0"
  4. Check firewall: Ensure port 8765 (and 8766 for dashboard) are open:

    # macOS
    sudo lsof -i :8765
    
    # Linux
    sudo ufw allow 8765
  5. Test endpoint directly:

    curl http://localhost:8765/sse

    Should return a stream or connection. If refused, check logs.

  6. Check logs for binding errors:

    tail -f ./logs/server.log | grep -i "bind\|port\|listen"

Blocked Function Error

Symptom: BlockedFunctionError: Function 'system' is blocked

Explanation: The security validator blocks dangerous functions by default to prevent shell injection and unauthorized file operations.

Solutions:

  1. Use MATLAB-native alternatives instead of blocked functions:

    • File operations: dir, mkdir, copyfile, movefile, delete
    • Environment variables: getenv, setenv
    • Avoid: system, unix, dos, ! (shell escape)
  2. View the blocked list:

    security:
      blocked_functions:
        - "system"
        - "unix"
        - "dos"
        - "!"
        - "eval"
        - "feval"
        - "evalc"
        - "evalin"
        - "assignin"
        - "perl"
        - "python"
  3. Disable blocklist (only for trusted, air-gapped servers):

    security:
      blocked_functions_enabled: false
  4. Remove specific functions from blocklist:

    security:
      blocked_functions:
        - "unix"
        - "dos"
        # "system" removed — now allowed
  5. Check code before execution: Use check_code to detect blocked functions before running:

    # Agent calls check_code with the code first

Job Stuck in "Running" State

Symptom: Job never completes, progress stops updating, or job appears to hang

Solutions:

  1. Cancel the job: Ask your agent to call cancel_job with the job ID. This interrupts execution:

    cancel_job job_id=j_abc123
  2. Check maximum execution time:

    execution:
      max_execution_time: 86400  # 24h hard limit

    If your job legitimately takes longer, increase this value.

  3. Check MATLAB code for infinite loops: Add progress reporting to debug stuck jobs:

    for i = 1:n
        result(i) = compute(data(i));
        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: Call get_pool_status to check if the engine is still responsive. If an engine is hung:

    • It will eventually be detected as unhealthy
    • A new engine will be spun up
    • The hung engine will be recycled
  5. Check for blocking I/O: Some MATLAB operations (network calls, file I/O on slow drives) may appear hung. Verify the MATLAB code isn't waiting on external resources.

  6. View error log: Call get_error_log to see if the engine reported any warnings or errors during execution.

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. Some complex or custom plot types may not convert properly.

Solutions:

  1. Check supported plot types:

    • Line plots
    • Scatter plots
    • Bar charts
    • Area plots
    • Histograms
    • Surface/mesh plots
    • Image displays
    • Subplots (with subplot or tiledlayout)
    • Multiple axes with linked legends
  2. Simplify the plot: Complex multi-axis, custom graphics objects, or specialized toolbox plots may not convert:

    % Instead of complex custom graphics:
    plot(x, y);  % Use standard MATLAB plotting
  3. Static fallback: A PNG image is always generated even if Plotly conversion fails. The agent will receive the static image.

  4. Disable Plotly: Fall back to static images only (faster if you don't need interactivity):

    output:
      plotly_conversion: false
  5. Check figure properties: Ensure the figure has properly set axes, labels, and data:

    plot(x, y);
    xlabel('X-axis Label');
    ylabel('Y-axis Label');
    title('Plot Title');
    legend('Data 1', 'Data 2');
  6. Enable debug logging to see Plotly conversion errors:

    server:
      log_level: "debug"

    Then check the log for plotly conversion messages.

Large Result Truncated

Symptom: Output is cut off, saved to file, or marked as "result too large"

Explanation: Results exceeding max_inline_text_length (50,000 chars) or large_result_threshold (10,000 elements) are automatically saved to a file to avoid overwhelming the agent.

Solutions:

  1. Increase inline limits:

    output:
      max_inline_text_length: 100000  # allow larger text results inline
      large_result_threshold: 50000   # allow larger matrices inline
  2. Use list_files + get_job_result + read_data to access the full output:

    # Agent calls:
    list_files                    # see output files
    read_data filename=result.csv # read the CSV directly
  3. Summarize large results in MATLAB before returning:

    % Instead of returning all 1M rows:
    summary_stats = struct(...
        'mean', mean(data),
        'std', std(data),
        'min', min(data),
        'max', max(data),
        'median', median(data)
    );
    disp(summary_stats);  % Return only summary
  4. Save large data to MAT file for later retrieval:

    large_matrix = randn(10000, 10000);
    save('large_result.mat', 'large_matrix');
    disp('Saved to large_result.mat');
  5. Check the file directly: Files are saved to the session result directory. Call list_files to see them, then read_data to retrieve them.

Enable Debug Logging

Quick Enable

export MATLAB_MCP_SERVER_LOG_LEVEL=debug
matlab-mcp

Or in config.yaml:

server:
  log_level: "debug"
  log_file: "./logs/server.log"

What Debug Logging Shows

  • MATLAB communication: Every command sent to/from MATLAB engines
  • Pool state: Engine startup, shutdown, scaling events
  • Job lifecycle: Submission, async promotion, progress updates, completion
  • API calls: Every MCP tool invocation with parameters and results
  • Security: Blocklist checks, function validation
  • Performance: Execution times, timeouts, retries

View Logs in Real-Time

# Follow logs
tail -f ./logs/server.log

# Filter for specific keywords
tail -f ./logs/server.log | grep -i "error\|warning"
tail -f ./logs/server.log | grep -i "engine"
tail -f ./logs/server.log | grep -i "plotly"

Log Rotation for Long-Running Servers

The server doesn't rotate logs automatically. For production, use a log rotation tool:

Linux (logrotate):

cat > /etc/logrotate.d/matlab-mcp << 'EOF'
./logs/server.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
}
EOF

macOS (manual):

# Compress and archive logs weekly
mv ./logs/server.log ./logs/server.log.$(date +%Y%m%d)
gzip ./logs/server.log.*

Redirect Logs to Syslog

Linux:

export MATLAB_MCP_SERVER_LOG_FILE=/dev/stderr
matlab-mcp 2>&1 | logger -t matlab-mcp

Disable Color Output (for logs to files)

Debug logs use color by default. For cleaner file output:

server:
  log_file: "./logs/server.log"  # logs to file with reduced colors

Workspace Isolation Issues

Symptom: Variables from one session affecting another, or workspace not clearing between jobs

Solutions:

  1. Enable workspace isolation (default is ON):

    execution:
      workspace_isolation: true

    Each session gets its own MATLAB workspace.

  2. Disable engine affinity if you want true isolation across jobs:

    execution:
      engine_affinity: false  # jobs can run on different engines

    With affinity OFF, each job gets a fresh workspace. With affinity ON, the same session's jobs reuse the same engine (faster, but workspace persists).

  3. Clear workspace between commands:

    clear  % clear all variables

Custom MATLAB Path Issues

Symptom: Function not found or File not found errors for custom code

Solutions:

  1. Add paths to startup configuration:

    workspace:
      default_paths:
        - "/path/to/my/libraries"
        - "/shared/toolboxes"

    These paths are added to MATLAB's path on every engine start.

  2. Verify path permissions: Ensure the MATLAB process can read the directories:

    ls -la /path/to/my/libraries
  3. Add path dynamically in code:

    addpath('/path/to/my/libraries');
    my_function();
  4. Check current working directory:

    pwd  % print working directory
    ls   % list files

    The session's working directory is the result directory.

Clone this wiki locally