🛡️ Security MCP Server
Production-Ready Model Context Protocol Server for Network Security Tools

Quick Start • Documentation • Examples • Contributing
📋 Table of Contents
For Users
For Developers
For Operators
Additional
🌟 Overview
What is Security MCP Server?
Security MCP Server is a production-ready implementation of the Model Context Protocol (MCP) that provides AI agents (like Claude) with secure, controlled access to network security tools. It transforms command-line security utilities into safe, monitored, API-accessible services with comprehensive safety controls.
🎯 Key Features
🔒 Security First
RFC1918/private IP enforcement
Command injection prevention
Whitelist-based validation
Resource limits
Intrusive operation controls
🏗️ Production Ready
Circuit breaker pattern
Health monitoring
Prometheus metrics
Graceful shutdown
Hot-reload configuration
🚀 Developer Friendly
Easy tool creation
Comprehensive testing
Clear documentation
Docker support
Extensible architecture
🛠️ Tool Ecosystem
📊 Observability
Real-time health checks
Prometheus metrics
Structured logging
Performance tracking
Error monitoring
🔄 Resilient
💡 Use Cases
AI-Assisted Network Discovery: Let Claude help you scan and analyze networks safely
Automated Security Audits: Run scheduled security scans with AI interpretation
Lab Environment Management: Safe tool execution in controlled environments
Security Training: Learn security tools with AI guidance
Infrastructure Monitoring: Combine network tools with AI analysis
🎬 Quick Demo
# AI agent (Claude) asks: "Can you scan 192.168.1.0/24 for web servers?"
# Security MCP Server:
# ✓ Validates target (RFC1918 ✓)
# ✓ Checks circuit breaker (CLOSED ✓)
# ✓ Executes: nmap -sV -p 80,443 --top-ports 1000 192.168.1.0/24
# ✓ Records metrics
# ✓ Returns structured results
# Response: Found 5 hosts with HTTP/HTTPS services...
🚀 Quick Start
Get up and running in under 5 minutes!
Prerequisites
✅ Python 3.11 or higher
✅ pip (Python package manager)
✅ nmap installed (sudo apt-get install nmap
on Ubuntu)
✅ Virtual environment support (recommended)
One-Command Installation
# Clone the repository
git clone https://github.com/nordeim/Security-MCP-Server.git
cd Security-MCP-Server
# Create virtual environment and install
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
First Run
# Start in HTTP mode for testing
export MCP_SERVER_TRANSPORT=http
python -m mcp_server.server
# Server starts on http://localhost:8080
# ✓ Health check: http://localhost:8080/health
# ✓ Tools list: http://localhost:8080/tools
# ✓ Metrics: http://localhost:8080/metrics
Verify Installation
# Check health
curl http://localhost:8080/health
# Expected response:
{
"status": "healthy",
"timestamp": "2024-01-15T10:30:00Z",
"checks": {
"system_resources": {"status": "healthy", ...},
"process_health": {"status": "healthy", ...}
}
}
# Test tool execution
curl -X POST http://localhost:8080/tools/NmapTool/execute \
-H "Content-Type: application/json" \
-d '{
"target": "192.168.1.1",
"extra_args": "-sV --top-ports 100"
}'
Next Steps
🏗️ Architecture
System Architecture
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#0066cc','primaryTextColor':'#fff','primaryBorderColor':'#004499','lineColor':'#0066cc','secondaryColor':'#66ccff','tertiaryColor':'#fff'}}}%%
graph TD
A[AI Agent / Claude] -->|MCP Protocol| B[MCP Server]
B --> C[Tool Registry]
B --> D[Health Manager]
B --> E[Metrics Manager]
B --> F[Config Manager]
C --> G[NmapTool]
C --> H[Custom Tools]
G --> I[Circuit Breaker]
H --> I
I --> J[Base Tool]
J --> K[Input Validation]
J --> L[Resource Limits]
J --> M[Command Execution]
D --> N[System Health]
D --> O[Tool Health]
D --> P[Dependency Health]
E --> Q[Prometheus]
E --> R[Internal Metrics]
F --> S[Environment]
F --> T[Config Files]
F --> U[Defaults]
style B fill:#0066cc,stroke:#004499,color:#fff
style C fill:#66ccff,stroke:#0066cc
style I fill:#ff9900,stroke:#cc7700
style D fill:#66cc66,stroke:#44aa44
style E fill:#cc66ff,stroke:#9944cc
Component Overview
Component | Responsibility | Key Features |
MCP Server | Request handling, protocol compliance | Dual transport (stdio/HTTP), async execution |
Tool Registry | Tool discovery, lifecycle management | Auto-discovery, enable/disable, validation |
Circuit Breaker | Fault tolerance, failure prevention | Auto-recovery, adaptive timeout, metrics |
Health Manager | System monitoring, availability checks | Priority-based, staleness detection, aggregation |
Metrics Manager | Performance tracking, observability | Prometheus export, percentiles, caching |
Base Tool | Common tool functionality | Validation, execution, error handling |
Config Manager | Configuration loading, validation | Multi-source, hot-reload, type safety |
Tool Execution Flow
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#0066cc','primaryTextColor':'#fff','primaryBorderColor':'#004499','lineColor':'#0066cc','secondaryColor':'#66ccff','tertiaryColor':'#fff'}}}%%
sequenceDiagram
participant AI as AI Agent
participant MCP as MCP Server
participant CB as Circuit Breaker
participant Tool as Tool (e.g., Nmap)
participant Metrics as Metrics
AI->>MCP: Execute Tool Request
MCP->>MCP: Validate Input
alt Invalid Input
MCP-->>AI: Validation Error
end
MCP->>CB: Check State
alt Circuit Open
CB-->>MCP: Circuit Open Error
MCP-->>AI: Service Unavailable
end
CB->>Tool: Execute (with timeout)
Tool->>Tool: Validate Target (RFC1918)
Tool->>Tool: Sanitize Arguments
Tool->>Tool: Apply Resource Limits
Tool->>Tool: Execute Command
alt Success
Tool-->>CB: Success Result
CB->>CB: Record Success
CB->>Metrics: Record Metrics
CB-->>MCP: Result
MCP-->>AI: Formatted Response
else Failure
Tool-->>CB: Error Result
CB->>CB: Record Failure
CB->>Metrics: Record Failure
alt Threshold Exceeded
CB->>CB: Open Circuit
end
CB-->>MCP: Error
MCP-->>AI: Error Response
end
Health Check System
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#0066cc','primaryTextColor':'#fff','primaryBorderColor':'#004499','lineColor':'#0066cc','secondaryColor':'#66ccff','tertiaryColor':'#fff'}}}%%
graph TD
A[Health Check Manager] --> B{Run All Checks}
B --> C[CRITICAL Priority]
B --> D[IMPORTANT Priority]
B --> E[INFORMATIONAL Priority]
C --> C1[System Resources]
C1 --> C1A[CPU < 80%]
C1 --> C1B[Memory < 80%]
C1 --> C1C[Disk < 80%]
D --> D1[Process Health]
D --> D2[Circuit Breakers]
D1 --> D1A[Process Running]
D1 --> D1B[Resource Usage OK]
E --> E1[Tool Availability]
E --> E2[Dependencies]
E1 --> E1A[nmap Available]
E1 --> E1B[Commands Resolve]
C1 --> F{Aggregate Status}
D1 --> F
D2 --> F
E1 --> F
E2 --> F
F -->|All CRITICAL OK| G[HEALTHY]
F -->|Any CRITICAL Failed| H[UNHEALTHY]
F -->|CRITICAL OK, IMPORTANT Failed| I[DEGRADED]
style C fill:#ff4444,stroke:#cc0000,color:#fff
style D fill:#ffaa44,stroke:#cc8800,color:#fff
style E fill:#4444ff,stroke:#0000cc,color:#fff
style G fill:#44ff44,stroke:#00cc00,color:#000
style H fill:#ff4444,stroke:#cc0000,color:#fff
style I fill:#ffaa44,stroke:#cc8800,color:#000
Technology Stack
Layer | Technologies |
Protocol | Model Context Protocol (MCP) 1.0 |
Language | Python 3.11+ |
Async Framework | asyncio, uvloop (optional) |
Web Framework | FastAPI, Uvicorn (HTTP mode) |
Validation | Pydantic v1/v2 compatible |
Metrics | Prometheus Client |
Monitoring | psutil, custom health checks |
Configuration | YAML, JSON, Environment Variables |
Logging | Python logging, structured output |
Containerization | Docker, Docker Compose |
Testing | pytest, pytest-asyncio |
Security Tools | nmap (extensible) |
✨ Features Deep Dive
🔒 Security Controls
Security MCP Server implements defense in depth with multiple layers of protection:
Network Restrictions
RFC1918 Enforcement: Only private IP ranges allowed (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
Domain Whitelisting: Only .lab.internal
domains permitted
CIDR Validation: Network ranges validated and size-limited (max 1024 hosts)
IP Version: IPv4 only (controlled attack surface)
# Automatic validation
ToolInput(target="192.168.1.1") # ✓ Allowed
ToolInput(target="8.8.8.8") # ✗ Rejected: Public IP
ToolInput(target="server.lab.internal") # ✓ Allowed
ToolInput(target="example.com") # ✗ Rejected: External domain
Input Validation
Shell Metacharacter Blocking: ; & | \
$ > < \n \r` completely blocked
Whitelist-Based Flags: Only pre-approved command flags allowed
Token Sanitization: All inputs validated against strict patterns
Length Limits: Arguments capped at 2048 bytes (configurable)
Resource Limits (Linux)
CPU Time: Limited per execution
Memory: 512MB default limit
File Descriptors: 256 limit
Output Size: stdout 1MB, stderr 256KB
Timeout: 300s default (configurable)
Intrusive Operation Control
Policy-Based: -A
flag and vulnerability scripts gated by configuration
Audit Logging: All intrusive operations logged
Granular Control: Per-script and per-category filtering
🔄 Circuit Breaker Pattern
Prevents cascade failures and enables graceful degradation:
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#0066cc','primaryTextColor':'#fff','primaryBorderColor':'#004499','lineColor':'#0066cc'}}}%%
stateDiagram-v2
[*] --> CLOSED: Initial State
CLOSED --> OPEN: Failures ≥ Threshold
OPEN --> HALF_OPEN: After Recovery Timeout
HALF_OPEN --> CLOSED: Success
HALF_OPEN --> OPEN: Failure
CLOSED --> CLOSED: Success
note right of OPEN
All requests rejected
Retry after timeout
end note
note right of HALF_OPEN
Test request allowed
Evaluate recovery
end note
note right of CLOSED
Normal operation
Track failures
end note
Features:
Adaptive timeout (exponential backoff)
Jitter to prevent thundering herd
Per-tool circuit breakers
Prometheus metrics integration
Detailed state tracking
Configuration:
MCP_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5 # Failures before opening
MCP_CIRCUIT_BREAKER_RECOVERY_TIMEOUT=60 # Seconds to wait
📊 Health Monitoring
Three-tier priority system ensures critical issues are detected:
Priority | Impact | Examples |
CRITICAL (0) | System failure → UNHEALTHY | CPU, Memory, Disk usage |
IMPORTANT (1) | Degraded service → DEGRADED | Process health, Circuit breakers |
INFORMATIONAL (2) | Logged only → No impact | Tool availability, Dependencies |
Staleness Detection: Health results older than 60s are considered stale
HTTP Endpoint:
GET /health
Response codes:
- 200: Healthy
- 207: Degraded (some issues)
- 503: Unhealthy (critical failure)
📈 Metrics & Observability
Prometheus Metrics:
# Execution metrics
mcp_tool_execution_total{tool="NmapTool", status="success"}
mcp_tool_execution_seconds{tool="NmapTool", quantile="0.99"}
mcp_tool_active{tool="NmapTool"}
# Circuit breaker
circuit_breaker_state{name="NmapTool"} # 0=closed, 1=open, 2=half-open
circuit_breaker_calls_total{name="NmapTool", result="success"}
Internal Metrics:
Success rate, latency percentiles (p50, p95, p99)
Error rates by type
Timeout counts
Active execution tracking
Historical trends (last 100 executions)
⚙️ Configuration Management
Multi-Source Priority (highest to lowest):
Environment variables
Configuration file (YAML/JSON)
Default values
Hot Reload: Configuration file changes detected and applied without restart
Type Safety: All values validated and clamped to safe ranges
Example (config.yaml):
server:
transport: http
port: 8080
host: 0.0.0.0
security:
allow_intrusive: false
max_args_length: 2048
timeout_seconds: 300
circuit_breaker:
failure_threshold: 5
recovery_timeout: 60.0
health:
check_interval: 30.0
cpu_threshold: 80.0
memory_threshold: 80.0
🛠️ Tool Ecosystem
Current Tools
NmapTool - Network Scanner
Host discovery
Port scanning
Service version detection
Safe script execution
Template-based scanning (Quick, Standard, Thorough)
Key Features:
Network size limits (max 1024 hosts)
Port range limits (max 100 ranges)
Script filtering (safe vs. intrusive)
Optimization (smart defaults)
Adding Custom Tools
Inherit from MCPBaseTool
and implement:
class MyTool(MCPBaseTool):
command_name = "mytool"
allowed_flags = ["-flag1", "-flag2"]
default_timeout_sec = 60.0
# Auto-discovered and registered!
See Developer Guide for complete tutorial.
📦 Installation & Setup
System Requirements
Component | Minimum | Recommended |
Python | 3.11 | 3.11+ |
CPU | 1 core | 2+ cores |
Memory | 512MB | 1GB+ |
Disk | 100MB | 500MB+ |
OS | Linux, macOS, Windows | Linux (Ubuntu 22.04+) |
System Tools (Optional but recommended):
nmap
- For NmapTool functionality
curl
- For HTTP health checks
docker
- For containerized deployment
Non-Docker Installation
1. Clone Repository
git clone https://github.com/nordeim/Security-MCP-Server.git
cd Security-MCP-Server
2. Create Virtual Environment
# Create virtual environment
python3.11 -m venv venv
# Activate (Linux/macOS)
source venv/bin/activate
# Activate (Windows)
venv\Scripts\activate
3. Install Dependencies
# Upgrade pip
pip install --upgrade pip setuptools wheel
# Install requirements
pip install -r requirements.txt
# Install in development mode (editable)
pip install -e .
4. Install System Tools
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y nmap netcat iputils-ping
# macOS (using Homebrew)
brew install nmap
# Verify installation
nmap --version
which nmap
5. Configure
# Option 1: Environment variables
export MCP_SERVER_TRANSPORT=http
export MCP_SERVER_PORT=8080
export LOG_LEVEL=INFO
# Option 2: Configuration file
cp config/config.example.yaml config/config.yaml
# Edit config/config.yaml as needed
export MCP_CONFIG_FILE=config/config.yaml
6. Verify Installation
# Run validation
./scripts/mcp_server_launcher.sh validate
# Expected output:
# [SUCCESS] Python 3.11.x found
# [SUCCESS] Virtual environment exists
# [SUCCESS] mcp_server package found
# [SUCCESS] All system tools available
# [SUCCESS] Validation passed! Server is ready to start.
Docker Installation
Option 1: Pre-Built Image (Recommended)
# Pull latest image
docker pull nordeim/security-mcp-server:latest
# Run in HTTP mode
docker run -d \
--name mcp-server \
-p 8080:8080 \
-e MCP_SERVER_TRANSPORT=http \
nordeim/security-mcp-server:latest
# Check health
curl http://localhost:8080/health
Option 2: Build from Source
# Clone repository
git clone https://github.com/nordheim/Security-MCP-Server.git
cd Security-MCP-Server
# Build image
docker build -t mcp-server:latest .
# Run
docker run -d \
--name mcp-server \
-p 8080:8080 \
-e MCP_SERVER_TRANSPORT=http \
mcp-server:latest
Option 3: Docker Compose (Best for Development)
# Create environment file
cp .env.docker .env
# Edit .env as needed
nano .env
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
docker-compose.yml highlights:
Automatic restarts
Resource limits
Health checks
Volume persistence
Network isolation
Configuration Guide
Environment Variables
Complete reference of all environment variables:
# Transport mode: stdio (for Claude) or http (for API)
MCP_SERVER_TRANSPORT=http
# HTTP server settings (http mode only)
MCP_SERVER_HOST=0.0.0.0
MCP_SERVER_PORT=8080
MCP_SERVER_WORKERS=1
MCP_SERVER_MAX_CONNECTIONS=100
MCP_SERVER_SHUTDOWN_GRACE_PERIOD=30
# Allow intrusive operations (nmap -A, vuln scripts)
# WARNING: Only enable in controlled environments!
MCP_SECURITY_ALLOW_INTRUSIVE=false
# Maximum argument length (bytes)
MCP_SECURITY_MAX_ARGS_LENGTH=2048
# Maximum output size (bytes)
MCP_SECURITY_MAX_OUTPUT_SIZE=1048576
# Default timeout (seconds)
MCP_SECURITY_TIMEOUT_SECONDS=300
# Concurrent operation limit
MCP_SECURITY_CONCURRENCY_LIMIT=2
# Failure threshold before opening circuit
MCP_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
# Recovery timeout (seconds)
MCP_CIRCUIT_BREAKER_RECOVERY_TIMEOUT=60
# Success threshold to close from half-open
MCP_CIRCUIT_BREAKER_HALF_OPEN_SUCCESS_THRESHOLD=1
# Health check interval (seconds)
MCP_HEALTH_CHECK_INTERVAL=30.0
# Resource thresholds (percentage)
MCP_HEALTH_CPU_THRESHOLD=80.0
MCP_HEALTH_MEMORY_THRESHOLD=80.0
MCP_HEALTH_DISK_THRESHOLD=80.0
# Metrics
MCP_METRICS_ENABLED=true
MCP_METRICS_PROMETHEUS_PORT=9090
# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_LEVEL=INFO
# Log format
LOG_FORMAT="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# Log file (optional, logs to stdout by default)
# MCP_LOGGING_FILE_PATH=/app/logs/mcp_server.log
Configuration File
config/config.yaml:
server:
transport: http # stdio or http
host: 0.0.0.0
port: 8080
shutdown_grace_period: 30
security:
allow_intrusive: false # Control intrusive operations
max_args_length: 2048
timeout_seconds: 300
concurrency_limit: 2
allowed_targets:
- RFC1918 # Private IP ranges
- .lab.internal # Internal domains
circuit_breaker:
failure_threshold: 5
recovery_timeout: 60.0
health:
check_interval: 30.0
cpu_threshold: 80.0
memory_threshold: 80.0
disk_threshold: 80.0
metrics:
enabled: true
prometheus_enabled: true
prometheus_port: 9090
logging:
level: INFO
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
tool:
default_timeout: 300
default_concurrency: 2
Load configuration:
export MCP_CONFIG_FILE=config/config.yaml
python -m mcp_server.server
🎮 Usage Guide
Running the Server
Stdio Mode (for Claude Desktop)
# Activate virtual environment
source venv/bin/activate
# Run in stdio mode
export MCP_SERVER_TRANSPORT=stdio
python -m mcp_server.server
# Server communicates via stdin/stdout
# Perfect for MCP client integration
HTTP Mode (for API access)
# Run in HTTP mode
export MCP_SERVER_TRANSPORT=http
export MCP_SERVER_PORT=8080
python -m mcp_server.server
# Server starts on http://localhost:8080
# API endpoints available
Using Launcher Script
# Make executable
chmod +x scripts/mcp_server_launcher.sh
# Start server
./scripts/mcp_server_launcher.sh start
# Check status
./scripts/mcp_server_launcher.sh status
# View logs
./scripts/mcp_server_launcher.sh logs
# Stop server
./scripts/mcp_server_launcher.sh stop
# Restart
./scripts/mcp_server_launcher.sh restart
Claude Desktop Integration
Locate Claude Desktop config:
# macOS
~/Library/Application Support/Claude/config.json
# Windows
%APPDATA%\Claude\config.json
# Linux
~/.config/Claude/config.json
Add MCP server configuration:
{
"mcpServers": {
"security-tools": {
"command": "/path/to/Security-MCP-Server/venv/bin/python",
"args": ["-m", "mcp_server.server"],
"env": {
"MCP_SERVER_TRANSPORT": "stdio",
"LOG_LEVEL": "INFO",
"MCP_SECURITY_ALLOW_INTRUSIVE": "false"
}
}
}
}
Restart Claude Desktop
Test integration:
Tool Invocation Examples
Basic Network Scan
# HTTP API
curl -X POST http://localhost:8080/tools/NmapTool/execute \
-H "Content-Type: application/json" \
-d '{
"target": "192.168.1.0/24",
"extra_args": "-sV --top-ports 100"
}'
In Claude:
User: Scan my lab network 192.168.1.0/24 for web servers
Claude: I'll scan the network for web servers using nmap.
[Executes: NmapTool with target "192.168.1.0/24" and args "-p 80,443 -sV"]
Results: Found 3 hosts running web servers:
- 192.168.1.10: Apache 2.4.41
- 192.168.1.20: nginx 1.18.0
- 192.168.1.30: Microsoft IIS 10.0
Service Version Detection
curl -X POST http://localhost:8080/tools/NmapTool/execute \
-H "Content-Type: application/json" \
-d '{
"target": "192.168.1.10",
"extra_args": "-sV --version-intensity 5"
}'
Using Scan Templates
# Python client example
import requests
response = requests.post(
"http://localhost:8080/tools/NmapTool/execute",
json={
"target": "192.168.1.0/24",
"extra_args": "-T4 -Pn --top-ports 1000 -sV", # Standard template
"timeout_sec": 600
}
)
result = response.json()
print(f"Scan completed in {result['execution_time']}s")
print(f"Return code: {result['returncode']}")
print(f"Output: {result['stdout']}")
Safe Script Scanning
# Safe scripts (always allowed)
curl -X POST http://localhost:8080/tools/NmapTool/execute \
-H "Content-Type: application/json" \
-d '{
"target": "192.168.1.10",
"extra_args": "--script safe -sV"
}'
# Intrusive scripts (requires MCP_SECURITY_ALLOW_INTRUSIVE=true)
curl -X POST http://localhost:8080/tools/NmapTool/execute \
-H "Content-Type: application/json" \
-d '{
"target": "192.168.1.10",
"extra_args": "--script vuln -sV"
}'
HTTP API Reference
Endpoints
Method | Endpoint | Description |
GET
| /
| Server information |
GET
| /health
| Health check |
GET
| /tools
| List available tools |
POST
| /tools/{tool_name}/execute
| Execute a tool |
POST
| /tools/{tool_name}/enable
| Enable a tool |
POST
| /tools/{tool_name}/disable
| Disable a tool |
GET
| /metrics
| Prometheus metrics |
GET
| /events
| SSE event stream |
GET
| /config
| Current configuration (redacted) |
Execute Tool
Request:
POST /tools/NmapTool/execute HTTP/1.1
Content-Type: application/json
{
"target": "192.168.1.1",
"extra_args": "-sV --top-ports 100",
"timeout_sec": 300,
"correlation_id": "scan-001"
}
Response (Success):
{
"stdout": "Starting Nmap 7.94...",
"stderr": "",
"returncode": 0,
"truncated_stdout": false,
"truncated_stderr": false,
"timed_out": false,
"error": null,
"error_type": null,
"execution_time": 45.23,
"correlation_id": "scan-001",
"metadata": {}
}
Response (Validation Error):
{
"detail": "Target must be RFC1918 IPv4 or a .lab.internal hostname"
}
Response (Rate Limited):
{
"detail": {
"error": "Rate limit exceeded",
"message": "Too many requests for NmapTool. Try again later.",
"retry_after": 60
}
}
Health Check
Response (Healthy - 200 OK):
{
"status": "healthy",
"timestamp": "2024-01-15T10:30:00Z",
"transport": "http",
"checks": {
"system_resources": {
"status": "healthy",
"message": "System resources healthy",
"metadata": {
"cpu_percent": 25.5,
"memory_percent": 45.2,
"disk_percent": 60.0
}
},
"process_health": {
"status": "healthy",
"message": "Process is running normally"
}
},
"summary": {
"total_checks": 5,
"healthy_checks": 5,
"degraded_checks": 0,
"unhealthy_checks": 0
}
}
Response (Degraded - 207 Multi-Status):
{
"status": "degraded",
"timestamp": "2024-01-15T10:30:00Z",
"checks": {
"system_resources": {
"status": "degraded",
"message": "Memory usage high: 85.0%"
}
}
}
Response (Unhealthy - 503 Service Unavailable):
{
"status": "unhealthy",
"timestamp": "2024-01-15T10:30:00Z",
"checks": {
"system_resources": {
"status": "unhealthy",
"message": "CPU usage critical: 92.0%"
}
}
}
🚀 Deployment Guide
Development Deployment
Local Development (Non-Docker)
# 1. Clone and setup
git clone https://github.com/nordeim/Security-MCP-Server.git
cd Security-MCP-Server
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install -e .
# 2. Configure for development
export MCP_SERVER_TRANSPORT=http
export LOG_LEVEL=DEBUG
export MCP_SECURITY_ALLOW_INTRUSIVE=true # For testing only!
# 3. Run with hot-reload (install watchdog)
pip install watchdog
watchmedo auto-restart --directory=./mcp_server --pattern='*.py' \
--recursive -- python -m mcp_server.server
# 4. In another terminal, test
curl http://localhost:8080/health
Docker Development
# 1. Use docker-compose with override
docker-compose up -d
# 2. Check logs
docker-compose logs -f mcp-server
# 3. Source code is mounted for hot-reload
# Edit files in ./mcp_server/ and changes reflect immediately
# 4. Run tests in container
docker-compose exec mcp-server pytest
# 5. Shell access
docker-compose exec mcp-server bash
Production Deployment
Production Non-Docker
Prerequisites:
Dedicated server or VM
systemd (Linux)
Firewall configured
Monitoring setup
Steps:
Create dedicated user:
sudo useradd -r -s /bin/bash -d /opt/mcp-server mcp
sudo mkdir -p /opt/mcp-server
sudo chown mcp:mcp /opt/mcp-server
Install as mcp user:
sudo -u mcp bash
cd /opt/mcp-server
git clone https://github.com/nordeim/Security-MCP-Server.git .
python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install -e .
Create systemd service:
sudo nano /etc/systemd/system/mcp-server.service
[Unit]
Description=MCP Network Tools Server
After=network.target
[Service]
Type=simple
User=mcp
Group=mcp
WorkingDirectory=/opt/mcp-server
Environment="PATH=/opt/mcp-server/venv/bin"
Environment="MCP_SERVER_TRANSPORT=http"
Environment="MCP_SERVER_PORT=8080"
Environment="LOG_LEVEL=INFO"
Environment="MCP_SECURITY_ALLOW_INTRUSIVE=false"
ExecStart=/opt/mcp-server/venv/bin/python -m mcp_server.server
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mcp-server
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mcp-server/logs /opt/mcp-server/data
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable mcp-server
sudo systemctl start mcp-server
sudo systemctl status mcp-server
Configure reverse proxy (nginx):
server {
listen 80;
server_name mcp.example.com;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE support
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
}
Production Docker
Single Container:
# 1. Pull production image
docker pull nordeim/security-mcp-server:latest
# 2. Create production env file
cat > /opt/mcp-server/.env << EOF
MCP_SERVER_TRANSPORT=http
MCP_SERVER_PORT=8080
LOG_LEVEL=INFO
MCP_SECURITY_ALLOW_INTRUSIVE=false
MCP_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
MCP_HEALTH_CHECK_INTERVAL=30
MCP_METRICS_ENABLED=true
EOF
# 3. Run with restart policy
docker run -d \
--name mcp-server \
--restart unless-stopped \
-p 8080:8080 \
--env-file /opt/mcp-server/.env \
--memory="1g" \
--cpus="2" \
-v mcp-logs:/app/logs \
-v mcp-data:/app/data \
--health-cmd='/app/docker/healthcheck.sh' \
--health-interval=30s \
nordeim/security-mcp-server:latest
# 4. Verify
docker ps
curl http://localhost:8080/health
Docker Compose Production:
# 1. Use production compose file only
docker-compose -f docker-compose.yml up -d
# 2. Monitor
docker-compose -f docker-compose.yml logs -f
# 3. Check health
docker-compose -f docker-compose.yml ps
Kubernetes Deployment (Bonus)
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
labels:
app: mcp-server
spec:
replicas: 2
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: nordeim/security-mcp-server:latest
ports:
- containerPort: 8080
name: http
- containerPort: 9090
name: metrics
env:
- name: MCP_SERVER_TRANSPORT
value: "http"
- name: MCP_SERVER_PORT
value: "8080"
- name: LOG_LEVEL
value: "INFO"
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "2000m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: mcp-server
spec:
selector:
app: mcp-server
ports:
- name: http
port: 80
targetPort: 8080
- name: metrics
port: 9090
targetPort: 9090
type: ClusterIP
ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mcp-server
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: mcp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mcp-server
port:
number: 80
Deploy:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
kubectl get pods -l app=mcp-server
Deployment Checklist
Pre-Deployment
Deployment
Application deployed
Health check passing
Metrics accessible
Logs flowing
Resource limits enforced
Post-Deployment
🛠️ Developer Guide
Project Structure
Security-MCP-Server/
├── 📄 README.md # This file
├── 📄 LICENSE # MIT License
├── 📄 requirements.txt # Python dependencies
├── 📄 setup.py # Package setup
├── 📄 mcp.json # MCP protocol configuration
├── 📄 .env.docker # Docker environment template
├── 📄 .dockerignore # Docker build exclusions
├── 📄 Dockerfile # Container image definition
├── 📄 docker-compose.yml # Production orchestration
├── 📄 docker-compose.override.yml # Development overrides
│
├── 📁 mcp_server/ # Main application package
│ ├── 📄 __init__.py
│ ├── 📄 server.py # MCP server implementation
│ ├── 📄 base_tool.py # Base tool class
│ ├── 📄 config.py # Configuration management
│ ├── 📄 health.py # Health monitoring system
│ ├── 📄 metrics.py # Metrics collection
│ ├── 📄 circuit_breaker.py # Circuit breaker pattern
│ └── 📁 tools/ # Tool implementations
│ ├── 📄 __init__.py
│ └── 📄 nmap_tool.py # Nmap integration
│
├── 📁 scripts/ # Utility scripts
│ └── 📄 mcp_server_launcher.sh # Server launcher
│
├── 📁 docker/ # Docker support files
│ ├── 📄 entrypoint.sh # Container entrypoint
│ └── 📄 healthcheck.sh # Container health check
│
├── 📁 config/ # Configuration files
│ ├── 📄 config.example.yaml # Example configuration
│ └── 📄 config.schema.json # Configuration schema
│
├── 📁 tests/ # Test suite
│ ├── 📄 __init__.py
│ ├── 📄 conftest.py # Pytest fixtures
│ ├── 📁 unit/ # Unit tests
│ │ ├── 📄 test_base_tool.py
│ │ ├── 📄 test_config.py
│ │ ├── 📄 test_health.py
│ │ ├── 📄 test_metrics.py
│ │ ├── 📄 test_circuit_breaker.py
│ │ └── 📁 tools/
│ │ └── 📄 test_nmap_tool.py
│ └── 📁 integration/ # Integration tests
│ ├── 📄 test_server.py
│ └── 📄 test_tool_execution.py
│
├── 📁 docs/ # Additional documentation
│ ├── 📄 architecture.md
│ ├── 📄 api_reference.md
│ └── 📄 deployment.md
│
├── 📁 logs/ # Application logs (gitignored)
└── 📁 data/ # Persistent data (gitignored)
Module Responsibilities
Module | Purpose | Key Classes/Functions |
server.py | MCP server, request handling, tool registry | EnhancedMCPServer
, ToolRegistry
, main_enhanced()
|
base_tool.py | Base tool implementation, validation, execution | MCPBaseTool
, ToolInput
, ToolOutput
|
config.py | Configuration loading, validation, hot-reload | MCPConfig
, get_config()
, reset_config()
|
health.py | Health monitoring, status aggregation | HealthCheckManager
, HealthCheck
, HealthStatus
|
metrics.py | Metrics collection, Prometheus integration | MetricsManager
, ToolMetrics
, PrometheusRegistry
|
circuit_breaker.py | Failure protection, auto-recovery | CircuitBreaker
, CircuitBreakerState
|
nmap_tool.py | Nmap integration, security controls | NmapTool
, ScanTemplate
|
Creating Custom Tools
Step-by-Step Tutorial
Let's create a simple PingTool
that safely pings hosts.
1. Create tool file:
touch mcp_server/tools/ping_tool.py
2. Implement tool class:
"""
Ping tool for network connectivity testing.
"""
import logging
from typing import Optional
from mcp_server.base_tool import MCPBaseTool, ToolInput, ToolOutput
log = logging.getLogger(__name__)
class PingTool(MCPBaseTool):
"""
ICMP ping tool for network connectivity testing.
Features:
- Safe ping execution
- Packet count control
- Timeout enforcement
- RFC1918/lab.internal only
Example:
# Ping a host 5 times
tool = PingTool()
result = await tool.run(ToolInput(
target="192.168.1.1",
extra_args="-c 5"
))
"""
# Required: Command name
command_name = "ping"
# Optional: Allowed flags (whitelist)
allowed_flags = [
"-c", # Count
"-i", # Interval
"-W", # Timeout
"-q", # Quiet
"-v", # Verbose
]
# Optional: Flags that require values
_FLAGS_REQUIRE_VALUE = {"-c", "-i", "-W"}
# Optional: Extra allowed tokens (for values)
_EXTRA_ALLOWED_TOKENS = {"1", "5", "10"}
# Optional: Custom timeout
default_timeout_sec = 30.0
# Optional: Concurrency limit
concurrency = 5
# Optional: Circuit breaker config
circuit_breaker_failure_threshold = 3
circuit_breaker_recovery_timeout = 30.0
def __init__(self):
"""Initialize ping tool."""
super().__init__()
log.info("ping_tool.initialized")
# Optional: Custom validation
async def _execute_tool(self, inp: ToolInput,
timeout_sec: Optional[float] = None) -> ToolOutput:
"""Execute ping with custom validation."""
# Add custom validation if needed
if inp.extra_args:
# Parse count
if "-c" in inp.extra_args:
# Ensure count is reasonable
try:
parts = inp.extra_args.split()
c_index = parts.index("-c")
count = int(parts[c_index + 1])
if count > 10:
# Override with max
parts[c_index + 1] = "10"
inp.extra_args = " ".join(parts)
log.warning("ping.count_clamped original=%d new=10", count)
except (ValueError, IndexError):
pass
# Call parent implementation
return await super()._execute_tool(inp, timeout_sec)
3. Tool is auto-discovered!
The tool will be automatically discovered and registered when the server starts.
4. Test your tool:
# tests/unit/tools/test_ping_tool.py
import pytest
from mcp_server.tools.ping_tool import PingTool
from mcp_server.base_tool import ToolInput
@pytest.mark.asyncio
async def test_ping_tool_basic():
"""Test basic ping execution."""
tool = PingTool()
result = await tool.run(ToolInput(
target="192.168.1.1",
extra_args="-c 3"
))
assert result.returncode == 0 or result.returncode == 1 # Success or host down
assert not result.timed_out
assert result.execution_time > 0
@pytest.mark.asyncio
async def test_ping_tool_public_ip_rejected():
"""Test that public IPs are rejected."""
tool = PingTool()
with pytest.raises(ValueError, match="RFC1918"):
await tool.run(ToolInput(
target="8.8.8.8",
extra_args="-c 1"
))
@pytest.mark.asyncio
async def test_ping_tool_count_clamping():
"""Test that large counts are clamped."""
tool = PingTool()
result = await tool.run(ToolInput(
target="192.168.1.1",
extra_args="-c 100" # Should be clamped to 10
))
# Verify clamping occurred
assert "-c 10" in result.metadata.get("actual_command", "")
5. Run tests:
pytest tests/unit/tools/test_ping_tool.py -v
6. Use your tool:
# HTTP API
curl -X POST http://localhost:8080/tools/PingTool/execute \
-H "Content-Type: application/json" \
-d '{"target": "192.168.1.1", "extra_args": "-c 5"}'
Advanced Tool Example
"""
Traceroute tool with advanced features.
"""
import re
from typing import Optional, List, Dict, Any
from mcp_server.base_tool import MCPBaseTool, ToolInput, ToolOutput
from mcp_server.config import get_config
class TracerouteTool(MCPBaseTool):
"""Advanced traceroute tool with hop analysis."""
command_name = "traceroute"
allowed_flags = ["-m", "-w", "-q", "-n"]
_FLAGS_REQUIRE_VALUE = {"-m", "-w", "-q"}
default_timeout_sec = 60.0
concurrency = 3
# Custom: Max hops limit
MAX_HOPS = 30
def __init__(self):
super().__init__()
self.config = get_config()
async def _execute_tool(self, inp: ToolInput,
timeout_sec: Optional[float] = None) -> ToolOutput:
"""Execute with hop limit enforcement."""
# Enforce max hops
if "-m" in (inp.extra_args or ""):
inp.extra_args = self._enforce_max_hops(inp.extra_args)
else:
# Add default max hops
inp.extra_args = f"-m {self.MAX_HOPS} {inp.extra_args or ''}"
# Execute
result = await super()._execute_tool(inp, timeout_sec)
# Parse hops
if result.returncode == 0:
hops = self._parse_hops(result.stdout)
result.metadata['hops'] = hops
result.metadata['hop_count'] = len(hops)
return result
def _enforce_max_hops(self, args: str) -> str:
"""Enforce maximum hop count."""
parts = args.split()
try:
m_index = parts.index("-m")
hops = int(parts[m_index + 1])
if hops > self.MAX_HOPS:
parts[m_index + 1] = str(self.MAX_HOPS)
log.warning("traceroute.hops_clamped original=%d new=%d",
hops, self.MAX_HOPS)
except (ValueError, IndexError):
pass
return " ".join(parts)
def _parse_hops(self, output: str) -> List[Dict[str, Any]]:
"""Parse traceroute output into structured hops."""
hops = []
hop_pattern = re.compile(
r'^\s*(\d+)\s+(\S+)\s+\((\d+\.\d+\.\d+\.\d+)\)\s+([\d.]+)\s*ms'
)
for line in output.split('\n'):
match = hop_pattern.match(line)
if match:
hop_num, hostname, ip, latency = match.groups()
hops.append({
'hop': int(hop_num),
'hostname': hostname,
'ip': ip,
'latency_ms': float(latency)
})
return hops
def get_tool_info(self) -> Dict[str, Any]:
"""Extended tool information."""
info = super().get_tool_info()
info.update({
'max_hops': self.MAX_HOPS,
'features': [
'Hop limit enforcement',
'Structured hop parsing',
'Latency tracking'
]
})
return info
Best Practices
Tool Design
✅ Inherit from MCPBaseTool: Don't reinvent the wheel
✅ Define allowed_flags: Whitelist approach for security
✅ Set reasonable timeouts: Balance functionality and resource usage
✅ Handle errors gracefully: Return ToolOutput even on failure
✅ Add comprehensive docstrings: Help users understand your tool
✅ Validate inputs: Additional validation beyond base class
✅ Parse outputs: Structure results for easy consumption
Security
✅ Validate all inputs: Never trust user input
✅ Enforce resource limits: Prevent DoS
✅ Use whitelist validation: Block by default, allow explicitly
✅ Sanitize arguments: Prevent injection attacks
✅ Audit intrusive operations: Log all sensitive actions
Performance
✅ Set appropriate concurrency: Balance load and responsiveness
✅ Use timeouts: Prevent hung operations
✅ Implement caching: Where appropriate (validation, resolution)
✅ Optimize regex: Compile patterns at class level
✅ Minimize I/O: Async operations, batch when possible
Testing
✅ Unit test validation: Test all validation paths
✅ Test error handling: Simulate failures
✅ Integration tests: Test with real commands
✅ Mock external deps: Don't rely on network in tests
✅ Test resource limits: Verify enforcement
Testing Guide
Running Tests
# All tests
pytest
# Unit tests only
pytest tests/unit/
# Integration tests only
pytest tests/integration/
# Specific test file
pytest tests/unit/test_base_tool.py
# Specific test
pytest tests/unit/test_base_tool.py::test_input_validation
# With coverage
pytest --cov=mcp_server --cov-report=html
# Verbose output
pytest -v
# Show print statements
pytest -s
# Stop on first failure
pytest -x
Writing Tests
Fixture example (conftest.py):
import pytest
import asyncio
from mcp_server.config import get_config, reset_config
from mcp_server.base_tool import MCPBaseTool
@pytest.fixture
def event_loop():
"""Create event loop for async tests."""
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()
@pytest.fixture
def test_config():
"""Provide test configuration."""
reset_config()
config = get_config(force_new=True)
config.security.allowed_targets = ["RFC1918", ".lab.internal"]
config.security.allow_intrusive = False
yield config
reset_config()
@pytest.fixture
def mock_tool(test_config):
"""Create mock tool for testing."""
class MockTool(MCPBaseTool):
command_name = "echo"
allowed_flags = ["-n", "-e"]
return MockTool()
Test example:
import pytest
from mcp_server.base_tool import ToolInput, ToolErrorType
@pytest.mark.asyncio
async def test_tool_execution_success(mock_tool):
"""Test successful tool execution."""
result = await mock_tool.run(ToolInput(
target="192.168.1.1",
extra_args="-n"
))
assert result.returncode == 0
assert not result.timed_out
assert result.execution_time > 0
assert result.correlation_id is not None
@pytest.mark.asyncio
async def test_input_validation_blocks_public_ip(mock_tool):
"""Test that public IPs are rejected."""
with pytest.raises(ValueError, match="RFC1918"):
ToolInput(target="8.8.8.8")
@pytest.mark.asyncio
async def test_command_injection_blocked(mock_tool):
"""Test that shell metacharacters are blocked."""
with pytest.raises(ValueError, match="forbidden metacharacters"):
ToolInput(target="192.168.1.1", extra_args="; rm -rf /")
Code Style & Standards
Style Guide: PEP 8
Docstrings: Google style
Type Hints: Comprehensive, Python 3.11+ syntax
Line Length: 100 characters max
Imports: Grouped (stdlib, third-party, local)
Logging: Structured, consistent format
Example:
"""
Module docstring with description.
This module provides...
"""
import asyncio
import logging
from typing import Optional, Dict, Any
from third_party import SomeClass
from mcp_server.base_tool import MCPBaseTool
log = logging.getLogger(__name__)
class MyTool(MCPBaseTool):
"""
Class docstring.
Longer description...
Attributes:
command_name: The system command to execute
Example:
>>> tool = MyTool()
>>> result = await tool.run(ToolInput(target="192.168.1.1"))
"""
command_name = "mytool"
async def my_method(self, param: str) -> Optional[Dict[str, Any]]:
"""
Method docstring.
Args:
param: Description of parameter
Returns:
Dictionary with results or None
Raises:
ValueError: If param is invalid
"""
log.info("my_method.called param=%s", param)
if not param:
raise ValueError("param cannot be empty")
return {"result": param}
📊 Monitoring & Operations
Health Checks
Endpoint Usage
# Basic health check
curl http://localhost:8080/health
# Detailed health information
curl http://localhost:8080/health | jq .
# Check specific aspect
curl http://localhost:8080/health | jq '.checks.system_resources'
# Monitor continuously
watch -n 5 'curl -s http://localhost:8080/health | jq .status'
Interpreting Results
Status Codes:
200 OK
: System healthy, all checks passed
207 Multi-Status
: System degraded, some issues detected
503 Service Unavailable
: System unhealthy, critical failure
Check Priorities:
CRITICAL (0): Failure causes UNHEALTHY status
CPU usage > 80%
Memory usage > 80%
Disk usage > 80%
IMPORTANT (1): Failure causes DEGRADED status
Process not running
Circuit breaker open
INFORMATIONAL (2): Logged only
Metrics
Prometheus Integration
Scrape configuration (prometheus.yml):
scrape_configs:
- job_name: 'mcp-server'
static_configs:
- targets: ['localhost:9090']
scrape_interval: 15s
Available Metrics
Tool Execution:
# Total executions
mcp_tool_execution_total{tool="NmapTool", status="success", error_type="none"}
# Execution latency histogram
mcp_tool_execution_seconds{tool="NmapTool", quantile="0.5"} # p50
mcp_tool_execution_seconds{tool="NmapTool", quantile="0.95"} # p95
mcp_tool_execution_seconds{tool="NmapTool", quantile="0.99"} # p99
# Active executions
mcp_tool_active{tool="NmapTool"}
# Errors
mcp_tool_errors_total{tool="NmapTool", error_type="timeout"}
Circuit Breaker:
# State (0=closed, 1=open, 2=half-open)
circuit_breaker_state{name="NmapTool_12345"}
# Calls
circuit_breaker_calls_total{name="NmapTool_12345", result="success"}
# State transitions
circuit_breaker_transitions_total{name="NmapTool_12345", from_state="CLOSED", to_state="OPEN"}
Grafana Dashboard
Import this into Grafana for instant monitoring:
{
"dashboard": {
"title": "MCP Server Monitoring",
"panels": [
{
"title": "Request Rate",
"targets": [
{
"expr": "rate(mcp_tool_execution_total[5m])"
}
]
},
{
"title": "Success Rate",
"targets": [
{
"expr": "rate(mcp_tool_execution_total{status=\"success\"}[5m]) / rate(mcp_tool_execution_total[5m])"
}
]
},
{
"title": "Latency Percentiles",
"targets": [
{
"expr": "histogram_quantile(0.50, mcp_tool_execution_seconds)",
"legendFormat": "p50"
},
{
"expr": "histogram_quantile(0.95, mcp_tool_execution_seconds)",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.99, mcp_tool_execution_seconds)",
"legendFormat": "p99"
}
]
},
{
"title": "Circuit Breaker States",
"targets": [
{
"expr": "circuit_breaker_state"
}
]
}
]
}
}
Logging
Log Levels
Level | Usage | Example |
DEBUG | Development, troubleshooting | Detailed function calls, variable values |
INFO | Normal operations | Request received, tool executed, config loaded |
WARNING | Potential issues | High resource usage, deprecated features |
ERROR | Errors requiring attention | Tool execution failed, validation errors |
CRITICAL | System-threatening issues | Cannot start, critical dependency missing |
Log Format
Default (human-readable):
2024-01-15 10:30:45,123 - mcp_server.server - INFO - tool.execution tool=NmapTool target=192.168.1.1 duration=2.34
JSON (machine-readable):
{
"timestamp": "2024-01-15T10:30:45.123Z",
"level": "INFO",
"logger": "mcp_server.server",
"message": "tool.execution",
"tool": "NmapTool",
"target": "192.168.1.1",
"duration": 2.34
}
Log Aggregation
Example: ELK Stack
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/mcp-server/*.log
json.keys_under_root: true
json.add_error_key: true
output.elasticsearch:
hosts: ["localhost:9200"]
index: "mcp-server-%{+yyyy.MM.dd}"
Troubleshooting
Common Issues
1. Server won't start
# Check Python version
python --version # Should be 3.11+
# Check dependencies
pip check
# Check configuration
python -c "from mcp_server.config import get_config; get_config()"
# Check ports
sudo lsof -i :8080 # HTTP port
sudo lsof -i :9090 # Metrics port
2. Tool execution fails
# Check tool availability
which nmap
# Check permissions
ls -l /usr/bin/nmap
# Test manually
nmap -sV --top-ports 10 192.168.1.1
# Check logs
./scripts/mcp_server_launcher.sh logs
3. High memory usage
# Check metrics
curl http://localhost:8080/metrics | grep memory
# Check active executions
curl http://localhost:8080/health | jq '.checks.process_health.metadata'
# Reduce concurrency
export MCP_TOOL_DEFAULT_CONCURRENCY=1
4. Circuit breaker constantly open
# Check circuit breaker state
curl http://localhost:8080/health | jq '.checks[] | select(.name | contains("circuit"))'
# Check error rates
curl http://localhost:8080/metrics | grep circuit_breaker
# Increase threshold
export MCP_CIRCUIT_BREAKER_FAILURE_THRESHOLD=10
# Decrease recovery timeout for testing
export MCP_CIRCUIT_BREAKER_RECOVERY_TIMEOUT=30
Debug Mode
# Enable debug logging
export LOG_LEVEL=DEBUG
python -m mcp_server.server
# Or in Docker
docker run -e LOG_LEVEL=DEBUG nordheim/security-mcp-server
Getting Help
🔒 Security
Security Model
Security MCP Server implements defense in depth with multiple security layers:
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#0066cc'}}}%%
graph TB
A[Request] --> B{Input Validation}
B -->|Invalid| C[Reject]
B -->|Valid| D{Network Check}
D -->|Public IP| C
D -->|Private IP| E{Argument Sanitization}
E -->|Dangerous| C
E -->|Safe| F{Resource Limits}
F -->|Exceeded| G[Timeout/Kill]
F -->|OK| H{Command Execution}
H --> I{Circuit Breaker}
I -->|Open| C
I -->|Closed| J[Execute]
J --> K[Monitor & Log]
K --> L[Return Result]
style C fill:#ff4444,color:#fff
style L fill:#44ff44,color:#000
Network Restrictions
Allowed:
✅ RFC1918 Private IPs: 10.0.0.0/8
, 172.16.0.0/12
, 192.168.0.0/16
✅ Loopback: 127.0.0.0/8
✅ .lab.internal domains: *.lab.internal
Blocked:
Input Validation
Shell Metacharacter Blocking:
Blocked characters: ; & | \
$ > < \n \r`
Whitelist-based flag validation
Token pattern matching: ^[A-Za-z0-9.:/=+,\-@%_]+$
Argument Limits:
Resource Limits
Process Limits (Linux only):
CPU time: Based on timeout setting
Memory: 512MB (configurable via MCP_MAX_MEMORY_MB
)
File descriptors: 256 (configurable via MCP_MAX_FILE_DESCRIPTORS
)
Core dump: Disabled
Output Limits:
Execution Limits:
Timeout: 300s default (configurable)
Concurrency: 2 per tool (configurable)
Process isolation: New session group
Reporting Vulnerabilities
We take security seriously. If you discover a security vulnerability:
DO NOT open a public issue
Email: security@example.com
Include:
We will respond within 48 hours
We will provide a fix within 7 days for critical issues
Security Best Practices
For Operators:
✅ Run as non-root user
✅ Use firewall rules (allow only necessary ports)
✅ Enable audit logging
✅ Regularly update dependencies
✅ Monitor for suspicious activity
✅ Use TLS for HTTP mode (reverse proxy)
✅ Implement rate limiting
✅ Keep MCP_SECURITY_ALLOW_INTRUSIVE=false
in production
For Developers:
✅ Validate all inputs
✅ Use whitelist approach for flags
✅ Sanitize before execution
✅ Enforce resource limits
✅ Log security events
✅ Handle errors gracefully
✅ Test security controls
❓ FAQ & Troubleshooting
Frequently Asked Questions
A: No, by design. Security MCP Server only allows RFC1918 private IPs and .lab.internal
domains. This prevents accidental scanning of external networks and ensures the tool is used only in controlled environments.
To scan external targets, you would need to modify the validation logic in base_tool.py
, but this is strongly discouraged for security and legal reasons.
A: Set the environment variable:
export MCP_SECURITY_ALLOW_INTRUSIVE=true
Or in configuration file:
security:
allow_intrusive: true
WARNING: Only enable in controlled lab environments. Intrusive scans can be detected and may violate policies.
A: Circuit breakers open after consecutive failures. Check:
Tool is actually installed (which nmap
)
Error logs for root cause
Failure threshold is appropriate
Network targets are reachable
Adjust settings:
# Increase threshold
export MCP_CIRCUIT_BREAKER_FAILURE_THRESHOLD=10
# Decrease recovery timeout
export MCP_CIRCUIT_BREAKER_RECOVERY_TIMEOUT=30
Force close:
from mcp_server.tools.nmap_tool import NmapTool
tool = NmapTool()
await tool._circuit_breaker.force_close()
A: Yes! Security MCP Server is production-ready with:
However, ensure you:
Use HTTPS (reverse proxy)
Enable authentication/authorization
Configure firewalls
Monitor actively
Keep dependencies updated
Follow security best practices
A: See the Creating Custom Tools section. In summary:
Create a new file in mcp_server/tools/
Inherit from MCPBaseTool
Define command_name
and allowed_flags
Optionally override methods for custom behavior
Tool is auto-discovered!
A: Yes! Configure mcp.json
in Claude Desktop:
{
"mcpServers": {
"security-tools": {
"command": "/path/to/venv/bin/python",
"args": ["-m", "mcp_server.server"],
"env": {
"MCP_SERVER_TRANSPORT": "stdio"
}
}
}
}
See Claude Desktop Integration for details.
A:
Feature | stdio | HTTP |
Use Case | AI agents (Claude) | APIs, monitoring, web apps |
Transport | stdin/stdout | HTTP REST |
I/O | Line-based | JSON |
Monitoring | Limited | Full (health, metrics) |
Multiple Clients | No (single process) | Yes (concurrent) |
Deployment | Simple | Production-ready |
Choose stdio for Claude Desktop, HTTP for everything else.
A: Multiple options:
Health Check:
curl http://localhost:8080/health
Prometheus Metrics:
curl http://localhost:8080/metrics
Server-Sent Events (real-time):
curl http://localhost:8080/events
Grafana Dashboard: Import the provided JSON (see Metrics)
Logs:
./scripts/mcp_server_launcher.sh logs
Common Issues & Solutions
Issue | Symptoms | Solution |
Import Error | ModuleNotFoundError: No module named 'mcp_server'
| Install in editable mode: pip install -e .
|
Permission Denied | Tool execution fails with permission error | Check nmap capabilities: getcap /usr/bin/nmap
|
Port Already in Use | Server won't start, Address already in use
| Change port: export MCP_SERVER_PORT=8081
or kill existing process |
Health Check Fails | /health
returns 503 | Check logs for specific failing checks |
Timeout Errors | Tool execution times out | Increase timeout: export MCP_TOOL_DEFAULT_TIMEOUT=600
|
High Memory | Container OOM or high usage | Reduce concurrency: export MCP_TOOL_DEFAULT_CONCURRENCY=1
|
🤝 Contributing
We welcome contributions! Here's how you can help:
How to Contribute
Fork the repository
git clone https://github.com/YOUR_USERNAME/Security-MCP-Server.git
cd Security-MCP-Server
Create a feature branch
git checkout -b feature/amazing-feature
Make your changes
Add features or fix bugs
Write tests
Update documentation
Follow code style
Test your changes
pytest
pytest --cov=mcp_server
Commit with clear messages
git commit -m "feat: add amazing feature"
Commit message format:
Push and create PR
git push origin feature/amazing-feature
Then create a Pull Request on GitHub
Development Setup
# Clone your fork
git clone https://github.com/YOUR_USERNAME/Security-MCP-Server.git
cd Security-MCP-Server
# Add upstream remote
git remote add upstream https://github.com/nordeim/Security-MCP-Server.git
# Create virtual environment
python3.11 -m venv venv
source venv/bin/activate
# Install dev dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt # If exists
pip install -e .
# Install pre-commit hooks
pip install pre-commit
pre-commit install
# Run tests
pytest
# Run linters
flake8 mcp_server/
black --check mcp_server/
mypy mcp_server/
Pull Request Process
✅ Update documentation if needed
✅ Add tests for new features
✅ Ensure all tests pass
✅ Update CHANGELOG.md
✅ Follow code style (PEP 8)
✅ Keep PRs focused (one feature/fix per PR)
✅ Respond to review feedback
Code of Conduct
Be respectful and inclusive
Constructive feedback only
Focus on the code, not the person
Help others learn and grow
Community
🗺️ Roadmap
Current Version: 2.0.0 ✅
Production-ready release with comprehensive features.
Planned Features
v2.1.0 (Q2 2024)
Additional Tools
Enhanced Metrics
OpenTelemetry support
Distributed tracing
Authentication
API key authentication
JWT support
OAuth2 integration
v2.2.0 (Q3 2024)
Result Storage
Scheduled Scans
Cron-like scheduling
Recurring scans
Email notifications
Web UI
Result visualization
Scan management
Real-time dashboard
v3.0.0 (Q4 2024)
Multi-Tenancy
Organization support
User management
RBAC
Advanced Security
High Availability
Redis for state
Leader election
Distributed execution
Known Limitations
IPv6 support not yet implemented
Windows resource limits not enforced (Linux only)
Single-instance deployment (no clustering yet)
Limited to command-line tools (no native SDK integrations)
Community Requests
Vote on features in GitHub Discussions!
📄 License & Credits
License
This project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2024 Security MCP Server Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Authors
Contributors
Thanks to all contributors who have helped make this project better!
Acknowledgments
Model Context Protocol - For the excellent MCP specification
Anthropic - For Claude and MCP inspiration
Nmap Project - For the powerful network scanning tool
FastAPI - For the modern web framework
Prometheus - For metrics and monitoring
Docker - For containerization platform
Third-Party Licenses
This project uses the following open-source packages:
Package | License | Purpose |
Python | PSF | Programming language |
FastAPI | MIT | Web framework |
Uvicorn | BSD-3 | ASGI server |
Pydantic | MIT | Data validation |
prometheus-client | Apache-2.0 | Metrics |
psutil | BSD-3 | System monitoring |
PyYAML | MIT | Configuration |
nmap | GPL-2.0 | Network scanning |
⭐ Star this repository if you find it helpful!
Built with ❤️ by the Security MCP Server community
⬆ Back to top