# Microsoft Teams configuration

> Microsoft Teams configuration keys, environment variables, and history limits

- 网址：https://funcoding.ai/agents/openclaw/channels/msteams/configuration/
- 来源：OpenClaw 官方文档原文（英文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/channels/msteams/configuration

---
The `channels.msteams` settings, the environment variables that stand in for the auth keys, and the history context rules.

## Multiple bot accounts

Use `channels.msteams.accounts.<id>` for each Teams bot registration, then route
that account with `bindings[].match.accountId`. Root settings are shared
defaults; account settings override them.

```json5
{
  bindings: [
    { agentId: "main", match: { channel: "msteams", accountId: "default" } },
    { agentId: "support", match: { channel: "msteams", accountId: "support" } },
  ],
  channels: {
    msteams: {
      enabled: true,
      tenantId: "<TENANT_ID>",
      webhook: { path: "/api/messages" },
      dmPolicy: "allowlist",
      allowFrom: ["00000000-0000-0000-0000-000000000000"],
      defaultAccount: "default",
      accounts: {
        default: {
          appId: "<PRIMARY_CLIENT_ID>",
          appPassword: "<PRIMARY_CLIENT_SECRET>",
        },
        support: {
          appId: "<SUPPORT_CLIENT_ID>",
          appPassword: "<SUPPORT_CLIENT_SECRET>",
          webhook: { path: "/api/messages/support" },
          allowFrom: ["11111111-1111-1111-1111-111111111111"],
        },
      },
    },
  },
}
```

- Enabled accounts must use unique `appId` values and webhook paths. All bots
  receive callbacks on `gateway.port`; separate listener ports are not required.
- The default account uses the root webhook path (`/api/messages` when omitted).
  A named account without an explicit path appends its normalized account ID:
  `support` uses `/api/messages/support`. Set each Azure Bot messaging endpoint
  to its own path, for example `https://gateway.example.com/api/messages/support`.
- Named accounts must define their own `appId` and `appPassword` for secret
  authentication. Those fields do not inherit from the root.
- `tenantId`, federated-auth settings, access policy, team/channel allowlists,
  streaming, SSO, delegated auth, and delivery settings inherit from the root
  unless an account overrides them. `legacyWebhook` never inherits into named
  accounts; keep compatibility listeners explicit and give each a unique port.
- Existing root-level single-bot credentials remain the default account for
  compatibility. Configure either that root identity or `accounts.default`,
  not both.

## Environment variables

These auth-related config keys can be set via environment variables instead of `openclaw.json` for the default account only. Named accounts must define their bot identity in config (other keys, such as `groupPolicy` or `historyLimit`, are config-only):

| Env var                              | Config key                | Notes                               |
| ------------------------------------ | ------------------------- | ----------------------------------- |
| `MSTEAMS_APP_ID`                     | `appId`                   |                                     |
| `MSTEAMS_APP_PASSWORD`               | `appPassword`             |                                     |
| `MSTEAMS_TENANT_ID`                  | `tenantId`                |                                     |
| `MSTEAMS_AUTH_TYPE`                  | `authType`                | `"secret"` or `"federated"`         |
| `MSTEAMS_CERTIFICATE_PATH`           | `certificatePath`         | federated + certificate             |
| `MSTEAMS_CERTIFICATE_THUMBPRINT`     | `certificateThumbprint`   | accepted, not required for auth     |
| `MSTEAMS_USE_MANAGED_IDENTITY`       | `useManagedIdentity`      | federated + managed identity        |
| `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID` | `managedIdentityClientId` | user-assigned managed identity only |

## History context

- `channels.msteams.historyLimit` controls how many recent channel/group messages are wrapped into the prompt. Falls back to `messages.groupChat.historyLimit`, then defaults to 50. Set `0` to disable.
- Graph thread context adds the parent and up to the oldest 50 replies alongside recent channel history. It excludes the triggering message and keeps history separate from the sender's command text, so commands quoted in history do not execute. Long fetched messages retain their beginning and end within the prompt's per-message limit.
- Thread and quoted attachment context follow `channels.msteams.contextVisibility`, falling back to `channels.defaults.contextVisibility`, then `all`. Use `allowlist` to filter both by sender allowlists (`allowFrom` / `groupAllowFrom`), or `allowlist_quote` to filter thread history while permitting quoted context.
- DM history can be limited with `channels.msteams.dmHistoryLimit` (user turns). Per-user overrides: `channels.msteams.dms["<user_id>"].historyLimit`.

## Configuration

Key settings (see [/gateway/configuration](https://funcoding.ai/agents/openclaw/gateway/configuration/) for shared channel patterns):

- `channels.msteams.enabled`: enable/disable the channel.
- `channels.msteams.defaultAccount`: account used when `accountId` is omitted.
- `channels.msteams.accounts.<id>.enabled`: enable/disable one Teams bot account.
- `channels.msteams.accounts.<id>.appId`, `channels.msteams.accounts.<id>.appPassword`, `channels.msteams.accounts.<id>.webhook.path`: per-bot identity, secret, and Gateway callback path.
- `channels.msteams.appId`, `channels.msteams.appPassword`, `channels.msteams.tenantId`: bot credentials.
- `channels.msteams.cloud`: Teams SDK cloud environment (`Public`, `USGov`, `USGovDoD`, or `China`; default `Public`). Set with `serviceUrl` for USGov/DoD SDK clouds; China uses the SDK preset and stored Azure China Bot Framework conversation references, with Graph-backed helpers disabled until Azure China Graph routing ships.
- `channels.msteams.serviceUrl`: Bot Connector service URL boundary for SDK proactive operations. Public cloud uses the SDK default; set for GCC (`https://smba.infra.gcc.teams.microsoft.com/teams`), GCC High, or DoD. China accepts Azure China Bot Framework channel hosts when the stored conversation reference comes from Teams operated by 21Vianet.
- `channels.msteams.webhook.path`: Gateway HTTP route (omitted or empty uses `/api/messages`), served on `gateway.port` (default `18789`).
- `channels.msteams.legacyWebhook`: explicit compatibility listener. `{ port, host? }` selects an endpoint, preserving the previous wildcard bind when `host` is omitted. Omitted or `false` opens no separate listener.
- `channels.msteams.dmPolicy`: `pairing | allowlist | open | disabled` (default `pairing`).
- `channels.msteams.allowFrom`: DM allowlist (AAD object IDs recommended). Stable AAD object IDs also authorize approval actions. The wizard resolves names to IDs during setup when Graph access is available.
- `channels.msteams.defaultTo`: default outbound target; a stable AAD object ID can also authorize approval actions.
- `channels.msteams.dangerouslyAllowNameMatching`: break-glass toggle to re-enable mutable UPN/display-name matching and direct team/channel name routing.
- `channels.msteams.textChunkLimit`: outbound text chunk size in characters (default `4000`, and hard-capped at `4000` regardless of a higher configured value).
- `channels.msteams.streaming.chunkMode`: `length` (default) or `newline` to split on blank lines (paragraph boundaries) before length chunking.
- `channels.msteams.mediaAllowHosts`: allowlist for inbound attachment hosts (defaults to Microsoft/Teams domains: Graph, SharePoint/OneDrive, Teams CDN, Bot Framework, Azure Media Services).
- `channels.msteams.mediaAuthAllowHosts`: allowlist for attaching Authorization headers on media retries (defaults to Graph + Bot Framework hosts).
- `channels.msteams.graphMediaFallback`: opt into Graph message lookups when channel/group HTML omits file markers (default `false`; see [Channel/group file recovery](https://funcoding.ai/agents/openclaw/channels/msteams/manifest-and-permissions/#channel%2Fgroup-file-recovery-graphmediafallback)).
- `channels.msteams.mediaMaxMb`: per-channel media size limit override in MB. Falls back to `agents.defaults.mediaMaxMb` when unset.
- `channels.msteams.requireMention`: require @mention in channels/groups (default `true`).
- `channels.msteams.requireMentionInBotThreads`: override mention gating in channel threads rooted at this bot's tracked messages. Omitted preserves current behavior; see [Bot-created threads](https://funcoding.ai/agents/openclaw/channels/msteams/access-control/#mentions-in-bot-created-threads).
- `channels.msteams.replyStyle`: `thread | top-level` (see [Reply style](https://funcoding.ai/agents/openclaw/channels/msteams/messaging/#reply-style-threads-vs-posts)).
- `channels.msteams.teams.<teamId>.replyStyle`: per-team override.
- `channels.msteams.teams.<teamId>.requireMention`: per-team override.
- `channels.msteams.teams.<teamId>.requireMentionInBotThreads`: per-team bot-thread override.
- `channels.msteams.teams.<teamId>.tools`: default per-team tool policy overrides (`allow`/`deny`/`alsoAllow`) used when a channel override is missing.
- `channels.msteams.teams.<teamId>.toolsBySender`: default per-team per-sender tool policy overrides (`"*"` wildcard supported).
- `channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle`: per-channel override.
- `channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention`: per-channel override.
- `channels.msteams.teams.<teamId>.channels.<conversationId>.requireMentionInBotThreads`: per-channel bot-thread override.
- `channels.msteams.teams.<teamId>.channels.<conversationId>.tools`: per-channel tool policy overrides (`allow`/`deny`/`alsoAllow`).
- `channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender`: per-channel per-sender tool policy overrides (`"*"` wildcard supported).
- `toolsBySender` keys use explicit prefixes: `channel:`, `id:`, `e164:`, `username:`, `name:`. Run `openclaw doctor --fix` to migrate retired unprefixed keys to `id:` entries.
- `channels.msteams.authType`: authentication type - `"secret"` (default) or `"federated"`.
- `channels.msteams.certificatePath`: path to PEM certificate file (federated + certificate auth).
- `channels.msteams.certificateThumbprint`: certificate thumbprint; accepted, not required for auth.
- `channels.msteams.useManagedIdentity`: enable managed identity auth (federated mode).
- `channels.msteams.managedIdentityClientId`: client ID for user-assigned managed identity.
- `channels.msteams.sharePointSiteId`: SharePoint site ID for file uploads in group chats/channels (see [Sending files in group chats](https://funcoding.ai/agents/openclaw/channels/msteams/messaging/#sending-files-in-group-chats)).
- `channels.msteams.welcomeCard`, `channels.msteams.groupWelcomeCard`, `channels.msteams.promptStarters`: welcome Adaptive Card shown on first DM/group contact, and its suggested prompt buttons.
- `channels.msteams.responsePrefix`: text prefixed to outbound replies.
- `channels.msteams.feedbackEnabled` (default `true`), `channels.msteams.feedbackReflection` (default `true`), `channels.msteams.feedbackReflectionCooldownMs`: thumbs-up/down feedback on replies and the negative-feedback reflection follow-up.
- `channels.msteams.sso`, `channels.msteams.delegatedAuth`: Bot Framework OAuth connection and delegated Graph scopes for SSO-backed flows; `sso.enabled: true` requires `sso.connectionName`.

## Migrating an existing webhook endpoint

Teams webhooks now share the Gateway HTTP listener. The Teams SDK still verifies
Azure JWT signatures; callers do not supply a Gateway token. Keep the public
HTTPS messaging endpoint in Azure Bot and change its reverse-proxy upstream to
Gateway port `18789` (or your `gateway.port`), preserving `/api/messages` or your
configured `webhook.path`. If you expose a port directly, update Azure Bot's
messaging endpoint to the public HTTPS URL that reaches this Gateway route.

Doctor pins `legacyWebhook: { port: 3978 }` once for an enabled Teams channel on
an existing installation that relied on the implicit port. Evidence of prior
operation is required; fresh installations open no separate listener. An
explicitly configured `webhook.port` moves to `legacyWebhook.port` through
Doctor's normal config backup and write flow. Pinned compatibility listeners
forward into the same Gateway route and JWT validation.

The deprecated TypeScript `webhook.port` input remains source-compatible until
the next Plugin SDK major. Runtime config uses `legacyWebhook`; run
`openclaw doctor --fix` to migrate the old key.

After confirming a delivery through the Gateway port, remove the
`channels.msteams.legacyWebhook` pin and any old firewall or Compose port mapping.
Keep `meta.migrations.webhookListeners`, which Doctor saves with the pin, so later
runs do not recreate it. See [webhook migrations](https://funcoding.ai/agents/openclaw/gateway/doctor/config-migrations/#channel-webhook-listeners)
for included and read-only config sources.
Explicit `false` also disables the listener. Doctor and startup print the
Gateway route and the setting to remove.

For an existing installation that supplies Teams credentials only through
environment variables, Doctor preserves the endpoint without enabling Teams in
the source config. If those credentials are visible only to the Gateway service,
Doctor leaves the decision pending until Gateway startup. Continue using
`gateway run --ambient-channels` to activate it. A listener setting alone no
longer enables Teams; use `enabled: true` for a permanent opt-in. Doctor adds that
flag to authored listener settings that previously implied activation, including
an explicit `legacyWebhook: false`. It does not add the flag to a generated pin
whose migration completion is already recorded.

A custom path also accepts the older `/api/messages` alias with its existing
deprecation warning when that route is available. If another plugin owns the
alias, startup logs the conflict and keeps serving the configured path. Update
Azure Bot to the configured path.

The Gateway reserves `/health`, `/healthz`, `/ready`, `/readyz`, `/startup`, and
`/startupz` for checks, including URLs with query strings. If your former Teams
callback uses one of these paths, set `webhook.path` to `/api/messages` and update
Azure Bot or the proxy upstream to match. Doctor reports this conflict. The
compatibility listener keeps the old endpoint working; startup refuses the
unusable Gateway route when no explicit legacy listener is configured. Verify
the replacement before removing that listener's pin.

Paths under `/api/channels` require Gateway authentication on the main listener,
including encoded spellings. Teams callbacks authenticate with Azure JWTs, so
use `/api/messages` instead. Doctor and startup report the same callback-change
action; the compatibility listener continues serving the old path until that
cutover is complete.

Express parameter, wildcard, and brace patterns continue working on the legacy
port. Gateway route registration uses literal paths. Before disabling the legacy
listener for a pattern, change the existing `webhook.path` to `/api/messages` and
update Azure Bot or your proxy. Doctor and startup identify these patterns; without
an explicit legacy listener, startup reports the required change instead of silently
dropping callbacks.
