MCP Audit Gateway
Puerta de enlace MCP que añade RBAC por herramienta, aislamiento de inquilinos, exportación de auditoría y redacción de PII a cualquier servidor.
Documentación
MCP Audit Gateway
Puerta de enlace MCP que añade RBAC por herramienta y un registro de auditoría exportable a cualquier servidor MCP, además de aislamiento por inquilino, redacción de PII en los resultados de las herramientas, límites de tasa por inquilino y políticas de permitir/denegar a nivel de inquilino. Se sitúa entre un cliente MCP (Claude Desktop, un runtime de agente, tu propia aplicación) y uno o más servidores MCP ascendentes. El caso concreto para el que fue construido: poner RBAC por herramienta y un registro de auditoría exportable frente a un servidor MCP de QuickBooks o HubSpot, para que cada tools/call contra los libros fluya a través de un punto de estrangulamiento aplicable, registrado y redactado.
Relacionado: QuickBooks Online MCP Server · HubSpot CRM MCP Server · Lo que MCP de producción realmente requiere
Apúntalo a cualquier servidor MCP, describe tus inquilinos y roles en YAML, y la política es un solo archivo que puedes leer en una revisión. Se incluyen firma de solicitudes HMAC y transportes stdio y HTTP transmisible. MIT, sin nivel de pago.
Por qué existe esto
Un servidor MCP desnudo expone cada herramienta a cada llamante sin identidad, sin cuota, sin registro y sin redacción. Eso está bien en una laptop y es imposible de enviar en un producto multiinquilino. Esta puerta de enlace añade ese plano de control sin tocar el servidor ascendente. El escrito complementario, docs/what-production-mcp-actually-requires.md, recorre cada característica junto a una historia de fallo concreta.
Herramientas
La puerta de enlace no expone herramientas propias. Hace proxy de tools/list y tools/call hacia los servidores MCP ascendentes configurados para el inquilino llamante, con espacios de nombres para cada herramienta proxied como <upstream>.<tool> y aplicando filtrado RBAC, límites de tasa y redacción de PII en el camino. Iniciada sin ascendentes configurados, initialize y tools/list aún tienen éxito y la lista de herramientas vuelve vacía.
Su propia superficie es el plano de control CLI:
validate: verifica un archivo de política (roles, principales, inquilinos, ascendentes, detectores) antes de que sirva cualquier tráfico.serve --transport stdio: ejecuta la puerta de enlace sobre stdio para un cliente MCP local como Claude Desktop.serve --transport http: ejecuta la puerta de enlace sobre HTTP transmisible para clientes remotos o de agentes.audit export --format csv: exporta el registro de auditoría como CSV para una hoja de cálculo o ingesta SIEM.audit export --format json: exporta los mismos registros como JSON.
Prueba: la demo de dos inquilinos
La evidencia aquí es una demo que ejecutas tú mismo, no un sitio en el que te pido confiar. demo/run_demo.py levanta la puerta de enlace frente a dos inquilinos, acme (un subproceso ascendente stdio) y globex (un ascendente HTTP transmisible), y ejecuta doce escenarios que ejercitan RBAC, interruptores de apagado de inquilino, redacción de PII, aislamiento entre inquilinos, firma HMAC, rechazo de herramientas desconocidas y límites de tasa por inquilino contra el servidor MCP de juguete incluido. No hay instancia alojada que mantener viva ni servicio externo al que llegar; todo se ejecuta en loopback y termina en segundos.
La salida confirmada es el artefacto:
- docs/demo-transcript.md: cada paso, su decisión de puerta de enlace y el resultado que el cliente realmente vio, seguido de una tabla resumen de resultados de auditoría.
- docs/demo-audit.csv: el rastro de auditoría completo legible por máquina que la misma ejecución produjo.
Ambos archivos se regeneran textualmente por python demo/run_demo.py, por lo que la transcripción y su tabla de auditoría siempre se reconcilian con una ejecución que puedes reproducir localmente.
Arquitectura
flowchart LR
subgraph Clients
C1[Tenant A client]
C2[Tenant B client]
end
subgraph Gateway [mcp-audit-gateway]
direction TB
AUTH[Authenticate principal] --> SIG[Verify HMAC signature]
SIG --> RBAC[RBAC and allow/deny policy]
RBAC --> RL[Per-tenant rate limit]
RL --> ROUTE[Resolve tenant upstream]
ROUTE --> RED[PII redaction on result]
RED --> AUD[(Audit log JSONL)]
end
subgraph Upstreams
U1[Tenant A MCP server<br/>stdio]
U2[Tenant B MCP server<br/>streamable HTTP]
end
C1 -->|signed JSON-RPC| AUTH
C2 -->|signed JSON-RPC| AUTH
ROUTE --> U1
ROUTE --> U2
U1 --> RED
U2 --> RED
RED -->|redacted result| C1
Cada solicitud se autentica a un principal, que la fija exactamente a un inquilino y rol. Un inquilino solo puede alcanzar sus propios ascendentes, credenciales y estado. El pipeline corta en cortocircuito en la primera compuerta que falla y registra la decisión.
Características
| Característica | Qué hace |
|---|---|
| RBAC por herramienta | Listas de permitir/denegar de rol a herramienta con patrones glob; denegar siempre gana. |
| Aislamiento por inquilino | Cada inquilino obtiene sus propios procesos/endpoints ascendentes, credenciales, catálogo de herramientas, cubo de límite de tasa y estado. Los nombres de herramientas entre inquilinos son invisibles. |
| Registro de auditoría | JSONL de solo añadir de quién llamó a qué herramienta, con qué argumentos (redactados), estado del resultado, latencia y conteos de redacción. Exportable a CSV y JSON. |
| Redacción de PII | Detectores configurables (correo electrónico, teléfono, SSN, SIN canadiense, tarjeta de crédito) aplicados a los resultados de las herramientas antes de que salgan de la puerta de enlace. Modos mask, hash o partial. |
| Límites de tasa | Cubo de tokens por inquilino (requests_per_minute + burst). |
| Políticas de permitir/denegar | Interruptor de apagado de herramientas a nivel de inquilino que anula roles: una capa de gobernanza por encima de RBAC. |
| Firma de solicitudes | HMAC-SHA256 sobre el cuerpo de la solicitud con una ventana de frescura de marca de tiempo para detener la reproducción. |
| Transportes | stdio y HTTP transmisible en ambos lados, el orientado al cliente y el orientado al ascendente. |
Inicio rápido
uv venv --python 3.12
uv pip install -e ".[dev]"
# Validate the bundled two-tenant demo config
python -m mcp_gateway validate --config config/demo.yaml
# Run the full scripted demo (starts a stdio upstream and an HTTP upstream,
# proves tenant isolation, and writes docs/demo-transcript.md)
python demo/run_demo.py
Instalado como paquete, los mismos comandos se ejecutan a través del script de consola mcp-audit-gateway.
Ejecutándolo desnudo
La puerta de enlace arranca sin archivo de configuración en absoluto, que es lo que un cliente MCP o un rastreador de registros ve en una primera sonda tools/list:
mcp-audit-gateway serve --transport stdio
Eso sirve a un principal local contra cero ascendentes: initialize y tools/list tienen éxito, la lista de herramientas está vacía, nada se escribe en disco. Apúntalo a un archivo de política para hacerlo útil, ya sea con --config o configurando MCP_AUDIT_GATEWAY_CONFIG.
Ejecutando la puerta de enlace
# Streamable HTTP, for remote/agent clients (reads host/port from the config)
python -m mcp_gateway serve --config config/demo.yaml --transport http
# stdio, for a local client such as Claude Desktop (pins the session to a principal)
python -m mcp_gateway serve --config config/demo.yaml --transport stdio --principal acme-admin
--principal solo se requiere cuando la configuración define más de uno; con un solo principal la sesión stdio lo usa.
El inquilino globex de la demo hace proxy de un ascendente HTTP esperado en http://127.0.0.1:9100/mcp. Para servir la puerta de enlace contra demo.yaml directamente, inicia ese ascendente primero:
python -m mcp_gateway.toy_upstream --transport http --host 127.0.0.1 --port 9100 --dataset globex
demo/run_demo.py maneja este cableado automáticamente en un puerto efímero, por lo que es la forma más rápida de ver todo funcionar.
Los comandos ascendentes stdio que comienzan con python o python3 se lanzan bajo el propio intérprete de la puerta de enlace, por lo que un ascendente python -m ... funciona ya sea que python esté en el PATH del llamante. Cualquier otro comando se ejecuta textualmente.
Exportando el registro de auditoría
python -m mcp_gateway audit export --input config/audit-log.jsonl --format csv --output audit.csv
python -m mcp_gateway audit export --input config/audit-log.jsonl --format json
Referencia de configuración
gateway:
name: mcp-audit-gateway-demo
http: { host: 127.0.0.1, port: 8080 }
security:
require_signature: true # enforce HMAC signing on incoming requests
signature_max_age_seconds: 300 # replay window
redaction:
enabled: true # redact tool RESULTS before returning them
mode: mask # mask | hash | partial
detectors: [email, phone, ssn, sin, credit_card]
redact_arguments: true # also redact arguments written to the audit log
audit:
enabled: true
path: audit-log.jsonl # relative to the config file's directory
argument_logging: redacted # redacted | full | keys_only | none
roles: # role -> tool allow/deny (glob patterns, deny wins)
admin: { allow_tools: ["*"] }
analyst: { allow_tools: ["billing.get_*", "billing.list_*"], deny_tools: ["billing.delete_*"] }
principals: # a credential = one identity = tenant + role + signing secret
- { id: acme-admin, tenant: acme, role: admin, secret: "demo-only-secret" }
tenants:
acme:
deny_tools: ["billing.delete_invoice"] # optional tenant-level kill switch
upstreams:
- { name: billing, transport: stdio, command: ["python", "-m", "mcp_gateway.toy_upstream", "--dataset", "acme"] }
rate_limit: { requests_per_minute: 60, burst: 10 }
Las herramientas se nombran con espacios de nombres como <upstream>.<tool> (por ejemplo billing.get_invoice), por lo que los patrones de RBAC y política son estables entre inquilinos y las colisiones entre ascendentes son imposibles.
Ejecutando las pruebas
uv run pytest
La suite es completamente offline. Los servidores MCP "externos" con los que habla son el ascendente de juguete incluido, ejercitado de verdad sobre stdio (subproceso) y HTTP transmisible (loopback): sin red, sin mocks-de-mocks, y termina en segundos.
Notas de seguridad y alcance
- Los secretos YAML estáticos son solo para demos locales. En producción, carga secretos de principales desde un gestor de secretos y prefiere credenciales de corta duración por solicitud; consulta el escrito.
- La firma HMAC protege el salto cliente-a-puerta de enlace. No es un sustituto de TLS o controles de red.
- La redacción es defensa en profundidad de mejor esfuerzo basada en regex, no una garantía DLP certificada. Trátala como una capa.
- El registro de auditoría es un registro puntual de lo que la puerta de enlace observó. No es una atestación de cumplimiento.
- Solo haz proxy e inspecciona servidores MCP que poseas o estés autorizado a operar.
Contrátame
Hago seguros para producción los backends de era IA y críticos para el dinero: autenticación, multiinquilino, gobernanza y la corrección aburrida que te mantiene fuera de incidentes. Disponible para trabajo de MCP, facturación y endurecimiento. Portafolio y contacto: https://amin-ale.github.io/portfolio-site · amin.ale.business@gmail.com.
Licencia
MIT. Consulta LICENSE.