Descubrimiento del servidor
Endpoints .well-known con los que los clientes OAuth, OpenID Connect y MCP se configuran solos: qué devuelve cada uno y para qué sirve.
Actualizado el . 5 min de lectura
Los endpoints de descubrimiento permiten que tu cliente se configure solo: en lugar de escribir a mano cada URL, la lee de un documento estándar. Las bibliotecas OpenID Connect (Auth.js, Authlib, oidc-client-ts) solo necesitan el emisor, https://os.utilia.ai, y los clientes MCP llegan por aquí al servidor de autorización. Todos son públicos: no envíes X-Api-Key ni Authorization.
Viven en la raíz del dominio, fuera de /api, porque así lo exigen las especificaciones: https://os.utilia.ai/.well-known/....
Así los encadena un cliente MCP que solo conoce la dirección del servidor, por ejemplo https://os.utilia.ai/api/mcp/crm:
Cómo se configura solo un cliente MCP
Participan: Cliente MCP, Servidor MCP, Servidor de autorización.
De Cliente MCP a Servidor MCP:
POST /api/mcp/crm
Primera llamada, todavía sin token.De Servidor MCP a Cliente MCP:
401 con WWW-Authenticate (respuesta)
La cabecera lleva resource_metadata con la dirección de los metadatos de ese servidor.De Cliente MCP a Servidor de autorización:
GET /.well-known/oauth-protected-resource?resource=...
Lee los scopes del servidor y quién autoriza (authorization_servers).De Cliente MCP a Servidor de autorización:
GET /.well-known/oauth-authorization-server
Obtiene las direcciones de registro, autorización y token.De Cliente MCP a Servidor de autorización:
POST /api/oauth/register
Registro dinámico: recibe su client_id.Nota en Servidor de autorización:
Autorización con PKCE y resource, y canje del código por tokens.De Cliente MCP a Servidor MCP:
POST /api/mcp/crm con Authorization: Bearer
Ya puede llamar a las herramientas en nombre de la persona.
El paso de autorización está contado en Flujo de autorización.
Metadatos del servidor de autorización (RFC 8414)
/.well-known/oauth-authorization-serverMetadatos del servidor de autorización
Devuelve las direcciones de autorización, token, registro, revocación e introspección y lo que admite el servidor. En el ejemplo, scopes_supported está recortado: la respuesta real trae el catálogo entero de scopes, incluidos los conjuntos (crm:read, finance:full...).
{
"issuer": "https://os.utilia.ai",
"authorization_endpoint": "https://os.utilia.ai/api/oauth/authorize",
"token_endpoint": "https://os.utilia.ai/api/oauth/token",
"registration_endpoint": "https://os.utilia.ai/api/oauth/register",
"revocation_endpoint": "https://os.utilia.ai/api/oauth/revoke",
"introspection_endpoint": "https://os.utilia.ai/api/oauth/introspect",
"scopes_supported": ["openid", "profile", "email", "crm:clients:view", "dev:projects:view", "..."],
"response_types_supported": ["code"],
"response_modes_supported": ["query"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "client_secret_post"],
"code_challenge_methods_supported": ["S256"],
"prompt_values_supported": ["none", "login", "select_account", "consent"],
"service_documentation": "https://os.utilia.ai/dashboard/docs/developers/mcp",
"logo_uri": "https://os.utilia.ai/icons/icon-192x192.png",
"service_name": "UTILIA OS"
}- issuerstringobligatorio
- Emisor. Es el valor del claim iss del id_token.
- authorization_endpointstringobligatorio
- Donde empieza la autorización (redirección de la persona).
- token_endpointstringobligatorio
- Canje del código y renovación de tokens.
- registration_endpointstringobligatorio
- Registro dinámico de clientes (RFC 7591).
- revocation_endpointstringobligatorio
- Revocación de tokens (RFC 7009).
- introspection_endpointstringobligatorio
- Introspección de access tokens (RFC 7662).
- scopes_supportedstring[]obligatorio
- Catálogo de scopes. Ver Scopes y recursos.
- code_challenge_methods_supportedstring[]obligatorio
- Solo S256.
- prompt_values_supportedstring[]
- Valores admitidos de prompt.
- logo_uristring
- Icono de UTILIA OS de 192 x 192 píxeles.
Configuración de OpenID Connect
/.well-known/openid-configurationMetadatos de OpenID Connect Discovery 1.0
Es el documento anterior con los campos de OpenID Connect añadidos:
- jwks_uristringobligatorio
- https://os.utilia.ai/api/oauth/jwks: claves públicas para verificar el id_token.
- userinfo_endpointstringobligatorio
- https://os.utilia.ai/api/oauth/userinfo
- end_session_endpointstringobligatorio
- https://os.utilia.ai/api/oauth/logout: cierre de sesión iniciado por tu aplicación.
- id_token_signing_alg_values_supportedstring[]obligatorio
- RS256.
- subject_types_supportedstring[]obligatorio
- public.
- claims_supportedstring[]obligatorio
- sub, iss, aud, exp, iat, name, given_name, family_name, picture, email, email_verified, at_hash y nonce.
Lee jwks_uri de aquí en lugar de escribirlo en tu código: así un cambio de claves no te obliga a tocar nada.
Metadatos de cada recurso protegido (RFC 9728)
Cada servidor MCP de UTILIA OS es un recurso protegido con su propia lista de scopes. Los clientes MCP leen estos documentos para saber qué pedir.
/.well-known/oauth-protected-resourceMetadatos del recurso protegido; admite ?resource=
Con ?resource= y la dirección de un servidor MCP devuelve los metadatos de ese servidor. Sin el parámetro, o con una dirección que no es de ningún servidor, devuelve los generales, con el recurso histórico /api/mcp y el catálogo entero.
{
"resource": "https://os.utilia.ai/api/mcp/crm",
"authorization_servers": ["https://os.utilia.ai"],
"scopes_supported": ["crm:clients:view", "crm:leads:view", "support:tickets:view", "dev:calendar:view", "org:plan:view", "..."],
"bearer_methods_supported": ["header"],
"resource_documentation": "https://os.utilia.ai/dashboard/docs/developers/mcp",
"logo_uri": "https://os.utilia.ai/icons/icon-192x192.png",
"resource_name": "UTILIA OS - CRM"
}Cada servidor tiene además un atajo con el mismo documento:
| Servidor | Atajo | resource anunciado | Qué anuncia |
|---|---|---|---|
| CRM | /.well-known/mcp-crm.json | /api/mcp/crm | crm:*, tickets de soporte, calendario, gestor de archivos, credenciales de API, la lectura de proveedores y los granulares de administración de la organización |
| Proyectos | /.well-known/mcp-work.json | /api/mcp/work | dev:*, tickets de soporte e integrations:* |
| Proyectos (alias) | /.well-known/mcp-dev.json | /api/mcp/dev | Lo mismo que mcp-work.json |
| Finanzas | /.well-known/mcp-finance.json | /api/mcp/finance | finance:*, crm:invoices:*, crm:treasury:*, crm:fiscal:* y la lectura de clientes y tareas |
| Marketing | /.well-known/mcp-marketing.json | /api/mcp/marketing | marketing:*, dominios de envío y las lecturas del CRM que necesita la vista previa de segmentos |
| Chat | /.well-known/mcp-chat.json | /api/mcp/chat | Una lista cerrada de chat:* |
| RRHH | /.well-known/mcp-rrhh.json | /api/mcp/rrhh | hr:* |
Todos anuncian además los transversales que su servidor necesita: el plan contratado (org:plan:*), los avisos (org:notifications:*) y, salvo CRM y Proyectos, que ya los incluyen, los tres de tickets propios (support:tickets:view, create y update).
Dos casos en los que el documento anuncia menos de lo que podría pedirse, a propósito:
- Chat no anuncia
chat:messages:send,chat:events:subscribenichat:agents:manage:external, ni los conjuntoschat:writeychat:full, que los incluyen: el servidor MCP de chat lee y organiza canales, pero no escribe mensajes. Publicar mensajes es cosa de la API externa (/api/external/v1/chat) conX-Api-Key. - Marketing no anuncia ningún
finance:*. Por eso sus operaciones de negocio originado por campaña devuelven recuentos, pero no importes. Lo explica Servidor MCP Marketing.
/api/mcp/work es la dirección pública del servidor de Proyectos; los tokens guardan como destinatario /api/mcp/dev, así que un mismo token sirve para las dos direcciones.
Otros documentos
/.well-known/jwks.jsonClaves públicas (JWKS) para verificar el id_token
Devuelve las mismas claves que GET /api/oauth/jwks. Solo lo necesitas si verificas tú la firma del id_token.
/.well-known/resource-server.jsonVariante antigua de los metadatos del recurso protegido
Devuelve lo mismo que /.well-known/oauth-protected-resource sin parámetro y existe solo para clientes antiguos. En una integración nueva, usa oauth-protected-resource con resource.
Ejemplos
# Servidor de autorización
curl -s 'https://os.utilia.ai/.well-known/oauth-authorization-server' | jq .
# OpenID Connect
curl -s 'https://os.utilia.ai/.well-known/openid-configuration' | jq .
# Recurso protegido del servidor de CRM
curl -s 'https://os.utilia.ai/.well-known/oauth-protected-resource?resource=https://os.utilia.ai/api/mcp/crm' | jq .
# Atajo del servidor de Finanzas
curl -s 'https://os.utilia.ai/.well-known/mcp-finance.json' | jq .Estos documentos admiten hasta 600 peticiones por minuto y dirección IP. Aun así, guárdalos en caché en tu cliente: cambian muy poco.
Siguiente paso: Flujo de autorización.