-
Notifications
You must be signed in to change notification settings - Fork 0
Security
The MATLAB MCP server implements security across multiple layers: HTTP authentication, MATLAB code validation, workspace isolation, and file upload protection. This page documents the complete security posture.
graph TB
Client["AI Agent Client"]
Auth["BearerAuthMiddleware<br/>(HTTP Layer)"]
MCP["FastMCP Server<br/>(MCP Protocol)"]
CodeVal["SecurityValidator<br/>(MATLAB Code)"]
Engine["MATLAB Engine<br/>(Workspace)"]
Client -->|Bearer Token| Auth
Auth -->|401 if Invalid| Client
Auth -->|Valid Token| MCP
MCP -->|execute_code| CodeVal
CodeVal -->|Blocked?| Client
CodeVal -->|Safe Code| Engine
Engine -->|Result| MCP
MCP -->|Response| Client
The server enforces HTTP bearer token authentication on all HTTP/SSE transports. Tokens are never stored in config files — only in the MATLAB_MCP_AUTH_TOKEN environment variable.
Generate a new 64-character hex token using the CLI:
matlab-mcp --generate-tokenOutput:
Generated bearer token: a1b2c3d4e5f6...7z8y9x0w
Export it as:
BASH/POSIX:
export MATLAB_MCP_AUTH_TOKEN="a1b2c3d4e5f6...7z8y9x0w"
Windows CMD:
set MATLAB_MCP_AUTH_TOKEN=a1b2c3d4e5f6...7z8y9x0w
Windows PowerShell:
$env:MATLAB_MCP_AUTH_TOKEN="a1b2c3d4e5f6...7z8y9x0w"
On every HTTP request, the middleware:
- Extracts the
Authorizationheader - Checks for the format
Bearer <token> - Compares the token using constant-time comparison (
hmac.compare_digest) to prevent timing attacks - Returns HTTP 401 with
WWW-Authenticate: Bearer realm="MATLAB MCP Server"header if invalid
Invalid requests return:
{
"error": "unauthorized",
"message": "Invalid or missing bearer token"
}-
/health— Health check for load balancers (no auth required) -
OPTIONS *— CORS preflight requests (no auth required) -
stdiotransport — Single-user mode, no HTTP layer, no auth needed
If MATLAB_MCP_AUTH_TOKEN is not set, authentication is disabled:
# No token env var set → auth disabled
matlab-mcp --transport streamablehttp
# Server binds to http://127.0.0.1:8765/mcp with no authWarning: This is only safe for single-user, localhost-only deployments.
For secure HTTP deployments:
# Generate and export token
export MATLAB_MCP_AUTH_TOKEN=$(python -c "import secrets; print(secrets.token_hex(32))")
# Start server with auth enabled
matlab-mcp --transport streamablehttpAgent examples with bearer token:
# Claude Code (claude_desktop_config.json)
{
"mcpServers": {
"matlab": {
"command": "bash",
"args": ["-c", "MATLAB_MCP_AUTH_TOKEN=$MATLAB_MCP_AUTH_TOKEN matlab-mcp --transport stdio"],
"env": {
"MATLAB_MCP_AUTH_TOKEN": "your-token-here"
}
}
}
}# Codex CLI (mcp.toml)
[[mcpServers]]
name = "matlab"
type = "streamable-http"
url = "http://127.0.0.1:8765/mcp"
headers = { "Authorization" = "Bearer your-token-here" }By default, these dangerous MATLAB functions are blocked:
| Function | Risk | Alternative |
|---|---|---|
system() |
Execute arbitrary OS commands | Use MATLAB built-ins instead |
unix() |
Execute Unix commands | Use built-ins |
dos() |
Execute DOS/Windows commands | Use built-ins |
! |
Shell escape operator | Use built-ins |
eval() |
Execute arbitrary string as code | Use feval() with safe inputs |
feval() |
Dynamic function calls by name | Pre-whitelist function names |
evalc() |
Evaluate and capture output | Use explicit output variables |
evalin() |
Evaluate in arbitrary scope | Avoid cross-scope execution |
assignin() |
Assign variables in arbitrary scope | Use function outputs instead |
perl() |
Execute Perl scripts | Not available, skip |
python() |
Execute Python scripts | Not available, skip |
The validator strips string literals and comments before scanning, preventing false positives:
% ✓ SAFE — "system" is in a comment:
% The system() function is dangerous
% ✓ SAFE — "system" is in a string:
msg = 'Operating system type';
% ✗ BLOCKED — actual function call:
system('ls -la')Override the default blocklist in config.yaml:
security:
blocked_functions_enabled: true
blocked_functions:
- "system"
- "unix"
- "dos"
- "!"
- "eval"
- "feval"
- "evalc"
- "evalin"
- "assignin"
- "perl"
- "python"
- "web" # Add custom entries here
- "importdata" # Example: block if neededSet blocked_functions_enabled: false to disable validation entirely (not recommended for multi-user deployments):
security:
blocked_functions_enabled: false # Disables ALL code validationWhen workspace_isolation: true (default), the server clears variables between sessions:
clear all; % Remove all local variables
clear global; % Remove global variables
clear functions; % Clear function definitions
fclose all; % Close open files
restoredefaultpath; % Reset MATLAB search pathThis prevents one session's variables, functions, and file handles from leaking to another.
- stdio transport: Single session, single temp directory (shared across all code)
- HTTP/SSE transport: Each client gets a unique session with its own temp directory
- Stateless HTTP mode: Each request gets an ephemeral temp directory (deleted after response)
Sessions expire after session_timeout seconds of inactivity (default 3600 = 1 hour). Expired sessions are cleaned up automatically, and their temp files are deleted if temp_cleanup_on_disconnect: true (default).
Configure the maximum upload size in config.yaml:
output:
max_upload_size_mb: 100 # Default: 100MBUploads exceeding this limit are rejected with an error.
Uploaded and downloaded filenames are validated against injection attacks:
-
Allowed characters:
[a-zA-Z0-9._-] -
Path traversal blocked: Filenames like
../../etc/passwdare rejected -
Absolute paths rejected: Filenames starting with
/orC:\are rejected
Example rejected filenames:
../../etc/passwd ✗ Path traversal
/etc/passwd ✗ Absolute path
C:\Windows\System32 ✗ Absolute path
file<script>.mat ✗ Invalid characters
Allowed filenames:
data.mat ✓
my-simulation.xlsx ✓
results_2024_01.csv ✓
When configured, the server can prompt an operator for approval before executing sensitive operations:
hitl:
approval_gates: true # Enable HITL
approve_all_execute: false # Require approval for every code execution
approve_protected_functions: true # Require approval for dangerous ops
approve_file_operations: true # Require approval for uploads/deletesProtected functions include those in the blocklist plus I/O operations (fopen, save, load, etc.).
When approval is required, the MCP server pauses execution and waits for human approval via the HumanApproval elicitation:
{
"type": "elicit",
"name": "HumanApproval",
"title": "Approve Code Execution",
"description": "Agent wants to execute: clf; plot(x, y); ylabel('Value')",
"fields": {
"approved": {
"type": "boolean",
"description": "Approve this action?"
}
}
}All sensitive settings can be overridden via environment variables using the MATLAB_MCP_* prefix:
# Override auth token
export MATLAB_MCP_AUTH_TOKEN="your-secret-token"
# Override session timeout
export MATLAB_MCP_SESSION_TIMEOUT=7200
# Override blocked functions
export MATLAB_MCP_BLOCKED_FUNCTIONS="system,eval"Environment variables always take precedence over config.yaml, so you can commit a safe default config and override it securely at runtime.
Store config.yaml with restricted permissions:
chmod 600 config.yaml # Only owner can readIf the file contains any token-like field (deprecated pattern), the server logs a WARNING at startup:
WARNING: Potential token found in config.yaml. Use MATLAB_MCP_AUTH_TOKEN env var instead.
server:
transport: "stdio" # Single process, no auth needed
host: "127.0.0.1"
security:
blocked_functions_enabled: true # Default blocklist
workspace_isolation: trueAuth: Not needed (stdio has no HTTP layer).
server:
transport: "streamablehttp"
host: "127.0.0.1" # Loopback only; agents on same machine
port: 8765
security:
blocked_functions_enabled: true
workspace_isolation: true
max_upload_size_mb: 100Auth: Recommended. Generate a shared token and distribute via environment variable or secrets manager.
Networking: Place behind a reverse proxy (nginx, Caddy) with TLS if exposing to multiple machines.
server:
transport: "streamablehttp"
host: "127.0.0.1" # Reverse proxy only
port: 8765 # Not exposed directly
security:
blocked_functions_enabled: true
blocked_functions:
# Extend with company-specific blocks
- "system"
- "eval"
- "fopen" # Prevent file I/O if not needed
workspace_isolation: true
max_upload_size_mb: 50
hitl:
approval_gates: true
approve_protected_functions: true
approve_file_operations: trueAuth: Required. Use MATLAB_MCP_AUTH_TOKEN environment variable with a strong, randomly generated token. Rotate tokens periodically by restarting the server with a new token.
Networking:
- Reverse proxy (nginx/Caddy) with TLS termination
- Restrict network access to approved subnets
- Monitor logs for failed auth attempts
- Use firewall rules to whitelist agent sources
Monitoring:
- Enable metrics collection (
monitoring.enabled: true) - Log all code execution (
tools.execute_code.log_all: true) - Set up alerting on:
- Blocked function attempts
- Failed auth attempts (HTTP 401)
- Sessions exceeding time limits
- Errors in MATLAB execution
-
MATLAB MCP logs: Controlled by
server.log_leveland printed to stderr - HTTP access logs: Captured by reverse proxy (if deployed)
-
Metrics & events: Stored in SQLite at
monitoring.database_path(default:.matlab_mcp/metrics.db)
Failed auth attempts:
grep "401\|Unauthorized" /var/log/nginx/access.logBlocked function attempts:
grep "BlockedFunctionError\|blocked" matlab_mcp.logSession abuse (many sessions from one IP):
grep "session_id\|Session" matlab_mcp.log | uniq -c | sort -rn-
Revoke compromised token: Stop the server, generate a new token, restart with new
MATLAB_MCP_AUTH_TOKEN - Review logs: Check which code was executed during compromise window
- Reset workspace: Restart the server to clear all sessions and temporary files
-
Update blocklist: Add any functions discovered in the attack to
blocked_functions
| Limitation | Impact | Mitigation |
|---|---|---|
| Regex-based code validation | Sophisticated regex evasion possible (e.g., eval_ aliased via feval) |
Use in conjunction with reverse proxy auth; assume agents are semi-trusted |
| No code sandboxing | Blocked code can still be executed via workarounds | Run on isolated machine; use Linux namespaces / containers if available |
| Tokens are static | Token compromise requires server restart to revoke | Rotate tokens regularly; monitor for failed auth attempts |
| No audit logging | Cannot track which agent executed which code | Enable metrics (monitoring.enabled: true) for metadata; add syslog integration |
| Transport | Auth | TLS | Use Case |
|---|---|---|---|
| stdio | None (by design) | N/A | Single-user, local development only |
| SSE (deprecated) | Optional middleware | Requires reverse proxy | Legacy multi-user, not recommended |
| Streamable HTTP | Bearer token required | Requires reverse proxy | Multi-user, recommended |
- Use environment variables for all secrets — Never commit tokens to config.yaml
-
Require bearer tokens on all HTTP deployments — Set
MATLAB_MCP_AUTH_TOKENbefore starting - Use a reverse proxy with TLS — Encrypt tokens in transit
-
Enable workspace isolation —
workspace_isolation: true(default) - Monitor blocked function attempts — Log them and investigate
- Rotate tokens periodically — At least quarterly; more often if shared across teams
- Restrict the blocklist thoughtfully — Over-blocking breaks legitimate use; under-blocking is a security risk
- Use HITL approval gates for sensitive operations — Require human sign-off on protected functions in production
- Segregate production instances — Don't share a server between teams; use network isolation
- Keep MATLAB updated — Security patches are released regularly
- Configuration Reference — All security-related settings
- Troubleshooting — Debug auth failures
- Architecture — How security validation integrates into the execution flow