Sensor read-only de ataques de MCP tool-poisoning / rug-pull: detecta cuando un servidor MCP cambia la descripción, el schema o los parámetros de una tool después de que el agente ya confió en ella, o inyecta instrucciones ocultas en el texto de la descripción. El sensor hace hashing y diffing de tool schemas MCP en cada conexión y emite alertas estructuradas cuando una tool "conocida" cambia de forma no declarada o sospechosa.
El sensor nunca modifica, bloquea ni mitiga: observa, alerta, y el operador decide (CONSTITUTION P1). Es coherente con el ecosistema de defensa de agentes IA de Pedro Sordo Martínez (proyecto hermano: mcp-core-defense).
| Tipo de cambio | Severidad | Señal |
|---|---|---|
| Parámetro nuevo, nombre normal | MEDIUM | param-added |
Parámetro nuevo, nombre de riesgo (exec*, shell, command…) |
CRITICAL | param-added-risk |
| Descripción con patrón de instrucción ("ignora las reglas anteriores", "ignore previous instructions"…) | CRITICAL | instruction-pattern |
| Rotación de endpoint / transporte sin re-autenticación | HIGH | endpoint-changed |
| Hashes cambiados SIN bump de versión | HIGH | silent-mutation |
| Version bump SIN cambio de hashes (señalización falsa) | MEDIUM | version-bump-no-change |
destructiveHint/annotations cambiadas |
HIGH | annotation-changed |
Las heurísticas son acumulativas (severidad máxima) y deterministas: catálogo versionado de patrones y nombres de riesgo, sin ML. El único "silencio" legítimo es el cambio declarado por el operador vía announcements (SPEC §5.4).
python -m venv .venv
.venv/bin/pip install -e .El núcleo (mcp_schema_sentinel_core) tiene cero dependencias fuera de la stdlib
— consumible como librería por otros proyectos (DEC-1). El adaptador del cliente MCP
es un extra opcional:
.venv/bin/pip install -e ".[agent]" # hook del cliente MCP (depende del SDK `mcp`)# 1. Inicializa la BD local (append-only, SQLite/WAL)
sentinel init
# 2. Observa el manifiesto de un servidor (baseline en la 1ª conexión)
sentinel observe manifest.json --name files
# 3. En conexiones siguientes: si una tool cambió sin declarar → alerta (exit=1)
sentinel observe manifest-v2.json --name files
# [CRITICAL] schema_change tool=read_file heur=param-added-risk
# 4. Declara cambios esperados (el único silencio legítimo)
sentinel announce add --server-id sha256:... --tool read_file \
--expected-change "add param format" --valid-until 2026-08-30T00:00:00
# 5. Consulta
sentinel status
sentinel alerts --since 2026-08-16T00:00:00+00:00La salida de alertas es JSONL (data_dir/alerts.jsonl) más log legible; el formato
exacto se valida contra data/alert_schema.json (jsonschema, AC-9).
~/.config/mcp-schema-sentinel/config.toml (o --config):
data_dir = "~/.local/share/mcp-schema-sentinel"
log_level = "INFO"
# Comando opcional del operador: recibe cada alerta por stdin (JSON)
# alert_hook = "/usr/local/bin/notify-sentinel"
# Bajar severidad exige explicit=true — falla-cerrada (CONSTITUTION P7)
# [severity_overrides."sha256:server1"]
# severity = "LOW"
# explicit = true
# Solo LOW/INFO son suprimibles (SPEC §5.5)
# [[suppressions]]
# server_id = "sha256:server1"
# tool = "read_file"from mcp_schema_sentinel_core.engine import Engine, observe
from mcp_schema_sentinel_core.store import Store
engine = Engine(Store("sentinel.db"))
alerts = observe(
engine,
manifest,
name="files",
protocol_version="2025-03-26",
observed_endpoint={"type": "streamable-http", "url": "https://…"},
)Ver SECURITY.md. KNOWN LIMITATIONS (SPEC §8): no detecta envenenamiento en la PRIMERA conexión (el baseline es la confianza inicial); el catálogo de patrones es regex determinista (evasión semántica posible); dos homoglifos adyacentes pueden evadir el guard de homoglifos. Todo documentado, nada oculto.
Copyright (C) 2026 Pedro Sordo Martínez amurlaniakea@gmail.com
AGPL-3.0-or-later. Este programa es software libre: puedes redistribuirlo y/o modificarlo bajo los términos de la GNU Affero General Public License, versión 3 o (at your option) cualquier versión posterior. Ver LICENSE para el texto completo.