> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formation.texturehq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Microsoft Teams

> Connect an agent to Teams with its own bot identity and privately install the app.

Formation receives Teams direct messages and @mentions in group chats and
standard-channel threads, runs the agent's normal turn pipeline, and replies as
that agent's dedicated bot. Every agent owns its own Entra app, credentials,
connection namespace and conversation perspective.

## Set up the connection

1. Choose **Add connection → Microsoft Teams** on the agent's Connections page,
   or pick Microsoft Teams while creating an agent.
2. Create a dedicated **Teams-managed bot** and **single-tenant Entra app**
   through [Teams Developer Portal](https://dev.teams.microsoft.com/) or the
   [Teams CLI](https://microsoft.github.io/teams-sdk/cli/commands/app/create/).
   Choose **HTTP** message delivery and generate a client secret. You need a
   work/school tenant that permits app registration and custom app installation;
   **no Azure subscription is required**. This is self-service registration,
   not Microsoft Store review. See the CLI recipe below.
3. Paste the **Application (client) ID**, **Directory (tenant) ID**, and client
   secret **value** into Formation. Formation checks token issuance and stores
   the secret encrypted under this agent's connector. Another agent cannot
   claim that application's identity, including through concurrent saves.
4. Copy the exact messaging endpoint shown after saving into the bot's
   configuration. It looks like
   `https://<formation-host>/connectors/teams/events/<application-id>`.
   Configure Formation's `PUBLIC_URL` before saving. Microsoft must be able to
   reach the endpoint over public HTTPS without an interactive login; a private
   tailnet URL is insufficient.
5. Download the app ZIP from Formation. In Teams, upload it through **Apps →
   Manage your apps → Upload a custom app**, then install it for yourself and
   in the test team or group chat. Your tenant administrator may need to permit
   custom app uploads or distribute it through the organization's app catalog.
   Public marketplace publication and Microsoft Store approval are unnecessary.
6. Send a DM and a channel @mention. Then send another @mention in the same
   thread and confirm the reply stays there. The connection page separately
   reports a message received and a provider-confirmed reply.

The generated app package contains public metadata and icons, never the client
secret. Its policy links describe the connection; operators should provide
their users with the installation's actual privacy, retention and terms policies.

### Teams-managed registration with the CLI

Install Microsoft's [Teams CLI](https://microsoft.github.io/teams-sdk/cli/getting-started/installation/)
and sign in with `teams login`. Create the agent's own registration:

```sh theme={null}
teams app create --name "Formation agent" --teams-managed --sign-in-audience myOrg --messaging-mode http
```

Privately copy `CLIENT_ID`, `TENANT_ID`, and `CLIENT_SECRET` from the result into
Formation's matching fields. Do not paste credentials into chat or commit them.
Save in Formation, then set the displayed endpoint in Developer Portal, or run:

```sh theme={null}
teams app update <teams-app-id> --messaging-mode http --endpoint https://<formation-host>/connectors/teams/events/<client-id>
```

Use the Teams app ID from Developer Portal for `<teams-app-id>` and the Entra
application client ID for `<client-id>`; do not assume they are interchangeable.
Download and install **Formation's ZIP** for the supported scopes and metadata,
rather than installing the CLI's generated package. Formation uses ordinary bot
credentials, not user OAuth or SSO. Teams-managed registration changes where
Microsoft manages the bot, not where Formation runs.

### Optional Azure registration

An existing **Single Tenant Azure Bot** works too. Create its dedicated Entra
app and client secret, enable its **Microsoft Teams channel**, and configure the
same Formation endpoint. This route requires an Azure subscription. Formation
itself can be hosted anywhere with a public HTTPS endpoint. See
[Microsoft's registration comparison](https://microsoft.github.io/teams-sdk/cli/concepts/bot-locations/).

## Participation and permissions

The package declares channel readiness with `supportsChannelFeatures: "tier1"`
using manifest v1.25 and app version 1.0.0. It requests the resource-specific
`ChannelMember.Read.Group` application permission for channel membership access,
as required by Microsoft's channel readiness guidance. Installation consent is
scoped to the resource; it grants no tenant-wide Graph access or message-read
permission. In group chats and channels it receives explicit bot
@mentions rather than the whole conversation. Select the actual bot from Teams'
mention picker: mention-shaped text alone is not authenticated mention evidence.
Unmentioned follow-ups may not be delivered by Teams. Formation cannot use
messages Microsoft did not deliver as context.

An accepted message follows Formation's existing addressing and admission rules.
The connector resolves the exact current conversation's roster when possible;
it never substitutes the entire tenant or parent team's membership for a room's
audience. Missing or incomplete evidence stays unknown and restricts private
recall. Private/shared channels, meetings, files, historical backfill, and proactive
messages are outside this release's supported flow. Teams does not deliver other
bots' messages through the ordinary bot activity stream.

The package's `webApplicationInfo.id` binds resource-specific consent to the
agent's own registered application. Each agent keeps its own app identity; no
shared acting account is introduced. See [Microsoft's resource-specific consent declaration](https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/declare-resource-specific-consent-requirements).

If Developer Portal rejects an older ZIP for a zero-prefixed app version or a
missing channel readiness declaration, update Formation and download the ZIP
again. Reuse the existing bot registration, credentials and messaging endpoint.
The readiness declaration is manifest compatibility, not evidence of live
private/shared-channel verification; begin testing with a DM and a standard
channel. See [Microsoft's channel requirements](https://learn.microsoft.com/en-us/microsoftteams/platform/build-apps-for-shared-private-channels).

## Streaming answers

Open this agent's Teams connection and enable **Stream answers**. It is off by
default and applies to new turns on this connection only. Slack has the same
independent opt-in. Turning either connection on does not enable the other.

**Show progress updates** independently controls Formation's brief, validated
progress messages during longer tasks. Existing installations keep those messages
enabled. These use Formation's existing progress-notice delivery; they are not
Teams informative streaming updates or Slack task cards.

**Live updates in** applies to both answer streaming and progress messages:
**Everywhere**, **Direct and group chats**, or **Direct messages only**. Completed
answers still arrive in every supported conversation. Settings apply to new
turns and are scoped to this agent's connection.

Formation streams authorized public answer text in direct messages, group chats
and standard-channel threads. Tool work and private reasoning are withheld. It
buffers updates for three seconds, sends cumulative Teams content with a durable
sequence cursor, and keeps the preview within one reply part. Longer answers
continue through ordinary multipart delivery. Final validation can correct the
preview: Formation closes the stream and updates the same activity with the
canonical first part, rather than posting a duplicate answer.

Both providers expire streams after ten minutes. Teams previews stop updating
before that deadline; the final answer still reconciles the known activity.
A rejected preview disables further updates for that attempt. Ambiguous stream
creation or append requests are never automatically replayed. The existing
reply journal governs final delivery and recovery. If the setting reports a
restart is required, restart Formation before testing a new turn.

Protocol references: [Teams streaming REST API](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/streaming-ux),
[Slack streaming](https://docs.slack.dev/reference/methods/chat.startStream/).

## Reliability and repair

The inbound endpoint checks the Connector JWT signature, issuer, audience,
expiry, Teams endorsement and service URL binding, plus the configured tenant.
It durably enqueues conversational observations before acknowledging delivery.
Non-message activities are authenticated and ignored. Ingress errors do not log
message bodies or credentials.

The credential-free reply address is persisted with the trigger message and
restored after worker loss. It includes Microsoft's exact conversation and
activity IDs and validated service URL; no process-local address cache is needed.
Outbound extended Markdown is chunked without truncating the canonical response.

Durable reply-part recovery resends only never-started or definitely rejected
parts. Confirmed parts are not posted again. HTTP 429 uses the provider's retry
minimum; credential rejection waits for connection repair. Timeouts, 5xx, and
missing receipts remain uncertain and are not automatically replayed. The
existing model/tools are not rerun merely to retry a reply.

To rotate the secret, open the connection and verify/save the replacement value.
The app identity remains the same. A changed `PUBLIC_URL` requires updating the
bot messaging endpoint manually; Formation does not request Azure resource
management credentials. If saving reports `saved_restart_required`, restart the
instance before sending the test message.

## Operator API

All routes use the existing agent-access authorization for sessions/API tokens:

```http theme={null}
POST /api/agents/{slug}/connectors/teams
{
  "values": {
    "app_id": "<application UUID>",
    "tenant_id": "<directory UUID>",
    "client_secret": "<secret value>"
  }
}
```

The response contains `status` and a connector with a non-secret `adapter` view:
its setup definition, public values, and exact `events_url`.
`GET /api/agents/{slug}/connectors/{connectorID}/app-package` downloads the ZIP.
`GET /api/agents/{slug}/readiness` reports receive/send evidence. Secrets are
write-only. Do not put a secret in a URL, app ZIP, ticket, or chat.

The descriptor catalog, ingress and provisioning routes can serve further
conversation adapters without new vendor cases in shared runtime or UI code.

Sources: [Teams-managed registration](https://microsoft.github.io/teams-sdk/cli/concepts/bot-locations/),
[endpoint configuration](https://microsoft.github.io/teams-sdk/cli/commands/app/update/),
[optional Azure registration](https://learn.microsoft.com/en-us/microsoftteams/platform/teams-sdk/teams/azure-configuration),
[private installation](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload),
[Connector authentication](https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-authentication).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.