PortHunter MCP

PortHunter MCP

Analyzes PCAP/PCAPNG network capture files to detect port scanning techniques (SYN, FIN, Xmas), classify scan patterns, and enrich suspicious IP addresses with threat intelligence data. Provides comprehensive network security analysis through natural language interactions.

Category
Visit Server

README

PortHunter MCP — Local MCP server for port-scan analysis (PCAP/PCAPNG)

PortHunter es un servidor MCP local (transport STDIO) que:

  • analiza capturas PCAP/PCAPNG,
  • detecta técnicas comunes de escaneo (SYN, FIN/NULL/Xmas),
  • clasifica patrones (horizontal / vertical),
  • lista sospechosos y obtiene el primer evento relevante,
  • puede enriquecer IPs públicas (OTX/GreyNoise/ASN/Geo) y correlacionarlas.

Está pensado para ser consumido por cualquier host/chatbot MCP.


Requisitos

  • Python 3.11+
  • Windows, Linux o macOS
  • (Opcional) Docker

Instalación

python -m venv .venv
# Windows PowerShell:  .\.venv\Scripts\Activate.ps1
# Linux/macOS:         source .venv/bin/activate
pip install -U pip
pip install -e .

El -e . instala el paquete porthunter en editable desde este repo.


Ejecución (STDIO)

Windows PowerShell (recomendado)

$env:PORT_HUNTER_TOKEN = "TEST_TOKEN"
$env:PORT_HUNTER_ALLOWED_DIR = (Get-Location).Path
python -m porthunter.server

Windows CMD

set PORT_HUNTER_TOKEN=TEST_TOKEN
set PORT_HUNTER_ALLOWED_DIR=%CD%
python -m porthunter.server

Linux/macOS

export PORT_HUNTER_TOKEN=TEST_TOKEN
export PORT_HUNTER_ALLOWED_DIR="$PWD"
python -m porthunter.server

El servidor queda escuchando por STDIO a la espera de llamadas MCP call_tool.


Variables de entorno (seguridad y límites)

Variable Default Descripción
PORT_HUNTER_TOKEN TEST_TOKEN Token requerido si PORT_HUNTER_REQUIRE_TOKEN=true.
PORT_HUNTER_REQUIRE_TOKEN true Exige auth_token en cada llamada de tool.
PORT_HUNTER_ALLOWED_DIR . Directorio raíz permitido para leer PCAP/PCAPNG.
PORT_HUNTER_MAX_PCAP_MB 50 Tamaño máximo del archivo a procesar.
PORT_HUNTER_ALLOW_PRIVATE false Si true, permite enriquecer IPs privadas (por defecto se omite).

mcp.json (ejemplo listo para usar)

{
  "name": "porthunter",
  "version": "0.1.0",
  "transport": {
    "stdio": { "command": "python", "args": ["-m", "porthunter.server"] }
  },
  "env": {
    "PORT_HUNTER_TOKEN": "TEST_TOKEN",
    "PORT_HUNTER_ALLOWED_DIR": ".",
    "PORT_HUNTER_REQUIRE_TOKEN": "true",
    "PORT_HUNTER_MAX_PCAP_MB": "50"
  },
  "tools": [
    "scan_overview",
    "list_suspects",
    "first_scan_event",
    "enrich_ip",
    "correlate"
  ]
}

Tools (API)

Todas las herramientas devuelven UTC ISO-8601 en generated_at.

1) scan_overview(path, time_window_s=60, top_k=20)

Input

{ "path": "captures/scan-demo.pcapng", "time_window_s": 60, "top_k": 20, "auth_token": "TEST_TOKEN" }

Return

{ "ok": true, "overview": { /* ver ejemplo */ }, "generated_at": "..." }

2) list_suspects(path, min_ports=10, min_rate_pps=5.0)

Input

{ "path": "captures/scan-demo.pcapng", "min_ports": 10, "min_rate_pps": 5.0, "auth_token": "TEST_TOKEN" }

Return

{ "ok": true, "suspects": [ /* items */ ], "generated_at": "..." }

3) first_scan_event(path)

Input

{ "path": "captures/scan-demo.pcapng", "auth_token": "TEST_TOKEN" }

Return

{ "ok": true, "first_event": { /* o null */ }, "generated_at": "..." }

4) enrich_ip(ip)

Input

{ "ip": "8.8.8.8", "auth_token": "TEST_TOKEN" }

Return (ok)

{ "ok": true, "enrichment": { "asn": "...", "org": "...", "geo": { "country": "US" }, "threat": { "otx": {...}, "greynoise": {...} } }, "generated_at": "..." }

Return (error)

{ "ok": false, "error": "invalid_ip", "generated_at": "..." }

5) correlate(ips[])

Input

{ "ips": ["abc", "192.168.0.10", "8.8.8.8"], "auth_token": "TEST_TOKEN" }

Return

{
  "ok": true,
  "results": [
    { "ip": "abc", "ok": false, "error": "invalid_ip" },
    { "ip": "192.168.0.10", "skipped": true, "reason": "private_ip" },
    { "ip": "8.8.8.8", "ok": true, "kind": "public", "enrichment": {/*...*/} }
  ],
  "generated_at": "..."
}

Ejemplos de JSON (respuestas reales)

scan_overview (ejemplo)

{
  "ok": true,
  "overview": {
    "file": "captures/scan.pcapng",
    "total_pkts": 12345,
    "interval_s": 600,
    "scanners": [
      {
        "ip": "1.2.3.4",
        "pkts": 500,
        "distinct_ports": 120,
        "distinct_hosts": 30,
        "flag_stats": { "SYN": 480, "FIN": 15, "XMAS": 5 }
      }
    ],
    "targets": [
      { "ip": "10.0.0.5", "pkts": 320, "ports_hit": [22, 80, 443] }
    ],
    "port_distribution": [
      { "port": 80, "hits": 450 }, { "port": 22, "hits": 120 }
    ],
    "suspected_patterns": ["syn_scan", "xmas_scan"]
  },
  "generated_at": "2025-09-20T23:00:02Z"
}

list_suspects (ejemplo)

{
  "ok": true,
  "suspects": [
    {
      "ip": "5.6.7.8",
      "kind": "horizontal",
      "distinct_ports": 50,
      "rate_pps": 7.2,
      "flags_seen": ["SYN"]
    },
    {
      "ip": "9.9.9.9",
      "kind": "vertical",
      "distinct_ports": 1,
      "rate_pps": 12.0,
      "flags_seen": ["SYN","FIN"]
    }
  ],
  "generated_at": "2025-09-20T23:01:12Z"
}

first_scan_event (ejemplo)

{
  "ok": true,
  "first_event": {
    "ts": "2025-09-20T22:59:58Z",
    "src": "1.2.3.4",
    "dst": "10.0.0.5",
    "port": 80,
    "flags": "S"
  },
  "generated_at": "2025-09-20T23:01:45Z"
}

enrich_ip (error por IP inválida)

{ "ok": false, "error": "invalid_ip", "generated_at": "2025-09-20T23:02:10Z" }

correlate (mixto)

{
  "ok": true,
  "results": [
    { "ip": "abc", "ok": false, "error": "invalid_ip" },
    { "ip": "192.168.0.10", "skipped": true, "reason": "private_ip" },
    { "ip": "8.8.8.8", "ok": true, "kind": "public" }
  ],
  "generated_at": "2025-09-20T23:02:30Z"
}

Errores comunes (contract)

  • Archivo fuera del directorio permitido:
{ "ok": false, "error": "path_outside_allowed_dir", "generated_at": "..." }
  • Extensión no soportada:
{ "ok": false, "error": "unsupported_file_type", "generated_at": "..." }
  • Excede tamaño máximo:
{ "ok": false, "error": "file_too_large", "generated_at": "..." }
  • Token faltante o incorrecto (si se requiere):
{ "ok": false, "error": "unauthorized", "generated_at": "..." }

Uso desde un host MCP (pseudo-cliente)

import asyncio, json
from mcp import StdioServerParameters, types
from mcp.client.stdio import stdio_client
from mcp.client.session import ClientSession

async def main():
    params = StdioServerParameters(
        command="python",
        args=["-m", "porthunter.server"],
        env={
            "PORT_HUNTER_TOKEN": "TEST_TOKEN",
            "PORT_HUNTER_ALLOWED_DIR": ".",
        }
    )
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            resp = await session.call_tool(
                name="scan_overview",
                arguments={"path": "captures/scan-demo-20250906-1.pcapng", "auth_token": "TEST_TOKEN"}
            )

            # structuredContent preferente
            sc = getattr(resp, "structuredContent", None)
            if isinstance(sc, dict):
                print(json.dumps(sc.get("result", sc), indent=2))
            else:
                text = "".join(b.text for b in resp.content if isinstance(b, types.TextContent))
                print(text)

asyncio.run(main())

Docker

docker build -t porthunter-mcp .
docker run --rm -it \
  -e PORT_HUNTER_TOKEN=TEST_TOKEN \
  -e PORT_HUNTER_ALLOWED_DIR=/data \
  -v "$PWD:/data" \
  porthunter-mcp

Benchmark (opcional)

python scripts/benchmark_porthunter.py captures/scan-demo-20250906-1.pcapng

Salida sugerida:

  • tamaño archivo,
  • paquetes totales,
  • duración total (s),
  • pps promedio.

Incluye una tablita de resultados en el README si vas a reportar métricas.


Desarrollo

  • Código fuente del servidor en porthunter/
  • Utilidades de PCAP e inteligencia en porthunter/utils/**
  • Ejecuta linters/tests en tu proyecto principal si los tienes allí.
  • Si subes pruebas mínimas aquí: pytest -q

Licencia

MIT (sugerida). Añade un archivo LICENSE si lo deseas.


Créditos y referencias


TL;DR

Arranca con:

$env:PORT_HUNTER_TOKEN = "TEST_TOKEN"
$env:PORT_HUNTER_ALLOWED_DIR = (Get-Location).Path
python -m porthunter.server

Llama scan_overview / list_suspects / first_scan_event / enrich_ip / correlate y consume el JSON como en los ejemplos de arriba.

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