-
Notifications
You must be signed in to change notification settings - Fork 0
Security
The MATLAB MCP server implements multi-layered security controls to enable safe code execution while protecting against misuse. This page covers authentication, authorization, code validation, and operational hardening.
graph TB
subgraph "Client Layer"
Agent["AI Agent<br/>(Claude, Codex, Cursor)"]
HTTP["HTTP/SSE Request<br/>with Bearer Token"]
end
subgraph "Authentication Layer"
Auth["BearerAuthMiddleware<br/>(Starlette ASGI)"]
AuthDB["Token Validation<br/>(MATLAB_MCP_AUTH_TOKEN)"]
end
subgraph "Session & Authorization"
Session["Session Manager<br/>(Workspace Isolation)"]
Scope["Tool Scope Check<br/>(execute vs admin)"]
end
subgraph "Code Security Layer"
Validator["SecurityValidator<br/>(MATLAB Code Analysis)"]
Blocklist["Blocked Functions<br/>(system, unix, eval, ...)"]
StringStrip["String Literal Stripping<br/>(Avoid False Positives)"]
end
subgraph "Execution & Output"
Executor["JobExecutor<br/>(Sandboxed Execution)"]
Output["Result Formatting<br/>(No Code Leakage)"]
end
subgraph "Infrastructure"
Cleanup["Session Cleanup<br/>(Temp Dir Removal)"]
Audit["Audit Logging<br/>(Events & Metrics)"]
end
Agent -->|Plain HTTP| HTTP
HTTP -->|401 if missing/invalid| Auth
Auth --> AuthDB
AuthDB -->|Valid token| Session
Session --> Scope
Scope -->|Check tool access| Validator
Validator --> Blocklist
Blocklist --> StringStrip
StringStrip -->|Approved code| Executor
Executor --> Output
Output --> Agent
Executor --> Cleanup
Validator --> Audit
Audit --> Cleanup
All HTTP-based transports (streamable HTTP and SSE) enforce bearer token authentication via the BearerAuthMiddleware class.
-
Client sends request with
Authorization: Bearer <token>header -
Middleware validates token against the configured secret (from
MATLAB_MCP_AUTH_TOKENenvironment variable) - Valid token → request proceeds to MCP layer
- Invalid/missing token → server returns HTTP 401 JSON response
# Generate a secure token
matlab-mcp --generate-token
# Output:
# Bearer Token: 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
#
# Add to your shell:
# export MATLAB_MCP_AUTH_TOKEN=1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p-
Environment variable (recommended):
MATLAB_MCP_AUTH_TOKEN- Set once per deployment; rotation requires updating env vars
- Works in Docker, K8s, systemd, supervisord, CI/CD pipelines
- Example:
export MATLAB_MCP_AUTH_TOKEN="your-64-char-hex-token" matlab-mcp --transport streamable-http
-
Never in config files: Config files can be accidentally committed. Always use environment variables.
- Type: 64-character hex string (256 bits of entropy)
-
Generated via:
secrets.token_hex(32)(cryptographically secure) -
Comparison: Constant-time comparison using
hmac.compare_digest()(prevents timing attacks)
The following endpoints bypass authentication to support health checks and monitoring:
-
GET /health— health status (HTTP 200 or 503) -
OPTIONS *— CORS pre-flight (allows browser-based clients)
All other endpoints require a valid bearer token.
(Planned for v2.1)
Tools will be grouped into two scopes:
| Scope | Tools | Use Case |
|---|---|---|
execute |
execute_code, check_code, get_workspace, upload_data, delete_file, list_files, read_*, custom tools |
AI agents executing code |
admin |
get_pool_status, cancel_job, server lifecycle commands |
Server operators only |
For now, all authenticated users have full access. Future versions will support granular token claims.
| Transport | Auth Required | Notes |
|---|---|---|
| stdio | No | Single-user, local only. Auth not applicable. |
| streamable-http | Yes | Recommended for remote agents. Bearer token enforced. |
| sse (deprecated) | Yes | Legacy multi-user transport. Bearer token enforced. |
All user-provided MATLAB code is validated before execution using the SecurityValidator class.
The validator checks code against a default blocklist:
security:
blocked_functions_enabled: true
blocked_functions:
- "system" # Execute OS commands
- "unix" # Execute Unix commands
- "dos" # Execute DOS/Windows commands
- "!" # Shell escape operator
- "eval" # Execute arbitrary string as MATLAB code
- "feval" # Call function by string name
- "evalc" # Evaluate with captured output
- "evalin" # Evaluate in different workspace
- "assignin" # Assign variable in different workspace
- "perl" # Execute Perl scripts
- "python" # Execute Python scripts
- "web" # Open web browserTo avoid false positives, the validator removes string literals and comments before checking:
% This is SAFE — "system" is in a comment and string:
disp('The operating system is great') % Safe
msg = "Using system() in strings"; % Safe
% This is BLOCKED — actual function call:
system('rm -rf /') % Blocked!The _strip_string_literals() helper removes:
- Single-quoted strings:
'string' - Double-quoted strings:
"string" - Line comments:
% comment - Block comments:
%{ ... %}
# Disable blocking entirely (not recommended)
security:
blocked_functions_enabled: false
# Extend the blocklist
security:
blocked_functions_enabled: true
blocked_functions:
- "system"
- "unix"
- "dos"
- "!"
- "eval"
- "feval"
- "evalc"
- "evalin"
- "assignin"
- "perl"
- "python"
- "web"
- "writefile" # Add custom blocks as needed
- "writetable"File uploads and deletions are validated against path traversal and invalid characters:
# Valid filenames:
"data.mat" # OK
"my_results_v2.csv" # OK
"figure_2024-01.png" # OK
# Invalid filenames:
"../../etc/passwd" # Path traversal — REJECTED
"file\nname.txt" # Newline — REJECTED
"file$name.mat" # $ character — REJECTEDAllowed characters: [a-zA-Z0-9._-] (alphanumeric, dot, underscore, hyphen)
When executing code, the server injects read-only context variables:
__mcp_job_id__ % Unique job identifier (UUID)
__mcp_session_id__ % Session identifier
__mcp_temp_dir__ % Session temp directory pathThese enable helper functions like mcp_progress() to report progress without user input.
server:
host: "127.0.0.1" # Bind to localhost by default (no Windows firewall UAC)
port: 8765 # IANA registered port for MCP
transport: "streamable-http" # Recommended: "stdio", "streamable-http", or "sse"Recommendation: Default 127.0.0.1 prevents accidental network exposure. Change to 0.0.0.0 only when deploying behind a reverse proxy with authentication.
security:
blocked_functions_enabled: true
blocked_functions: [...] # See "Blocked Functions" section above
workspace_isolation: true # Clear workspace between sessions
upload_max_size_mb: 100 # Max file upload size
filename_max_length: 255 # Max filename lengthWorkspace isolation is critical for multi-user deployments. When enabled:
clear all
clear global
clear functions
fclose all
restoredefaultpathsession:
max_sessions: 50 # Prevent resource exhaustion
session_timeout_seconds: 3600 # 1 hour idle timeout
temp_cleanup_on_disconnect: true # Delete temp files when session endsmonitoring:
enabled: true
store_path: "metrics.db" # SQLite for audit log
events:
- "execution_started"
- "execution_completed"
- "execution_failed"
- "blocked_function_attempt" # Logged when validator blocks code
- "upload_attempted"
- "session_created"
- "session_destroyed"# Single-user, no network exposure
matlab-mcp --transport stdio
# No authentication needed; socket-based communication with local tool# config.yaml
server:
transport: "streamable-http"
host: "0.0.0.0"
port: 8765
security:
blocked_functions_enabled: true
workspace_isolation: true
require_proxy_auth: false # You're using bearer token instead# Terminal
export MATLAB_MCP_AUTH_TOKEN="your-secure-token"
matlab-mcp --config config.yamlNetwork setup:
- Deploy on a private network (VPN, intranet, corporate LAN)
- Share the bearer token via secure channel (1Password, Vault, GitOps secret)
- Agents connect with:
http://internal-host:8765/mcp
# config.yaml
server:
transport: "streamable-http"
host: "127.0.0.1" # Bind to localhost ONLY
port: 8765
security:
blocked_functions_enabled: true
workspace_isolation: trueNetwork setup:
-
Reverse proxy (nginx, Caddy, Traefik) with:
- TLS termination (HTTPS)
- Reverse proxy auth (Basic Auth, OAuth2, API key validation)
- Rate limiting
- Server receives traffic from proxy only, never from internet directly
-
Agents connect via:
https://your-domain.com/mcp
Example nginx config:
server {
listen 443 ssl;
server_name your-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location /mcp {
# Require Authorization header (agent sets this)
auth_request /validate_token;
proxy_pass http://127.0.0.1:8765;
proxy_set_header Authorization $http_authorization;
proxy_set_header Host $host;
}
location /validate_token {
# Custom auth validation (can call external service)
proxy_pass http://auth-service:9000;
}
}FROM python:3.12-slim
# Install MATLAB Engine API
COPY matlab_engine*.tar.gz /tmp/
RUN pip install /tmp/matlab_engine*.tar.gz
# Install MCP server
RUN pip install matlab-mcp-python
# Non-root user
RUN useradd -m matlab_mcp
USER matlab_mcp
EXPOSE 8765
# Token from environment variable
CMD ["matlab-mcp", "--transport", "streamable-http", "--host", "0.0.0.0"]Run with:
docker run \
-e MATLAB_MCP_AUTH_TOKEN="your-token" \
-e MATLAB_ROOT="/opt/matlab" \
-v /opt/matlab:/opt/matlab:ro \
-p 8765:8765 \
matlab-mcp:latestapiVersion: v1
kind: Secret
metadata:
name: matlab-mcp-auth
type: Opaque
stringData:
token: "your-secure-token"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: matlab-mcp
spec:
replicas: 1 # Elastic engine pool doesn't scale horizontally
selector:
matchLabels:
app: matlab-mcp
template:
metadata:
labels:
app: matlab-mcp
spec:
containers:
- name: mcp
image: matlab-mcp:latest
env:
- name: MATLAB_MCP_AUTH_TOKEN
valueFrom:
secretKeyRef:
name: matlab-mcp-auth
key: token
ports:
- containerPort: 8765
resources:
requests:
memory: "2Gi"
cpu: "1"
limits:
memory: "4Gi"
cpu: "2"
livenessProbe:
httpGet:
path: /health
port: 8765
initialDelaySeconds: 30
periodSeconds: 10If you discover a security vulnerability in the MATLAB MCP server:
- Do NOT open a public GitHub issue
-
Email: security@hansur94.dev with:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if you have one)
We aim to respond within 48 hours and will coordinate a fix and disclosure timeline with you.
- Private disclosure period: Up to 90 days
- Credit: Your name/organization in release notes (if desired)
- CVE request: We will request a CVE for critical vulnerabilities
- Public disclosure: GitHub Security Advisory after fix is released
| Issue | Status | Workaround |
|---|---|---|
| Regex-based code validation (not a parser) | By design | Enable auto_check_before_execute: true in config |
| SSE transport deprecated | v2.0+ | Use streamable-http instead |
| No token rotation during runtime | Planned v2.1 | Restart server to rotate tokens |
| No per-tool scopes (yet) | Planned v2.1 | Use admin tokens carefully |
- Configuration — Full config reference
- Windows Deployment — No-admin setup guide
- Troubleshooting — Debug auth and security issues