Security MCP Server

Security MCP Server

Provides AI agents like Claude with secure, controlled access to network security tools like nmap for scanning private networks and lab environments. Features comprehensive safety controls, circuit breakers, and production-ready monitoring.

Category
Visit Server

README

<div align="center">

🛡️ Security MCP Server

Production-Ready Model Context Protocol Server for Network Security Tools

Build Status Coverage License: MIT Python 3.11+ Docker MCP Protocol

Quick StartDocumentationExamplesContributing

</div>


📋 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

<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

# 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):

  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):

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:

<details> <summary><b>Server Configuration (click to expand)</b></summary>

# 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>

# 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>

# 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>

# 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>

# 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:

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

  1. Locate Claude Desktop config:
# macOS
~/Library/Application Support/Claude/config.json

# Windows
%APPDATA%\Claude\config.json

# Linux
~/.config/Claude/config.json
  1. 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"
      }
    }
  }
}
  1. Restart Claude Desktop

  2. 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

# 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

GET /health HTTP/1.1

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:

  1. 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
  1. 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 .
  1. 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
  1. Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable mcp-server
sudo systemctl start mcp-server
sudo systemctl status mcp-server
  1. 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)

<details> <summary><b>Kubernetes Manifests (click to expand)</b></summary>

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

</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:

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

<details> <summary><b>TracerouteTool with Custom Features (click to expand)</b></summary>

"""
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

# 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

    • Tool commands not found
    • Optional dependencies missing

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

<details> <summary><b>Example Grafana Dashboard JSON (click to expand)</b></summary>

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"
          }
        ]
      }
    ]
  }
}

</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):

export LOG_FORMAT=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

# 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:

  • ❌ 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

  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:

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. </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:

# 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()

</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 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:

{
  "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. </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:

    curl http://localhost:8080/health
    
  2. Prometheus Metrics:

    curl http://localhost:8080/metrics
    
  3. Server-Sent Events (real-time):

    curl http://localhost:8080/events
    
  4. Grafana Dashboard: Import the provided JSON (see Metrics)

  5. Logs:

    ./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

    git clone https://github.com/YOUR_USERNAME/Security-MCP-Server.git
    cd Security-MCP-Server
    
  2. Create a feature branch

    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

    pytest
    pytest --cov=mcp_server
    
  5. Commit with clear messages

    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

    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

  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


🗺️ 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!


📄 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!

<!-- 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

💡 Have an idea? Start a discussion


Built with ❤️ by the Security MCP Server community

⬆ Back to top

</div>

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured