The MCP DevTools security framework provides a layer protection to help protect against malicious content, unauthorised file access, and dangerous network requests. It operates as a configurable, multi-layered security framework that can be enabled or disabled as needed.
You should never trust the security framework alone to protect you, it is designed to be a first line of defence and should be used in conjunction with other security measures and secure agentic coding practices.
Important: This feature should be considered in BETA, if you find bugs and have solutions please feel free to raise a PR.
- Overview
- Architecture
- Configuration
- Security Rules
- Integration Patterns
- Enabling Security
- Security Actions
- Override System
- Performance Considerations
- Troubleshooting
- Security Caveats
The security framework provides three main layers of protection:
- Access Control: Prevents tools from accessing sensitive files and domains
- Content Analysis: Scans returned content for security threats
- Lightweight Event Audit Logging: Tracks all security events for review
The intent with the security framework is that the tool (software) fetches the content and checks there are not warn/block rules that match it and then it returns it to the AI model / AI agent so that the agent does not end up with potentially malicious content in it's context.
- Configurable Rules: YAML-based security rules with pattern matching
- Domain Filtering: Block access to dangerous or untrusted domains
- File Access Control: Prevent access to sensitive system files
- Content Scanning: Detect malicious patterns in returned content
- Override System: Allow bypassing security blocks when needed
- Performance Optimised: Minimal impact when disabled, efficient when enabled
- Graceful Degradation: Tools work normally when security is disabled
Example of the security framework blocking the tools from fetching and returning potentially malicious content to the LLM / Agent:
The security system is controlled by the ENABLE_ADDITIONAL_TOOLS environment variable and requires the security tool to be included.
# Enable security system and override tool
ENABLE_ADDITIONAL_TOOLS="security,security_override"graph TB
subgraph "MCP Tools Layer"
FT[Filesystem Tool]
WT[WebFetch Tool]
GT[GitHub Tool]
IT[Internet Search]
OT[Other Tools...]
end
subgraph "Security Helper Functions"
OPS[Operations Instance]
SHG[SafeHTTPGet/Post]
SFR[SafeFileRead/Write]
SHR[SafeHTTPResponse]
SFC[SafeFileContent]
end
subgraph "Security Integration Layer"
CFA[CheckFileAccess]
CDA[CheckDomainAccess]
AC[AnalyseContent]
ITC[isTextContent]
end
subgraph "Security Core"
SM[Security Manager]
RE[Rule Engine]
DLC[Deny List Checker]
CA[Content Analyser]
end
subgraph "Configuration Layer"
YR[YAML Rules]
PC[Pattern Compiler]
PM[Pattern Matchers]
end
subgraph "Security Components"
ST[Source Trust]
TA[Threat Analyser]
OM[Override Manager]
CACHE[Security Cache]
end
subgraph "Pattern Types"
LM[Literal Matcher]
RM[Regex Matcher]
CM[Contains Matcher]
EM[Entropy Matcher]
GM[Glob Matcher]
end
%% Tool to Helper Functions Integration
FT --> OPS
WT --> OPS
GT --> OPS
IT --> OPS
OT --> OPS
%% Helper Functions Operations
OPS --> SHG
OPS --> SFR
SHG --> SHR
SFR --> SFC
%% Helper Functions to Security Integration
SHG --> CDA
SHG --> AC
SHG --> ITC
SFR --> CFA
SFR --> AC
SFR --> ITC
%% Security Integration to Core
CFA --> SM
CDA --> SM
AC --> SM
ITC --> SM
%% Security Manager Components
SM --> RE
SM --> DLC
SM --> CA
SM --> ST
SM --> TA
SM --> OM
SM --> CACHE
%% Rule Engine to Configuration
RE --> YR
RE --> PC
PC --> PM
%% Pattern Matchers
PM --> LM
PM --> RM
PM --> CM
PM --> EM
PM --> GM
%% Styling
classDef toolLayer fill:#E6E6FA,stroke:#756BB1,color:#756BB1
classDef helperLayer fill:#E5F5E0,stroke:#31A354,color:#31A354
classDef integrationLayer fill:#FEE0D2,stroke:#E6550D,color:#E6550D
classDef coreLayer fill:#EFF3FF,stroke:#9ECAE1,color:#3182BD
classDef configLayer fill:#FFF5EB,stroke:#FD8D3C,color:#E6550D
classDef componentLayer fill:#F2F0F7,stroke:#BCBDDC,color:#756BB1
classDef patternLayer fill:#FCE4EC,stroke:#E91E63,color:#E91E63
class FT,WT,GT,IT,OT toolLayer
class OPS,SHG,SFR,SHR,SFC helperLayer
class CFA,CDA,AC,ITC integrationLayer
class SM,RE,DLC,CA coreLayer
class YR,PC,PM configLayer
class ST,TA,OM,CACHE componentLayer
class LM,RM,CM,EM,GM patternLayer
Components:
- Security Manager: Central coordinator that manages all security operations
- Rule Engine: Loads and compiles YAML security rules into efficient matchers
- Deny List Checker: Blocks access to explicitly denied files and domains
- Content Analyser: Scans content for security threats using pattern matching
- Source Trust: Manages trusted domains and exception handling
- Override Manager: Handles security bypasses when authorised
- Pattern Matchers: Efficient pattern matching implementations for different content types
flowchart TD
U[User/Agent] --> T[MCP Tool]
T --> SM[Security Middleware]
SM --> D{Security<br>Decision}
D -->|Allow| A[✓ Return Content]
D -->|Warn| W[⚠ Log Warning<br>+ Return Content]
D -->|Block| B[🚫 Block Request<br>+ Security ID]
A --> U
W --> U
B --> OV[Override Available<br>with Security ID]
OV --> U
classDef userAgent fill:#E6F3FF,stroke:#4A90E2,color:#4A90E2
classDef tool fill:#F0E6FF,stroke:#8E44AD,color:#8E44AD
classDef security fill:#FFF0E6,stroke:#E67E22,color:#E67E22
classDef decision fill:#E8F5E8,stroke:#27AE60,color:#27AE60
classDef allow fill:#E8F5E8,stroke:#27AE60,color:#27AE60
classDef warn fill:#FFF3CD,stroke:#F39C12,color:#F39C12
classDef block fill:#F8D7DA,stroke:#E74C3C,color:#E74C3C
classDef override fill:#E1ECFF,stroke:#6C7B7F,color:#6C7B7F
class U userAgent
class T tool
class SM security
class D decision
class A allow
class W warn
class B block
class OV override
Security configuration is managed primarily through YAML files, with minimal environment variable support.
By default, the security configuration is stored at:
- Rules:
~/.mcp-devtools/security.yaml - Logs:
~/.mcp-devtools/logs/security.log(or as configured in rules file)
Override rules file path with environment variable:
MCP_SECURITY_RULES_PATH="/custom/path/security.yaml"Only minimal environment variables are supported. Most configuration is done via the YAML rules file.
| Variable | Default | Description |
|---|---|---|
MCP_SECURITY_RULES_PATH |
~/.mcp-devtools/security.yaml |
Custom rules file path |
All other configuration options are now managed through the YAML rules file configuration.
The security system provides CLI commands to help manage configuration:
# Validate security configuration
mcp-devtools security-config-validate
# Validate custom config path
mcp-devtools security-config-validate --config-path /path/to/security.yaml# Show differences between user config and default
mcp-devtools security-config-diff
# Update user config with new defaults (creates backup)
mcp-devtools security-config-diff --update
# Use custom config path
mcp-devtools security-config-diff --config-path /path/to/security.yaml --updateversion: "1.0"
metadata:
description: "MCP DevTools Security Rules"
created: "2024-01-01T00:00:00Z"
settings:
enabled: true
default_action: warn
auto_reload: true
case_sensitive: false
enable_notifications: true
max_content_size: 1024 # KB - Maximum content size to scan
max_entropy_size: 64 # KB - Maximum size for entropy analysis
size_exceeded_behaviour: allow # What to do when size limits exceeded: "allow", "warn", "block"
log_path: "" # Custom log file path (empty = default)
max_scan_size: 512 # KB - Maximum content size to scan
threat_threshold: 0.7 # Threat detection threshold
cache_enabled: true # Enable security result caching
cache_max_age: "1h" # Maximum cache age
cache_max_size: 1000 # Maximum cache entries
# Trusted sources (exception lists for rules)
trusted_domains:
- docs.docker.com
- kubernetes.io
- "*.github.io"
- golang.org
# Access Control: Completely block access to these files/domains
access_control:
deny_files:
- "~/.ssh/id_rsa"
- "~/.aws/credentials"
- "/etc/passwd"
deny_domains:
- "malicious-site.com"
- "*.suspicious-tld"
# Content Analysis Rules
rules:
# ... (see Security Rules section)The security system enforces size limits on content to prevent processing of extremely large files or responses that could impact performance. The behaviour when these limits are exceeded is configurable:
max_content_size: Maximum content size to scan for security threats (KB)max_scan_size: Maximum overall content size limit (KB)size_exceeded_behaviour: How to handle size limit violations
| Behaviour | Description | Use Case |
|---|---|---|
allow |
Log debug message and continue processing (may truncate content) | Default - backward compatible, permissive |
warn |
Log warning but allow processing to continue | Monitor size violations without blocking |
block |
Prevent processing entirely and return security block | Strict size enforcement |
settings:
max_content_size: 1024 # 1MB content analysis limit
max_scan_size: 512 # 512KB overall size limit
size_exceeded_behaviour: warn # Warn but allow processingWhen content exceeds limits:
- allow: Content is truncated for analysis but processing continues
- warn: Warning logged with security ID, processing continues
- block: Processing blocked with security ID for override
Security overrides can be used to bypass size limit blocks when needed.
Security rules define patterns to detect in content and actions to take when patterns match.
rule_name:
description: "Human-readable description"
patterns:
- literal: "exact string match"
- contains: "substring match"
- regex: "(?i)regex pattern"
- entropy: 6.5 # High entropy threshold
- file_path: "file path pattern"
action: warn|warn_high|block|allow|ignore
severity: low|medium|high|critical
exceptions: [trusted_domains]| Pattern Type | Description | Example |
|---|---|---|
literal |
Exact string match | "rm -rf /" |
contains |
Substring match (supports home expansion) | "~/.aws/credentials" |
regex |
Regular expression | "(?i)curl.*\|.*sh" |
entropy |
High entropy detection | 6.5 |
file_path |
File path matching | "*/etc/passwd" |
glob |
Glob pattern matching | "*.exe" |
starts_with |
Prefix matching | "http://" |
ends_with |
Suffix matching | ".exe" |
The system includes some basic built-in rules:
- Shell Injection
- Command injection via pipes (
curl | bash) - Command substitution (
$(command)) - Backtick execution (
`command`) - Base64 encoded commands
- Command injection via pipes (
- Data Exfiltration
- DNS exfiltration attempts
- Raw socket operations
- SSH command execution
- Browser credential theft
- Keychain/keyring access
- Prompt Injection
- "Ignore previous instructions" attacks
- API key/password enumeration requests
- Conversation history extraction
- Environment variable exports
- Invisible Unicode character attacks
- Persistence Mechanisms
- Launchctl persistence (macOS)
- Systemd service persistence (Linux)
- Crontab modifications
- RC script modifications
- Sensitive File References
- SSH private keys
- AWS credentials
- Database passwords
- Certificate files
These should only be seen as a starting point, you should add your own rules to cover your specific use cases and threats.
Add custom rules for specific threats:
rules:
company_secrets:
description: "Detect company secret patterns"
patterns:
- regex: "(?i)company[_-]?(api[_-]?key|secret|token)"
- contains: "ACME_CORP_SECRET"
action: block
severity: high
internal_domains:
description: "Detect internal domain references"
patterns:
- regex: ".*\\.internal\\.company\\.com"
action: warn
severity: medium
exceptions: [trusted_domains]The security system supports different action types for handling detected threats:
| Action | Behaviour | Use Case |
|---|---|---|
allow |
Allow content unconditionally | Whitelist trusted content |
block |
Block content completely | Prevent access to malicious content |
ignore |
Skip security checks | Performance optimisation |
notify |
Send notification, allow content | Alert on specific patterns |
warn_high |
Log high-priority warning | Flag dangerous but not malicious content |
warn |
Log warning, allow content | Monitor suspicious content |
The security system provides an override mechanism for bypassing security blocks when necessary.
When content is blocked, users can override the decision using the security_override tool:
{
"name": "security_override",
"arguments": {
"security_id": "sec_block_1625234567_abc123",
"justification": "This content is safe for my use case",
"duration": "1h"
}
}security_id: Unique ID from the security block messagejustification: Human-readable reason for overrideduration: How long the override is valid (e.g., "1h", "24h", "permanent")
Override Management
- Temporary Overrides: Expire after specified duration
- Audit Trail: All overrides are logged with justification
- Revocation: Overrides can be manually revoked
- Scope: Overrides apply to specific content patterns, not global bypasses
The security system is designed for minimal performance impact:
- Lazy Loading: Security components loaded only when needed
- Pattern Compilation: Regex patterns compiled once at startup
- Content Size Limits: Large content truncated before analysis
- Caching: Security analysis results cached for repeated content
- Early Termination: Stop scanning at first match for block rules
Based on performance testing:
- File Access Checks: ~1µs per check
- Domain Access Checks: ~1µs per check
- Content Analysis: 10-650µs depending on content size and complexity
- Memory Usage: <10MB for typical rule sets
- Startup Overhead: <100ms for rule compilation
settings:
max_content_size: 512 # Reduce for faster scanning
max_entropy_size: 32 # Reduce entropy analysis size
case_sensitive: false # Faster case-insensitive matchingSymptoms: Security checks not working, no security logs Solution:
- Verify
securityis inENABLE_ADDITIONAL_TOOLS - Check rules file path and permissions
- Review security logs for errors, if you don't see logs, try running the mcp server with
-dto enable debug logging
Symptoms: Legitimate content being blocked Solution:
- Add content source to
trusted_domains - Create exception patterns in rules
- Use security override for immediate access
- Adjust rule sensitivity
Symptoms: Tools responding slowly Solution:
- Reduce
max_content_sizein settings - Disable entropy analysis for large content
- Optimise regex patterns
- Enable result caching
All MCP tools that access files or make HTTP requests must integrate with the security system. There are two approaches: Helper Functions (Recommended) and Manual Integration.
The recommended approach is to use security helper functions that provide simplified APIs with automatic security integration and content integrity preservation.
import "github.com/sammcj/mcp-devtools/internal/security"
func (t *MyTool) Execute(ctx context.Context, logger *logrus.Logger, cache *sync.Map, args map[string]interface{}) (*mcp.CallToolResult, error) {
// Create operations instance for your tool
ops := security.NewOperations("my-tool")
// Secure HTTP GET with content integrity
safeResp, err := ops.SafeHTTPGet("https://example.com/api/data")
if err != nil {
// Handle security blocks or network errors
if secErr, ok := err.(*security.SecurityError); ok {
return nil, fmt.Errorf("security block [ID: %s]: %s", secErr.GetSecurityID(), secErr.Error())
}
return nil, err
}
// Content is EXACT bytes from server
content := safeResp.Content
// Check for security warnings (non-blocking)
if safeResp.SecurityResult != nil && safeResp.SecurityResult.Action == security.ActionWarn {
logger.Warnf("Security warning: %s", safeResp.SecurityResult.Message)
// Content is still available despite warning
}
return processContent(content)
}HTTP Operations:
// Secure HTTP GET with content integrity preservation
func (o *Operations) SafeHTTPGet(urlStr string) (*SafeHTTPResponse, error)
// Secure HTTP POST with content integrity preservation
func (o *Operations) SafeHTTPPost(urlStr string, body io.Reader) (*SafeHTTPResponse, error)File Operations:
// Secure file read with content integrity preservation
func (o *Operations) SafeFileRead(path string) (*SafeFileContent, error)
// Secure file write with access control
func (o *Operations) SafeFileWrite(path string, content []byte) errorResponse Types:
type SafeHTTPResponse struct {
Content []byte // EXACT original bytes - never modified
ContentType string // Original content type
StatusCode int // Original status code
Headers http.Header // Original headers
SecurityResult *SecurityResult // nil if safe, populated if warn
}
type SafeFileContent struct {
Content []byte // EXACT file bytes - never modified
Path string // Resolved path
Info os.FileInfo // Original file info
SecurityResult *SecurityResult // nil if safe, populated if warn
}- 80-90% Boilerplate Reduction: From 30+ lines to 5-10 lines
- Content Integrity: Guaranteed exact byte preservation
- Security Compliance: Automatic integration with security framework
- Error Handling: Consistent security error patterns
- Performance: Same security guarantees with simpler code
All MCP DevTools now use the standardised security helper functions. The security system automatically handles:
- Domain Access Control: Checks against deny lists before making requests
- Content Analysis: Scans text content for security threats using pattern matching
- Binary Content Detection: Automatically skips analysis for non-text content
- Content Integrity: Preserves exact original bytes without modification
- Error Handling: Consistent security error patterns with override IDs
Before (Manual Integration - 30+ lines):
// Domain check
parsedURL, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
if err := security.CheckDomainAccess(parsedURL.Hostname()); err != nil {
return nil, err
}
// HTTP request
resp, err := http.Get(urlStr)
if err != nil {
return nil, err
}
defer resp.Body.Close()
content, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Security analysis
sourceCtx := security.SourceContext{
URL: urlStr,
Domain: parsedURL.Hostname(),
ContentType: resp.Header.Get("Content-Type"),
Tool: "tool-name",
}
secResult, err := security.AnalyseContent(string(content), sourceCtx)
if err != nil {
logger.WithError(err).Warn("Security analysis failed")
}
if secResult != nil && secResult.Action == security.ActionBlock {
return nil, &security.SecurityError{
ID: secResult.ID,
Message: secResult.Message,
Action: security.ActionBlock,
}
}
if secResult != nil && secResult.Action == security.ActionWarn {
security.LogSecurityEvent(secResult.ID, "warn", secResult.Analysis, urlStr, "tool-name")
logger.WithField("security_warning", true).Info("Content analysis warning")
}After (Helper Functions - 5-10 lines):
ops := security.NewOperations("tool-name")
safeResp, err := ops.SafeHTTPGet(urlStr)
if err != nil {
if secErr, ok := err.(*security.SecurityError); ok {
return nil, fmt.Errorf("security block [ID: %s]: %s", secErr.GetSecurityID(), secErr.Error())
}
return nil, err
}
// Handle warnings if present
if safeResp.SecurityResult != nil && safeResp.SecurityResult.Action == security.ActionWarn {
logger.Warnf("Security warning [ID: %s]: %s", safeResp.SecurityResult.ID, safeResp.SecurityResult.Message)
}
// Process exact content
return processContent(safeResp.Content)Enable debug logging for detailed security analysis:
MCP_DEBUG=true
MCP_SECURITY_LOG_LEVEL=debug
./bin/mcp-devtools stdioTest regex patterns before adding to rules:
# Test a pattern against sample content
echo "test content" | grep -E "your_regex_pattern"
# Use online regex testers for complex patterns
# https://regex101.com/For a very simple test to demonstrate the security system in action, ask the AI agent to use the web_fetch tool on any of these URLs:
- https://gist.githubusercontent.com/sammcj/a37fb6d5f2aa53993281b365496adcef/raw/98e6f8e5d9238a278a3350a94c0b250afc6ef5de/test-bad-content.txt - Contains a bad command
- https://gist.githubusercontent.com/sammcj/a37fb6d5f2aa53993281b365496adcef/raw/c154135289c5c2bf802bc02a454f160ae29940f0/test-bad-content.txt - Contains a base64 encoded string, but it's not long and doesn't contain anything malicious
- https://gist.githubusercontent.com/sammcj/a37fb6d5f2aa53993281b365496adcef/raw/1ded814929f40e157a9650688242ca86a927594a/test-bad-content.txt - Contains a base64 encoded string that decodes to a short malicious command
- https://gist.githubusercontent.com/sammcj/a37fb6d5f2aa53993281b365496adcef/raw/25c5df220e47b40b7f918e3479da29435cd0d794/test-bad-content.txt - Contains a base64 encoded prompt injection example
- Content is analysed AFTER fetching: The security system analyses content after tools have already accessed it
- Network requests still made: Domain blocks prevent requests, but content analysis happens post-fetch
- File access occurs: File access blocks prevent reading, but content analysis happens post-read
- Regex Performance: Complex regex patterns can impact performance
- Encoding Evasion: Base64 or other encoding may bypass simple patterns
- Context Loss: Patterns match content snippets, not semantic meaning
- False Negatives: Sophisticated attacks may evade pattern detection
- Rules File Access: Security rules file must be protected from modification
- Environment Variables: Security settings in environment variables can be modified
- Override Abuse: Security overrides can be misused if not properly managed
- Direct File Access: Local file system access outside MCP tools bypasses security
- Alternative Tools: Non-MCP tools not subject to security controls
- Configuration Changes: Security can be disabled via environment variables
The MCP DevTools security system is one layer of security. For comprehensive protection:
- System-Level Security: Use OS-level access controls and firewalls
- Network Security: Implement network-level filtering and monitoring
- Application Security: Validate all user inputs and outputs
- Monitoring: Implement comprehensive logging and alerting
- Regular Updates: Keep all software components updated
- User Training: Educate users about security best practices
The security system provides valuable protection but should be part of a broader security strategy, not the sole security measure.
