Teams MCP - FAQ — Unique AI Documentation

Teams MCP - FAQ

General

What type of MCP server is this?

Answer: The Teams MCP Server is both a connector and an interactive MCP server. It does two things simultaneously: it automatically ingests meeting transcripts into the Unique knowledge base in the background, and it exposes an interactive tool surface of 12 MCP tools that AI clients can call on demand.

What it does:

What the user sees:

Design rationale:

Authentication & Permissions

Why do I need admin consent?

Answer:OnlineMeetingRecording.Read.All and OnlineMeetingTranscript.Read.All require admin consent because they access sensitive meeting content (audio/video recordings and transcripts). This is a Microsoft requirement, not a Teams MCP requirement.

What to do:

  1. Go to Azure Portal → App Registration → API permissions
  2. Click "Grant admin consent for [Your Organization]"
  3. Users can then connect and grant their own consent

Why do users still need to consent after admin consent?

Answer: This is standard Microsoft behavior for delegated permissions. Even after admin consent, each user must individually consent because delegated permissions act on behalf of the signed-in user. This ensures users are aware of what data the app can access.

This is not a bug - it's how Microsoft OAuth works for all Microsoft 365 apps.

What is the "login flicker" when users reconnect?

Answer: After a user has connected once, Microsoft Entra ID uses silent authentication on subsequent connections. The browser quickly redirects through the OAuth flow to validate the existing session, creating a brief "flicker" effect. This is normal Microsoft OAuth behavior, not a bug.

Why can't I use certificate authentication?

Answer: While it's technically possible to use certificate authentication with the Authorization Code flow, it would require significant additional implementation effort in our OAuth packages. The standard approach for delegated permissions is to use a client secret, which is simpler to implement and maintain.

Why do I need a client ID and client secret?

Answer: Microsoft Graph API uses OAuth 2.0 for authentication, which requires a CLIENT_ID to identify and authorize applications. The CLIENT_SECRET proves to Microsoft that your server is the legitimate application (not an imposter). It's used during the OAuth token exchange to securely obtain Microsoft access and refresh tokens.

The CLIENT_ID enables Microsoft to verify application identity, enforce permissions, enable consent flows, track and audit API usage, and ensure delegated authorization is scoped to data the signed-in user can access.

Security note: The client secret is never sent to clients - it's only used server-side during the OAuth flow.

Why can't I use application permissions instead of delegated?

Answer: Application permissions would require tenant administrators to create Application Access Policies via PowerShell for each user. This defeats the self-service MCP model where users connect their own accounts without IT involvement.

What's the difference between delegated and application permissions?

Answer:

Teams MCP uses delegated permissions for self-service user connections.

Why can't I use Client Credentials flow?

Answer: Client Credentials flow only supports application permissions, which would require tenant admins to create Application Access Policies per user via PowerShell. This is impractical for self-service MCP connections. Delegated permissions require the Authorization Code flow.

Why can't I use multiple app registrations?

Answer: Each Teams MCP deployment uses one Microsoft Entra ID app registration. The app can be configured as multi-tenant to serve users from multiple organizations, but you don't need separate app registrations per tenant.

Single App Registration Architecture:

This design uses a single OAuth application that can serve users across multiple tenants, rather than requiring separate app registrations per organization.

Configuration

Why do I need a Zitadel service account?

Answer: The Teams MCP Server requires a Zitadel service account to authenticate with the Unique Public API and perform operations on behalf of the server.

What the service account is used for:

How it works:

What's the redirect URI format?

Answer: The redirect URI must match exactly:

https://<your-domain>/auth/callback

Common mistakes:

Why do I need a webhook secret?

Answer: The MICROSOFT_WEBHOOK_SECRET validates that incoming webhook notifications are actually from Microsoft Graph, not from an attacker. It's sent to Microsoft when creating subscriptions and returned in every webhook payload for validation.

Generate:openssl rand -hex 64 (128 characters)

What happens if I change the encryption key?

Answer: All stored Microsoft tokens become unreadable. All users must reconnect to the MCP server to re-authenticate. There is no zero-downtime rotation for the encryption key.

Best practice: Plan for a maintenance window and notify users before rotating the encryption key.

What happens if I change the client secret?

Answer: Update the Kubernetes secret and restart the pods. Users don't need to reconnect - the server will use the new secret for token refresh operations.

Rotation process:

  1. Create new secret in Entra ID
  2. Update Kubernetes secret
  3. Restart pods
  4. Verify authentication works
  5. Delete old secret from Entra ID

What happens if I change the webhook secret?

Answer: Rotation is currently not possible - There is no easy way to invalidate all existing subscriptions that were created with the old secret. The MICROSOFT_WEBHOOK_SECRET is sent to Microsoft as clientState when creating subscriptions. When the secret changes, all existing subscriptions will fail webhook validation because they contain the old secret, but there's no automated mechanism to recreate all subscriptions.

If rotation becomes necessary, it would require manually deleting all subscriptions and having all users reconnect, which may miss transcripts created during the gap.

Architecture & Design

Why are Microsoft tokens never sent to clients?

Answer: This is a critical security design. Microsoft OAuth tokens (access and refresh) are exchanged entirely on the server and stored encrypted. The server then issues separate opaque JWT tokens to clients for MCP API authentication. This ensures: - Microsoft tokens never leave the server - Clients cannot access Microsoft Graph API directly - All Microsoft API calls are made by the server on behalf of authenticated users

Token Isolation Design:

  1. Microsoft OAuth Flow: User authenticates with Microsoft Entra ID
  2. Token Exchange: Server exchanges authorization code for Microsoft tokens (using CLIENT_SECRET)
  3. Token Storage: Microsoft tokens are encrypted and stored on the server only
  4. Client Authentication: Server issues separate opaque JWT tokens to the client for MCP API access

Why are MCP tokens hashed but Microsoft tokens encrypted?

Answer:

Hashing reduces attack surface (no decryption key needed for MCP tokens), while encryption enables token retrieval for Microsoft API calls.

Why use AES-GCM for token encryption?

Answer: AES-GCM provides authenticated encryption - both confidentiality and integrity. It prevents tampering with ciphertext and is an industry standard for token encryption.

Why refresh tokens rotate?

Answer: Refresh token rotation with family-based revocation detects token theft. If a refresh token is reused (indicating possible theft), the entire token family is revoked. This prevents attackers from using stolen tokens while the legitimate client continues working.

Why are subscriptions renewed instead of recreated?

Answer: The biggest reason is that recreation may miss transcripts. Microsoft Graph only sends notifications for transcripts created while a subscription is active. When recreating a subscription (DELETE + POST), there's a gap where no subscription exists. Any transcripts created during that gap will never generate notifications—those transcripts are lost forever.

Renewal (PATCH) keeps the subscription continuously active, eliminating this gap. Additionally, renewal is more efficient than recreation—it preserves the subscription ID and reduces API calls. Renewal happens automatically before expiration (default: 3 AM UTC daily) to ensure token validity is checked consistently.

Token Management

What happens if token refresh fails?

Possible causes:

Resolution: User must reconnect to MCP server to re-authenticate.

What happens if a token family is revoked?

Answer: All refresh operations fail for that user. The user must re-authenticate completely. This happens automatically when refresh token reuse is detected (possible token theft).

What happens if the encryption key changes?

Answer: All stored Microsoft tokens become unreadable. All users must reconnect to obtain fresh tokens. There is no zero-downtime rotation for the encryption key.

Why are MCP access tokens so short-lived (60 seconds)?

Answer: Short-lived access tokens reduce the impact of token theft. If an access token is compromised, it expires quickly. Refresh tokens are used to obtain new access tokens without user re-authentication.

Data Sync

Why can't historical transcripts be synced?

Answer: Microsoft Graph does not provide a way to list transcripts across all past meetings using delegated permissions. The only cross-meeting transcript listing API is getAllTranscripts:

GET /users/{userId}/onlineMeetings/getAllTranscripts(meetingOrganizerUserId='{userId}',startDateTime=...)

This API requires application permissions (OnlineMeetingTranscript.Read.All). Microsoft explicitly marks delegated (user) permissions as Not supported for this endpoint.

Teams MCP uses delegated permissions so users can connect their own Microsoft account without IT administrator involvement. With delegated permissions the only supported path is GET /users/{userId}/onlineMeetings/{meetingId}/transcripts, which requires knowing the meeting ID in advance — making bulk historical enumeration impossible.

As a result, Teams MCP can only capture transcripts for meetings that occur after the user connects. Any meetings that took place before the subscription was created are inaccessible.

Why is there no delta sync?

Answer: Microsoft Graph does expose delta APIs for transcripts and recordings — callTranscript: delta and callRecording: delta — which support both full initial sync and incremental sync (returning only items added since a $deltaToken). However, these APIs require application permissions. Microsoft explicitly marks delegated permissions as Not supported:

Permission type Support
Delegated (work or school account) Not supported
Delegated (personal Microsoft account) Not supported
Application OnlineMeetingTranscript.Read.All

Because Teams MCP uses delegated permissions, delta sync is unavailable. The service instead relies on real-time webhook notifications (change notifications), which deliver new transcript events as they occur. This covers all meetings going forward but cannot recover transcripts missed due to a subscription gap.

What happens if I miss transcripts during a subscription gap?

Answer: They are permanently lost. Microsoft Graph only delivers webhook notifications for transcripts created while a subscription is active. If a subscription expires (or is deleted and recreated), any transcripts produced during the gap will never generate a notification.

To minimise the risk:

Subscriptions & Processing

Why do subscriptions expire?

Answer: Microsoft Graph subscriptions expire after a maximum of 3 days. Teams MCP automatically renews subscriptions before they expire (default: 3 AM UTC daily). This ensures token validity is checked consistently.

What happens if a subscription renewal fails?

Answer: The subscription is deleted and the user must reconnect to the MCP server to re-authenticate. This can happen if:

Any transcripts produced between the failed renewal and the user reconnecting are permanently lost — there is no backfill or catch-up mechanism once a subscription lapses.

Why aren't transcripts appearing in Unique?

Answer: Check the following:

  1. User has active subscription - Verify the user successfully connected and subscription was created
  2. Webhook notifications received - Check if Microsoft is sending notifications
  3. RabbitMQ queue processing - Verify messages are being processed
  4. No processing errors - Check logs for any failures during transcript processing

Webhooks & Processing

Why use RabbitMQ for webhook processing?

Answer: Microsoft requires webhook endpoints to respond within 10 seconds, or it considers the delivery failed and retries. However, processing transcript notifications involves database lookups, multiple Microsoft Graph API calls, user resolution, and content ingestion, which can take 30+ seconds.

RabbitMQ decouples webhook reception from processing:

This ensures we meet Microsoft's strict timeout requirements while processing transcripts reliably.

Can I deploy without RabbitMQ?

Answer: No. RabbitMQ is required to meet Microsoft's webhook response time requirements. Without it, webhook processing would timeout and Microsoft would stop sending notifications.

How does webhook validation work?

Answer: When creating a subscription, the server sends MICROSOFT_WEBHOOK_SECRET as clientState to Microsoft. Microsoft returns this value in every webhook payload. The server validates that the received clientState matches the configured secret, rejecting invalid requests.

What happens if webhook validation fails?

Answer: The request is rejected with 401 Unauthorized. Microsoft will retry the notification. If validation consistently fails, Microsoft may stop sending notifications for that subscription.

What happens to messages that fail processing?

Answer: Failed transcript processing messages are nacked and routed to a Dead Letter Exchange (DLX). Messages accumulate there indefinitely — there is no automatic TTL or retry from the DLQ.

An operator must inspect the DLQ manually (e.g., via the RabbitMQ management UI) to decide whether to republish a message for retry or discard it.

Deployment

What happens if the database is full?

Answer: Write operations will fail. Solutions:

Data Model

Why track token families?

Answer: Token family tracking enables theft detection. Each OAuth session has a token_family identifier. If a refresh token is reused (indicating possible theft), the entire family is revoked. This prevents attackers from using stolen tokens while the legitimate client continues working.

Why store MCP tokens as hashes?

Answer: MCP tokens are opaque JWTs - the server doesn't need to read them, only validate them. Hash comparison is sufficient for validation and reduces attack surface (no decryption key needed).

Why encrypt Microsoft tokens instead of hashing?

Answer: Microsoft tokens must be decrypted to use for Graph API calls. Encryption allows retrieval, while hashing is one-way and would prevent token usage.

Security

How are Microsoft tokens stored?

Answer: Microsoft access and refresh tokens are encrypted at rest using AES-256-GCM and stored in the user_profiles table. They are never sent to clients - only opaque JWT tokens are issued to clients for MCP authentication.

What happens if a refresh token is stolen?

Answer: If a refresh token is reused (indicating possible theft), the entire token family is revoked. The user must re-authenticate completely. This is detected automatically by the refresh token rotation mechanism.

Why use PKCE?

Answer: PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks. It's required for all OAuth flows in OAuth 2.1 and uses S256 challenge method (SHA-256).

Why separate MCP tokens from Microsoft tokens?

Answer: This design ensures:

What's the threat model?

Answer: The security architecture protects against:

Microsoft Graph Integration

Why single app registration architecture?

Answer: Each MCP deployment uses one Microsoft Entra ID app registration that can serve users from multiple Microsoft tenants. When tenant admins grant consent, Microsoft creates Enterprise Applications in their tenants. This is simpler than managing multiple app registrations.

How does multi-tenant authentication work?

Answer:

  1. App registration configured as multi-tenant ("Accounts in any organizational directory")
  2. Tenant admin grants consent → Microsoft creates Enterprise Application in their tenant
  3. Users authenticate via Enterprise Application in their tenant
  4. One MCP deployment serves all tenants

Multi-Tenant

Can a user connect multiple Microsoft tenants?

Answer: Not in a single session. One OAuth login covers exactly one Microsoft tenant. If a user belongs to multiple tenants (e.g., their home tenant plus a guest tenant), they must authenticate separately for each tenant they want to capture meetings from.

Can one deployment serve multiple Microsoft tenants?

Answer: Yes. Configure the app registration with "Accounts in any organizational directory" (multi-tenant). When each organization's admin grants consent, Microsoft creates an Enterprise Application in their tenant. One MCP deployment serves all tenants.