MCP en una empresa: el problema no es conectarlo, es decidir qué permisos darle

Análisis crítico sobre permisos, alcance, auditoría y límites cuando conectas agentes de IA a sistemas reales con MCP.

Cover for MCP en una empresa: el problema no es conectarlo, es decidir qué permisos darle

En el artículo anterior sobre MCP vs Skills expliqué qué es cada cosa y cuándo tiene sentido usar una u otra. Ahí ya adelantaba que la parte de seguridad merecía un artículo aparte. Este es ese artículo.

Lo que estoy viendo en empresas me preocupa. Equipos que conectan agentes de IA a bases de datos de producción, a repos de código, a sistemas de ticketing, a herramientas de infraestructura… y cuando preguntas “qué permisos tiene este agente”, la respuesta suele ser un silencio incómodo o un “los mismos que el usuario que lo configuró”. Eso es un problema serio.

Conectar un MCP es fácil. Decidir qué puede hacer, qué no puede hacer, quién lo revisa y qué pasa cuando se equivoca es lo que de verdad importa. Y es lo que casi nadie está planteando.


El principio de mínimo privilegio aplicado a agentes

El principio de mínimo privilegio no es nuevo. Cualquier ingeniero con experiencia en seguridad lo conoce: un componente del sistema solo debe tener acceso a los recursos que necesita estrictamente para cumplir su función. Ni más, ni menos.

Con agentes de IA conectados vía MCP, este principio se vuelve más importante y más difícil de aplicar al mismo tiempo. Más importante porque el agente puede tomar decisiones impredecibles. Más difícil porque el alcance de lo que “necesita” no siempre está claro.

Un agente no es un script. Un script hace exactamente lo que le programas. Un agente interpreta instrucciones y decide qué herramientas usar y cómo. Esa diferencia cambia completamente el perfil de riesgo.

Cuando le das a un script acceso de lectura a una base de datos, sabes exactamente qué queries va a ejecutar. Cuando le das el mismo acceso a un agente, no lo sabes. Puede decidir hacer un SELECT * de una tabla con datos sensibles porque le pareció relevante para responder una pregunta. No por malicia, sino porque no tiene concepto de “eso no deberías verlo”.


Casos que deberían quitarte el sueño

Voy a listar situaciones que he visto o que me han descrito colegas. Todas reales. Todas prevenibles.

Agente con acceso a la base de datos de producción

El caso clásico. Alguien configura un MCP que conecta al agente con PostgreSQL para que pueda “consultar datos y generar informes”. Le da credenciales de un usuario con permisos amplios porque “solo va a leer”.

El problema: el agente recibe una petición ambigua, construye una query que hace un full table scan de la tabla de usuarios (con emails, nombres, teléfonos), y devuelve esos datos en una respuesta que queda logueada en el historial del chat. Ahora tienes datos personales expuestos en un sistema que probablemente no cumple con la política de retención de datos de tu empresa.

Variante aún peor: le diste permisos de escritura “por si necesita crear tablas temporales”. El agente interpreta mal una instrucción y ejecuta un UPDATE que no debería.

Agente que puede crear Pull Requests

Conectar un agente al repo de código vía MCP para que genere PRs suena productivo. Pero si el agente puede crear PRs directamente a la rama principal, sin revisión, estás delegando control de tu código a un sistema que no entiende el contexto completo de tu arquitectura.

He visto agentes que generan código que pasa los tests pero introduce dependencias inseguras, cambia contratos de API sin avisar, o sobreescribe configuración de seguridad porque “simplificó” el código.

Agente con acceso a infraestructura

Este es el más peligroso. Un MCP que conecta al agente con Kubernetes, AWS, o tu herramienta de CI/CD. “Para que pueda revisar logs y diagnosticar problemas”. El agente, intentando resolver un issue, escala un deployment, cambia una variable de entorno o reinicia un servicio.

No es ciencia ficción. Es lo que pasa cuando das herramientas potentes a un sistema que optimiza por “resolver la petición del usuario” sin entender las consecuencias operacionales.


Matriz de permisos: qué debería poder hacer cada herramienta

Antes de conectar cualquier MCP, deberías tener una matriz clara de permisos. Esto no es burocracia, es higiene básica. Una tabla como esta, adaptada a tu contexto:

Herramienta MCPLecturaEscrituraScopeRequiere aprobaciónDatos sensibles
Base de datos (prod)Solo vistas predefinidasNoTablas no-PIINoSi, restringir
Base de datos (staging)Solo tablas tempSchema específicoNoNo
Repositorio GitSolo ramas feature/Repos no-infraSí (PR review)No
Jira / LinearLectura de ticketsCrear comentariosProyecto específicoNoNo
Jira / Linear-Crear/mover ticketsProyecto específicoNo
SlackLectura canales públicosEnviar mensajesCanales designadosPosible
AWS / InfraSolo lectura de logsNoRead-only roleNoPosible (logs)
CI/CDVer estado de pipelinesNo-NoNo
CI/CD-Trigger/retry buildsRepos específicosNo

Si no puedes rellenar esta tabla para cada MCP que tienes conectado, tienes un problema de gobernanza. No de IA, de gobernanza.

Algunas reglas que aplico siempre:

1. Producción es solo lectura, y con scope limitado. Nunca escritura. Sin excepciones. Si el agente necesita modificar algo en producción, genera una propuesta que un humano ejecuta.

2. Los datos personales no pasan por el agente. Si una tabla tiene PII (datos personales), el agente no debería poder acceder a ella. Usa vistas que enmascaren o excluyan esos campos.

3. La escritura siempre requiere aprobación. Cualquier acción que modifique estado (crear un ticket, enviar un mensaje, hacer un commit) pasa por revisión humana.


Logs y auditoría: qué hizo, cuándo, con qué datos

Si un agente interactúa con tus sistemas y no tienes logs detallados de esa interacción, estás volando a ciegas. No basta con saber que “el agente usó el MCP de base de datos”. Necesitas saber:

  • Qué herramienta MCP usó exactamente.
  • Qué parámetros envió (la query, el comando, el contenido).
  • Qué respuesta recibió (y si contenía datos sensibles).
  • Quién inició la petición (qué usuario pidió al agente que hiciera eso).
  • Cuándo ocurrió.
  • Cuánto tardó.

Un ejemplo de estructura de log para auditoría:

{
  "timestamp": "2026-05-18T14:23:45Z",
  "event_type": "mcp_tool_call",
  "agent_id": "support-agent-01",
  "user_id": "user-4521",
  "session_id": "sess-abc123",
  "tool": {
    "name": "database_query",
    "mcp_server": "postgres-readonly",
    "parameters": {
      "query": "SELECT order_id, status, created_at FROM orders WHERE user_id = $1",
      "params": ["user-4521"]
    }
  },
  "result": {
    "status": "success",
    "rows_returned": 3,
    "execution_time_ms": 45,
    "contains_pii": false
  },
  "context": {
    "user_prompt": "¿Cuál es el estado de mis últimos pedidos?",
    "conversation_turn": 2
  }
}

Estos logs no son opcionales. Son tu única forma de:

  • Investigar incidentes: si algo sale mal, necesitas reconstruir exactamente qué hizo el agente.
  • Detectar anomalías: un agente que de repente hace 500 queries por minuto cuando lo normal son 10 es una señal de alerta.
  • Cumplir regulación: GDPR, SOC2, ISO 27001… todos requieren trazabilidad de acceso a datos.
  • Mejorar el sistema: sin datos de uso real, no puedes optimizar ni los prompts ni los permisos.

Alertas que deberías tener

No basta con loguear. Necesitas alertas activas:

alertas_mcp:
  - nombre: "Volumen anómalo de llamadas"
    condicion: "calls_per_minute > 50 para un mismo agent_id"
    severidad: warning

  - nombre: "Acceso a datos sensibles"
    condicion: "result.contains_pii == true"
    severidad: critical

  - nombre: "Error rate elevado"
    condicion: "error_rate > 20% en ventana de 5 minutos"
    severidad: warning

  - nombre: "Tool no autorizado"
    condicion: "tool.name not in allowed_tools[agent_id]"
    severidad: critical

  - nombre: "Latencia excesiva"
    condicion: "execution_time_ms > 10000"
    severidad: info

Human-in-the-loop: cuándo obligar revisión humana

No todo necesita aprobación humana. Si cada acción del agente requiere que alguien dé al botón de “aceptar”, pierdes todo el valor de la automatización. La clave está en definir bien la frontera.

Mi regla general: las acciones reversibles y de bajo impacto pueden ser automáticas. Las acciones irreversibles o de alto impacto requieren aprobación.

En la práctica:

Automático (sin aprobación)

  • Consultar estado de un ticket.
  • Leer logs de un servicio.
  • Buscar documentación interna.
  • Generar un borrador de respuesta.
  • Consultar métricas de un dashboard.

Requiere aprobación humana

  • Crear o modificar un ticket.
  • Enviar un mensaje a un canal de Slack o un email.
  • Crear una Pull Request o hacer commit.
  • Modificar cualquier dato en cualquier entorno.
  • Ejecutar acciones en infraestructura.
  • Acceder a datos que podrían contener PII.

Requiere aprobación + segunda revisión

  • Cualquier acción en producción que modifique estado.
  • Despliegues.
  • Cambios en configuración de seguridad.
  • Acceso a secretos o credenciales.

La pregunta no es “confío en la IA”. La pregunta es “si esto sale mal, cuál es el impacto y cuánto tardo en revertirlo”. Si la respuesta es “alto impacto y difícil de revertir”, pones un humano delante. Siempre.

El flujo típico que implemento:

Usuario pide algo al agente
    → Agente decide qué tool usar
    → ¿La acción requiere aprobación?
        → NO: ejecutar y loguear
        → SÍ: generar propuesta
            → Notificar al reviewer (Slack, email, dashboard)
            → Esperar aprobación (con timeout)
                → Aprobado: ejecutar y loguear
                → Rechazado: loguear y notificar al usuario
                → Timeout: loguear como "no ejecutado"

Implementación práctica: middleware de permisos

Una forma efectiva de implementar esto es con un middleware que intercepta cada llamada MCP antes de que llegue al servidor:

class McpPermissionMiddleware:
    def __init__(self, policy: PermissionPolicy, audit_log: AuditLogger):
        self.policy = policy
        self.audit_log = audit_log

    async def intercept(self, tool_call: ToolCall, context: AgentContext) -> ToolResult:
        # 1. Verificar que el agente tiene permiso para usar esta herramienta
        permission = self.policy.check(
            agent_id=context.agent_id,
            tool_name=tool_call.name,
            action_type=tool_call.action_type,
            parameters=tool_call.parameters
        )

        if permission == Permission.DENIED:
            self.audit_log.record_denied(tool_call, context)
            raise PermissionDeniedError(
                f"Agent {context.agent_id} no tiene permiso para {tool_call.name}"
            )

        if permission == Permission.REQUIRES_APPROVAL:
            approval = await self.request_human_approval(tool_call, context)
            if not approval.granted:
                self.audit_log.record_rejected(tool_call, context, approval)
                return ToolResult.rejected("Acción rechazada por reviewer")

        # 2. Ejecutar la llamada
        result = await self.execute_tool(tool_call)

        # 3. Verificar el resultado (¿contiene datos sensibles?)
        if self.policy.requires_pii_check(tool_call.name):
            result = self.sanitize_pii(result)

        # 4. Loguear todo
        self.audit_log.record_execution(tool_call, context, result)

        return result

La política de permisos se define en un fichero de configuración que vive en el repo, versionado y revisable:

# mcp-permissions.yaml
agents:
  support-agent:
    allowed_tools:
      - name: "database_query"
        scope: "readonly"
        allowed_tables: ["orders", "products", "order_status"]
        blocked_tables: ["users", "payments", "credentials"]
        max_rows: 100
      - name: "jira_read"
        scope: "project:SUPPORT"
      - name: "jira_comment"
        scope: "project:SUPPORT"
        requires_approval: true
    blocked_tools:
      - "git_*"
      - "infra_*"
      - "deploy_*"

  dev-assistant:
    allowed_tools:
      - name: "git_read"
        scope: "repos:backend-*"
      - name: "git_create_pr"
        scope: "repos:backend-*"
        requires_approval: true
        target_branches_blocked: ["main", "release/*"]
      - name: "database_query"
        scope: "readonly"
        environment: "staging"
    blocked_tools:
      - "infra_*"
      - "deploy_*"

Lo que nadie te cuenta: el problema organizativo

La tecnología es la parte fácil. Lo realmente difícil es el lado organizativo:

Quién define los permisos. En la mayoría de empresas no hay un rol claro que sea responsable de los permisos de los agentes de IA. No es el equipo de seguridad (no entienden el contexto de uso). No es el equipo de producto (no entienden las implicaciones técnicas). No es el desarrollador que configura el MCP (no tiene visión global).

Mi recomendación: el equipo de plataforma o ingeniería define las políticas base, el equipo de seguridad las revisa, y el equipo de producto define los casos de uso. Los tres juntos.

Quién revisa las aprobaciones. Si pones human-in-the-loop pero nadie revisa las peticiones, el agente se queda bloqueado y los usuarios se frustran. Necesitas un proceso claro: quién revisa, en qué horario, con qué SLA, y qué pasa cuando no hay nadie disponible.

Cómo evolucionan los permisos. Los permisos que defines hoy no valen para siempre. Los casos de uso cambian, los equipos crecen, los agentes se vuelven más capaces. Necesitas una revisión periódica. Yo sugiero trimestral como mínimo.


Checklist antes de conectar un MCP a un sistema real

Antes de dar el OK a cualquier integración MCP en tu empresa, pasa por esta lista:

  1. Existe una matriz de permisos documentada para este agente.
  2. El acceso a producción es solo de lectura (sin excepciones).
  3. Los datos personales están excluidos o enmascarados.
  4. Hay logs de auditoría para cada llamada MCP.
  5. Hay alertas configuradas para anomalías.
  6. Las acciones de escritura requieren aprobación humana.
  7. Hay un proceso claro para revocar permisos de emergencia.
  8. Los permisos están versionados en el repositorio.
  9. Hay un responsable definido para revisar los permisos periódicamente.
  10. Se ha hecho una prueba de “qué pasa si el agente hace lo peor posible con estos permisos”.

Ese último punto es clave. Antes de dar acceso, pregúntate: si este agente se vuelve loco y usa todos los permisos que tiene de la peor forma posible, qué es lo máximo que puede romper. Si la respuesta te asusta, reduce los permisos.


No es paranoia, es ingeniería

Nada de lo que he descrito aquí es paranoia ni anti-IA. Al contrario: la única forma de que la integración de agentes en empresas escale de forma sostenible es con controles serios. Las empresas que hoy están conectando agentes sin gobernanza van a tener incidentes. Algunas ya los están teniendo.

La IA en empresa no es un playground. Es infraestructura productiva que interactúa con datos reales, clientes reales y dinero real. Trátala como tal.

OshyTech

Ingeniería backend y de datos orientada a sistemas escalables, automatización e IA.

Navegación

Copyright 2026 OshyTech. Todos los derechos reservados