Skip to main content
Glama

🛡️ MCP Security Vision

Servidor MCP (Model Context Protocol) para videovigilancia inteligente en tiempo real: conecta cámaras de seguridad (IP por RTSP, analógicas por DVR o capturadora USB) con agentes de IA como Claude Desktop, Cursor, LangChain, AutoGen o tus propios bots.

YOLOv8 detecta objetos, face_recognition identifica personas conocidas y polígonos de intrusión vigilan zonas restringidas. Todo el historial se guarda en SQLite y se expone al agente como herramientas MCP.

Captura anotada de demostración

Imagen generada por overlay.py con la cámara sintética (CAMERA_SOURCE=synthetic): objetos YOLO, rostro identificado y dos zonas restringidas, una de ellas en alerta (rojo).

CI Docker Hub Python MCP License: MIT


📚 Índice


Related MCP server: Universal Database MCP Server

✨ Características

🎯 Detección de objetos

YOLOv8 (personas, autos, mascotas, mochilas, paquetes…) con confianza configurable

🧑 Reconocimiento facial

Identifica personas conocidas (known_faces/) vs. desconocidos, con estabilización temporal anti-falsos positivos

🚧 Zonas restringidas

Polígonos de intrusión normalizados (0..1), por cámara y por tipo de objeto, con tiempo de permanencia

🗄️ Historial permanente

SQLite con eventos, zonas, personas y rutas de evidencia; consultas por fecha, cámara y tipo

🎥 Multicámara

Varias cámaras definidas en JSON, cada una con su hilo, tracker y estado

🧵 Multihilo con reconexión

Bucle de vídeo en segundo plano, backoff exponencial si se cae el RTSP, nunca bloquea MCP

🖼️ Capturas para agentes multimodales

capture_snapshot devuelve una imagen JPEG (con cajas/zonas opcionales)

🔔 Notificaciones

Webhook JSON opcional (n8n, Home Assistant, Slack, Telegram vía bot) para alertas

🐳 Docker listo

Dockerfile multi-stage + docker-compose + publicación automática en Docker Hub

✅ CI con GitHub Actions

Lint, 144 tests (matriz Python 3.10/3.11/3.12 × MCP SDK 1.x/2.x) y smoke test de la imagen

🔒 Controles de seguridad

Credenciales solo en .env, contraseñas RTSP enmascaradas en logs, HTTP ligado a loopback con validación de Host/Origin, usuario no-root en Docker


🆕 Novedades de la v2.0 / v2.1

v2.1.0 es la revisión de seguridad y robustez: HTTP en loopback con validación de Host/Origin, cleanup_history con confirmación, esquema SQLite v2, backoff real de cámara, inferencia serializada y 144 tests. Ver CHANGELOG.md.

v2.0.1 corrige la guía de problemas frecuentes tras verificarla contra el código (mensajes de consola reales, RTSP_TRANSPORT, FACE_MODEL, validación de YOLO_IMGSZ, comprobación de puerto antes de cargar modelos) y añade los scripts de publicación. Ver CHANGELOG.md.

La v2.0 incorporó las extensiones solicitadas:

  1. Base de datos SQLite para historial permanente (mcp_security_vision/database.py)

    • Tablas events, zones, people, índices y WAL para escrituras concurrentes.

    • Herramientas get_security_report, filtros por horas/tipo y cleanup_history con retención.

  2. GitHub Actions para pruebas y publicación en Docker Hub

    • .github/workflows/ci.yml: lint + tests + smoke test del contenedor.

    • .github/workflows/docker-publish.yml: build multi-arquitectura (amd64/arm64) y push con tags semánticos.

  3. Zonas restringidas (polígonos de intrusión) (mcp_security_vision/zones.py)

    • Detección punto-en-polígono, tracker por IoU para no duplicar eventos, dwell time y evidencia fotográfica.

    • Herramientas MCP add_restricted_zone, list_restricted_zones, remove_restricted_zone, get_active_intrusions.

Y de la hoja de ruta v2.0 original:

  1. Soporte multicámara con CAMERAS en JSON y camera_id en todas las herramientas.

  2. Arquitectura desacoplada (paquete mcp_security_vision/), lista para combinarse con otros servidores MCP (Telegram, WhatsApp, Notion…) sin tocar el código de visión, más webhook opcional para reaccionar a alertas.


🏗️ Arquitectura

                    ┌──────────────────────────────┐
   Claude Desktop   │                              │
   Cursor / Cline ──┤        Servidor MCP          │
   LangChain/AutoGen│  server.py  (13 tools + 1    │
   HTTP / Docker ───┤  recurso security://status)  │
                    └──────────────┬───────────────┘
                                   │  (mismo proceso, sin bloqueo)
                    ┌──────────────▼───────────────┐
                    │        VisionSystem          │
                    │  cámaras · zonas · registro  │
                    └──────┬─────────────┬─────────┘
        ┌──────────────────┼─────────────┼──────────────────┐
        ▼                  ▼             ▼                  ▼
 ┌────────────┐    ┌─────────────┐  ┌──────────┐    ┌────────────┐
 │ CameraWorker│   │  Pipeline   │  │  SQLite  │    │ Snapshots  │
 │ (1 hilo por │   │ YOLO → IoU  │  │ events   │    │  alertas   │
 │  cámara)    │   │ → caras →   │  │ zones    │    │  .jpg      │
 │ reconexión  │   │ zonas → log │  │ people   │    │ retención  │
 └────────────┘    └─────────────┘  └──────────┘    └────────────┘
        │                  │
        │                  └─────► Webhook JSON (opcional)
        └── RTSP · USB · DVR · synthetic

Estructura del repositorio

mcp-security-vision/
├── mcp_security_vision/          # Paquete instalable
│   ├── server.py                 # Herramientas MCP + arranque (compat. SDK 1.x/2.x)
│   ├── system.py                 # Fachada de negocio (lo que usan las tools)
│   ├── camera.py                 # Hilo por cámara + reconexión + estado
│   ├── pipeline.py               # Detección → tracking → caras → zonas → eventos
│   ├── detectors.py              # YOLOv8 + utilidades de cajas
│   ├── faces.py                  # Registro y reconocimiento facial
│   ├── zones.py                  # Polígonos de intrusión + monitor
│   ├── tracker.py                # Tracker IoU (IDs estables)
│   ├── database.py               # SQLite: eventos, zonas, personas
│   ├── snapshots.py              # Evidencias JPEG y retención
│   ├── overlay.py                # Dibujo de cajas, rostros y zonas
│   ├── notifications.py          # Webhook opcional en segundo plano
│   ├── synthetic.py              # Cámara sintética para demos/CI
│   ├── fakes.py                  # Modelos simulados (CI, sin torch ni dlib)
│   └── config.py                 # Settings desde .env (+ multicámara JSON)
├── config/zones.example.json     # Zonas iniciales (seed)
├── known_faces/                  # Fotos de personas conocidas (nombre_apellido.jpg)
├── snapshots/                    # Evidencias generadas
├── data/                         # security.db (SQLite)
├── docs/
│   ├── TROUBLESHOOTING.md        # Problemas frecuentes (verificados con tests)
│   ├── PUBLICAR_EN_GITHUB.md     # Cómo subir el repo (manual, gh, script, agente)
│   └── demo_annotated.jpg        # Captura anotada de ejemplo
├── scripts/
│   ├── check_setup.py            # Diagnóstico de instalación
│   ├── draw_zones.py             # Editor visual de polígonos
│   ├── configure_repo.py         # Quita placeholders antes de publicar
│   └── publish_github.sh         # Push seguro con verificación de secretos
├── tests/                        # 144 tests (unitarios + integración MCP)
├── .github/workflows/            # ci.yml + docker-publish.yml
├── .github/ISSUE_TEMPLATE/       # plantillas de bug y propuesta
├── SECURITY.md · CONTRIBUTING.md # política de seguridad y guía de contribución
├── server.py                     # Atajo: python server.py
├── Dockerfile · docker-compose.yml · Makefile
├── requirements.txt · requirements-dev.txt · pyproject.toml
└── .env.example

🚀 Instalación

Requisitos

  • Python 3.10, 3.11 o 3.12 (dlib todavía no soporta 3.13+)

  • cmake y compilador C++ (para dlib, que usa face-recognition)

    • Debian/Ubuntu: sudo apt install build-essential cmake libopenblas-dev liblapack-dev libgl1

    • macOS: brew install cmake

    • Windows: Visual Studio Build Tools con la carga de trabajo Desarrollo para el escritorio con C++ + CMake

  • Opcional: GPU NVIDIA con CUDA para acelerar YOLO (YOLO_DEVICE=0)

Pasos

git clone https://github.com/kfr0st/mcp-security-vision.git
cd mcp-security-vision

python -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate

pip install -r requirements.txt
cp .env.example .env              # configura tus cámaras y rutas
python scripts/check_setup.py --read-frames

¿Sin cámara a mano? Prueba todo el flujo con la cámara sintética y modelos simulados:

VISION_FAKE_MODELS=1 CAMERA_SOURCE=synthetic python server.py --transport streamable-http --host 127.0.0.1

O simplemente make demo.

Instalación como paquete (opcional)

pip install ".[vision]"     # código + YOLO + dlib
mcp-security-vision --check # comando instalado

📷 Configuración de cámaras

Todo se define en .env (nunca en el código). Ver .env.example para la lista completa.

Una sola cámara

# Webcam o capturadora USB (índice del dispositivo)
CAMERA_SOURCE=0

# Cámara IP / DVR por RTSP
# CAMERA_SOURCE=rtsp://usuario:clave@192.168.1.50:554/Streaming/Channels/101

Varias cámaras

CAMERAS={"entrada": "rtsp://admin:clave@192.168.1.50:554/Streaming/Channels/101", "patio": 0, "demo": "synthetic"}

# O con nombres visibles y cámaras deshabilitadas:
# CAMERAS=[{"id":"entrada","name":"Puerta principal","source":"rtsp://..."},
#          {"id":"patio","name":"Patio trasero","source":0},
#          {"id":"cochera","name":"Cochera","source":2,"enabled":false}]

Todas las herramientas aceptan camera_id; si se omite se usa la primera cámara habilitada.

URLs RTSP habituales

Marca

URL del canal 1 (principal)

Substream (menos CPU)

Hikvision (cámara)

rtsp://user:pass@IP:554/Streaming/Channels/101

.../102

Hikvision (DVR/NVR)

rtsp://user:pass@IP:554/Streaming/Channels/101

.../102

Dahua

rtsp://user:pass@IP:554/cam/realmonitor?channel=1&subtype=0

subtype=1

TP-Link Tapo

rtsp://user:pass@IP:554/stream1

stream2

Reolink

rtsp://user:pass@IP:554/h264Preview_01_main

_sub

Amcrest

rtsp://user:pass@IP:554/cam/realmonitor?channel=1&subtype=0

subtype=1

🎥 Cámaras analógicas (coaxial/BNC): sin cambiar una línea de código.

  1. Vía DVR/XVR (recomendado): conecta el DVR al router y usa su RTSP por canal.

  2. Vía capturadora RCA/BNC → USB (~10 USD): el sistema la ve como webcam CAMERA_SOURCE=0/1.


⚙️ Variables de entorno principales

Variable

Por defecto

Descripción

CAMERA_SOURCE / CAMERAS

0

Fuente única o JSON multicámara (RTSP, índice USB, synthetic)

PROCESS_EVERY_N_FRAMES

5

Analiza IA cada N fotogramas (sube si la CPU va justa)

YOLO_MODEL

yolov8n.pt

yolov8n/s/m/l/x.pt (n = más rápido)

YOLO_CONF

0.5

Umbral de confianza de objetos

YOLO_DEVICE

(auto)

cpu, 0 (GPU CUDA), mps (Apple)

FACE_TOLERANCE

0.6

Distancia máxima para considerar la misma persona (menor = más estricto)

FACE_MODEL

hog

hog (rápido, CPU) o cnn (más preciso, GPU)

FACE_SCALE

0.25

Escala a la que se buscan rostros (súbela si las caras son pequeñas)

FACE_STABILIZER_WINDOW / ..._MIN_VOTES

3 / 2

Anti-parpadeo del reconocimiento

FACES_WITHOUT_PERSON

false

Buscar rostros incluso sin detección de "person"

EVENT_COOLDOWN_SECONDS

20

Anti-spam del mismo evento

INTRUSION_COOLDOWN_SECONDS

30

Anti-spam de reentradas a una zona

PRESENCE_TIMEOUT_SECONDS

2.5

Tiempo sin ver a alguien para considerar que salió de la zona

SNAPSHOT_ON_ALERT

true

Guardar evidencia JPEG de cada alerta

DB_PATH

data/security.db

Base de datos SQLite

KNOWN_FACES_DIR

known_faces

Fotos de referencia

SNAPSHOTS_DIR

snapshots

Capturas

ZONES_SEED_FILE

config/zones.example.json

Zonas iniciales (solo se importan si no existen)

RECONNECT_DELAY_SECONDS / MAX_...

5 / 60

Backoff de reconexión RTSP

RTSP_TRANSPORT

tcp

tcp (estable), udp o auto (deja que FFmpeg decida)

MCP_TRANSPORT

stdio

stdio, sse o streamable-http

MCP_HOST / MCP_PORT

127.0.0.1 / 8000

Solo para transportes HTTP

ALERT_WEBHOOK_URL

(vacío)

Webhook JSON para alertas

VISION_FAKE_MODELS

false

Modo demo/CI sin YOLO ni dlib


🤖 Conexión con agentes de IA

Claude Desktop / Cursor (transporte stdio)

Edita claude_desktop_config.json (~/Library/Application Support/Claude/ en macOS, %APPDATA%\Claude\ en Windows) y añade:

{
  "mcpServers": {
    "security-camera": {
      "command": "/ruta/absoluta/a/mcp-security-vision/venv/bin/python",
      "args": ["/ruta/absoluta/a/mcp-security-vision/server.py"],
      "env": {
        "CAMERA_SOURCE": "rtsp://usuario:clave@192.168.1.50:554/Streaming/Channels/101"
      }
    }
  }
}

En Windows usa C:\\ruta\\...\\venv\\Scripts\\python.exe. Los logs del servidor van a stderr, así que no rompen el protocolo stdio.

Clientes HTTP (Docker, remoto, agentes web)

docker compose up -d --build          # endpoint: http://localhost:8000/mcp
# o en local (solo accesible desde tu máquina):
python server.py --transport streamable-http --host 127.0.0.1 --port 8000

Ejemplo mínimo con el SDK oficial de Python:

import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client


async def main():
    async with streamablehttp_client("http://localhost:8000/mcp") as streams:
        read, write = streams[0], streams[1]  # 3 valores en SDK 1.x, 2 en SDK 2.x
        async with ClientSession(read, write) as session:
            await session.initialize()
            status = await session.call_tool("get_live_status", {})
            print(status.content[0].text)


asyncio.run(main())

El SDK 2.x renombró algunas funciones; el servidor incluye un shim para funcionar con MCP SDK 1.x y 2.x sin cambios.

Prompts de ejemplo

  • «¿Hay alguien en la entrada ahora mismo? ¿Es alguien conocido?»

  • «Toma una captura anotada del patio y dime si el repartidor dejó un paquete en el suelo.»

  • «Revisa los registros de las últimas 24 horas y dime a qué hora pasó Carlos.»

  • «Define una zona restringida llamada "Caja fuerte" con el polígono [[0.6,0.4],[0.95,0.4],[0.95,0.9],[0.6,0.9]] en cam1.»

  • «¿Hay alguna intrusión activa en este momento?»

  • «Estoy frente a la cámara: regístrame como "Administrador".»


🧰 Herramientas MCP

Herramienta

Parámetros

Devuelve

list_cameras

—

Cámaras, fuente enmascarada, estado y FPS

get_live_status

camera_id=""

Objetos, rostros, zonas con intrusos y últimos eventos

capture_snapshot

camera_id="", annotate=false, save=false

Imagen JPEG (con cajas y zonas si annotate=true); save=true la guarda además en snapshots/

get_security_logs

limit=20, camera_id="", hours=0, event_type=""

Historial SQLite filtrado

get_security_report

hours=24, camera_id=""

Totales por tipo/cámara, rostros y zonas

get_active_intrusions

camera_id=""

Personas/objetos dentro de zonas ahora

list_known_people

—

Personas registradas (foto + alta)

register_current_face

person_name, camera_id=""

Guarda el rostro actual (exige 1 sola persona)

forget_known_person

person_name

Elimina foto, memoria y fila SQLite

list_restricted_zones

camera_id=""

Polígonos, etiquetas y estado

add_restricted_zone

camera_id, name, points, labels=["person"], enabled=true

Crea/actualiza zona

remove_restricted_zone

camera_id, name

Elimina zona

cleanup_history

keep_days=30, purge_snapshots=false, confirm=false

Purga eventos antiguos (y capturas si purge_snapshots=true); exige confirm=true

(recurso) security://status

—

JSON con cámaras, personas, zonas y últimos eventos

Eventos registrados (event_type)

intrusion · face_known · face_unknown · person_unidentified · camera_online · camera_offline · face_registered · face_forgotten · zone_added · zone_removed · system


🚧 Zonas restringidas (intrusión)

Las coordenadas son normalizadas (0..1) respecto al ancho y alto de la imagen: (0,0) = esquina superior izquierda, (1,1) = inferior derecha. Así la zona funciona con 720p, 1080p o 4K y sobrevive a reconexiones.

[
  [0.35, 0.30],
  [0.65, 0.30],
  [0.65, 0.95],
  [0.35, 0.95]
]

Cómo crear zonas

  1. Pidiéndoselo al agente (herramienta add_restricted_zone).

  2. Con el editor visual (recomendado para ajustar a mano):

    python scripts/draw_zones.py --camera-id cam1 --name "Puerta trasera" --labels person,car
    # clic = vértice · u = deshacer · c = limpiar · s = guardar
  3. Con el archivo semilla config/zones.example.json (se importa al arrancar si la zona no existe).

Mecánica anti-spam

  • El tracker asigna un ID estable (#1, #2…) a cada objeto; solo se registra una intrusión por entrada.

  • Al salir de la zona (sin detección durante PRESENCE_TIMEOUT_SECONDS) se libera el estado, y una nueva entrada vuelve a alertar (respetando INTRUSION_COOLDOWN_SECONDS).

  • Cada intrusión guarda una captura de evidencia y se acompaña de dwell_seconds (tiempo dentro).


🗄️ Base de datos SQLite

Archivo: data/security.db (WAL activado para escrituras concurrentes desde varios hilos de cámara).

-- Esquema resumido
events(id, camera_id, created_at, event_type, severity, description,
       object_label, track_id, zone_names, snapshot_path, metadata)
zones(id, camera_id, name, points, labels, enabled, created_at, updated_at)
people(id, name, slug, file_name, created_at, updated_at)

Consultas útiles:

-- ¿Quién pasó hoy?
SELECT created_at, description FROM events
WHERE event_type = 'face_known' AND created_at >= date('now', 'start of day');

-- Intrusiones por zona en los últimos 7 días
SELECT zone_names, COUNT(*) FROM events
WHERE event_type = 'intrusion' AND created_at >= datetime('now', '-7 days')
GROUP BY zone_names;

-- Agenda de presencia por persona
SELECT json_extract(metadata, '$.person') AS persona, MIN(created_at), MAX(created_at), COUNT(*)
FROM events WHERE event_type = 'face_known' GROUP BY persona;

Las marcas de tiempo son hora local del servidor en ISO-8601 (YYYY-MM-DDTHH:MM:SS), ordenables como texto.

Respaldo: copia data/security.db (con WAL, usa sqlite3 data/security.db ".backup copia.db"). Retención: cleanup_history(keep_days=90, confirm=true); añade purge_snapshots=true para borrar también las capturas. Sin confirm=true la herramienta solo describe lo que haría.


🐳 Docker

# 1. Configura el entorno
cp .env.example .env

# 2. Construye y levanta (endpoint MCP en http://localhost:8000/mcp)
docker compose up -d --build
docker compose logs -f

# 3. Prueba rápida sin cámara (modo demo)
docker run --rm -p 127.0.0.1:8000:8000 -e VISION_FAKE_MODELS=1 -e CAMERA_SOURCE=synthetic \
  kfr0st/mcp-security-vision:latest
  • Imagen multi-stage (dlib se compila en el builder; la imagen final no lleva compiladores).

  • Corre como usuario no-root (vision).

  • Volúmenes: data (SQLite), snapshots, known_faces, config, yolo-models (pesos persistentes).

  • Para cámara USB en Linux añade devices: ["/dev/video0:/dev/video0"] y group_add: ["video"].

  • Por defecto solo se aceptan hosts locales (localhost, 127.0.0.1, [::1] y sus puertos). Si publicas detrás de un proxy, añade tu dominio a MCP_ALLOWED_HOSTS (por ejemplo, MCP_ALLOWED_HOSTS=mcp.midominio.com,mcp.midominio.com:*) y define MCP_ALLOWED_ORIGINS=https://mcp.midominio.com si usas un navegador.

  • El transporte HTTP no trae autenticación. No lo expongas directamente a Internet: usa un proxy con TLS y autenticación, o una red privada/VPN.

  • PRELOAD_MODELS=true (build-arg) incluye yolov8n.pt en la imagen para despliegues sin Internet.

  • El contenedor corre como UID 1000. Si usas bind mounts en Linux y ves Permission denied: sudo chown -R 1000:1000 data snapshots known_faces (o usa volúmenes nombrados).


🔁 GitHub Actions y Docker Hub

CI (.github/workflows/ci.yml)

Se ejecuta en cada push y pull request:

  1. Lint: ruff check + ruff format --check.

  2. Tests: matriz Python 3.10 / 3.11 / 3.12 × MCP SDK 1.x / 2.x, con VISION_FAKE_MODELS=1 (sin torch ni dlib → CI en ~1 min), cobertura y JUnit XML.

  3. Smoke test Docker: construye la imagen, arranca el contenedor en modo demo y espera a que abra el puerto 8000.

Publicación en Docker Hub (.github/workflows/docker-publish.yml)

Se dispara con tags v*.*.*, pushes a main o manualmente. Construye linux/amd64 + linux/arm64 y publica:

Evento

Tags

Tag v1.2.3

1.2.3, 1.2, 1, latest

Push a main

main, sha-xxxxxxx, latest

Configuración (una sola vez)

  1. Crea un repositorio en Docker Hub: kfr0st/mcp-security-vision.

  2. Genera un Access Token en Docker Hub → Account settings → Security.

  3. En GitHub → Settings → Secrets and variables → Actions, añade:

    • DOCKERHUB_USERNAME

    • DOCKERHUB_TOKEN

    • (opcional) DOCKERHUB_REPO si el repo no se llama mcp-security-vision.

  4. Publica:

    git tag v2.1.0 && git push origin v2.1.0

Si faltan los secrets, el workflow solo hace build (con un warning) y no falla.


🧪 Desarrollo y pruebas

pip install -r requirements-dev.txt      # sin torch/dlib
pip install --no-deps -e .

make test      # pytest + cobertura (144 tests, ~25 s)
make lint      # ruff check
make format    # ruff format + fixes
make demo      # servidor con cámara sintética y modelos falsos
make check     # valida .env y rutas

Qué cubren los tests:

  • Parseo de configuración (multicámara, validaciones, enmascarado de credenciales).

  • SQLite: eventos, filtros temporales, resúmenes, zonas, personas y persistencia.

  • Geometría de polígonos + monitor de intrusiones (entrada, dwell, reentrada, etiquetas).

  • Tracker IoU, estabilizador de nombres, registro/reconocimiento facial (con backend falso).

  • Pipeline completo con detectores simulados y evidencias JPEG.

  • Webhook de notificaciones contra un servidor HTTP local.

  • Integración MCP real: levanta server.py en un subproceso, lista herramientas, llama a get_live_status, add_restricted_zone, get_security_logs, capture_snapshot (verifica JPEG) y el recurso security://status.

server.py se ejecuta en un subproceso durante los tests, por eso la cobertura global (~81 %) es menor que la de los módulos de lógica (~90 %); el arranque está cubierto end-to-end por el test de integración.


🔒 Seguridad y privacidad

  • Las contraseñas de cámaras viven solo en .env (ignorado por git) o en variables de entorno.

  • Los logs muestran las URLs con la clave y los tokens de la query enmascarados (rtsp://admin:***@...).

  • known_faces/, snapshots/ y data/ están en .gitignore: no subas fotos de personas al repo.

  • Recomendado: usuarios RTSP de solo lectura y contraseñas fuertes; segmenta las cámaras en una VLAN.

  • El reconocimiento facial biométrico es dato sensible: informa a las personas y cumple tu normativa local (GDPR/RGPD, LFPDPPP, Ley 29733 en Perú, etc.).

  • En Docker el proceso corre sin privilegios y con no-new-privileges.

  • El transporte HTTP escucha en loopback y valida Host/Origin por defecto, pero no incluye autenticación: si lo expones, ponlo detrás de HTTPS + autenticación y limita MCP_ALLOWED_HOSTS.

  • cleanup_history exige confirm=true y no borra capturas salvo que pidas purge_snapshots=true.

Checklist para producción

  • MCP_HOST=127.0.0.1 o proxy con TLS y autenticación.

  • MCP_ALLOWED_HOSTS / MCP_ALLOWED_ORIGINS ajustados a tu dominio real.

  • .env fuera de git y con permisos restringidos (chmod 600).

  • Usuario RTSP de solo lectura y cámaras en una VLAN segmentada.

  • Retención definida (cleanup_history) y copias de seguridad de data/security.db.

  • Aviso de privacidad y base legal para las personas grabadas.

  • Contenedor como usuario no-root y volúmenes con permisos mínimos.

  • Dependencias auditadas (pip-audit, Dependabot) y tokens rotados.


🩺 Problemas frecuentes

Guía completa y verificada ejecutando el código: docs/TROUBLESHOOTING.md. Cada fila está cubierta por tests (tests/test_troubleshooting.py), así que no se queda desfasada.

Síntoma

Causa / solución verificada

pip install face-recognition falla compilando dlib

face-recognition no tiene binarios: dlib se compila. Instala build-essential cmake python3-dev libopenblas-dev liblapack-dev (el paquete python3-dev es imprescindible y casi siempre se olvida). Windows: Build Tools C++ + CMake. Usa Python 3.10–3.12 (dlib falla en 3.13+). Alternativa sin compilar: imagen Docker o VISION_FAKE_MODELS=1

La cámara entra en bucle de «sin señal»

El mensaje real es [cam1] Cámara SIN SEÑAL: … Reintentando en 5s... (no [WARN] Señal de cámara perdida). Comprueba URL/credenciales con ffplay -rtsp_transport tcp <url>, usa el substream (/102, stream2, _sub), revisa el canal del DVR y el códec (H.264 básico). El transporte es TCP por defecto (RTSP_TRANSPORT); si tu equipo necesita UDP: RTSP_TRANSPORT=udp. Diagnóstico: python scripts/check_setup.py --read-frames

La imagen va a tirones / con retraso

El análisis corre en el hilo de la cámara. Orden de impacto: FACES_ENABLED=false → FACE_SCALE=0.15 → PROCESS_EVERY_N_FRAMES=10 → YOLO_IMGSZ=480 (debe ser múltiplo de 32, se valida al arrancar) → substream → YOLO_DEVICE=0 (GPU)

No reconoce a nadie / dice «Desconocido»

Foto reciente, de frente, iluminada y con un solo rostro. FACE_TOLERANCE=0.65 ayuda, pero también: cara pequeña → FACE_SCALE=0.5; pocas lecturas → FACE_STABILIZER_MIN_VOTES=1; YOLO no ve «person» → FACES_WITHOUT_PERSON=true; FACE_MODEL=cnn (más preciso, lento en CPU). list_known_people avisa si una foto no tiene rostro detectable

Falsos positivos de personas

YOLO_CONF=0.6 y FACE_STABILIZER_MIN_VOTES=3 con FACE_STABILIZER_WINDOW=5 (si MIN_VOTES > WINDOW el arranque falla con ConfigError). No subas FACE_TOLERANCE en ese caso

Address already in use

Solo ocurre con sse/streamable-http (con stdio no hay puerto). Desde v2.0.1 el servidor comprueba el puerto antes de cargar los modelos y muestra cómo liberarlo o cambiarlo (MCP_PORT=8001)

Claude Desktop no conecta

Ruta absoluta al python del venv (.../venv/bin/python o ...\venv\Scripts\python.exe). Logs: macOS ~/Library/Logs/Claude/mcp.log y mcp-server-security-camera.log; Windows %APPDATA%\Claude\logs\. Prueba antes python server.py --check y reinicia la app por completo

El contenedor no ve /dev/video0

Añade devices: ["/dev/video0:/dev/video0"] + group_add: ["video"]. Solo funciona en Linux: Docker Desktop en macOS/Windows no puede pasar dispositivos USB (usa RTSP)

La zona nunca dispara

El punto de referencia es el centro inferior de la caja (los pies), no la cabeza. Además: coordenadas 0..1, labels=["person"] (etiqueta exacta de YOLO, no «Persona»), zona enabled, camera_id correcto y respetar el cooldown de 30 s entre entradas. Verifica con capture_snapshot(annotate=true)

Mensaje

Significado

[cam1] Primer fotograma recibido: 1920x1080 (...)

La cámara entrega vídeo ✅

[cam1] Cámara RECONECTADA (...)

Se recuperó de una caída

ConfigError: YOLO_IMGSZ debe ser múltiplo de 32

Resolución de inferencia inválida (usa 320/480/512/640)

SDK sin soporte de transport_security

Actualiza mcp a ≥1.9

⚠️ face_recognition no está instalado

Falta dlib: instala requirements.txt o usa el modo demo


🗺️ Roadmap

  • Tracking con ByteTrack/BoTSORT para oclusiones y multitudes.

  • Embeddings en SQLite (evitar re-calcular rostros al arrancar) y cifrado en reposo.

  • Panel web (FastAPI + HTMX) con stream anotado y mapa de zonas.

  • Notificaciones nativas a Telegram/WhatsApp como MCP aparte o plugin.

  • Zonas por horario («solo de 22:00 a 06:00») y reglas de dirección (entrar vs. salir).

  • Exportación de clips MP4 alrededor de cada alerta.

  • Autenticación OAuth para el transporte HTTP.


📤 Publicar en GitHub

Guía paso a paso (manual, con gh, con script y prompt listo para el agente de opencode): docs/PUBLICAR_EN_GITHUB.md

# 1) personaliza badges/URLs/autor con tus datos
python scripts/configure_repo.py --github-user kfr0st --name "kfr0st"

# 2) publica (aborta si detecta .env, *.db, *.pt o fotos de known_faces/)
bash scripts/publish_github.sh git@github.com:kfr0st/mcp-security-vision.git

🤝 Contribuir

Lee CONTRIBUTING.md para el entorno de desarrollo, estilo y comprobaciones antes del PR. Para vulnerabilidades usa el reporte privado de SECURITY.md; no abras un issue público.

  1. Haz fork y crea una rama: git checkout -b feature/mi-mejora.

  2. make lint && make test en verde.

  3. Pull request describiendo el cambio y, si aplica, nuevos tests.

📄 Licencia

MIT © 2026 kfr0st. Ver LICENSE.


Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides comprehensive SQLite database interaction for AI agents, including data manipulation, schema inspection, and automated query logging. It features a unique context preservation pattern that uses a dedicated meta-table to help autonomous agents maintain self-documenting database architectures.
    18 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Connect AI agents to SQL databases (SQLite, PostgreSQL, MySQL) with a unified interface for querying data, exploring schemas, inserting rows, and exporting results to CSV. Includes safety features like dangerous query blocking and write guards.
    3 npm
    40 PyPI
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI agents to interact with local SQLite databases with full CRUD, schema introspection, foreign key relations, generated columns, and multi-format import/export (CSV, JSON, XLSX) through natural language.
    26
    2 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to store, search, and manage persistent memories, todos, kanban boards, reminders, and progress trackers in a local SQLite database.
    1
    Apache 2.0