MCP: scopes y tokens

Cómo delimitar qué herramientas del servidor MCP puede usar cada token mediante scopes.

El servidor MCP de HotelDataHub (POST /mcp) expone herramientas ("tools") agrupadas por dominio (documentación, logs, contactos, movimientos, clientes, hoteles, segmentos y fidelización). Cada token puede limitarse a un subconjunto de esas herramientas mediante scopes, de forma que, por ejemplo, una persona pueda tener acceso solo a la documentación y los logs, y otra solo a los contactos.

Tabla de contenidos

Cómo funciona

La identidad detrás de un token (tanto un API key como un token OAuth2) es una Customer OAuth Application. Esa aplicación lleva una lista de scopes concedidos. La autorización se aplica en dos momentos:

  1. tools/list — el token solo "ve" las herramientas para las que tiene scope. Las demás no aparecen, de modo que el agente no intenta usarlas.
  2. tools/call — antes de ejecutar una herramienta se vuelve a comprobar el scope. Si falta, la llamada devuelve un error: {"error": "Permiso denegado: se requiere el scope 'contacts:read'"}.

Catálogo de scopes

Los scopes siguen la convención dominio:acción (read para lectura, write para creación/modificación):

Scope Permite
docs:read Buscar en la documentación
logs:read Consultar logs de la API HDH, peticiones push y eventos internos (Elasticsearch)
contacts:read Leer contactos
contacts:write Crear/modificar contactos
movements:read Leer movimientos (reservas)
movements:write Crear/modificar movimientos
customers:read Leer clientes (cadenas), hoteles y conexiones
hotels:read Leer hoteles de Fideltour
segments:read Leer segmentos/audiencias
loyalty:read Leer información de fidelización

Los scopes de escritura de dominios que aún no tienen herramienta de escritura (customers:write, hotels:write, segments:write, loyalty:write) existen en el catálogo para el futuro, pero hoy no habilitan ninguna herramienta.

Qué herramienta requiere qué scope

El scope de cada herramienta se deduce de su dominio y de si lee o escribe. Ejemplos:

Herramienta Scope
search_documentation docs:read
list_api_users, search_api_requests, get_api_request_body logs:read
search_push_requests, get_push_request_body, list_loggable_integrations logs:read
search_integration_events, search_internal_logs, search_logs logs:read
search_contact_by_email, list_contacts, … contacts:read
create_contact contacts:write
list_movements, search_movement_by_localizer, … movements:read
create_movement movements:write
list_customers, get_customer_summary, list_connections, … customers:read
list_hotels, get_hotel hotels:read
list_segments, get_segment, get_segment_contacts segments:read
list_operations, list_products, list_levels, … loyalty:read

Crear un token con scopes

Desde el admin de Django (Customer OAuth Applications):

  1. Crea (o edita) una aplicación, asígnale un user y un customer (cadena) para limitar los datos a ese cliente. Si la aplicación es para procesos internos de Fideltour y debe poder consultar cualquier cadena, deja el customer vacío y marca Internal application (ver Aplicaciones internas).
  2. En la sección Scopes, marca las casillas que correspondan. Para un token de "documentación y logs", marca solo docs:read y logs:read.
  3. Guarda. Las credenciales client_id / client_secret son el token.

Aplicaciones internas (acceso a todos los customers)

Una Customer OAuth Application normal queda ligada a una única cadena: sus tokens solo pueden consultar datos del customer asignado. Para procesos internos de Fideltour que necesitan preguntar por cualquier cadena existe el flag Internal application (is_internal):

  • Se marca en el admin, en la misma pantalla de la aplicación, dejando el campo customer vacío (son mutuamente excluyentes: el admin no permite guardar una app interna con customer asignado).
  • El token resultante (tanto por API key como por OAuth2) puede pasar cualquier customer_code a las herramientas del MCP, y list_customers / search_customer devuelven todas las cadenas.
  • Los scopes siguen aplicando igual: una app interna con solo contacts:read no puede usar herramientas de otros dominios.

Una aplicación sin customer y sin is_internal queda bloqueada: no puede acceder a los datos de ninguna cadena (las herramientas devuelven Not authorized). Esto evita que una app creada por error sin customer obtenga acceso global.

Comportamiento al usar el token

Con un API key (client_id:client_secret), listar herramientas:

curl -s -X POST https://<host>/mcp \
  -H "X-API-Key: <client_id>:<client_secret>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Un token con ["docs:read","logs:read"] solo verá search_documentation y las herramientas de logs (más las herramientas genéricas sin scope). Si intenta llamar a search_contact_by_email, recibirá un error de permiso.

Usuarios internos (JWT)

Los usuarios autenticados por JWT (staff interno) no tienen aplicación asociada y, por tanto, no están limitados por scopes: siguen viendo y pudiendo usar todas las herramientas. Los scopes solo afectan a clientes externos vía API key u OAuth2.