Skip to content
github-actions[bot] edited this page Mar 23, 2026 · 20 revisions

FAQ

General / Overview

What is this project?

The MATLAB MCP Server is a Model Context Protocol (MCP) server that enables AI agents (Claude, Cursor, etc.) to execute MATLAB code, discover toolboxes, manage long-running jobs, and integrate with custom MATLAB libraries. It provides a secure, multi-user capable bridge between AI agents and MATLAB.

What MATLAB versions are supported?

MATLAB R2022b and later. The MATLAB Engine API for Python must be installed from your MATLAB distribution.

What license is this under?

Check the LICENSE file in the repository. The project is open-source and welcomes contributions.

What platforms are supported?

  • Windows (10, 11) via install.bat or PyPI
  • macOS (Intel/Apple Silicon) via PyPI or Docker
  • Linux via PyPI or Docker

Docker images are provided for simplified deployment without a local MATLAB installation (MATLAB must be mounted as a volume).

Can I use it without MATLAB installed?

No. The server requires a local MATLAB installation with the Engine API available. It communicates with real MATLAB engines; there is no fallback simulator.

Which AI agents are supported?

Any agent implementing the Model Context Protocol:

  • Claude Desktop (with MCP plugin)
  • Claude Code
  • Cursor
  • Custom agents built with MCP SDKs (Python, TypeScript, etc.)

Setup / Installation

How do I install the MATLAB Engine API?

On Windows:

cd "C:\Program Files\MATLAB\R2024a\extern\engines\python"
pip install .

On macOS:

cd /Applications/MATLAB_R2024a.app/extern/engines/python
pip install .

On Linux:

cd /usr/local/MATLAB/R2024a/extern/engines/python
pip install .

Adjust the path for your MATLAB version. See Installation for details.

How do I install the server?

From PyPI:

pip install matlab-mcp-python
matlab-mcp --config config.yaml

From source:

git clone https://github.com/HanSur94/matlab-mcp-server-python
cd matlab-mcp-server-python
pip install -e .
python -m matlab_mcp.server --config config.yaml

Docker:

docker-compose up

See Installation for complete setup instructions including Docker.

What is the difference between stdio and SSE transport?

graph LR
    subgraph stdio["stdio (Single User)"]
        Agent1["Agent"]
        Server1["MCP Server"]
        Agent1 -->|spawn process| Server1
        Agent1 <-->|stdin/stdout| Server1
    end
    
    subgraph sse["SSE (Multi User)"]
        Agent2["Agent 1"]
        Agent3["Agent 2"]
        RProxy["Reverse Proxy<br/>+ Auth"]
        Server2["MCP Server"]
        Agent2 -->|HTTP| RProxy
        Agent3 -->|HTTP| RProxy
        RProxy -->|localhost| Server2
        Server2 -->|Server Sent<br/>Events| RProxy
    end
Loading
  • stdio: Single-user, no network setup. Agent launches the server process directly.
  • SSE: Multi-user, requires HTTP setup. Server runs continuously; agents connect via HTTP. Always put behind an authenticating reverse proxy.

For personal use or local agent testing, choose stdio. For team deployments, choose SSE with a reverse proxy.

Can I run the server remotely?

Yes, with SSE transport. Place the server behind a reverse proxy (nginx, Caddy) with authentication. Never expose it directly to the internet without auth. See Security and Installation.

How do I configure the server?

Edit config.yaml and pass it to the server:

matlab-mcp --config /path/to/config.yaml

Configuration covers engine pool sizing, timeouts, security, output formatting, monitoring, and more. See Configuration for full reference.

What is custom tools?

Custom tools let you expose your own MATLAB functions as first-class MCP tools. Define them in custom_tools.yaml:

tools:
  - name: "analyze_signal"
    matlab_function: "signal_analysis.process"
    description: "Analyze frequency content of a signal"
    parameters:
      signal_data:
        type: "array"
        description: "Input signal"
      sample_rate:
        type: "number"
        description: "Sampling rate in Hz"
    returns:
      type: "object"
      description: "Frequency spectrum"

See Custom Tools for full syntax and examples.


Performance / Optimization

How many engines should I run?

graph LR
    A["1-2 engines"] --> B["Personal use<br/>single agent"]
    C["2-4 engines"] --> D["Small team<br/>2-5 concurrent users"]
    E["4-8+ engines"] --> F["Larger team<br/>10+ concurrent users"]
    G["macOS limit"] --> H["~4 engines max<br/>per Python process"]
    style H fill:#ffcccc
Loading
  • Personal: 1-2 engines
  • Small team (2-5 users): 2-4 engines
  • Larger deployments: Scale based on concurrent usage, respecting MATLAB license limits
  • macOS: Stability issues above 4 engines due to MATLAB Engine API limitations

How much memory does each engine use?

Typically 500MB–2GB per engine depending on:

  • MATLAB version
  • Loaded toolboxes (Simulink, Deep Learning, etc. add overhead)
  • User code and data

A 4-engine pool might consume 2–8GB total.

What happens when all engines are busy?

Requests queue (configurable via queue_max_size, default 50). If the pool hasn't reached max_engines, new engines are started proactively up to the limit. Requests are served FIFO as engines become available.

How do I optimize for long-running jobs?

  1. Use async execution: Code exceeding sync_timeout (default 30s) is automatically promoted. No extra configuration needed.
  2. Report progress: Call mcp_progress(__mcp_job_id__, percentage, 'message') to send progress updates to the agent.
  3. Increase timeouts if needed: max_execution_time controls the absolute limit (default 24 hours).

See Async Jobs for examples.

Can I adjust pool scaling parameters?

Yes, in config.yaml:

pool:
  min_engines: 2           # Always keep running
  max_engines: 10          # Absolute limit
  scale_down_idle_timeout: 900     # Seconds before idle engine stops
  proactive_warmup_threshold: 0.8  # Start new engine when utilization > 80%
  health_check_interval: 60        # Health check frequency (seconds)

See Configuration for all pool settings.


Integration / CI-CD & Other Tools

How do I integrate with Claude Desktop?

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "matlab": {
      "command": "python",
      "args": ["-m", "matlab_mcp.server", "--config", "/path/to/config.yaml"]
    }
  }
}

Restart Claude Desktop. MATLAB tools appear in the tool palette.

How do I integrate with Cursor?

Similar to Claude Desktop. See Installation for details. Cursor supports MCP natively via similar config files.

Can I use this in a GitHub Actions workflow?

Yes, if your GitHub runner has MATLAB installed:

- name: Run MATLAB via MCP
  run: |
    pip install matlab-mcp-python
    matlab-mcp --config config.yaml &
    # Connect your agent to the running server

However, GitHub-hosted runners do not include MATLAB. You would need a self-hosted runner with MATLAB pre-installed.

How do I deploy to Kubernetes?

The docker-compose.yml provides a foundation. For Kubernetes:

  1. Build the Docker image with MATLAB mounted or pre-installed
  2. Create a Kubernetes Deployment
  3. Mount MATLAB as a hostPath or NFS volume
  4. Expose via a Service and Ingress with authentication

See Installation for Docker setup details before advancing to Kubernetes.

How do I monitor the server?

The server exposes:

  • HTTP /health endpoint — health status (healthy/degraded/unhealthy)
  • HTTP /metrics endpoint — live metrics snapshot (JSON)
  • Web dashboard at http://localhost:8766/dashboard — interactive charts, event logs

Enable monitoring in config.yaml:

monitoring:
  enabled: true
  dashboard_enabled: true
  http_port: 8766  # Separate from main server port

Query tools via MCP: get_server_health, get_server_metrics, get_error_log.

See Architecture for the monitoring subsystem diagram.

How do I integrate custom build toolchains?

You can call the server from within your CI pipeline. Use the SSE transport and hit the HTTP endpoints to fetch results:

import requests
import base64

# Upload a data file
with open("data.csv", "rb") as f:
    content = base64.b64encode(f.read()).decode()

# Call via MCP (if agent integration) or direct HTTP if exposed

See Examples for integration patterns.


Architecture & Data Flow

graph TB
    Agent["AI Agent<br/>(Claude, Cursor, etc.)"]
    MCP["MCP Server<br/>(FastMCP)"]
    
    subgraph Tools["Tool Handlers"]
        Core["execute_code<br/>check_code"]
        Discovery["list_toolboxes<br/>list_functions"]
        Files["upload_data<br/>read_script<br/>read_image"]
        Jobs["get_job_status<br/>cancel_job"]
        Custom["Custom Tools<br/>(user-defined)"]
    end
    
    Executor["JobExecutor"]
    Tracker["JobTracker<br/>(async jobs)"]
    Pool["EnginePoolManager<br/>(elastic scaling)"]
    
    subgraph Engines["MATLAB Engines"]
        E1["Engine 1"]
        E2["Engine 2"]
        EN["Engine N"]
    end
    
    Security["SecurityValidator<br/>(blocklist)"]
    Formatter["ResultFormatter<br/>(Plotly convert)"]
    Sessions["SessionManager<br/>(isolation)"]
    
    Agent -->|MCP call| MCP
    MCP --> Tools
    Tools --> Security
    Security --> Executor
    Executor --> Tracker
    Executor --> Pool
    Pool --> Engines
    Executor --> Formatter
    Executor --> Sessions
    
    Formatter -->|response| Agent
    
    style Agent fill:#e1f5ff
    style MCP fill:#fff3e0
    style Engines fill:#f3e5f5
    style Security fill:#ffebee
Loading

The architecture flows: Agent → MCP Server → Tool Handlers → Security Validator → JobExecutor → Engine Pool → MATLAB Engines → Result Formatter → Agent.

See Architecture for detailed component descriptions.


Common Issues & Troubleshooting

"Engine failed to start" error

Symptoms: Requests fail with "Engine failed to start" message.

Causes:

  • MATLAB not installed or MATLAB_ROOT not found
  • MATLAB Engine API for Python not installed
  • MATLAB license unavailable or locked

Solutions:

  1. Verify MATLAB installation: matlab -r "quit"
  2. Verify Engine API: python -c "import matlab.engine; print('OK')"
  3. Check MATLAB_ROOT environment variable
  4. Ensure MATLAB license is valid and available

See Troubleshooting for detailed verification steps.

"Blocked function error" on legitimate code

Symptom: execute_code returns "blocked function" error for code that should be allowed.

Cause: The security validator may have a false positive if the blocklist is too strict.

Solution: Review the blocklist in your config.yaml. If you trust the code source, you can disable specific functions:

security:
  blocked_functions_enabled: true
  blocked_functions:
    - "system"
    - "unix"
    - "dos"
    # Remove "eval" if you need it for your use case

The validator strips string literals and comments, so msg = "system() call" will NOT be blocked.

See Security for the smart scanning logic.

Jobs stuck in "running" state

Symptom: A job never completes; get_job_status always shows "running".

Causes:

  • Code has an infinite loop
  • Code is waiting for user input (dialog, input())
  • Long-running code without progress reporting

Solutions:

  1. Cancel the job: cancel_job(job_id) stops the execution
  2. Increase timeouts: Adjust max_execution_time in config if the job legitimately takes hours
  3. Add progress reporting: Use mcp_progress() to confirm the job is progressing

See Async Jobs for progress reporting syntax.

"Path traversal" rejection on valid filenames

Symptom: upload_data or read_image rejects a filename you believe is safe.

Cause: The security validator sanitizes filenames to prevent ../../etc/passwd style attacks.

Solution: Use simple, alphanumeric filenames with ., _, -:

  • data_v1.csv, plot.png, my-file.m
  • ../data.csv, file@2024.txt, folder/data.csv

Plotly conversion failed; static PNG used instead

Symptom: execute_code with a plot returns a static PNG instead of interactive Plotly JSON.

Causes:

  • Unsupported plot type (custom graphics, uicontrols, etc.)
  • Missing mcp_extract_props.m MATLAB helper
  • Large plot with too many data points

Solution:

  • Check that plotly_conversion: true in config
  • Ensure MATLAB helpers are in the search path (automatic if installed from PyPI)
  • Reduce plot complexity or switch to a supported plot type (line, scatter, bar, surface, histogram)

See Troubleshooting for Plotly debugging tips.

macOS: "Too many open files" or crashes with 4+ engines

Symptom: On macOS, running > 4 concurrent MATLAB engines causes crashes or file descriptor errors.

Cause: MATLAB Engine API on macOS has known stability limits with multiple engines in a single Python process.

Solution: Limit max_engines to 4 or fewer in config.yaml:

pool:
  max_engines: 4

This is not a limitation of the MCP server itself, but of the underlying MATLAB Engine API. See Troubleshooting for workarounds.


Development & Contributing

How do I run tests?

pip install -e ".[dev]"
pytest tests/ -v
pytest tests/ --cov=src/matlab_mcp  # With coverage

Tests use a mock MATLAB engine; no MATLAB installation needed. CI automatically runs tests on Python 3.10, 3.11, 3.12.

How do I add a new MCP tool?

  1. Implement the handler in src/matlab_mcp/tools/ (or extend an existing module):

    async def my_new_tool_impl(param: str) -> dict:
        """Docstring for MCP tool."""
        return {"result": "value"}
  2. Register in server.py:

    @mcp.tool()
    async def my_new_tool(param: str) -> dict:
        return await my_new_tool_impl(param, ...)
  3. Add tests in tests/test_tools_*.py:

    @pytest.mark.asyncio
    async def test_my_new_tool():
        result = await my_new_tool_impl("test")
        assert result["result"] == "value"
  4. Document in MCP-Tools-Reference.

How do I debug the server locally?

# Run with debug logging
MATLAB_MCP_LOG_LEVEL=debug python -m matlab_mcp.server --config config.yaml

# Or set in config.yaml
server:
  log_level: debug
  log_file: ./logs/debug.log

Log files are written to log_file path. Watch the logs while the agent runs code to diagnose issues.

Can I contribute?

Yes! The project welcomes pull requests and issues on GitHub.

Before submitting:

  • Run pytest to ensure tests pass
  • Run ruff check for linting
  • Add tests for new features
  • Update MCP-Tools-Reference if adding tools

For more details, see:

Clone this wiki locally