Teams MCP - Flows
3 min read
User Connection Flow
Everything starts when a user connects to the MCP server. This triggers OAuth authentication. After authentication, the user can start the KB integration via the start_kb_integration tool to begin receiving meeting notifications. Alternatively, operators can enable MICROSOFT_AUTO_START_INGESTION, in which case every login automatically enqueues a transcript subscription (no tool call required).
OAuth Scopes Required: See Microsoft Graph Permissions for detailed justification.
Important: Microsoft access and refresh tokens are never sent to the client. They are received by the server, encrypted, and stored securely. After the Microsoft OAuth flow completes, the server issues opaque JWT tokens to the client for MCP authentication.
Microsoft OAuth Setup Flow
The following sequence shows the complete Microsoft OAuth authentication flow with detailed token handling:
Microsoft Token Refresh Flow
Microsoft tokens are refreshed on-demand when the Graph API returns a 401 error:
Subscription Lifecycle
Subscriptions are renewed (not recreated) before they expire. If renewal fails for any reason, the subscription is deleted and the user must reconnect to the MCP server to re-authenticate.
Subscription Scheduling:
Subscriptions are set to expire at a configured UTC hour (default: 3 AM)
This batches all renewals to a single time window
Daily renewal ensures token validity is checked consistently
Minimum 2-hour subscription lifetime required for lifecycle notifications
If renewal fails: Subscription is deleted and user must reconnect to MCP server
See Microsoft Graph Webhooks - Lifecycle Notifications for details
Transcript Processing Flow
When a meeting transcript becomes available, Microsoft Graph sends a webhook notification. The recording is fetched if available (correlated by contentCorrelationId).
Webhook Validation:
Microsoft Graph sends a
clientStatevalue with each notificationThe server validates this matches the secret configured during subscription creation
Invalid
clientStateresults in request rejection
Recording Handling:
Recording fetch uses
contentCorrelationIdto find the matching recording for a transcriptIf the recording is not available, only the transcript is captured
Recording failures are logged but don't fail transcript processing
Recordings are stored with
SKIP_INGESTIONmode (no RAG processing)Both transcript and recording share the same
content_correlation_idin metadata
Access Control:
Meeting organizer receives write + read access
Meeting participants receive read access
Users are resolved by email or username in Unique platform
Chat Flows
The Chat Module exposes a synchronous request/response tool surface. Each tool call is handled inline — there is no queue or background worker. This is distinct from the async webhook/transcript ingestion path above.
Each tool targets a chat or channel by id: list_* tools return identifiers that the caller passes to subsequent get_*_messages or send_*_message calls. See also: Tools Reference.
Chat Read Flow
The read flow applies to both personal chats (list_chats → get_chat_messages) and team channels (list_teams → list_channels → get_channel_messages). The diagram below shows the personal chat variant; the channel variant substitutes list_teams/list_channels for list_chats and queries /teams/{teamId}/channels/{channelId}/messages instead of /chats/{chatId}/messages.
Key points:
list_chatsreturns a single bounded page (no auto-pagination);hasMoreindicates whether more chats exist.Graph does not support server-side
messageTypefiltering on message endpoints. WhenexcludeSystemMessages=true, the server pages through results client-side until the requested number of user messages is collected.Message bodies are returned as-is from Graph (HTML). The
get_channel_messagespath is identical but targets/teams/{teamId}/channels/{channelId}/messages.
Chat Search Flow
search_messages queries the Microsoft Search API (POST /search/query on Graph v1.0) and optionally hydrates each hit with its full message body.
Key points:
Pagination uses
offset/sizeon the request body andmoreResultsAvailableon the response — not@odata.nextLink. The caller advances the page by incrementingoffsetbysize.The source filter (
chat/channel/all) is applied client-side after the Graph response, because the Search API'sentityTypes: ['chatMessage']covers both containers with no sub-filter.detail=fullissues one additional Graph call per hit. Concurrency is capped at 5 to avoid Graph throttling. A forbidden or deleted hit falls back to its summary row rather than failing the page.See Tools Reference for the full
search_messagesparameter list.
Chat Send Flow
The send flow applies to personal chats (send_chat_message) and team channels (send_channel_message). The caller must first obtain the target ID via a list_* call.
Key points:
Only plain-text messages are supported (
contentType: 'text'). Rich HTML or adaptive cards are not sent.send_channel_messagereturns awebUrllinking directly to the posted message in Teams.send_chat_messagereturns only the messageid.The entire flow is synchronous — the tool returns only after Graph confirms the message was created.
Related Documentation
Architecture - System components and infrastructure
Security - Encryption, PKCE, and threat model
Microsoft Graph Permissions - Required scopes and least-privilege justification
Standard References
Microsoft Graph API - Graph API overview
Microsoft Graph Webhooks - Webhook documentation
Microsoft Graph Subscriptions - Subscription API reference