-
Notifications
You must be signed in to change notification settings - Fork 0
Security
The MATLAB MCP Server implements multiple security layers to prevent misuse while keeping MATLAB accessible to AI agents. This page documents authentication, authorization, input validation, secure deployment practices, and vulnerability reporting.
graph TD
A["HTTP Request / stdio Message"] -->|Bearer Token| B["BearerAuthMiddleware"]
B -->|Validation via HMAC| C{"Token Valid?"}
C -->|No| D["401 Unauthorized"]
C -->|Yes| E["MCP Layer"]
E -->|Code Submission| F["SecurityValidator"]
F -->|Blocked Fn Check| G{"Function Safe?"}
G -->|No| H["BlockedFunctionError"]
G -->|Yes| I["SessionManager"]
I -->|Workspace Isolation| J["EnginePoolManager"]
J -->|Acquire Engine| K["Execute in Session"]
K -->|Result| L["ResultFormatter"]
L -->|Sanitize Output| M["Send Response"]
style A fill:#e1f5ff
style B fill:#fff3e0
style F fill:#f3e5f5
style I fill:#e8f5e9
style M fill:#fce4ec
The server enforces HTTP Bearer token authentication on HTTP and SSE transports. The stdio transport does not use HTTP and therefore bypasses HTTP-level auth (suitable for local, single-user, or containerized scenarios where network isolation is provided externally).
Tokens are read exclusively from the MATLAB_MCP_AUTH_TOKEN environment variable at server startup:
# Generate a 64-character random token
MATLAB_MCP_AUTH_TOKEN=$(python -c "import secrets; print(secrets.token_hex(32))")
# Export for the server process
export MATLAB_MCP_AUTH_TOKEN
# Start the server
python -m matlab_mcp --transport streamablehttpOr use the built-in --generate-token flag:
$ python -m matlab_mcp --generate-token
Generated token (copy to your environment):
MATLAB_MCP_AUTH_TOKEN=a7f3e2c5b9d1f4a6e8c2b7f1d4a6c9e2
For Bash/Zsh:
export MATLAB_MCP_AUTH_TOKEN=a7f3e2c5b9d1f4a6e8c2b7f1d4a6c9e2
For Windows PowerShell:
$env:MATLAB_MCP_AUTH_TOKEN='a7f3e2c5b9d1f4a6e8c2b7f1d4a6c9e2'
For Windows Command Prompt:
set MATLAB_MCP_AUTH_TOKEN=a7f3e2c5b9d1f4a6e8c2b7f1d4a6c9e2Every HTTP request must include the token in the Authorization header:
GET /mcp HTTP/1.1
Host: 127.0.0.1:8765
Authorization: Bearer a7f3e2c5b9d1f4a6e8c2b7f1d4a6c9e2
Content-Type: application/jsonToken Comparison: Uses constant-time comparison (hmac.compare_digest) to prevent timing attacks.
Bypassed Endpoints:
-
/health— Health checks do not require auth (allows monitoring tools to verify server status) -
OPTIONSrequests — CORS pre-flight requests bypass auth
Disabled-by-Default: When MATLAB_MCP_AUTH_TOKEN is not set, auth middleware is disabled and all requests are accepted (suitable for development or when network-level auth is provided externally).
Valid token:
HTTP/1.1 200 OK
Content-Type: application/json
(MCP response body)Invalid/missing token:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="MATLAB MCP Server"
Content-Type: application/json
{"error": "Invalid or missing Authorization header"}For browser-based agents and cross-origin requests:
server:
cors_origins: "*" # Allow any origin
cors_methods: ["GET", "POST", "OPTIONS"]
cors_allow_credentials: falseAll HTTP and SSE transports automatically wire CORS middleware (Starlette CORSMiddleware) to handle preflight requests.
Before executing any MATLAB code, the SecurityValidator performs static analysis:
By default, these MATLAB functions are blocked to prevent privilege escalation, code injection, and system compromise:
| Function | Risk | Example Block |
|---|---|---|
system() |
Execute arbitrary OS commands | system('rm -rf /') |
unix() |
Execute Unix shell commands | unix('curl malicious.com') |
dos() |
Execute DOS/Windows commands | dos('del C:\Windows\System32') |
! |
Shell escape operator | !shutdown /s |
eval() |
Execute arbitrary string as code | eval(['delete(' file ')']) |
feval() |
Call function by name (dynamic) | feval(user_input) |
evalc() |
Evaluate and capture output | evalc(user_input) |
evalin() |
Evaluate in caller/base workspace | evalin('base', code) |
assignin() |
Assign variables in other workspaces | assignin('base', 'x', user_var) |
perl() |
Execute Perl scripts | perl('system("ls -la")') |
python() |
Execute Python scripts | `python('os.system("...")') |
web() |
Open external browser (SSRF risk) | web('http://internal-server') |
The validator strips string literals and comments before checking, preventing false positives:
% These are SAFE and will NOT be blocked:
title('The system is great') % "system" inside a string
msg = "unix-based"; % "unix" inside string literal
% system('ls') % "system" inside comment
disp('Running: system(''id'')') % Nested quotes, still a string
% This WILL be blocked:
result = system('whoami') % Actual function call
cmd = '!ls'; eval(cmd) % Indirect eval of shell commandIn config.yaml:
security:
blocked_functions_enabled: true # Set false to disable entirely
blocked_functions: # Override defaults
- "system"
- "unix"
- "dos"
- "!"
- "eval"
- "feval"
- "evalc"
- "evalin"
- "assignin"
- "perl"
- "python"
- "web"Or via environment variable:
# Disable blocking entirely (not recommended for production)
export MATLAB_MCP_SECURITY_BLOCKED_FUNCTIONS_ENABLED=false
# Or set a custom list (JSON array)
export MATLAB_MCP_SECURITY_BLOCKED_FUNCTIONS='["system", "eval"]'security:
max_upload_size_mb: 100 # Default: 100 MB per fileUploads exceeding this limit are rejected before writing to disk.
Filenames are restricted to alphanumeric characters, dots, hyphens, and underscores to prevent:
-
Path traversal:
../../etc/passwd→ rejected - Control character injection: NULL bytes, newlines → rejected
-
OS-specific attacks:
:in Windows, leading-in shell commands → rejected
Allowed characters: [a-zA-Z0-9._-]
Examples:
% These are ALLOWED:
upload_data('measurement_2024-03-15.csv')
upload_data('signal-processing_v1.0.mat')
% These are BLOCKED:
upload_data('../../../etc/passwd') % Path traversal
upload_data('data\nmalicious') % Newline injection
upload_data('file\x00.mat') % Null byte injectionEach session runs in an isolated MATLAB workspace. Between sessions (when workspace_isolation: true, the default), the server executes:
clear all; % Clear all variables
clear global; % Clear global variables
clear functions; % Clear persistent function state
fclose all; % Close all file handles
restoredefaultpath; % Reset MATLAB path to defaultsThis ensures one user's variables, loaded functions, and file handles do not leak to another user in a multi-user deployment.
execution:
workspace_isolation: true # Always keep this enabled in shared deploymentsserver:
transport: "streamablehttp" # "stdio" | "sse" | "streamablehttp"
host: "127.0.0.1" # Default: localhost only (prevents Windows Firewall popups)
port: 8765 # Any port > 1024 (no admin needed on Windows)
security:
require_proxy_auth: false # Set true if behind a reverse proxy with auth| Option | Default | Purpose |
|---|---|---|
transport |
"stdio" |
Transport mode (see best practices below) |
host |
"127.0.0.1" |
Bind address (loopback = no firewall issues on Windows) |
require_proxy_auth |
false |
Suppress warning if auth is handled by reverse proxy |
security:
blocked_functions_enabled: true
blocked_functions: [...]
execution:
workspace_isolation: true
sync_timeout: 5.0 # Seconds (prevents hung jobs)
pool:
health_check_interval: 30 # Seconds (detect crashed engines)security:
max_upload_size_mb: 100 # Prevent disk exhaustion
execution:
temp_dir: "/tmp/matlab_mcp" # Session-isolated subdirectoriessessions:
max_sessions: 100 # Prevent resource exhaustion
session_timeout: 3600 # 1 hour idle timeout
temp_cleanup_on_disconnect: true # Delete session files when session endsmonitoring:
enabled: true
metrics_db: "monitoring/metrics.db" # SQLite backend
server:
log_level: "INFO" # Set "DEBUG" for detailed audit logsSuitable when the developer runs the server and agent on the same machine:
server:
transport: "stdio"Security profile:
- ✅ No network exposure
- ✅ No auth needed (OS-level isolation)
- ✅ Simplest setup
Recommended for: Claude Code desktop, Cursor, personal projects
Suitable when multiple team members need access via a shared server:
server:
transport: "streamablehttp"
host: "127.0.0.1"
port: 8765
security:
require_proxy_auth: true # Acknowledge reverse proxy handles authNetwork setup:
[Agent on Engineer's Machine]
↓ (HTTPS)
[Reverse Proxy (nginx/Caddy)]
├─ TLS termination
├─ Authentication (OAuth 2.0, OIDC, Basic Auth)
├─ Rate limiting
└─ Logging/audit
↓ (HTTP, localhost only)
[MATLAB MCP Server (127.0.0.1:8765)]
Reverse proxy example (nginx):
server {
listen 443 ssl;
server_name matlab-mcp.company.com;
ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/private/key.pem;
auth_request /oauth2/auth; # Your auth handler
location / {
proxy_pass http://127.0.0.1:8765;
proxy_set_header Authorization $http_authorization;
proxy_read_timeout 300s; # Jobs may take time
proxy_http_version 1.1;
}
}Security profile:
- ✅ TLS encryption in transit
- ✅ User authentication at proxy layer
- ✅ Bearer token auth inside server (defense-in-depth)
- ✅ No firewall exceptions needed
⚠️ Proxy must trust the server (use internal network or VPN)
Recommended for: Team deployments, CI/CD integration, Codex CLI
For agents that need remote access via untrusted networks:
server:
transport: "streamablehttp"
host: "0.0.0.0" # Only if using reverse proxy with TLS
port: 8765
security:
max_upload_size_mb: 50 # Stricter limits for untrusted clients
blocked_functions_enabled: true
blocked_functions: [...] # Review for your use caseNetwork setup:
[Remote Agent]
↓ (HTTPS via TLS Terminator)
[Cloudflare / AWS API Gateway / nginx]
├─ TLS encryption (mandatory)
├─ OAuth 2.0 / OIDC (mandatory)
├─ Rate limiting
├─ DDoS protection
└─ IP whitelisting (if possible)
↓ (HTTP, internal network)
[MATLAB MCP Server]
Environment:
# Set strong token (64+ characters of random data)
export MATLAB_MCP_AUTH_TOKEN=$(python -c "import secrets; print(secrets.token_hex(32))")
# Minimal engine pool (fewer engines = fewer resource risks)
export MATLAB_MCP_POOL_MIN_ENGINES=1
export MATLAB_MCP_POOL_MAX_ENGINES=4
# Short timeouts (prevent hung jobs consuming resources)
export MATLAB_MCP_EXECUTION_SYNC_TIMEOUT=10
# Aggressive session cleanup
export MATLAB_MCP_SESSIONS_SESSION_TIMEOUT=600 # 10 minutes
export MATLAB_MCP_SESSIONS_TEMP_CLEANUP_ON_DISCONNECT=trueSecurity profile:
- ✅✅✅ TLS encryption (mandatory)
- ✅✅✅ OAuth 2.0 user authentication (mandatory)
- ✅ Bearer token server-side auth (defense-in-depth)
⚠️ High-trust infrastructure required⚠️ Monitor for abuse
Recommended for: Enterprise integrations with external parties, public APIs, SaaS deployments
The server defaults to 127.0.0.1 binding to avoid Windows Firewall UAC prompts when running without admin rights:
server:
host: "127.0.0.1" # Never change this to "0.0.0.0" unless absolutely needed
port: 8765Why loopback?
- ✅ No Firewall exception required
- ✅ No UAC prompts
- ✅ No admin rights needed
⚠️ Only accessible from the same machine
If you need remote access on Windows, use a reverse proxy on a higher-privilege host that connects back to 127.0.0.1:8765.
FROM python:3.11-slim
# Install MATLAB Engine (or skip for inspect-only mode)
COPY matlab-engine.whl /tmp/
RUN pip install /tmp/matlab-engine.whl
# Install MCP server
RUN pip install matlab-mcp-python[monitoring]
# Copy config
COPY config.yaml /app/config.yaml
# Run with bearer token from env
ENV MATLAB_MCP_AUTH_TOKEN=${AUTH_TOKEN}
ENV MATLAB_MCP_POOL_MIN_ENGINES=2
ENV MATLAB_MCP_POOL_MAX_ENGINES=8
EXPOSE 8765
CMD ["python", "-m", "matlab_mcp", "--config", "/app/config.yaml", "--transport", "streamablehttp"]Kubernetes secret:
kubectl create secret generic matlab-mcp-auth \
--from-literal=token=$(python -c "import secrets; print(secrets.token_hex(32))")
# Reference in pod spec:
# env:
# - name: MATLAB_MCP_AUTH_TOKEN
# valueFrom:
# secretKeyRef:
# name: matlab-mcp-auth
# key: tokenIf you discover a security vulnerability in the MATLAB MCP Server, please report it responsibly:
- ❌ Open a public GitHub issue with vulnerability details
- ❌ Post in discussions or forums
- ❌ Email the maintainer's personal account (no guarantee of response)
-
✅ Email security@example.com with:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (optional)
-
✅ Allow 7–14 days for a response
-
✅ Expect an acknowledgment, timeframe, and patch schedule
-
✅ Coordinate public disclosure with the maintainers after a fix is available
- Day 1–3: Acknowledgment and initial triage
- Day 7–14: Fix verified in development branch
- Day 14–21: Fix released in a patch version
- Day 21: Public disclosure (GitHub advisory, release notes)
| Version | Status | Security Updates |
|---|---|---|
| 2.x (current) | Active | Yes, security patches released within 7 days |
| 1.x | Maintenance | Critical issues only, no minor fixes |
| 0.x | EOL | No updates |
Use this checklist before deploying to production:
-
Authentication
-
MATLAB_MCP_AUTH_TOKENis set to a 64+ character random value - Token is stored securely (K8s secret, env var, not in config file)
- All HTTP/SSE endpoints behind TLS (reverse proxy or mTLS)
-
-
Authorization
- Reverse proxy authenticates users before routing to server
- Session timeout is set appropriately for your use case
- Max sessions limit prevents resource exhaustion
-
Code Safety
-
blocked_functions_enabled: true(default) - Blocklist reviewed for your MATLAB use case
-
workspace_isolation: true(always in multi-user)
-
-
File Operations
-
max_upload_size_mbset to a sensible limit - Session temp directories cleaned up on disconnect
- No world-writable paths in
temp_dir
-
-
Deployment
- Server bound to
127.0.0.1(unless behind reverse proxy) - TLS enabled on reverse proxy (HTTPS, not HTTP)
- Rate limiting configured at proxy layer
- Monitoring/alerting enabled for failed authentications
- Server bound to
-
Monitoring
-
monitoring.enabled: true - SQLite metrics database on a persistent volume
- Alerts configured for:
- High error rates
- Engine pool exhaustion
- Repeated failed authentications
- Large uploads
-
-
Documentation
- Deployment architecture documented
- Incident response plan in place
- Maintainers aware of production deployments
- MATLAB Engine Safety: Mathworks documentation on workspace isolation
- Web Security: OWASP Top 10
- Token-Based Auth: RFC 6750 OAuth 2.0 Bearer Token
- TLS Best Practices: Mozilla SSL Configuration Generator