Teams MCP - Subscription Management
4 min read
Teams MCP - Subscription Management
A Microsoft Graph webhook subscription must be active for meeting transcripts to be ingested automatically. The server manages the full lifecycle — creation, renewal, expiry detection, and removal — and exposes it through three tools: start_kb_integration, stop_kb_integration, and verify_kb_integration_status.
Transcripts only
This subscription covers meeting-transcript ingestion into the Unique knowledge base. Chat and channel messages are read live through Microsoft Graph and are never subscribed to or ingested. The ingest_meeting tool does not require a subscription — it pulls a single meeting's transcript on demand.
Subscription Creation
Unlike a background-only connector, ingestion is opt-in per user: a subscription is created when the user calls start_kb_integration (it is not created automatically on connect).
start_kb_integrationinvokesSubscriptionCreateService.subscribe()The service creates a Graph subscription for the resource
users/{providerUserId}/onlineMeetings/getAllTranscriptswithchangeType: createdThe subscription is registered with
notificationUrl(transcript notifications) andlifecycleNotificationUrl(lifecycle events), authenticated with aclientStatewebhook secretThe subscription record is stored in the
subscriptionstable (internalType: 'transcript') with the Graph subscription id and its expiration time
The expiration time is set to the next occurrence of the configured off-peak UTC hour (see MICROSOFT_SUBSCRIPTION_EXPIRATION_TIME_HOURS_UTC below), giving a predictable renewal window.
Subscription Renewal
Subscriptions are renewed via Microsoft Graph lifecycle notifications:
Microsoft sends a
reauthorizationRequiredlifecycle notification before the subscription expires (the exact timing varies; Microsoft does not guarantee a fixed window, but notifications arrive at least ~15 minutes before expiry)The lifecycle webhook controller enqueues the event, and
SubscriptionReauthorizeService.reauthorize()PATCHes/subscriptions/{id}with a newexpirationDateTimeThe new expiration is again the next configured UTC expiration hour, and the
subscriptionsrecord is updated to match
The database is the source of truth: a reauthorizationRequired notification for a subscription id that is not in the subscriptions table is ignored.
Subscription Status
The verify_kb_integration_status tool reports one of four statuses:
Status | Meaning | Action |
|---|---|---|
| Subscription valid, more than 15 minutes until expiry | None required |
| 15 minutes or less until expiry | Renewal is automatic; no action needed |
| Subscription has lapsed | Call |
| No subscription exists | Call |
start_kb_integration
Safe to call at any time — it is idempotent and inspects the existing subscription before acting:
No subscription exists: creates a new subscription (
created)Valid subscription, more than 15 minutes until expiry: returns
already_active, no changes madeValid subscription, expiring within 15 minutes: returns
expiring_soon, no changes made — automatic renewal is either in progress or imminent, so a new subscription is deliberately not forced (avoids racing an in-flight renewal)Expired subscription: deletes the lapsed record and creates a fresh subscription (
created)
stop_kb_integration
Removes the transcript-ingestion subscription:
Deletes the
subscriptionsrecord (the source of truth), then issuesDELETE /subscriptions/{id}to Microsoft GraphReturns
removedwhen a record was deleted, ornot_foundwhen nothing was active
Removal stops future automatic ingestion. Previously ingested transcripts remain in the Unique knowledge base — stop_kb_integration does not delete content. To resume automatic ingestion, call start_kb_integration again.
Graph deletion is best-effort
Because the database is the source of truth, the local record is removed first. If the subsequent Graph DELETE fails, the orphaned Graph subscription is harmless: any later notification it produces is discarded because no matching record exists in the subscriptions table.
Subscription Failure Handling
Microsoft Graph sends lifecycle notifications when a subscription's state changes. The server handles the two it acts on automatically; all other lifecycle events are discarded.
Condition | What Happens | User Action Required? |
|---|---|---|
| Server automatically PATCHes the subscription with a new expiration time | No |
| Server deletes the local | Yes — user must call |
Other lifecycle events (e.g. | Discarded and logged; no recovery action is taken | No (but missed transcripts are not retroactively recovered — see note) |
Subscription expired (missed renewal) |
| Yes — user must call |
No subscription exists |
| Yes — user must call |
No automatic gap recovery
Teams MCP does not run a catch-up pass for transcripts missed while a subscription was lapsed or after a missed lifecycle event. To ingest a specific meeting whose transcript was not captured, use ingest_meeting with the meeting's join URL.
Configuration
Variable | Default | Description |
|---|---|---|
|
| Hour of day (UTC, 0–23) at which scheduled subscription expirations are set. Choose an off-peak hour to avoid disrupting incoming notifications. |
| (required) | Secret sent as the subscription |
|
| Public URL Microsoft Graph posts notifications to. |
Related Documentation
Tools -
start_kb_integration,stop_kb_integration,verify_kb_integration_status, andingest_meetingtool referenceFlows - Subscription lifecycle and transcript-processing sequence diagrams
Permissions - The
OnlineMeetingTranscript.Read.All/OnlineMeetingRecording.Read.Alladmin-consent scopes the subscription depends onConfiguration -
MICROSOFT_SUBSCRIPTION_EXPIRATION_TIME_HOURS_UTCand webhook settings