README.md•71.5 kB
<div align="center">
# 🛡️ Security MCP Server
### Production-Ready Model Context Protocol Server for Network Security Tools
[](https://github.com/nordeim/Security-MCP-Server)
[](https://github.com/nordeim/Security-MCP-Server)
[](LICENSE)
[](https://www.python.org/downloads/)
[](https://hub.docker.com/r/nordeim/security-mcp-server)
[](https://modelcontextprotocol.io)
[Quick Start](#-quick-start) • [Documentation](#-table-of-contents) • [Examples](#-usage-guide) • [Contributing](#-contributing)
</div>
---
## 📋 Table of Contents
### For Users
- [Overview](#-overview)
- [Quick Start](#-quick-start)
- [Installation](#-installation--setup)
- [Usage Guide](#-usage-guide)
- [Deployment](#-deployment-guide)
- [FAQ & Troubleshooting](#-faq--troubleshooting)
### For Developers
- [Architecture](#-architecture)
- [Developer Guide](#-developer-guide)
- [Creating Custom Tools](#creating-custom-tools)
- [Testing](#testing-guide)
- [Contributing](#-contributing)
### For Operators
- [Monitoring & Operations](#-monitoring--operations)
- [Security](#-security)
- [API Reference](#-api-reference)
### Additional
- [Roadmap](#-roadmap)
- [License](#-license--credits)
---
## 🌟 Overview
### What is Security MCP Server?
Security MCP Server is a **production-ready** implementation of the [Model Context Protocol (MCP)](https://modelcontextprotocol.io) 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
<table>
<tr>
<td width="33%">
#### 🔒 Security First
- RFC1918/private IP enforcement
- Command injection prevention
- Whitelist-based validation
- Resource limits
- Intrusive operation controls
</td>
<td width="33%">
#### 🏗️ Production Ready
- Circuit breaker pattern
- Health monitoring
- Prometheus metrics
- Graceful shutdown
- Hot-reload configuration
</td>
<td width="33%">
#### 🚀 Developer Friendly
- Easy tool creation
- Comprehensive testing
- Clear documentation
- Docker support
- Extensible architecture
</td>
</tr>
<tr>
<td width="33%">
#### 🛠️ Tool Ecosystem
- **Nmap** - Network scanning
- **Extensible** - Add your own
- **Template-based** - Quick scans
- **Validated** - Safe inputs
</td>
<td width="33%">
#### 📊 Observability
- Real-time health checks
- Prometheus metrics
- Structured logging
- Performance tracking
- Error monitoring
</td>
<td width="33%">
#### 🔄 Resilient
- Auto-retry with backoff
- Circuit breaker protection
- Resource limits
- Timeout enforcement
- Graceful degradation
</td>
</tr>
</table>
### 💡 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
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# 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
- 📖 Read the [Usage Guide](#-usage-guide)
- 🔧 Configure for [Claude Desktop](#claude-desktop-integration)
- 🐳 Try [Docker Deployment](#docker-installation)
- 🛠️ Learn to [Create Custom Tools](#creating-custom-tools)
---
## 🏗️ Architecture
### System Architecture
```mermaid
%%{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
```mermaid
%%{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
```mermaid
%%{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)
```python
# 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:
```mermaid
%%{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**:
```bash
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**:
```bash
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):
1. Environment variables
2. Configuration file (YAML/JSON)
3. 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):
```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:
```python
class MyTool(MCPBaseTool):
command_name = "mytool"
allowed_flags = ["-flag1", "-flag2"]
default_timeout_sec = 60.0
# Auto-discovered and registered!
```
See [Developer Guide](#-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
```bash
git clone https://github.com/nordeim/Security-MCP-Server.git
cd Security-MCP-Server
```
#### 2. Create Virtual Environment
```bash
# Create virtual environment
python3.11 -m venv venv
# Activate (Linux/macOS)
source venv/bin/activate
# Activate (Windows)
venv\Scripts\activate
```
#### 3. Install Dependencies
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# 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)
```bash
# 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
```bash
# 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)
```bash
# 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:
<details>
<summary><b>Server Configuration (click to expand)</b></summary>
```bash
# 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
```
</details>
<details>
<summary><b>Security Settings (click to expand)</b></summary>
```bash
# 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
```
</details>
<details>
<summary><b>Circuit Breaker (click to expand)</b></summary>
```bash
# 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
```
</details>
<details>
<summary><b>Health & Metrics (click to expand)</b></summary>
```bash
# 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
```
</details>
<details>
<summary><b>Logging (click to expand)</b></summary>
```bash
# 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
```
</details>
#### Configuration File
**config/config.yaml**:
```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**:
```bash
export MCP_CONFIG_FILE=config/config.yaml
python -m mcp_server.server
```
---
## 🎮 Usage Guide
### Running the Server
#### Stdio Mode (for Claude Desktop)
```bash
# 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)
```bash
# 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
```bash
# 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
1. **Locate Claude Desktop config**:
```bash
# macOS
~/Library/Application Support/Claude/config.json
# Windows
%APPDATA%\Claude\config.json
# Linux
~/.config/Claude/config.json
```
2. **Add MCP server configuration**:
```json
{
"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"
}
}
}
}
```
3. **Restart Claude Desktop**
4. **Test integration**:
- Ask Claude: "Can you scan 192.168.1.1 for open ports?"
- Claude will use the NmapTool via MCP
### Tool Invocation Examples
#### Basic Network Scan
```bash
# 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
```bash
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
# 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
```bash
# 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**:
```http
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)**:
```json
{
"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)**:
```json
{
"detail": "Target must be RFC1918 IPv4 or a .lab.internal hostname"
}
```
**Response (Rate Limited)**:
```json
{
"detail": {
"error": "Rate limit exceeded",
"message": "Too many requests for NmapTool. Try again later.",
"retry_after": 60
}
}
```
#### Health Check
```http
GET /health HTTP/1.1
```
**Response (Healthy - 200 OK)**:
```json
{
"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)**:
```json
{
"status": "degraded",
"timestamp": "2024-01-15T10:30:00Z",
"checks": {
"system_resources": {
"status": "degraded",
"message": "Memory usage high: 85.0%"
}
}
}
```
**Response (Unhealthy - 503 Service Unavailable)**:
```json
{
"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)
```bash
# 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
```bash
# 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**:
1. **Create dedicated user**:
```bash
sudo useradd -r -s /bin/bash -d /opt/mcp-server mcp
sudo mkdir -p /opt/mcp-server
sudo chown mcp:mcp /opt/mcp-server
```
2. **Install as mcp user**:
```bash
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 .
```
3. **Create systemd service**:
```bash
sudo nano /etc/systemd/system/mcp-server.service
```
```ini
[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
```
4. **Enable and start**:
```bash
sudo systemctl daemon-reload
sudo systemctl enable mcp-server
sudo systemctl start mcp-server
sudo systemctl status mcp-server
```
5. **Configure reverse proxy** (nginx):
```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**:
```bash
# 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**:
```bash
# 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)
<details>
<summary><b>Kubernetes Manifests (click to expand)</b></summary>
**deployment.yaml**:
```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**:
```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**:
```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:
```bash
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
kubectl get pods -l app=mcp-server
```
</details>
### Deployment Checklist
- [ ] **Pre-Deployment**
- [ ] System requirements met
- [ ] Dependencies installed
- [ ] Configuration reviewed
- [ ] Security settings verified
- [ ] Firewall rules configured
- [ ] Monitoring setup ready
- [ ] **Deployment**
- [ ] Application deployed
- [ ] Health check passing
- [ ] Metrics accessible
- [ ] Logs flowing
- [ ] Resource limits enforced
- [ ] **Post-Deployment**
- [ ] Smoke tests passed
- [ ] Integration tests passed
- [ ] Performance tests passed
- [ ] Security scan passed
- [ ] Documentation updated
- [ ] Monitoring alerts configured
- [ ] Backup/restore tested
---
## 🛠️ 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**:
```bash
touch mcp_server/tools/ping_tool.py
```
**2. Implement tool class**:
```python
"""
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**:
```python
# 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**:
```bash
pytest tests/unit/tools/test_ping_tool.py -v
```
**6. Use your tool**:
```bash
# 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
<details>
<summary><b>TracerouteTool with Custom Features (click to expand)</b></summary>
```python
"""
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
```
</details>
### 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
```bash
# 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):
```python
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**:
```python
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**:
```python
"""
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
```bash
# 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
- Tool commands not found
- Optional dependencies missing
### Metrics
#### Prometheus Integration
**Scrape configuration** (prometheus.yml):
```yaml
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
<details>
<summary><b>Example Grafana Dashboard JSON (click to expand)</b></summary>
Import this into Grafana for instant monitoring:
```json
{
"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"
}
]
}
]
}
}
```
</details>
### 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):
```bash
export LOG_FORMAT=json
```
```json
{
"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**
```yaml
# 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**
```bash
# 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**
```bash
# 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**
```bash
# 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**
```bash
# 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
```bash
# 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
- 📖 **Documentation**: This README, `/docs` folder
- 🐛 **Issues**: [GitHub Issues](https://github.com/nordeim/Security-MCP-Server/issues)
- 💬 **Discussions**: [GitHub Discussions](https://github.com/nordeim/Security-MCP-Server/discussions)
- 📧 **Email**: [security-mcp@example.com](mailto:security-mcp@example.com)
---
## 🔒 Security
### Security Model
Security MCP Server implements **defense in depth** with multiple security layers:
```mermaid
%%{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**:
- ❌ Public IP addresses
- ❌ External domains
- ❌ IPv6 addresses (not yet supported)
### Input Validation
**Shell Metacharacter Blocking**:
- Blocked characters: `; & | \` $ > < \n \r`
- Whitelist-based flag validation
- Token pattern matching: `^[A-Za-z0-9.:/=+,\-@%_]+$`
**Argument Limits**:
- Maximum length: 2048 bytes (configurable)
- Maximum port ranges: 100
- Maximum network size: 1024 hosts
### 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**:
- stdout: 1MB max (configurable via `MCP_MAX_STDOUT_BYTES`)
- stderr: 256KB max (configurable via `MCP_MAX_STDERR_BYTES`)
**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:
1. **DO NOT** open a public issue
2. Email: [security@example.com](mailto:security@example.com)
3. Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
4. We will respond within **48 hours**
5. 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
<details>
<summary><b>Q: Can I scan public IP addresses?</b></summary>
**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.
</details>
<details>
<summary><b>Q: How do I enable intrusive scans (nmap -A)?</b></summary>
**A:** Set the environment variable:
```bash
export MCP_SECURITY_ALLOW_INTRUSIVE=true
```
Or in configuration file:
```yaml
security:
allow_intrusive: true
```
**WARNING**: Only enable in controlled lab environments. Intrusive scans can be detected and may violate policies.
</details>
<details>
<summary><b>Q: Why is my circuit breaker always open?</b></summary>
**A:** Circuit breakers open after consecutive failures. Check:
1. Tool is actually installed (`which nmap`)
2. Error logs for root cause
3. Failure threshold is appropriate
4. Network targets are reachable
Adjust settings:
```bash
# Increase threshold
export MCP_CIRCUIT_BREAKER_FAILURE_THRESHOLD=10
# Decrease recovery timeout
export MCP_CIRCUIT_BREAKER_RECOVERY_TIMEOUT=30
```
Force close:
```python
from mcp_server.tools.nmap_tool import NmapTool
tool = NmapTool()
await tool._circuit_breaker.force_close()
```
</details>
<details>
<summary><b>Q: Can I use this in production?</b></summary>
**A:** Yes! Security MCP Server is production-ready with:
- Circuit breakers for resilience
- Health monitoring
- Metrics & observability
- Graceful shutdown
- Resource limits
- Comprehensive testing
However, ensure you:
- Use HTTPS (reverse proxy)
- Enable authentication/authorization
- Configure firewalls
- Monitor actively
- Keep dependencies updated
- Follow security best practices
</details>
<details>
<summary><b>Q: How do I add my own tools?</b></summary>
**A:** See the [Creating Custom Tools](#creating-custom-tools) section. In summary:
1. Create a new file in `mcp_server/tools/`
2. Inherit from `MCPBaseTool`
3. Define `command_name` and `allowed_flags`
4. Optionally override methods for custom behavior
5. Tool is auto-discovered!
</details>
<details>
<summary><b>Q: Does this work with Claude Desktop?</b></summary>
**A:** Yes! Configure `mcp.json` in Claude Desktop:
```json
{
"mcpServers": {
"security-tools": {
"command": "/path/to/venv/bin/python",
"args": ["-m", "mcp_server.server"],
"env": {
"MCP_SERVER_TRANSPORT": "stdio"
}
}
}
}
```
See [Claude Desktop Integration](#claude-desktop-integration) for details.
</details>
<details>
<summary><b>Q: What's the difference between stdio and HTTP mode?</b></summary>
**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.
</details>
<details>
<summary><b>Q: How do I monitor performance?</b></summary>
**A:** Multiple options:
1. **Health Check**:
```bash
curl http://localhost:8080/health
```
2. **Prometheus Metrics**:
```bash
curl http://localhost:8080/metrics
```
3. **Server-Sent Events** (real-time):
```bash
curl http://localhost:8080/events
```
4. **Grafana Dashboard**: Import the provided JSON (see [Metrics](#metrics))
5. **Logs**:
```bash
./scripts/mcp_server_launcher.sh logs
```
</details>
### 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
1. **Fork the repository**
```bash
git clone https://github.com/YOUR_USERNAME/Security-MCP-Server.git
cd Security-MCP-Server
```
2. **Create a feature branch**
```bash
git checkout -b feature/amazing-feature
```
3. **Make your changes**
- Add features or fix bugs
- Write tests
- Update documentation
- Follow code style
4. **Test your changes**
```bash
pytest
pytest --cov=mcp_server
```
5. **Commit with clear messages**
```bash
git commit -m "feat: add amazing feature"
```
Commit message format:
- `feat:` New feature
- `fix:` Bug fix
- `docs:` Documentation
- `test:` Testing
- `refactor:` Code refactoring
- `perf:` Performance improvement
6. **Push and create PR**
```bash
git push origin feature/amazing-feature
```
Then create a Pull Request on GitHub
### Development Setup
```bash
# 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
1. ✅ **Update documentation** if needed
2. ✅ **Add tests** for new features
3. ✅ **Ensure all tests pass**
4. ✅ **Update CHANGELOG.md**
5. ✅ **Follow code style** (PEP 8)
6. ✅ **Keep PRs focused** (one feature/fix per PR)
7. ✅ **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
- 💬 [GitHub Discussions](https://github.com/nordeim/Security-MCP-Server/discussions)
- 🐛 [Issue Tracker](https://github.com/nordeim/Security-MCP-Server/issues)
- 📧 [Mailing List](mailto:mcp-server-dev@example.com)
---
## 🗺️ Roadmap
### Current Version: 2.0.0 ✅
Production-ready release with comprehensive features.
### Planned Features
#### v2.1.0 (Q2 2024)
- [ ] Additional Tools
- [ ] Masscan integration
- [ ] Nikto web scanner
- [ ] SSLScan for certificate analysis
- [ ] Enhanced Metrics
- [ ] OpenTelemetry support
- [ ] Distributed tracing
- [ ] Authentication
- [ ] API key authentication
- [ ] JWT support
- [ ] OAuth2 integration
#### v2.2.0 (Q3 2024)
- [ ] Result Storage
- [ ] Database integration (PostgreSQL)
- [ ] Historical scan data
- [ ] Result comparison
- [ ] 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
- [ ] mTLS support
- [ ] Hardware security module integration
- [ ] Audit logging
- [ ] 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](https://github.com/nordeim/Security-MCP-Server/discussions/categories/feature-requests)!
---
## 📄 License & Credits
### License
This project is licensed under the **MIT License** - see the [LICENSE](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
- **Nordeim** - *Initial work* - [@nordeim](https://github.com/nordeim)
### Contributors
Thanks to all contributors who have helped make this project better!
<!-- Contributors will be automatically listed here -->
### 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 |
---
<div align="center">
### ⭐ Star this repository if you find it helpful!
### 🐛 Found a bug? [Open an issue](https://github.com/nordeim/Security-MCP-Server/issues)
### 💡 Have an idea? [Start a discussion](https://github.com/nordeim/Security-MCP-Server/discussions)
---
**Built with ❤️ by the Security MCP Server community**
[⬆ Back to top](#-security-mcp-server)
</div>