Mainstream messaging

Microsoft Teams

Status: Text + DM-Anhänge werden unterstützt; das Senden von Dateien in Kanälen/Gruppen erfordert sharePointSiteId + Graph-Berechtigungen (siehe Dateien in Gruppenchats senden). Umfragen werden über Adaptive Cards gesendet. Nachrichtenaktionen stellen explizit upload-file für dateizentriertes Senden bereit.

Gebündeltes Plugin

Microsoft Teams wird in aktuellen OpenClaw-Versionen als gebündeltes Plugin ausgeliefert, daher ist im normalen paketierten Build keine separate Installation erforderlich.

Wenn Sie einen älteren Build oder eine benutzerdefinierte Installation verwenden, die gebündeltes Teams ausschließt, installieren Sie das npm-Paket direkt:

openclaw plugins install @openclaw/msteams

Verwenden Sie das reine Paket, um dem aktuellen offiziellen Release-Tag zu folgen. Pinnen Sie eine exakte Version nur dann, wenn Sie eine reproduzierbare Installation benötigen.

Lokaler Checkout (wenn Sie aus einem Git-Repo ausführen):

openclaw plugins install ./path/to/local/msteams-plugin

Details: Plugins

Schnelle Einrichtung

Die @microsoft/teams.cli übernimmt Bot-Registrierung, Manifest-Erstellung und Anmeldedatengenerierung in einem einzigen Befehl.

1. Installieren und anmelden

npm install -g @microsoft/teams.cli@preview
teams login
teams status   # verify you're logged in and see your tenant info

2. Einen Tunnel starten (Teams kann localhost nicht erreichen)

Installieren und authentifizieren Sie die devtunnel CLI, falls Sie dies noch nicht getan haben (Einstiegsanleitung).

# 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

Alternativen: ngrok http 3978 oder tailscale funnel 3978 (diese können jedoch in jeder Sitzung URLs ändern).

3. Die App erstellen

teams app create \
  --name "OpenClaw" \
  --endpoint "https://<your-tunnel-url>/api/messages"

Dieser einzelne Befehl:

  • Erstellt eine Entra ID-Anwendung (Azure AD)
  • Generiert ein Client-Geheimnis
  • Erstellt ein Teams-App-Manifest (mit Symbolen) und lädt es hoch
  • Registriert den Bot (standardmäßig von Teams verwaltet - kein Azure-Abonnement erforderlich)

Die Ausgabe zeigt CLIENT_ID, CLIENT_SECRET, TENANT_ID und eine Teams-App-ID - notieren Sie diese für die nächsten Schritte. Außerdem wird angeboten, die App direkt in Teams zu installieren.

4. OpenClaw konfigurieren mit den Anmeldedaten aus der Ausgabe:

{
  channels: {
    msteams: {
      enabled: true,
      appId: "&lt;CLIENT_ID&gt;",
      appPassword: "&lt;CLIENT_SECRET&gt;",
      tenantId: "&lt;TENANT_ID&gt;",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}

Oder verwenden Sie Umgebungsvariablen direkt: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.

5. Die App in Teams installieren

teams app create fordert Sie auf, die App zu installieren - wählen Sie „Install in Teams“. Wenn Sie dies übersprungen haben, können Sie den Link später abrufen:

teams app get <teamsAppId> --install-link

6. Prüfen, ob alles funktioniert

teams app doctor <teamsAppId>

Dies führt Diagnosen für Bot-Registrierung, AAD-App-Konfiguration, Manifest-Gültigkeit und SSO-Einrichtung aus.

Für Produktionsbereitstellungen sollten Sie föderierte Authentifizierung (Zertifikat oder Managed Identity) anstelle von Client-Geheimnissen in Betracht ziehen.

Ziele

  • Mit OpenClaw über Teams-DMs, Gruppenchats oder Kanäle sprechen.
  • Routing deterministisch halten: Antworten gehen immer an den Kanal zurück, über den sie eingegangen sind.
  • Standardmäßig sicheres Kanalverhalten verwenden (Erwähnungen erforderlich, sofern nicht anders konfiguriert).

Konfigurationsschreibvorgänge

Standardmäßig darf Microsoft Teams Konfigurationsaktualisierungen schreiben, die durch /config set|unset ausgelöst werden (erfordert commands.config: true).

Deaktivieren mit:

{
  channels: { msteams: { configWrites: false } },
}

Zugriffskontrolle (DMs + Gruppen)

DM-Zugriff

  • Standard: channels.msteams.dmPolicy = "pairing". Unbekannte Absender werden ignoriert, bis sie genehmigt wurden.
  • channels.msteams.allowFrom sollte stabile AAD-Objekt-IDs verwenden.
  • Verlassen Sie sich bei Allowlists nicht auf UPN-/Anzeigenamen-Abgleich - diese können sich ändern. OpenClaw deaktiviert direkten Namensabgleich standardmäßig; aktivieren Sie ihn explizit mit channels.msteams.dangerouslyAllowNameMatching: true.
  • Der Assistent kann Namen über Microsoft Graph in IDs auflösen, wenn die Anmeldedaten dies erlauben.

Gruppenzugriff

  • Standard: channels.msteams.groupPolicy = "allowlist" (blockiert, sofern Sie groupAllowFrom nicht hinzufügen). Verwenden Sie channels.defaults.groupPolicy, um den Standardwert zu überschreiben, wenn er nicht gesetzt ist.
  • channels.msteams.groupAllowFrom steuert, welche Absender in Gruppenchats/Kanälen auslösen können (fällt auf channels.msteams.allowFrom zurück).
  • Setzen Sie groupPolicy: "open", um jedes Mitglied zu erlauben (standardmäßig weiterhin durch Erwähnungen gesteuert).
  • Um keine Kanäle zu erlauben, setzen Sie channels.msteams.groupPolicy: "disabled".

Beispiel:

{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["[email protected]"],
    },
  },
}

Teams + Kanal-Allowlist

  • Begrenzen Sie Gruppen-/Kanalantworten, indem Sie Teams und Kanäle unter channels.msteams.teams auflisten.
  • Schlüssel sollten stabile Teams-Konversations-IDs aus Teams-Links verwenden, nicht veränderliche Anzeigenamen.
  • Wenn groupPolicy="allowlist" ist und eine Teams-Allowlist vorhanden ist, werden nur aufgelistete Teams/Kanäle akzeptiert (durch Erwähnungen gesteuert).
  • Der Konfigurationsassistent akzeptiert Team/Channel-Einträge und speichert sie für Sie.
  • Beim Start löst OpenClaw Team-/Kanal- und Benutzer-Allowlist-Namen in IDs auf (wenn Graph-Berechtigungen dies erlauben) und protokolliert die Zuordnung; nicht aufgelöste Team-/Kanalnamen werden wie eingegeben beibehalten, aber standardmäßig für das Routing ignoriert, sofern channels.msteams.dangerouslyAllowNameMatching: true nicht aktiviert ist.

Beispiel:

{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      teams: {
        "My Team": {
          channels: {
            General: { requireMention: true },
          },
        },
      },
    },
  },
}
Manuelle Einrichtung (ohne die Teams CLI)

Wenn Sie die Teams CLI nicht verwenden können, können Sie den Bot manuell über das Azure Portal einrichten.

Funktionsweise

  1. Stellen Sie sicher, dass das Microsoft Teams-Plugin verfügbar ist (in aktuellen Releases gebündelt).
  2. Erstellen Sie einen Azure Bot (App-ID + Geheimnis + Mandanten-ID).
  3. Erstellen Sie ein Teams-App-Paket, das auf den Bot verweist und die unten aufgeführten RSC-Berechtigungen enthält.
  4. Laden/installieren Sie die Teams-App in ein Team (oder im persönlichen Geltungsbereich für DMs).
  5. Konfigurieren Sie msteams in ~/.openclaw/openclaw.json (oder Env Vars) und starten Sie das Gateway.
  6. Das Gateway lauscht standardmäßig unter /api/messages auf Bot Framework-Webhook-Traffic.

Schritt 1: Azure Bot erstellen

  1. Gehen Sie zu Create Azure Bot

  2. Füllen Sie die Registerkarte Basics aus:

    Feld Wert
    Bot handle Ihr Bot-Name, z. B. openclaw-msteams (muss eindeutig sein)
    Subscription Wählen Sie Ihr Azure-Abonnement
    Resource group Neu erstellen oder vorhandene verwenden
    Pricing tier Free für Entwicklung/Tests
    Type of App Single Tenant (empfohlen - siehe Hinweis unten)
    Creation type Create new Microsoft App ID
  1. Klicken Sie auf Review + createCreate (warten Sie ca. 1-2 Minuten)

Schritt 2: Anmeldedaten abrufen

  1. Gehen Sie zu Ihrer Azure Bot-Ressource → Configuration
  2. Kopieren Sie Microsoft App ID → dies ist Ihre appId
  3. Klicken Sie auf Manage Password → gehen Sie zur App-Registrierung
  4. Unter Certificates & secretsNew client secret → kopieren Sie den Value → dies ist Ihr appPassword
  5. Gehen Sie zu Overview → kopieren Sie Directory (tenant) ID → dies ist Ihre tenantId

Schritt 3: Messaging-Endpunkt konfigurieren

  1. In Azure Bot → Configuration
  2. Setzen Sie Messaging endpoint auf Ihre Webhook-URL:
    • Produktion: https://your-domain.com/api/messages
    • Lokale Entwicklung: Verwenden Sie einen Tunnel (siehe Lokale Entwicklung unten)

Schritt 4: Teams-Kanal aktivieren

  1. In Azure Bot → Channels
  2. Klicken Sie auf Microsoft Teams → Configure → Save
  3. Akzeptieren Sie die Terms of Service

Schritt 5: Teams-App-Manifest erstellen

  • Fügen Sie einen bot-Eintrag mit botId = &lt;App ID&gt; hinzu.
  • Geltungsbereiche: personal, team, groupChat.
  • supportsFiles: true (erforderlich für die Dateiverarbeitung im persönlichen Geltungsbereich).
  • Fügen Sie RSC-Berechtigungen hinzu (siehe RSC-Berechtigungen).
  • Erstellen Sie Symbole: outline.png (32x32) und color.png (192x192).
  • Zippen Sie alle drei Dateien zusammen: manifest.json, outline.png, color.png.

Schritt 6: OpenClaw konfigurieren

{
  channels: {
    msteams: {
      enabled: true,
      appId: "&lt;APP_ID&gt;",
      appPassword: "&lt;APP_PASSWORD&gt;",
      tenantId: "&lt;TENANT_ID&gt;",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}

Umgebungsvariablen: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.

Schritt 7: Das Gateway ausführen

Der Teams-Kanal startet automatisch, wenn das Plugin verfügbar ist und eine msteams-Konfiguration mit Anmeldedaten vorhanden ist.

Föderierte Authentifizierung (Zertifikat plus Managed Identity)

Hinzugefügt in 2026.4.11

Für Produktionsbereitstellungen unterstützt OpenClaw föderierte Authentifizierung als sicherere Alternative zu Client-Geheimnissen. Zwei Methoden sind verfügbar:

Option A: Zertifikatbasierte Authentifizierung

Verwenden Sie ein PEM-Zertifikat, das in Ihrer Entra ID-App-Registrierung registriert ist.

Einrichtung:

  1. Generieren oder beschaffen Sie ein Zertifikat (PEM-Format mit privatem Schlüssel).
  2. In Entra ID → App Registration → Certificates & secretsCertificates → Laden Sie das öffentliche Zertifikat hoch.

Konfiguration:

{
  channels: {
    msteams: {
      enabled: true,
      appId: "&lt;APP_ID&gt;",
      tenantId: "&lt;TENANT_ID&gt;",
      authType: "federated",
      certificatePath: "/path/to/cert.pem",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}

Env Vars:

  • MSTEAMS_AUTH_TYPE=federated
  • MSTEAMS_CERTIFICATE_PATH=/path/to/cert.pem

Option B: Azure Managed Identity

Verwenden Sie Azure Managed Identity für passwortlose Authentifizierung. Dies ist ideal für Bereitstellungen auf Azure-Infrastruktur (AKS, App Service, Azure VMs), bei denen eine Managed Identity verfügbar ist.

Funktionsweise:

  1. Der Bot-Pod/die VM verfügt über eine Managed Identity (systemseitig zugewiesen oder benutzerseitig zugewiesen).
  2. Eine föderierte Identitätsanmeldedaten verknüpft die Managed Identity mit der Entra ID-App-Registrierung.
  3. Zur Laufzeit verwendet OpenClaw @azure/identity, um Token vom Azure IMDS-Endpunkt (169.254.169.254) abzurufen.
  4. Das Token wird zur Bot-Authentifizierung an das Teams SDK übergeben.

Voraussetzungen:

  • Azure-Infrastruktur mit aktivierter Managed Identity (AKS Workload Identity, App Service, VM)
  • Föderierte Identitätsanmeldedaten, die in der Entra ID-App-Registrierung erstellt wurden
  • Netzwerkzugriff auf IMDS (169.254.169.254:80) vom Pod/von der VM

Konfiguration (systemseitig zugewiesene Managed Identity):

{
  channels: {
    msteams: {
      enabled: true,
      appId: "&lt;APP_ID&gt;",
      tenantId: "&lt;TENANT_ID&gt;",
      authType: "federated",
      useManagedIdentity: true,
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}

Konfiguration (benutzerzugewiesene Managed Identity):

{
  channels: {
    msteams: {
      enabled: true,
      appId: "&lt;APP_ID&gt;",
      tenantId: "&lt;TENANT_ID&gt;",
      authType: "federated",
      useManagedIdentity: true,
      managedIdentityClientId: "&lt;MI_CLIENT_ID&gt;",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}

Umgebungsvariablen:

  • MSTEAMS_AUTH_TYPE=federated
  • MSTEAMS_USE_MANAGED_IDENTITY=true
  • MSTEAMS_MANAGED_IDENTITY_CLIENT_ID=<client-id> (nur für benutzerzugewiesene)

Einrichtung der AKS Workload Identity

Für AKS-Bereitstellungen mit Workload Identity:

  1. Aktivieren Sie Workload Identity in Ihrem AKS-Cluster.

  2. Erstellen Sie eine Anmeldeinformation für eine Verbundidentität in der Entra ID-App-Registrierung:

    az ad app federated-credential create --id &lt;APP_OBJECT_ID&gt; --parameters '{
      "name": "my-bot-workload-identity",
      "issuer": "&lt;AKS_OIDC_ISSUER_URL&gt;",
      "subject": "system:serviceaccount:&lt;NAMESPACE&gt;:&lt;SERVICE_ACCOUNT&gt;",
      "audiences": ["api://AzureADTokenExchange"]
    }'
    
  3. Annotieren Sie das Kubernetes-Dienstkonto mit der App-Client-ID:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: my-bot-sa
      annotations:
        azure.workload.identity/client-id: "&lt;APP_CLIENT_ID&gt;"
    
  4. Kennzeichnen Sie den Pod für die Workload-Identity-Injektion:

    metadata:
      labels:
        azure.workload.identity/use: "true"
    
  5. Stellen Sie Netzwerkzugriff auf IMDS (169.254.169.254) sicher. Wenn Sie NetworkPolicy verwenden, fügen Sie eine Egress-Regel hinzu, die Datenverkehr zu 169.254.169.254/32 auf Port 80 erlaubt.

Vergleich der Authentifizierungstypen

Methode Konfiguration Vorteile Nachteile
Client Secret appPassword Einfache Einrichtung Secret-Rotation erforderlich, weniger sicher
Zertifikat authType: "federated" + certificatePath Kein gemeinsames Secret über das Netzwerk Verwaltungsaufwand für Zertifikate
Managed Identity authType: "federated" + useManagedIdentity Passwortlos, keine Secrets zu verwalten Azure-Infrastruktur erforderlich

Standardverhalten: Wenn authType nicht festgelegt ist, verwendet OpenClaw standardmäßig die Authentifizierung per Client Secret. Bestehende Konfigurationen funktionieren weiterhin ohne Änderungen.

Lokale Entwicklung (Tunneling)

Teams kann localhost nicht erreichen. Verwenden Sie einen persistenten Entwicklungstunnel, damit Ihre URL über Sitzungen hinweg gleich bleibt:

# 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

Alternativen: ngrok http 3978 oder tailscale funnel 3978 (URLs können sich bei jeder Sitzung ändern).

Wenn sich Ihre Tunnel-URL ändert, aktualisieren Sie den Endpunkt:

teams app update <teamsAppId> --endpoint "https://<new-url>/api/messages"

Bot testen

Diagnose ausführen:

teams app doctor <teamsAppId>

Prüft Bot-Registrierung, AAD-App, Manifest und SSO-Konfiguration in einem Durchlauf.

Testnachricht senden:

  1. Installieren Sie die Teams-App (verwenden Sie den Installationslink aus teams app get <id> --install-link)
  2. Suchen Sie den Bot in Teams und senden Sie eine DM
  3. Prüfen Sie die Gateway-Logs auf eingehende Aktivität

Umgebungsvariablen

Alle Konfigurationsschlüssel können stattdessen über Umgebungsvariablen gesetzt werden:

  • MSTEAMS_APP_ID
  • MSTEAMS_APP_PASSWORD
  • MSTEAMS_TENANT_ID
  • MSTEAMS_AUTH_TYPE (optional: "secret" oder "federated")
  • MSTEAMS_CERTIFICATE_PATH (federated + Zertifikat)
  • MSTEAMS_CERTIFICATE_THUMBPRINT (optional, für die Authentifizierung nicht erforderlich)
  • MSTEAMS_USE_MANAGED_IDENTITY (federated + Managed Identity)
  • MSTEAMS_MANAGED_IDENTITY_CLIENT_ID (nur benutzerzugewiesene MI)

member-info-Aktion

OpenClaw stellt für Microsoft Teams eine Graph-gestützte member-info-Aktion bereit, damit Agenten und Automatisierungen Details zu Kanalmitgliedern (Anzeigename, E-Mail, Rolle) direkt aus Microsoft Graph auflösen können.

Anforderungen:

  • RSC-Berechtigung Member.Read.Group (bereits im empfohlenen Manifest enthalten)
  • Für teamübergreifende Abfragen: Graph-Anwendungsberechtigung User.Read.All mit Administratorzustimmung

Die Aktion wird durch channels.msteams.actions.memberInfo gesteuert (Standard: aktiviert, wenn Graph-Anmeldeinformationen verfügbar sind).

Verlaufskontext

  • channels.msteams.historyLimit steuert, wie viele aktuelle Kanal-/Gruppennachrichten in den Prompt eingebettet werden.
  • Fällt auf messages.groupChat.historyLimit zurück. Setzen Sie 0, um dies zu deaktivieren (Standard 50).
  • Der abgerufene Thread-Verlauf wird nach Absender-Allowlists (allowFrom / groupAllowFrom) gefiltert, sodass das Vorbelegen des Thread-Kontexts nur Nachrichten von erlaubten Absendern enthält.
  • Kontext aus zitierten Anhängen (ReplyTo*, abgeleitet aus Teams-Antwort-HTML) wird derzeit so weitergegeben, wie er empfangen wurde.
  • Anders gesagt: Allowlists steuern, wer den Agenten auslösen kann; derzeit werden nur bestimmte ergänzende Kontextpfade gefiltert.
  • Der DM-Verlauf kann mit channels.msteams.dmHistoryLimit begrenzt werden (Benutzer-Turns). Überschreibungen pro Benutzer: channels.msteams.dms["<user_id>"].historyLimit.

Aktuelle Teams-RSC-Berechtigungen (Manifest)

Dies sind die bestehenden resourceSpecific-Berechtigungen in unserem Teams-App-Manifest. Sie gelten nur innerhalb des Teams/Chats, in dem die App installiert ist.

Für Kanäle (Team-Scope):

  • ChannelMessage.Read.Group (Application) - alle Kanalnachrichten ohne @mention empfangen
  • ChannelMessage.Send.Group (Application)
  • Member.Read.Group (Application)
  • Owner.Read.Group (Application)
  • ChannelSettings.Read.Group (Application)
  • TeamMember.Read.Group (Application)
  • TeamSettings.Read.Group (Application)

Für Gruppenchats:

  • ChatMessage.Read.Chat (Application) - alle Gruppenchatnachrichten ohne @mention empfangen

So fügen Sie RSC-Berechtigungen über die Teams-CLI hinzu:

teams app rsc add <teamsAppId> ChannelMessage.Read.Group --type Application

Beispiel für ein Teams-Manifest (geschwärzt)

Minimales, gültiges Beispiel mit den erforderlichen Feldern. Ersetzen Sie IDs und URLs.

{
  $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" },
      ],
    },
  },
}

Manifest-Hinweise (Pflichtfelder)

  • bots[].botId muss mit der Azure Bot-App-ID übereinstimmen.
  • webApplicationInfo.id muss mit der Azure Bot-App-ID übereinstimmen.
  • bots[].scopes muss die Oberflächen enthalten, die Sie verwenden möchten (personal, team, groupChat).
  • bots[].supportsFiles: true ist für die Dateiverarbeitung im persönlichen Scope erforderlich.
  • authorization.permissions.resourceSpecific muss Lesen/Senden für Kanäle enthalten, wenn Sie Kanalverkehr wünschen.

Eine vorhandene App aktualisieren

So aktualisieren Sie eine bereits installierte Teams-App (z. B. um RSC-Berechtigungen hinzuzufügen):

# 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

Installieren Sie die App nach der Aktualisierung in jedem Team neu, damit neue Berechtigungen wirksam werden, und beenden Sie Teams vollständig und starten Sie es neu (nicht nur das Fenster schließen), um zwischengespeicherte App-Metadaten zu löschen.

Manuelle Manifest-Aktualisierung (ohne CLI)
  1. Aktualisieren Sie Ihre manifest.json mit den neuen Einstellungen
  2. Erhöhen Sie das Feld version (z. B. 1.0.01.1.0)
  3. Packen Sie das Manifest mit Icons erneut als ZIP (manifest.json, outline.png, color.png)
  4. Laden Sie die neue ZIP-Datei hoch:
    • Teams Admin Center: Teams-Apps → Apps verwalten → Ihre App suchen → Neue Version hochladen
    • Sideload: In Teams → Apps → Ihre Apps verwalten → Benutzerdefinierte App hochladen

Funktionen: Nur RSC vs. Graph

Mit nur Teams RSC (App installiert, keine Graph-API-Berechtigungen)

Funktioniert:

  • Textinhalt von Kanalnachrichten lesen.
  • Textinhalt von Kanalnachrichten senden.
  • Dateianhänge in persönlichen Nachrichten (DMs) empfangen.

Funktioniert NICHT:

  • Bild- oder Dateiinhalte in Kanälen/Gruppen (Payload enthält nur einen HTML-Stub).
  • Herunterladen von Anhängen, die in SharePoint/OneDrive gespeichert sind.
  • Lesen des Nachrichtenverlaufs (über das Live-Webhook-Ereignis hinaus).

Mit Teams RSC + Microsoft Graph-Anwendungsberechtigungen

Fügt hinzu:

  • Herunterladen gehosteter Inhalte (in Nachrichten eingefügte Bilder).
  • Herunterladen von Dateianhängen, die in SharePoint/OneDrive gespeichert sind.
  • Lesen des Kanal-/Chat-Nachrichtenverlaufs über Graph.

RSC vs. Graph-API

Funktion RSC-Berechtigungen Graph-API
Echtzeitnachrichten Ja (über Webhook) Nein (nur Polling)
Historische Nachrichten Nein Ja (Verlauf kann abgefragt werden)
Einrichtungsaufwand Nur App-Manifest Erfordert Administratorzustimmung + Token-Flow
Funktioniert offline Nein (muss laufen) Ja (jederzeit abfragen)

Kurz gesagt: RSC ist für Echtzeit-Listening gedacht; die Graph-API ist für historischen Zugriff gedacht. Um verpasste Nachrichten nachzuholen, während Sie offline waren, benötigen Sie die Graph-API mit ChannelMessage.Read.All (erfordert Administratorzustimmung).

Graph-gestützte Medien + Verlauf (für Kanäle erforderlich)

Wenn Sie Bilder/Dateien in Kanälen benötigen oder den Nachrichtenverlauf abrufen möchten, müssen Sie Microsoft Graph-Berechtigungen aktivieren und Administratorzustimmung erteilen.

  1. Fügen Sie in Entra ID (Azure AD) unter App-Registrierung Microsoft Graph-Anwendungsberechtigungen hinzu:
    • ChannelMessage.Read.All (Kanalanhänge + Verlauf)
    • Chat.Read.All oder ChatMessage.Read.All (Gruppenchats)
  2. Erteilen Sie Administratorzustimmung für den Mandanten.
  3. Erhöhen Sie die Manifestversion der Teams-App, laden Sie sie erneut hoch und installieren Sie die App in Teams neu.
  4. Beenden Sie Teams vollständig und starten Sie es neu, um zwischengespeicherte App-Metadaten zu löschen.

Zusätzliche Berechtigung für Benutzererwähnungen: Benutzer-@mentions funktionieren für Benutzer in der Unterhaltung standardmäßig. Wenn Sie jedoch dynamisch nach Benutzern suchen und Benutzer erwähnen möchten, die nicht in der aktuellen Unterhaltung sind, fügen Sie die Berechtigung User.Read.All (Application) hinzu und erteilen Sie Administratorzustimmung.

Bekannte Einschränkungen

Webhook-Timeouts

Teams übermittelt Nachrichten über HTTP-Webhook. Wenn die Verarbeitung zu lange dauert (z. B. langsame LLM-Antworten), kann Folgendes auftreten:

  • Gateway-Timeouts
  • Teams versucht die Nachricht erneut zuzustellen (verursacht Duplikate)
  • Verworfene Antworten

OpenClaw handhabt dies, indem es schnell zurückkehrt und Antworten proaktiv sendet, aber sehr langsame Antworten können weiterhin Probleme verursachen.

Formatierung

Teams-Markdown ist eingeschränkter als Slack oder Discord:

  • Grundlegende Formatierung funktioniert: fett, kursiv, code, Links
  • Komplexes Markdown (Tabellen, verschachtelte Listen) wird möglicherweise nicht korrekt gerendert
  • Adaptive Cards werden für Umfragen und semantische Präsentationssendungen unterstützt (siehe unten)

Konfiguration

Wichtige Einstellungen (siehe /gateway/configuration für gemeinsame Kanal-Muster):

  • channels.msteams.enabled: Kanal aktivieren/deaktivieren.
  • channels.msteams.appId, channels.msteams.appPassword, channels.msteams.tenantId: Bot-Zugangsdaten.
  • channels.msteams.webhook.port (Standard 3978)
  • channels.msteams.webhook.path (Standard /api/messages)
  • channels.msteams.dmPolicy: pairing | allowlist | open | disabled (Standard: Pairing)
  • channels.msteams.allowFrom: DM-Zulassungsliste (AAD-Objekt-IDs empfohlen). Der Assistent löst Namen während der Einrichtung zu IDs auf, wenn Graph-Zugriff verfügbar ist.
  • channels.msteams.dangerouslyAllowNameMatching: Notfall-Umschalter, um veränderliches Matching nach UPN/Anzeigename und direktes Team-/Kanalnamen-Routing wieder zu aktivieren.
  • channels.msteams.textChunkLimit: Größe ausgehender Textabschnitte.
  • channels.msteams.chunkMode: length (Standard) oder newline, um vor der Längenaufteilung an Leerzeilen (Absatzgrenzen) zu trennen.
  • channels.msteams.mediaAllowHosts: Zulassungsliste für Hosts eingehender Anhänge (standardmäßig Microsoft-/Teams-Domains).
  • channels.msteams.mediaAuthAllowHosts: Zulassungsliste für das Anhängen von Authorization-Headern bei Medien-Wiederholungsversuchen (standardmäßig Graph- und Bot-Framework-Hosts).
  • channels.msteams.requireMention: @mention in Kanälen/Gruppen erfordern (Standard: true).
  • channels.msteams.replyStyle: thread | top-level (siehe Antwortstil).
  • channels.msteams.teams.<teamId>.replyStyle: Überschreibung pro Team.
  • channels.msteams.teams.<teamId>.requireMention: Überschreibung pro Team.
  • channels.msteams.teams.<teamId>.tools: Standardmäßige Tool-Richtlinienüberschreibungen pro Team (allow/deny/alsoAllow), die verwendet werden, wenn eine Kanalüberschreibung fehlt.
  • channels.msteams.teams.<teamId>.toolsBySender: Standardmäßige Tool-Richtlinienüberschreibungen pro Team und Absender ("*"-Wildcard unterstützt).
  • channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: Überschreibung pro Kanal.
  • channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: Überschreibung pro Kanal.
  • channels.msteams.teams.<teamId>.channels.<conversationId>.tools: Tool-Richtlinienüberschreibungen pro Kanal (allow/deny/alsoAllow).
  • channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: Tool-Richtlinienüberschreibungen pro Kanal und Absender ("*"-Wildcard unterstützt).
  • toolsBySender-Schlüssel sollten explizite Präfixe verwenden: id:, e164:, username:, name: (veraltete Schlüssel ohne Präfix werden weiterhin nur id: zugeordnet).
  • channels.msteams.actions.memberInfo: die Graph-gestützte Aktion für Mitgliedsinformationen aktivieren oder deaktivieren (Standard: aktiviert, wenn Graph-Zugangsdaten verfügbar sind).
  • channels.msteams.authType: Authentifizierungstyp - "secret" (Standard) oder "federated".
  • channels.msteams.certificatePath: Pfad zur PEM-Zertifikatsdatei (föderierte Authentifizierung + Zertifikatauthentifizierung).
  • channels.msteams.certificateThumbprint: Zertifikat-Fingerabdruck (optional, für die Authentifizierung nicht erforderlich).
  • channels.msteams.useManagedIdentity: Authentifizierung mit verwalteter Identität aktivieren (föderierter Modus).
  • channels.msteams.managedIdentityClientId: Client-ID für benutzerzugewiesene verwaltete Identität.
  • channels.msteams.sharePointSiteId: SharePoint-Website-ID für Datei-Uploads in Gruppenchats/Kanälen (siehe Dateien in Gruppenchats senden).

Routing und Sitzungen

  • Sitzungsschlüssel folgen dem standardmäßigen Agent-Format (siehe /concepts/session):
    • Direktnachrichten teilen sich die Hauptsitzung (agent:<agentId>:<mainKey>).
    • Kanal-/Gruppennachrichten verwenden die Konversations-ID:
      • agent:<agentId>:msteams:channel:<conversationId>
      • agent:<agentId>:msteams:group:<conversationId>

Antwortstil: Threads vs. Beiträge

Teams hat kürzlich zwei Kanal-UI-Stile über demselben zugrunde liegenden Datenmodell eingeführt:

Stil Beschreibung Empfohlener replyStyle
Beiträge (klassisch) Nachrichten erscheinen als Karten mit Thread-Antworten darunter thread (Standard)
Threads (Slack-ähnlich) Nachrichten laufen linear, eher wie in Slack top-level

Das Problem: Die Teams-API legt nicht offen, welchen UI-Stil ein Kanal verwendet. Wenn Sie den falschen replyStyle verwenden:

  • thread in einem Kanal im Threads-Stil → Antworten erscheinen ungeschickt verschachtelt
  • top-level in einem Kanal im Beiträge-Stil → Antworten erscheinen als separate Beiträge auf oberster Ebene statt im Thread

Lösung: Konfigurieren Sie replyStyle pro Kanal entsprechend der Einrichtung des Kanals:

{
  channels: {
    msteams: {
      replyStyle: "thread",
      teams: {
        "19:[email protected]": {
          channels: {
            "19:[email protected]": {
              replyStyle: "top-level",
            },
          },
        },
      },
    },
  },
}

Anhänge und Bilder

Aktuelle Einschränkungen:

  • DMs: Bilder und Dateianhänge funktionieren über Teams-Bot-Datei-APIs.
  • Kanäle/Gruppen: Anhänge liegen im M365-Speicher (SharePoint/OneDrive). Die Webhook-Nutzlast enthält nur einen HTML-Stub, nicht die tatsächlichen Dateibytes. Graph-API-Berechtigungen sind erforderlich, um Kanalanhänge herunterzuladen.
  • Verwenden Sie für explizite Datei-zuerst-Sendungen action=upload-file mit media / filePath / path; das optionale message wird zum begleitenden Text/Kommentar, und filename überschreibt den hochgeladenen Namen.

Ohne Graph-Berechtigungen werden Kanalnachrichten mit Bildern nur als Text empfangen (der Bildinhalt ist für den Bot nicht zugänglich). Standardmäßig lädt OpenClaw Medien nur von Microsoft-/Teams-Hostnamen herunter. Überschreiben Sie dies mit channels.msteams.mediaAllowHosts (verwenden Sie ["*"], um jeden Host zuzulassen). Authorization-Header werden nur für Hosts in channels.msteams.mediaAuthAllowHosts angehängt (standardmäßig Graph- und Bot-Framework-Hosts). Halten Sie diese Liste strikt (vermeiden Sie Multi-Tenant-Suffixe).

Dateien in Gruppenchats senden

Bots können Dateien in DMs mit dem FileConsentCard-Ablauf senden (integriert). Das Senden von Dateien in Gruppenchats/Kanälen erfordert jedoch zusätzliche Einrichtung:

Kontext Wie Dateien gesendet werden Erforderliche Einrichtung
DMs FileConsentCard → Benutzer akzeptiert → Bot lädt hoch Funktioniert sofort
Gruppenchats/Kanäle Upload zu SharePoint → Freigabelink Erfordert sharePointSiteId + Graph-Berechtigungen
Bilder (beliebiger Kontext) Base64-codiert inline Funktioniert sofort

Warum Gruppenchats SharePoint benötigen

Bots haben kein persönliches OneDrive-Laufwerk (der Graph-API-Endpunkt /me/drive funktioniert nicht für Anwendungsidentitäten). Um Dateien in Gruppenchats/Kanälen zu senden, lädt der Bot sie auf eine SharePoint-Website hoch und erstellt einen Freigabelink.

Einrichtung

  1. Fügen Sie Graph-API-Berechtigungen in Entra ID (Azure AD) → App-Registrierung hinzu:

    • Sites.ReadWrite.All (Anwendung) - Dateien nach SharePoint hochladen
    • Chat.Read.All (Anwendung) - optional, aktiviert Freigabelinks pro Benutzer
  2. Erteilen Sie Administratorzustimmung für den Tenant.

  3. Rufen Sie Ihre SharePoint-Website-ID ab:

    # 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"
    
  4. Konfigurieren Sie OpenClaw:

    {
      channels: {
        msteams: {
          // ... other config ...
          sharePointSiteId: "contoso.sharepoint.com,guid1,guid2",
        },
      },
    }
    

Freigabeverhalten

Berechtigung Freigabeverhalten
Nur Sites.ReadWrite.All Organisationsweiter Freigabelink (jeder in der Organisation kann zugreifen)
Sites.ReadWrite.All + Chat.Read.All Freigabelink pro Benutzer (nur Chat-Mitglieder können zugreifen)

Die Freigabe pro Benutzer ist sicherer, da nur die Chat-Teilnehmer auf die Datei zugreifen können. Wenn die Berechtigung Chat.Read.All fehlt, fällt der Bot auf organisationsweite Freigabe zurück.

Fallback-Verhalten

Szenario Ergebnis
Gruppenchat + Datei + sharePointSiteId konfiguriert Upload zu SharePoint, Freigabelink senden
Gruppenchat + Datei + kein sharePointSiteId OneDrive-Upload versuchen (kann fehlschlagen), nur Text senden
Persönlicher Chat + Datei FileConsentCard-Ablauf (funktioniert ohne SharePoint)
Beliebiger Kontext + Bild Base64-codiert inline (funktioniert ohne SharePoint)

Speicherort der Dateien

Hochgeladene Dateien werden in einem /OpenClawShared/-Ordner in der Standarddokumentbibliothek der konfigurierten SharePoint-Website gespeichert.

Umfragen (Adaptive Cards)

OpenClaw sendet Teams-Umfragen als Adaptive Cards (es gibt keine native Teams-Umfrage-API).

  • CLI: openclaw message poll --channel msteams --target conversation:<id> ...
  • Stimmen werden vom Gateway in ~/.openclaw/msteams-polls.json aufgezeichnet.
  • Das Gateway muss online bleiben, um Stimmen aufzuzeichnen.
  • Umfragen veröffentlichen noch keine Ergebniszusammenfassungen automatisch (prüfen Sie bei Bedarf die Speicherdatei).

Präsentationskarten

Senden Sie semantische Präsentationsnutzlasten mit dem message-Tool oder der CLI an Teams-Benutzer oder -Konversationen. OpenClaw rendert sie aus dem generischen Präsentationsvertrag als Teams Adaptive Cards.

Der Parameter presentation akzeptiert semantische Blöcke. Wenn presentation angegeben wird, ist der Nachrichtentext optional.

Agent-Tool:

{
  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!"}]}'

Details zum Zielformat finden Sie unten unter Zielformate.

Zielformate

MSTeams-Ziele verwenden Präfixe, um zwischen Benutzern und Konversationen zu unterscheiden:

Zieltyp Format Beispiel
Benutzer (nach ID) user:<aad-object-id> user:40a1a0ed-4ff2-4164-a219-55518990c197
Benutzer (nach Name) user:<display-name> user:John Smith (erfordert Graph-API)
Gruppe/Kanal conversation:<conversation-id> conversation:19:[email protected]
Gruppe/Kanal (roh) <conversation-id> 19:[email protected] (wenn @thread enthalten ist)

CLI-Beispiele:

# 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"}]}'

Beispiele für Agententools:

{
  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" }],
  },
}

Proaktives Messaging

  • Proaktive Nachrichten sind nur möglich, nachdem ein Benutzer interagiert hat, da wir an diesem Punkt Konversationsreferenzen speichern.
  • Siehe /gateway/configuration für dmPolicy und Allowlist-Steuerung.

Team- und Kanal-IDs (häufige Stolperfalle)

Der Abfrageparameter groupId in Teams-URLs ist NICHT die Team-ID, die für die Konfiguration verwendet wird. Extrahieren Sie IDs stattdessen aus dem URL-Pfad:

Team-URL:

https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
                                    └────────────────────────────┘
                                    Team-Konversations-ID (URL-dekodieren)

Kanal-URL:

https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
                                      └─────────────────────────┘
                                      Kanal-ID (URL-dekodieren)

Für die Konfiguration:

  • Team-Schlüssel = Pfadsegment nach /team/ (URL-dekodiert, z. B. 19:[email protected]; ältere Tenants können @thread.skype anzeigen, was ebenfalls gültig ist)
  • Kanal-Schlüssel = Pfadsegment nach /channel/ (URL-dekodiert)
  • Ignorieren Sie den Abfrageparameter groupId für das OpenClaw-Routing. Er ist die Microsoft-Entra-Gruppen-ID, nicht die Bot-Framework-Konversations-ID, die in eingehenden Teams-Aktivitäten verwendet wird.

Private Kanäle

Bots unterstützen private Kanäle nur eingeschränkt:

Funktion Standardkanäle Private Kanäle
Bot-Installation Ja Eingeschränkt
Echtzeitnachrichten (Webhook) Ja Funktioniert möglicherweise nicht
RSC-Berechtigungen Ja Können sich anders verhalten
@mentions Ja Wenn der Bot zugänglich ist
Graph-API-Verlauf Ja Ja (mit Berechtigungen)

Ausweichlösungen, wenn private Kanäle nicht funktionieren:

  1. Verwenden Sie Standardkanäle für Bot-Interaktionen
  2. Verwenden Sie DMs - Benutzer können dem Bot jederzeit direkt schreiben
  3. Verwenden Sie die Graph API für historischen Zugriff (erfordert ChannelMessage.Read.All)

Fehlerbehebung

Häufige Probleme

  • Bilder werden in Kanälen nicht angezeigt: Graph-Berechtigungen oder Administratorzustimmung fehlen. Installieren Sie die Teams-App erneut und beenden/öffnen Sie Teams vollständig neu.
  • Keine Antworten im Kanal: Erwähnungen sind standardmäßig erforderlich; setzen Sie channels.msteams.requireMention=false oder konfigurieren Sie dies pro Team/Kanal.
  • Versionskonflikt (Teams zeigt weiterhin altes Manifest): Entfernen Sie die App, fügen Sie sie erneut hinzu und beenden Sie Teams vollständig, um die Ansicht zu aktualisieren.
  • 401 Unauthorized vom Webhook: Beim manuellen Testen ohne Azure JWT erwartet - bedeutet, dass der Endpunkt erreichbar ist, die Authentifizierung aber fehlgeschlagen ist. Verwenden Sie Azure Web Chat für einen korrekten Test.

Fehler beim Manifest-Upload

  • "Icon file cannot be empty": Das Manifest verweist auf Symboldateien mit 0 Bytes. Erstellen Sie gültige PNG-Symbole (32x32 für outline.png, 192x192 für color.png).
  • "webApplicationInfo.Id already in use": Die App ist noch in einem anderen Team/Chat installiert. Suchen und deinstallieren Sie sie zuerst, oder warten Sie 5-10 Minuten auf die Propagierung.
  • "Something went wrong" beim Upload: Laden Sie stattdessen über https://admin.teams.microsoft.com hoch, öffnen Sie die Browser-DevTools (F12) → Registerkarte „Network“ und prüfen Sie den Antworttext auf den tatsächlichen Fehler.
  • Sideload schlägt fehl: Versuchen Sie stattdessen „Upload an app to your org's app catalog“ statt „Upload a custom app“ - dadurch werden Sideload-Einschränkungen oft umgangen.

RSC-Berechtigungen funktionieren nicht

  1. Prüfen Sie, ob webApplicationInfo.id exakt mit der App-ID Ihres Bots übereinstimmt
  2. Laden Sie die App erneut hoch und installieren Sie sie im Team/Chat neu
  3. Prüfen Sie, ob der Administrator Ihrer Organisation RSC-Berechtigungen blockiert hat
  4. Bestätigen Sie, dass Sie den richtigen Scope verwenden: ChannelMessage.Read.Group für Teams, ChatMessage.Read.Chat für Gruppenchats

Referenzen

Verwandte Themen