Mainstream messaging
Microsoft Teams
Estado: se admiten texto y archivos adjuntos en DM; el envío de archivos en canales/grupos requiere sharePointSiteId + permisos de Graph (consulta Enviar archivos en chats grupales). Las encuestas se envían mediante Adaptive Cards. Las acciones de mensaje exponen upload-file explícito para envíos donde el archivo va primero.
Plugin incluido
Microsoft Teams se distribuye como un Plugin incluido en las versiones actuales de OpenClaw, por lo que no se requiere una instalación separada en la compilación empaquetada normal.
Si usas una compilación anterior o una instalación personalizada que excluye Teams incluido, instala el paquete npm directamente:
openclaw plugins install @openclaw/msteams
Usa el paquete sin versión para seguir la etiqueta de la versión oficial actual. Fija una versión exacta solo cuando necesites una instalación reproducible.
Checkout local (cuando se ejecuta desde un repositorio git):
openclaw plugins install ./path/to/local/msteams-plugin
Detalles: Plugins
Configuración rápida
@microsoft/teams.cli gestiona el registro del bot, la creación del manifiesto y la generación de credenciales en un solo comando.
1. Instala e inicia sesión
npm install -g @microsoft/teams.cli@preview
teams login
teams status # verify you're logged in and see your tenant info
2. Inicia un túnel (Teams no puede alcanzar localhost)
Instala y autentica la CLI de devtunnel si aún no lo has hecho (guía de primeros pasos).
# One-time setup (persistent URL across sessions):
devtunnel create my-openclaw-bot --allow-anonymous
devtunnel port create my-openclaw-bot -p 3978 --protocol auto
# Each dev session:
devtunnel host my-openclaw-bot
# Your endpoint: https://<tunnel-id>.devtunnels.ms/api/messages
Alternativas: ngrok http 3978 o tailscale funnel 3978 (pero estas pueden cambiar las URL en cada sesión).
3. Crea la aplicación
teams app create \
--name "OpenClaw" \
--endpoint "https://<your-tunnel-url>/api/messages"
Este único comando:
- Crea una aplicación de Entra ID (Azure AD)
- Genera un secreto de cliente
- Crea y carga un manifiesto de aplicación de Teams (con iconos)
- Registra el bot (gestionado por Teams de forma predeterminada; no se necesita suscripción de Azure)
La salida mostrará CLIENT_ID, CLIENT_SECRET, TENANT_ID y un ID de aplicación de Teams; anótalos para los pasos siguientes. También ofrece instalar la aplicación directamente en Teams.
4. Configura OpenClaw con las credenciales de la salida:
{
channels: {
msteams: {
enabled: true,
appId: "<CLIENT_ID>",
appPassword: "<CLIENT_SECRET>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
O usa variables de entorno directamente: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.
5. Instala la aplicación en Teams
teams app create te pedirá instalar la aplicación: selecciona "Install in Teams". Si lo omitiste, puedes obtener el enlace más tarde:
teams app get <teamsAppId> --install-link
6. Verifica que todo funcione
teams app doctor <teamsAppId>
Esto ejecuta diagnósticos en el registro del bot, la configuración de la aplicación AAD, la validez del manifiesto y la configuración de SSO.
Para despliegues de producción, considera usar autenticación federada (certificado o identidad administrada) en lugar de secretos de cliente.
Objetivos
- Hablar con OpenClaw mediante DM, chats grupales o canales de Teams.
- Mantener el enrutamiento determinista: las respuestas siempre vuelven al canal por el que llegaron.
- Usar de forma predeterminada un comportamiento de canal seguro (se requieren menciones salvo que se configure lo contrario).
Escrituras de configuración
De forma predeterminada, Microsoft Teams tiene permiso para escribir actualizaciones de configuración activadas por /config set|unset (requiere commands.config: true).
Desactívalo con:
{
channels: { msteams: { configWrites: false } },
}
Control de acceso (DM + grupos)
Acceso por DM
- Predeterminado:
channels.msteams.dmPolicy = "pairing". Los remitentes desconocidos se ignoran hasta que se aprueban. channels.msteams.allowFromdebe usar ID de objeto AAD estables.- No dependas de la coincidencia de UPN/nombre visible para listas de permitidos: pueden cambiar. OpenClaw desactiva la coincidencia directa por nombre de forma predeterminada; actívala explícitamente con
channels.msteams.dangerouslyAllowNameMatching: true. - El asistente puede resolver nombres a ID mediante Microsoft Graph cuando las credenciales lo permitan.
Acceso de grupo
- Predeterminado:
channels.msteams.groupPolicy = "allowlist"(bloqueado salvo que agreguesgroupAllowFrom). Usachannels.defaults.groupPolicypara sobrescribir el valor predeterminado cuando no esté definido. channels.msteams.groupAllowFromcontrola qué remitentes pueden activar respuestas en chats grupales/canales (recurre achannels.msteams.allowFrom).- Establece
groupPolicy: "open"para permitir a cualquier miembro (aun así controlado por menciones de forma predeterminada). - Para no permitir ningún canal, establece
channels.msteams.groupPolicy: "disabled".
Ejemplo:
{
channels: {
msteams: {
groupPolicy: "allowlist",
groupAllowFrom: ["[email protected]"],
},
},
}
Lista de permitidos de Teams + canal
- Acota las respuestas de grupo/canal enumerando equipos y canales en
channels.msteams.teams. - Las claves deben usar ID de conversación de Teams estables provenientes de enlaces de Teams, no nombres visibles mutables.
- Cuando
groupPolicy="allowlist"y hay una lista de permitidos de equipos presente, solo se aceptan los equipos/canales listados (controlado por menciones). - El asistente de configuración acepta entradas
Team/Channely las almacena por ti. - Al iniciar, OpenClaw resuelve los nombres de equipos/canales y usuarios de la lista de permitidos a ID (cuando los permisos de Graph lo permitan)
y registra el mapeo; los nombres de equipos/canales no resueltos se conservan tal como se escribieron, pero se ignoran para el enrutamiento de forma predeterminada salvo que
channels.msteams.dangerouslyAllowNameMatching: trueesté habilitado.
Ejemplo:
{
channels: {
msteams: {
groupPolicy: "allowlist",
teams: {
"My Team": {
channels: {
General: { requireMention: true },
},
},
},
},
},
}
Configuración manual (sin la CLI de Teams)
Si no puedes usar la CLI de Teams, puedes configurar el bot manualmente mediante Azure Portal.
Cómo funciona
- Asegúrate de que el Plugin de Microsoft Teams esté disponible (incluido en las versiones actuales).
- Crea un Azure Bot (ID de aplicación + secreto + ID de inquilino).
- Crea un paquete de aplicación de Teams que haga referencia al bot e incluya los permisos RSC siguientes.
- Carga/instala la aplicación de Teams en un equipo (o en ámbito personal para DM).
- Configura
msteamsen~/.openclaw/openclaw.json(o variables de entorno) e inicia el Gateway. - El Gateway escucha tráfico de Webhook de Bot Framework en
/api/messagesde forma predeterminada.
Paso 1: Crear Azure Bot
-
Ve a Crear Azure Bot
-
Completa la pestaña Conceptos básicos:
Campo Valor Identificador del bot El nombre de tu bot, por ejemplo, openclaw-msteams(debe ser único)Suscripción Selecciona tu suscripción de Azure Grupo de recursos Crea uno nuevo o usa uno existente Nivel de precios Gratis para desarrollo/pruebas Tipo de aplicación Inquilino único (recomendado; consulta la nota siguiente) Tipo de creación Crear nuevo Microsoft App ID
- Haz clic en Revisar y crear → Crear (espera ~1-2 minutos)
Paso 2: Obtener credenciales
- Ve a tu recurso de Azure Bot → Configuración
- Copia Microsoft App ID → este es tu
appId - Haz clic en Administrar contraseña → ve al registro de la aplicación
- En Certificados y secretos → Nuevo secreto de cliente → copia el Valor → este es tu
appPassword - Ve a Información general → copia ID de directorio (inquilino) → este es tu
tenantId
Paso 3: Configurar el endpoint de mensajería
- En Azure Bot → Configuración
- Establece Endpoint de mensajería en la URL de tu Webhook:
- Producción:
https://your-domain.com/api/messages - Desarrollo local: usa un túnel (consulta Desarrollo local más abajo)
- Producción:
Paso 4: Habilitar el canal de Teams
- En Azure Bot → Canales
- Haz clic en Microsoft Teams → Configurar → Guardar
- Acepta los Términos del Servicio
Paso 5: Crear el manifiesto de aplicación de Teams
- Incluye una entrada
botconbotId = <App ID>. - Ámbitos:
personal,team,groupChat. supportsFiles: true(obligatorio para el manejo de archivos en ámbito personal).- Agrega permisos RSC (consulta Permisos RSC).
- Crea iconos:
outline.png(32x32) ycolor.png(192x192). - Comprime los tres archivos juntos:
manifest.json,outline.png,color.png.
Paso 6: Configurar OpenClaw
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
appPassword: "<APP_PASSWORD>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Variables de entorno: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.
Paso 7: Ejecutar el Gateway
El canal de Teams se inicia automáticamente cuando el Plugin está disponible y existe configuración de msteams con credenciales.
Autenticación federada (certificado más identidad administrada)
Añadido en 2026.4.11
Para despliegues de producción, OpenClaw admite autenticación federada como una alternativa más segura a los secretos de cliente. Hay dos métodos disponibles:
Opción A: Autenticación basada en certificado
Usa un certificado PEM registrado con el registro de tu aplicación de Entra ID.
Configuración:
- Genera u obtén un certificado (formato PEM con clave privada).
- En Entra ID → Registro de aplicaciones → Certificados y secretos → Certificados → Carga el certificado público.
Configuración:
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
certificatePath: "/path/to/cert.pem",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Variables de entorno:
MSTEAMS_AUTH_TYPE=federatedMSTEAMS_CERTIFICATE_PATH=/path/to/cert.pem
Opción B: Azure Managed Identity
Usa Azure Managed Identity para autenticación sin contraseña. Es ideal para despliegues en infraestructura de Azure (AKS, App Service, VM de Azure) donde hay una identidad administrada disponible.
Cómo funciona:
- El pod/VM del bot tiene una identidad administrada (asignada por el sistema o asignada por el usuario).
- Una credencial de identidad federada vincula la identidad administrada con el registro de la aplicación de Entra ID.
- En tiempo de ejecución, OpenClaw usa
@azure/identitypara adquirir tokens del endpoint de Azure IMDS (169.254.169.254). - El token se pasa al SDK de Teams para la autenticación del bot.
Requisitos previos:
- Infraestructura de Azure con identidad administrada habilitada (identidad de carga de trabajo de AKS, App Service, VM)
- Credencial de identidad federada creada en el registro de la aplicación de Entra ID
- Acceso de red a IMDS (
169.254.169.254:80) desde el pod/VM
Configuración (identidad administrada asignada por el sistema):
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
useManagedIdentity: true,
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Config (identidad administrada asignada por el usuario):
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
useManagedIdentity: true,
managedIdentityClientId: "<MI_CLIENT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Variables de entorno:
MSTEAMS_AUTH_TYPE=federatedMSTEAMS_USE_MANAGED_IDENTITY=trueMSTEAMS_MANAGED_IDENTITY_CLIENT_ID=<client-id>(solo para asignada por el usuario)
Configuración de Workload Identity en AKS
Para implementaciones de AKS que usan identidad de carga de trabajo:
-
Habilita la identidad de carga de trabajo en tu clúster de AKS.
-
Crea una credencial de identidad federada en el registro de la aplicación de Entra ID:
az ad app federated-credential create --id <APP_OBJECT_ID> --parameters '{ "name": "my-bot-workload-identity", "issuer": "<AKS_OIDC_ISSUER_URL>", "subject": "system:serviceaccount:<NAMESPACE>:<SERVICE_ACCOUNT>", "audiences": ["api://AzureADTokenExchange"] }' -
Anota la cuenta de servicio de Kubernetes con el ID de cliente de la aplicación:
apiVersion: v1 kind: ServiceAccount metadata: name: my-bot-sa annotations: azure.workload.identity/client-id: "<APP_CLIENT_ID>" -
Etiqueta el pod para la inyección de identidad de carga de trabajo:
metadata: labels: azure.workload.identity/use: "true" -
Asegura el acceso de red a IMDS (
169.254.169.254): si usas NetworkPolicy, agrega una regla de salida que permita el tráfico a169.254.169.254/32en el puerto 80.
Comparación de tipos de autenticación
| Método | Config | Ventajas | Desventajas |
|---|---|---|---|
| Secreto de cliente | appPassword |
Configuración sencilla | Requiere rotación de secretos, menos seguro |
| Certificado | authType: "federated" + certificatePath |
Sin secreto compartido por la red | Sobrecarga de gestión de certificados |
| Identidad administrada | authType: "federated" + useManagedIdentity |
Sin contraseña, sin secretos que gestionar | Requiere infraestructura de Azure |
Comportamiento predeterminado: Cuando authType no está definido, OpenClaw usa de forma predeterminada la autenticación con secreto de cliente. Las configuraciones existentes siguen funcionando sin cambios.
Desarrollo local (tunelización)
Teams no puede alcanzar localhost. Usa un túnel de desarrollo persistente para que tu URL se mantenga igual entre sesiones:
# One-time setup:
devtunnel create my-openclaw-bot --allow-anonymous
devtunnel port create my-openclaw-bot -p 3978 --protocol auto
# Each dev session:
devtunnel host my-openclaw-bot
Alternativas: ngrok http 3978 o tailscale funnel 3978 (las URL pueden cambiar en cada sesión).
Si la URL de tu túnel cambia, actualiza el endpoint:
teams app update <teamsAppId> --endpoint "https://<new-url>/api/messages"
Pruebas del bot
Ejecutar diagnósticos:
teams app doctor <teamsAppId>
Comprueba el registro del bot, la aplicación AAD, el manifiesto y la configuración de SSO en una sola pasada.
Enviar un mensaje de prueba:
- Instala la aplicación de Teams (usa el enlace de instalación de
teams app get <id> --install-link) - Busca el bot en Teams y envía un DM
- Revisa los registros del Gateway para ver la actividad entrante
Variables de entorno
Todas las claves de configuración se pueden definir mediante variables de entorno:
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_IDMSTEAMS_AUTH_TYPE(opcional:"secret"o"federated")MSTEAMS_CERTIFICATE_PATH(federado + certificado)MSTEAMS_CERTIFICATE_THUMBPRINT(opcional, no requerido para autenticación)MSTEAMS_USE_MANAGED_IDENTITY(federado + identidad administrada)MSTEAMS_MANAGED_IDENTITY_CLIENT_ID(solo MI asignada por el usuario)
Acción de información de miembros
OpenClaw expone una acción member-info respaldada por Graph para Microsoft Teams, de modo que los agentes y las automatizaciones puedan resolver detalles de miembros del canal (nombre para mostrar, correo electrónico, rol) directamente desde Microsoft Graph.
Requisitos:
- Permiso RSC
Member.Read.Group(ya incluido en el manifiesto recomendado) - Para búsquedas entre equipos: permiso de aplicación de Graph
User.Read.Allcon consentimiento de administrador
La acción está controlada por channels.msteams.actions.memberInfo (valor predeterminado: habilitada cuando las credenciales de Graph están disponibles).
Contexto de historial
channels.msteams.historyLimitcontrola cuántos mensajes recientes de canal/grupo se envuelven en el prompt.- Recurre a
messages.groupChat.historyLimit. Define0para deshabilitarlo (valor predeterminado 50). - El historial de hilos obtenido se filtra por listas de permitidos de remitentes (
allowFrom/groupAllowFrom), por lo que la inicialización del contexto de hilo solo incluye mensajes de remitentes permitidos. - El contexto de adjuntos citados (
ReplyTo*derivado del HTML de respuesta de Teams) actualmente se pasa tal como se recibe. - En otras palabras, las listas de permitidos controlan quién puede activar al agente; hoy solo se filtran rutas específicas de contexto suplementario.
- El historial de DM se puede limitar con
channels.msteams.dmHistoryLimit(turnos de usuario). Sobrescrituras por usuario:channels.msteams.dms["<user_id>"].historyLimit.
Permisos RSC actuales de Teams (manifiesto)
Estos son los permisos resourceSpecific existentes en nuestro manifiesto de la aplicación de Teams. Solo se aplican dentro del equipo/chat donde está instalada la aplicación.
Para canales (ámbito de equipo):
ChannelMessage.Read.Group(Application): recibir todos los mensajes de canal sin @menciónChannelMessage.Send.Group(Application)Member.Read.Group(Application)Owner.Read.Group(Application)ChannelSettings.Read.Group(Application)TeamMember.Read.Group(Application)TeamSettings.Read.Group(Application)
Para chats grupales:
ChatMessage.Read.Chat(Application): recibir todos los mensajes de chat grupal sin @mención
Para agregar permisos RSC mediante la CLI de Teams:
teams app rsc add <teamsAppId> ChannelMessage.Read.Group --type Application
Ejemplo de manifiesto de Teams (redactado)
Ejemplo mínimo y válido con los campos requeridos. Reemplaza los ID y las URL.
{
$schema: "https://developer.microsoft.com/en-us/json-schemas/teams/v1.23/MicrosoftTeams.schema.json",
manifestVersion: "1.23",
version: "1.0.0",
id: "00000000-0000-0000-0000-000000000000",
name: { short: "OpenClaw" },
developer: {
name: "Your Org",
websiteUrl: "https://example.com",
privacyUrl: "https://example.com/privacy",
termsOfUseUrl: "https://example.com/terms",
},
description: { short: "OpenClaw in Teams", full: "OpenClaw in Teams" },
icons: { outline: "outline.png", color: "color.png" },
accentColor: "#5B6DEF",
bots: [
{
botId: "11111111-1111-1111-1111-111111111111",
scopes: ["personal", "team", "groupChat"],
isNotificationOnly: false,
supportsCalling: false,
supportsVideo: false,
supportsFiles: true,
},
],
webApplicationInfo: {
id: "11111111-1111-1111-1111-111111111111",
},
authorization: {
permissions: {
resourceSpecific: [
{ name: "ChannelMessage.Read.Group", type: "Application" },
{ name: "ChannelMessage.Send.Group", type: "Application" },
{ name: "Member.Read.Group", type: "Application" },
{ name: "Owner.Read.Group", type: "Application" },
{ name: "ChannelSettings.Read.Group", type: "Application" },
{ name: "TeamMember.Read.Group", type: "Application" },
{ name: "TeamSettings.Read.Group", type: "Application" },
{ name: "ChatMessage.Read.Chat", type: "Application" },
],
},
},
}
Advertencias del manifiesto (campos obligatorios)
bots[].botIddebe coincidir con el ID de la aplicación de Azure Bot.webApplicationInfo.iddebe coincidir con el ID de la aplicación de Azure Bot.bots[].scopesdebe incluir las superficies que planeas usar (personal,team,groupChat).bots[].supportsFiles: truees obligatorio para gestionar archivos en el ámbito personal.authorization.permissions.resourceSpecificdebe incluir lectura/envío de canal si quieres tráfico de canal.
Actualizar una aplicación existente
Para actualizar una aplicación de Teams ya instalada (por ejemplo, para agregar permisos RSC):
# Download, edit, and re-upload the manifest
teams app manifest download <teamsAppId> manifest.json
# Edit manifest.json locally...
teams app manifest upload manifest.json <teamsAppId>
# Version is auto-bumped if content changed
Después de actualizar, reinstala la aplicación en cada equipo para que los nuevos permisos surtan efecto y sal de Teams por completo y vuelve a abrirlo (no solo cierres la ventana) para borrar los metadatos de la aplicación en caché.
Actualización manual del manifiesto (sin CLI)
- Actualiza tu
manifest.jsoncon la nueva configuración - Incrementa el campo
version(por ejemplo,1.0.0→1.1.0) - Vuelve a comprimir el manifiesto con los iconos (
manifest.json,outline.png,color.png) - Sube el nuevo zip:
- Centro de administración de Teams: Aplicaciones de Teams → Administrar aplicaciones → busca tu aplicación → Subir nueva versión
- Carga lateral: En Teams → Aplicaciones → Administrar tus aplicaciones → Subir una aplicación personalizada
Capacidades: solo RSC frente a Graph
Con solo RSC de Teams (aplicación instalada, sin permisos de Graph API)
Funciona:
- Leer contenido de texto de mensajes de canal.
- Enviar contenido de texto de mensajes de canal.
- Recibir adjuntos de archivo personales (DM).
No funciona:
- Imágenes o contenido de archivos de canal/grupo (la carga útil solo incluye un stub HTML).
- Descargar adjuntos almacenados en SharePoint/OneDrive.
- Leer historial de mensajes (más allá del evento Webhook en vivo).
Con RSC de Teams + permisos de aplicación de Microsoft Graph
Agrega:
- Descargar contenidos alojados (imágenes pegadas en mensajes).
- Descargar adjuntos de archivo almacenados en SharePoint/OneDrive.
- Leer historial de mensajes de canal/chat mediante Graph.
RSC frente a Graph API
| Capacidad | Permisos RSC | Graph API |
|---|---|---|
| Mensajes en tiempo real | Sí (mediante Webhook) | No (solo sondeo) |
| Mensajes históricos | No | Sí (puede consultar historial) |
| Complejidad de configuración | Solo manifiesto de la aplicación | Requiere consentimiento de administrador + flujo de tokens |
| Funciona sin conexión | No (debe estar en ejecución) | Sí (consulta en cualquier momento) |
Conclusión: RSC es para escucha en tiempo real; Graph API es para acceso histórico. Para ponerse al día con mensajes perdidos mientras estás sin conexión, necesitas Graph API con ChannelMessage.Read.All (requiere consentimiento de administrador).
Medios e historial habilitados con Graph (requerido para canales)
Si necesitas imágenes/archivos en canales o quieres obtener historial de mensajes, debes habilitar los permisos de Microsoft Graph y conceder consentimiento de administrador.
- En el registro de aplicación de Entra ID (Azure AD), agrega permisos de aplicación de Microsoft Graph:
ChannelMessage.Read.All(adjuntos de canal + historial)Chat.Read.AlloChatMessage.Read.All(chats grupales)
- Concede consentimiento de administrador para el inquilino.
- Incrementa la versión del manifiesto de la aplicación de Teams, vuelve a subirla y reinstala la aplicación en Teams.
- Sal de Teams por completo y vuelve a abrirlo para borrar los metadatos de la aplicación en caché.
Permiso adicional para menciones de usuario: Las @menciones de usuarios funcionan de forma predeterminada para los usuarios de la conversación. Sin embargo, si quieres buscar y mencionar dinámicamente usuarios que no están en la conversación actual, agrega el permiso User.Read.All (Application) y concede consentimiento de administrador.
Limitaciones conocidas
Tiempos de espera de Webhook
Teams entrega mensajes mediante Webhook HTTP. Si el procesamiento tarda demasiado (por ejemplo, respuestas lentas del LLM), puedes ver:
- Tiempos de espera del Gateway
- Teams reintentando el mensaje (lo que causa duplicados)
- Respuestas descartadas
OpenClaw gestiona esto respondiendo rápidamente y enviando respuestas de forma proactiva, pero las respuestas muy lentas aún pueden causar problemas.
Formato
El markdown de Teams es más limitado que el de Slack o Discord:
- El formato básico funciona: negrita, cursiva,
code, enlaces - El markdown complejo (tablas, listas anidadas) puede no renderizarse correctamente
- Adaptive Cards es compatible con encuestas y envíos de presentaciones semánticas (ver abajo)
Configuración
Ajustes clave (consulta /gateway/configuration para patrones compartidos de canales):
channels.msteams.enabled: habilita/deshabilita el canal.channels.msteams.appId,channels.msteams.appPassword,channels.msteams.tenantId: credenciales del bot.channels.msteams.webhook.port(predeterminado3978)channels.msteams.webhook.path(predeterminado/api/messages)channels.msteams.dmPolicy:pairing | allowlist | open | disabled(predeterminado: pairing)channels.msteams.allowFrom: lista de permitidos para DM (se recomiendan IDs de objeto AAD). El asistente resuelve nombres a IDs durante la configuración cuando el acceso a Graph está disponible.channels.msteams.dangerouslyAllowNameMatching: interruptor de emergencia para volver a habilitar la coincidencia mutable de UPN/nombre para mostrar y el enrutamiento directo por nombre de equipo/canal.channels.msteams.textChunkLimit: tamaño de fragmento de texto saliente.channels.msteams.chunkMode:length(predeterminado) onewlinepara dividir en líneas en blanco (límites de párrafo) antes de fragmentar por longitud.channels.msteams.mediaAllowHosts: lista de permitidos para hosts de adjuntos entrantes (predeterminada a dominios de Microsoft/Teams).channels.msteams.mediaAuthAllowHosts: lista de permitidos para adjuntar encabezados Authorization en reintentos de medios (predeterminada a hosts de Graph + Bot Framework).channels.msteams.requireMention: requiere @mención en canales/grupos (predeterminado true).channels.msteams.replyStyle:thread | top-level(ver Estilo de respuesta).channels.msteams.teams.<teamId>.replyStyle: anulación por equipo.channels.msteams.teams.<teamId>.requireMention: anulación por equipo.channels.msteams.teams.<teamId>.tools: anulaciones predeterminadas por equipo de la política de herramientas (allow/deny/alsoAllow) usadas cuando falta una anulación de canal.channels.msteams.teams.<teamId>.toolsBySender: anulaciones predeterminadas por equipo y remitente de la política de herramientas (comodín"*"compatible).channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: anulación por canal.channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: anulación por canal.channels.msteams.teams.<teamId>.channels.<conversationId>.tools: anulaciones por canal de la política de herramientas (allow/deny/alsoAllow).channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: anulaciones por canal y remitente de la política de herramientas (comodín"*"compatible).- Las claves de
toolsBySenderdeben usar prefijos explícitos:id:,e164:,username:,name:(las claves heredadas sin prefijo todavía se asignan solo aid:). channels.msteams.actions.memberInfo: habilita o deshabilita la acción de información de miembros respaldada por Graph (predeterminado: habilitada cuando las credenciales de Graph están disponibles).channels.msteams.authType: tipo de autenticación -"secret"(predeterminado) o"federated".channels.msteams.certificatePath: ruta al archivo de certificado PEM (autenticación federada + certificado).channels.msteams.certificateThumbprint: huella digital del certificado (opcional, no requerida para autenticación).channels.msteams.useManagedIdentity: habilita la autenticación de identidad administrada (modo federado).channels.msteams.managedIdentityClientId: ID de cliente para identidad administrada asignada por el usuario.channels.msteams.sharePointSiteId: ID del sitio de SharePoint para cargas de archivos en chats grupales/canales (ver Enviar archivos en chats grupales).
Enrutamiento y sesiones
- Las claves de sesión siguen el formato estándar de agente (consulta /concepts/session):
- Los mensajes directos comparten la sesión principal (
agent:<agentId>:<mainKey>). - Los mensajes de canal/grupo usan el id de conversación:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- Los mensajes directos comparten la sesión principal (
Estilo de respuesta: hilos frente a publicaciones
Teams introdujo recientemente dos estilos de interfaz de canal sobre el mismo modelo de datos subyacente:
| Estilo | Descripción | replyStyle recomendado |
|---|---|---|
| Publicaciones (clásico) | Los mensajes aparecen como tarjetas con respuestas en hilo debajo | thread (predeterminado) |
| Hilos (tipo Slack) | Los mensajes fluyen linealmente, más parecido a Slack | top-level |
El problema: La API de Teams no expone qué estilo de interfaz usa un canal. Si usas el replyStyle incorrecto:
threaden un canal con estilo de hilos → las respuestas aparecen anidadas de forma incómodatop-levelen un canal con estilo de publicaciones → las respuestas aparecen como publicaciones de nivel superior separadas en vez de dentro del hilo
Solución: Configura replyStyle por canal según cómo esté configurado el canal:
{
channels: {
msteams: {
replyStyle: "thread",
teams: {
"19:[email protected]": {
channels: {
"19:[email protected]": {
replyStyle: "top-level",
},
},
},
},
},
},
}
Adjuntos e imágenes
Limitaciones actuales:
- DMs: Las imágenes y los adjuntos de archivo funcionan mediante las API de archivos para bots de Teams.
- Canales/grupos: Los adjuntos residen en almacenamiento M365 (SharePoint/OneDrive). La carga útil del Webhook solo incluye un fragmento HTML, no los bytes reales del archivo. Se requieren permisos de Graph API para descargar adjuntos de canal.
- Para envíos explícitos centrados primero en archivos, usa
action=upload-fileconmedia/filePath/path;messageopcional se convierte en el texto/comentario acompañante, yfilenameanula el nombre cargado.
Sin permisos de Graph, los mensajes de canal con imágenes se recibirán solo como texto (el contenido de la imagen no es accesible para el bot).
De forma predeterminada, OpenClaw solo descarga medios desde nombres de host de Microsoft/Teams. Anúlalo con channels.msteams.mediaAllowHosts (usa ["*"] para permitir cualquier host).
Los encabezados Authorization solo se adjuntan para hosts en channels.msteams.mediaAuthAllowHosts (predeterminado a hosts de Graph + Bot Framework). Mantén esta lista estricta (evita sufijos multiinquilino).
Enviar archivos en chats grupales
Los bots pueden enviar archivos en DMs usando el flujo FileConsentCard (integrado). Sin embargo, enviar archivos en chats grupales/canales requiere configuración adicional:
| Contexto | Cómo se envían los archivos | Configuración necesaria |
|---|---|---|
| DMs | FileConsentCard → el usuario acepta → el bot carga | Funciona sin configuración adicional |
| Chats grupales/canales | Cargar a SharePoint → compartir enlace | Requiere sharePointSiteId + permisos de Graph |
| Imágenes (cualquier contexto) | Inline codificado en Base64 | Funciona sin configuración adicional |
Por qué los chats grupales necesitan SharePoint
Los bots no tienen una unidad personal de OneDrive (el endpoint /me/drive de Graph API no funciona para identidades de aplicación). Para enviar archivos en chats grupales/canales, el bot carga a un sitio de SharePoint y crea un enlace para compartir.
Configuración
-
Agrega permisos de Graph API en Entra ID (Azure AD) → Registro de aplicación:
Sites.ReadWrite.All(Application) - cargar archivos a SharePointChat.Read.All(Application) - opcional, habilita enlaces para compartir por usuario
-
Concede consentimiento de administrador para el inquilino.
-
Obtén tu ID de sitio de SharePoint:
# Via Graph Explorer or curl with a valid token: curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}" # Example: for a site at "contoso.sharepoint.com/sites/BotFiles" curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles" # Response includes: "id": "contoso.sharepoint.com,guid1,guid2" -
Configura OpenClaw:
{ channels: { msteams: { // ... other config ... sharePointSiteId: "contoso.sharepoint.com,guid1,guid2", }, }, }
Comportamiento de uso compartido
| Permiso | Comportamiento de uso compartido |
|---|---|
Solo Sites.ReadWrite.All |
Enlace para compartir en toda la organización (cualquier persona de la org puede acceder) |
Sites.ReadWrite.All + Chat.Read.All |
Enlace para compartir por usuario (solo los miembros del chat pueden acceder) |
El uso compartido por usuario es más seguro, ya que solo los participantes del chat pueden acceder al archivo. Si falta el permiso Chat.Read.All, el bot recurre al uso compartido para toda la organización.
Comportamiento de reserva
| Escenario | Resultado |
|---|---|
Chat grupal + archivo + sharePointSiteId configurado |
Carga a SharePoint, envía enlace para compartir |
Chat grupal + archivo + sin sharePointSiteId |
Intenta cargar a OneDrive (puede fallar), envía solo texto |
| Chat personal + archivo | Flujo FileConsentCard (funciona sin SharePoint) |
| Cualquier contexto + imagen | Inline codificado en Base64 (funciona sin SharePoint) |
Ubicación de archivos almacenados
Los archivos cargados se almacenan en una carpeta /OpenClawShared/ en la biblioteca de documentos predeterminada del sitio de SharePoint configurado.
Encuestas (Adaptive Cards)
OpenClaw envía encuestas de Teams como Adaptive Cards (no existe una API nativa de encuestas de Teams).
- CLI:
openclaw message poll --channel msteams --target conversation:<id> ... - Los votos los registra el Gateway en
~/.openclaw/msteams-polls.json. - El Gateway debe permanecer en línea para registrar votos.
- Las encuestas todavía no publican automáticamente resúmenes de resultados (inspecciona el archivo de almacenamiento si es necesario).
Tarjetas de presentación
Envía cargas útiles de presentación semántica a usuarios o conversaciones de Teams usando la herramienta message o la CLI. OpenClaw las renderiza como Adaptive Cards de Teams desde el contrato de presentación genérico.
El parámetro presentation acepta bloques semánticos. Cuando se proporciona presentation, el texto del mensaje es opcional.
Herramienta de agente:
{
action: "send",
channel: "msteams",
target: "user:<id>",
presentation: {
title: "Hello",
blocks: [{ type: "text", text: "Hello!" }],
},
}
CLI:
openclaw message send --channel msteams \
--target "conversation:19:[email protected]" \
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello!"}]}'
Para detalles del formato de destino, consulta Formatos de destino abajo.
Formatos de destino
Los destinos de MSTeams usan prefijos para distinguir entre usuarios y conversaciones:
| Tipo de destino | Formato | Ejemplo |
|---|---|---|
| Usuario (por ID) | user:<aad-object-id> |
user:40a1a0ed-4ff2-4164-a219-55518990c197 |
| Usuario (por nombre) | user:<display-name> |
user:John Smith (requiere Graph API) |
| Grupo/canal | conversation:<conversation-id> |
conversation:19:[email protected] |
| Grupo/canal (raw) | <conversation-id> |
19:[email protected] (si contiene @thread) |
Ejemplos de CLI:
# Send to a user by ID
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"
# Send to a user by display name (triggers Graph API lookup)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"
# Send to a group chat or channel
openclaw message send --channel msteams --target "conversation:19:[email protected]" --message "Hello"
# Send a presentation card to a conversation
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello"}]}'
Ejemplos de herramientas del agente:
{
action: "send",
channel: "msteams",
target: "user:John Smith",
message: "Hello!",
}
{
action: "send",
channel: "msteams",
target: "conversation:19:[email protected]",
presentation: {
title: "Hello",
blocks: [{ type: "text", text: "Hello" }],
},
}
Mensajería proactiva
- Los mensajes proactivos solo son posibles después de que un usuario haya interactuado, porque almacenamos las referencias de conversación en ese momento.
- Consulta
/gateway/configurationparadmPolicyy el control por lista de permitidos.
Identificadores de equipo y canal (error común)
El parámetro de consulta groupId en las URL de Teams NO es el ID de equipo usado para la configuración. Extrae los ID desde la ruta de la URL en su lugar:
URL de equipo:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
└────────────────────────────┘
ID de conversación del equipo (decodifica esto de la URL)
URL de canal:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
└─────────────────────────┘
ID de canal (decodifica esto de la URL)
Para la configuración:
- Clave de equipo = segmento de ruta después de
/team/(decodificado de URL, por ejemplo,19:[email protected]; los tenants más antiguos pueden mostrar@thread.skype, que también es válido) - Clave de canal = segmento de ruta después de
/channel/(decodificado de URL) - Ignora el parámetro de consulta
groupIdpara el enrutamiento de OpenClaw. Es el ID de grupo de Microsoft Entra, no el ID de conversación de Bot Framework usado en las actividades entrantes de Teams.
Canales privados
Los bots tienen soporte limitado en canales privados:
| Función | Canales estándar | Canales privados |
|---|---|---|
| Instalación del bot | Sí | Limitada |
| Mensajes en tiempo real (webhook) | Sí | Puede no funcionar |
| Permisos RSC | Sí | Pueden comportarse de forma diferente |
| @menciones | Sí | Si el bot está accesible |
| Historial de Graph API | Sí | Sí (con permisos) |
Soluciones alternativas si los canales privados no funcionan:
- Usa canales estándar para las interacciones con el bot
- Usa mensajes directos: los usuarios siempre pueden enviar mensajes directamente al bot
- Usa Graph API para acceso histórico (requiere
ChannelMessage.Read.All)
Solución de problemas
Problemas comunes
- Las imágenes no aparecen en los canales: faltan permisos de Graph o consentimiento del administrador. Reinstala la aplicación de Teams y cierra por completo/vuelve a abrir Teams.
- No hay respuestas en el canal: las menciones son obligatorias de forma predeterminada; establece
channels.msteams.requireMention=falseo configura por equipo/canal. - Incompatibilidad de versión (Teams sigue mostrando el manifiesto antiguo): quita y vuelve a agregar la aplicación, y cierra por completo Teams para actualizar.
- 401 Unauthorized desde el webhook: esperado al probar manualmente sin Azure JWT; significa que el endpoint es accesible, pero falló la autenticación. Usa Azure Web Chat para probar correctamente.
Errores al cargar el manifiesto
- "Icon file cannot be empty": el manifiesto hace referencia a archivos de iconos de 0 bytes. Crea iconos PNG válidos (32x32 para
outline.png, 192x192 paracolor.png). - "webApplicationInfo.Id already in use": la aplicación aún está instalada en otro equipo/chat. Búscala y desinstálala primero, o espera entre 5 y 10 minutos para la propagación.
- "Something went wrong" al cargar: carga desde https://admin.teams.microsoft.com en su lugar, abre DevTools del navegador (F12) → pestaña Network y revisa el cuerpo de la respuesta para ver el error real.
- Error de carga lateral: prueba "Upload an app to your org's app catalog" en lugar de "Upload a custom app"; esto a menudo evita las restricciones de carga lateral.
Los permisos RSC no funcionan
- Verifica que
webApplicationInfo.idcoincida exactamente con el App ID de tu bot - Vuelve a cargar la aplicación y reinstálala en el equipo/chat
- Comprueba si el administrador de tu organización ha bloqueado los permisos RSC
- Confirma que estás usando el ámbito correcto:
ChannelMessage.Read.Grouppara equipos,ChatMessage.Read.Chatpara chats grupales
Referencias
- Crear Azure Bot - guía de configuración de Azure Bot
- Teams Developer Portal - crear/administrar aplicaciones de Teams
- Esquema del manifiesto de aplicación de Teams
- Recibir mensajes de canal con RSC
- Referencia de permisos RSC
- Manejo de archivos de bots de Teams (canal/grupo requiere Graph)
- Mensajería proactiva
- @microsoft/teams.cli - CLI de Teams para la administración de bots
Relacionado
- Resumen de canales - todos los canales compatibles
- Emparejamiento - autenticación por mensaje directo y flujo de emparejamiento
- Grupos - comportamiento del chat grupal y control mediante menciones
- Enrutamiento de canales - enrutamiento de sesiones para mensajes
- Seguridad - modelo de acceso y fortalecimiento