Skip to main content
Glama
brendanong95

tenable-activity-mcp

by brendanong95

tenable-activity-mcp

Tests

Un servidor MCP que expone el registro de auditoría/actividad de Tenable Vulnerability Management (GET /audit-log/v1/events) como un pequeño conjunto de herramientas, para que cualquier cliente MCP pueda preguntar sobre la actividad de la plataforma, el uso de claves API y comportamientos anómalos bajo demanda.

El servidor hace el análisis. El conteo, la agrupación, los cálculos de tasas y las comparaciones de umbrales se realizan en Python; las herramientas devuelven resultados estructurados y finales (failure_rate_pct, by_actor, findings con razonamiento) en lugar de volcar eventos sin procesar para que el modelo los sume.

Lo que te ofrece

Herramienta

Propósito

list_activity_events

Flujo de eventos para una ventana, con filtros de actor/acción. La paginación se sigue automáticamente; devuelve un next_token reanudable si se alcanza un límite de seguridad.

summarize_activity

Resumen determinista para una ventana: recuentos por actor, acción, tipo CRUD y tipo de acceso, además de tasas de fallo/anónimo.

get_api_key_usage

Solo actividad impulsada por claves API, agrupada por actor: desglose de acciones, IPs de origen distintas, primera/última vez visto.

detect_anomalies

Compara una ventana con la línea base almacenada de cada actor. Señala nuevos actores, picos de volumen, IPs de origen no vistas, ráfagas de eventos fallidos, tasas de fallo sostenidas, picos fuera de horario y acciones nunca antes vistas, cada uno con evidencia y una frase de razonamiento.

get_actor_profile

La imagen completa de un actor: rol (mejor esfuerzo), desglose de acciones de todos los tiempos, tipos de acceso, cada IP de origen vista.

check_permission_prereqs

Aprobado/fallido sobre si las claves configuradas pueden realmente leer el registro de auditoría, con texto de remediación.

Propiedades de seguridad que vale la pena conocer:

  • Nunca se devuelve nada que parezca una credencial. Los valores de campos cuyos nombres de clave sugieran un secreto (secret_key, api_key, token, password, ...) o cuyo valor parezca material de clave de Tenable se enmascaran a sus últimos 4 caracteres.

  • La paginación está limitada a 20 páginas / 100k eventos por llamada de herramienta; alcanzar el límite se informa explícitamente junto con el cursor necesario para continuar.

  • Los 429 retroceden usando el encabezado X-RateLimit-Reset (el endpoint no envía Retry-After), con retroceso exponencial y un techo de reintentos.

Related MCP server: Entra Identity Posture MCP

Requisitos

  • Python 3.11+

  • uv

  • Claves API de Tenable VM cuyo propietario pueda leer el registro de auditoría

Rol / permisos de Tenable

Leer audit-log/v1/events requiere el rol Administrador, o un rol personalizado con permiso explícito de lectura del registro de auditoría, en el usuario que posee las claves API. Cualquier cosa menos obtiene HTTP 403; check_permission_prereqs informa eso en lenguaje claro.

Genera claves en Tenable VM bajo Configuración → Mi cuenta → Claves API. Las claves heredan los permisos del usuario que las creó.

get_actor_profile además intenta resolver el rol de un actor desde el directorio de usuarios. Si las claves no pueden listar usuarios, el perfil aún se devuelve, solo que sin la etiqueta de rol.

Configuración

uv sync --extra dev

Luego copia .env.example a .env y completa tus claves:

cp .env.example .env

Verifica las credenciales y permisos antes de conectarlo a un cliente:

uv run python -c "from dotenv import load_dotenv; load_dotenv(); from src.server import check_permission_prereqs; print(check_permission_prereqs())"

Ejecuta el servidor directamente (habla MCP sobre stdio, así que simplemente se quedará esperando a un cliente; ese es el comportamiento correcto):

uv run python -m src.server

Conectando un cliente

Usa la ruta absoluta a tu clon en la configuración a continuación. Para imprimirla, ejecuta pwd desde la raíz del repositorio en macOS/Linux, o (Get-Location).Path en PowerShell.

Claude Desktop

Edita claude_desktop_config.json:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "tenable-activity": {
      "command": "uv",
      "args": [
        "--directory",
        "C:\\path\\to\\tenable-activity-mcp",
        "run",
        "python",
        "-m",
        "src.server"
      ],
      "env": {
        "TENABLE_ACCESS_KEY": "your_access_key",
        "TENABLE_SECRET_KEY": "your_secret_key",
        "TENABLE_MCP_BASE_URL": "https://cloud.tenable.com"
      }
    }
  }
}

Reinicia Claude Desktop después. En macOS/Linux usa una ruta POSIX (/Users/you/tenable-activity-mcp).

Si uv no está en el PATH del lanzador, usa su ruta absoluta (which uv / (Get-Command uv).Source) como command.

Claude Code

claude mcp add tenable-activity --env TENABLE_ACCESS_KEY=your_access_key --env TENABLE_SECRET_KEY=your_secret_key -- uv --directory /absolute/path/to/tenable-activity-mcp run python -m src.server

O agrega el mismo bloque de arriba a un .mcp.json a nivel de proyecto.

Las credenciales pasadas mediante env tienen prioridad sobre .env; el archivo .env es una conveniencia para desarrollo local, y cualquiera de los dos mecanismos funciona.

Preguntas de ejemplo para hacer una vez conectado

  • "Comprueba si mis credenciales de Tenable pueden leer el registro de auditoría."

  • "Resume la actividad de la plataforma Tenable de los últimos 7 días: ¿quién fue más activo y cuál es la tasa de fallos?"

  • "¿Qué claves API se usaron contra Tenable en los últimos 30 días y desde qué IPs de origen?"

  • "Busca anomalías en la actividad de Tenable de los últimos 3 días contra una línea base de 30 días, y explica cualquier cosa que señales."

  • "Muéstrame todo lo que el actor 00000000-1111-4222-8333-444444444444 ha hecho alguna vez: acciones, tipos de acceso e IPs."

Cómo funciona la detección de anomalías

detect_anomalies necesita historial para comparar, que vive en un archivo SQLite local (state.db, creado automáticamente):

  1. Si las líneas base almacenadas son más antiguas que BASELINE_REFRESH_MAX_AGE_HOURS (12), el servidor obtiene los baseline_days inmediatamente anteriores a tu ventana y recalcula los promedios por actor, IPs conocidas, acciones conocidas y un histograma de hora del día.

  2. Tu ventana se obtiene y se compara contra esas líneas base.

  3. Los eventos en la ventana analizada no se incorporan a la línea base, por lo que volver a ejecutar la misma ventana devuelve los mismos hallazgos.

Cada umbral es una constante nombrada al inicio de src/anomaly.py y se repite en cada resultado bajo thresholds:

Constante

Predeterminado

Significado

SPIKE_MULTIPLIER

3.0

Los eventos/día de la ventana deben exceder este múltiplo del promedio de la línea base

SPIKE_MIN_WINDOW_EVENTS

20

Mínimo antes de que un pico pueda señalarse en absoluto

NEW_IP_LOOKBACK_DAYS

30

Cuán recientemente debe haberse visto una IP para contar como "conocida"

FAILED_AUTH_BURST_COUNT / FAILED_AUTH_BURST_WINDOW_MINUTES

5 / 10

Disparador de agrupación de fallos

HIGH_FAILURE_RATE_PCT

50.0

Disparador de tasa de fallo sostenida (sobre al menos 10 eventos)

OFF_HOURS_START_HOUR / OFF_HOURS_END_HOUR

20 / 6 (UTC)

Banda fuera de horario

OFF_HOURS_RATIO_MULTIPLIER

2.0

La proporción fuera de horario debe exceder este múltiplo de la proporción de la línea base del actor

Las líneas base son por actor, por lo que una cuenta de servicio que legítimamente ejecuta 500 escaneos al día no se señala por hacer exactamente eso.

Estructura

src/
  server.py          MCP entrypoint (FastMCP-style) + the six tool definitions
  tenable_client.py  Auth, filter building, cursor pagination, 429 backoff, typed errors
  classifier.py      API-key vs UI/session tagging, IP extraction, redaction, rollups
  anomaly.py         Thresholds and the individual anomaly checks
  state.py           SQLite: cursors, accumulated actor history, computed baselines
tests/
  test_pagination.py test_classifier.py test_anomaly.py

La dirección de dependencias es unidireccional: server → {anomaly, classifier, state} → tenable_client.

Pruebas

Tres niveles, en el orden en que deberías ejecutarlos.

1. Pruebas unitarias (sin credenciales, sin red)

uv run pytest -q

105 pruebas que cubren manejo de paginación/cursor, retroceso de límite de tasa, clasificación de clave API vs sesión, redacción y cada umbral de anomalía. Cada respuesta de API se simula a través de un transporte stub, por lo que la suite nunca toca un tenant en vivo.

2. Extremo a extremo sin conexión (sin credenciales, sin red)

uv run python scripts/smoke_local.py

Ejecuta las seis herramientas contra un Tenable falso con guion (un mes de línea base tranquilo, luego una noche ruidosa desde una IP nueva) y verifica los resultados: anomalías señaladas, secretos plantados redactados, entrada incorrecta devuelta como error estructurado en lugar de excepción. Sale con código no cero en cualquier fallo, por lo que funciona como puerta de pre-commit o CI.

3. Verificación en vivo contra tu tenant (solo lectura)

Con .env completado:

uv run python scripts/live_check.py 7

Primero verifica los permisos del registro de auditoría y se detiene con texto de remediación si son incorrectos, luego imprime un resumen real, desglose de uso de claves API, hallazgos de anomalías y el perfil del actor más ocupado de los últimos N días (predeterminado 7). Todas las llamadas son GET; no se escribe nada en Tenable.

4. A través de un cliente MCP

Cualquier cliente MCP funciona. Para probar las herramientas interactivamente sin un cliente de chat:

npx @modelcontextprotocol/inspector uv --directory . run python -m src.server

O conéctalo a Claude Desktop / Claude Code (arriba) y haz una de las preguntas de ejemplo. check_permission_prereqs es la primera llamada correcta: confirma que el servidor se inició, encontró sus credenciales y puede llegar al registro de auditoría.

Inspeccionando el estado local

uv run python -c "from src.state import StateStore; print(StateStore().stats())"

Elimina state.db para restablecer las líneas base; la próxima llamada a detect_anomalies las reconstruye.

Limitaciones conocidas

  • Requiere el rol de Administrador. La lectura de audit-log/v1/events requiere el rol de Administrador, o un rol personalizado con permiso explícito de lectura del registro de auditoría, en el usuario propietario de las claves de API. Cualquier permiso inferior devuelve HTTP 403. Ejecute check_permission_prereqs primero: informa exactamente de esto, con texto de corrección.

  • La detección de anomalías necesita historial antes de ser útil. La primera llamada a detect_anomalies contra un state.db nuevo construye las líneas base a partir de los 30 días anteriores a su ventana y luego compara contra ellas. Los actores con poca o ninguna actividad previa se marcan como new_actor, por lo que las primeras ejecuciones son más ruidosas que las posteriores.

  • La resolución de roles es de mejor esfuerzo. get_actor_profile intenta resolver el rol de Tenable de un actor desde el directorio de usuarios. Si las claves no pueden listar usuarios, el perfil se devuelve igualmente, solo que sin la etiqueta del rol.

  • La detección de horas no laborables usa una banda UTC fija. La ventana de horas no laborables es 20:00-06:00 UTC y no se ajusta a la zona horaria de trabajo del inquilino. Los equipos distribuidos verán hallazgos de horas no laborables que son simplemente la mañana laboral de otra región.

  • Las líneas base son locales a la máquina que ejecuta el servidor. state.db no se comparte entre instalaciones, por lo que dos operadores que ejecutan sus propias copias construyen líneas base independientes y pueden llegar a conclusiones diferentes sobre la misma ventana.

  • Las ventanas amplias devuelven resultados parciales por diseño. Una llamada de herramienta sigue como máximo 20 páginas / 100.000 eventos. Alcanzar ese límite se informa explícitamente junto con el next_token necesario para reanudar, por lo que nunca es una truncación silenciosa, pero una ventana muy grande requiere varias llamadas.

  • Solo los primeros 1.000 eventos se devuelven en línea. list_activity_events limita el array events en línea a 1.000 y establece inline_truncated cuando lo hace. El bloque summary sigue cubriendo todos los eventos recuperados, por lo que los números agregados permanecen correctos incluso cuando la lista en línea se recorta.

  • get_actor_profile mira hacia atrás 365 días como máximo, y no puede ver más atrás de lo que el propio registro de auditoría conserva.

Notas

  • Desarrollado con mcp==2.0.0, donde el SDK renombró FastMCP a MCPServer. server.py importa el nombre que proporcione el SDK instalado, por lo que también funciona en mcp 1.x.

  • La recuperación de eventos pasa por la sesión TenableIO de pyTenable (audit_log.events(..., return_json=True)), que mantiene el manejo de autenticación y conexión en la biblioteca mantenida, dejando el cursor pagination.next visible para nosotros. Si pyTenable no está disponible, un transporte equivalente con requests que usa la cabecera X-ApiKeys: accessKey=...;secretKey=... toma el relevo.

  • Las marcas de tiempo están en UTC en todas partes, incluida la banda de horas no laborables.

  • state.db acumula el historial por actor. Elimínelo para restablecer todas las líneas base; la siguiente llamada a detect_anomalies las reconstruye.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Exposes Azure Log Analytics workspace data with tools for querying AuditLogs and AzureActivity tables, supporting custom KQL queries, time range filters, and pagination.
  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server for Tenable Vulnerability Management and the Tenable One platform, enabling LLMs to query assets, vulnerabilities, scans, exposure metrics, attack paths, and more via natural language.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    MCP server for Tenable.io/One Vulnerability Management that provides read-only tools for querying scans, assets, plugins, and vulnerabilities, plus specialized reporting tools for VPR re-prioritization, CISA KEV/EPSS exposure, and scan delta comparisons.
    11
    2
    MIT

View all related MCP servers

Related MCP Connectors

  • A paid remote MCP for AI SDK data query MCP, built to return verdicts, receipts, usage logs, and aud

  • Read-only MCP access to sessions, funnels, campaigns, errors, live visitors, and anomalies.

  • Read-only access to Auralogs production logs: search logs, inspect errors, review AI analyses.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/brendanong95/tenable-activity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server