Announcing CIMD support for MCP Client registration
Learn more

Microsoft Teams MCP vs Microsoft Teams API for AI Agent Development

TL;DR

  • The official Teams MCP server (Work IQ Teams) is in preview and exposes about two dozen Graph-backed tools for chat, channel, team, and message CRUD. Microsoft Graph is GA and exposes the full Teams surface: messages, channels, chats, members, online meetings, shifts, presence, change notifications, and search.
  • The Teams MCP server authenticates with Microsoft Entra ID using delegated permissions only. Application-only (headless) authentication is not supported, and the Copilot Studio path requires a Microsoft 365 Copilot license. Graph supports both delegated and application permissions.
  • The Teams write path has a constraint most builders miss: posting channel and chat messages requires delegated, user-context permissions on Graph. Application-only message posting is restricted to migration scenarios (Teamwork.Migrate.All). So "use the API for clean headless auth" is only half true for Teams.
  • For multi-tenant B2B agents, both paths produce one delegated credential per user. Neither stores, refreshes, or revokes those tokens for you. That remains infrastructure regardless of path.
  • Scalekit's Microsoft Teams connector handles the per-user OAuth flow, the vaulted token lifecycle, and per-user scoped tool access for the Graph-backed path, so the MCP vs API decision does not change your auth infrastructure.

Your agent needs to work with Microsoft Teams. It has to summarize the #engineering channel, post a status update, pull meeting context before a standup, maybe manage who is in a team. Microsoft now ships an official Teams MCP server (the Work IQ Teams server), and it has shipped the Microsoft Graph API for Teams for years. They cover overlapping but not identical ground, they put you on different auth models, and one of them is still in preview. Here is how to pick.

What's Microsoft Teams MCP

Microsoft's official Teams MCP server ships as the Work IQ Teams server (server ID mcp_TeamsServer) inside the Agent 365 and Work IQ tooling layer. It is hosted by Microsoft and surfaced through Copilot Studio, Azure AI Foundry, and Agent 365, with a tenant-scoped endpoint of the form https://agent365.svc.cloud.microsoft/agents/tenants/{tenantId}/servers/mcp_TeamsServer.

One thing to be clear about up front: it is in preview. Microsoft states the feature has restricted functionality, is not meant for production, and that tool names and parameters may change. Auth is Microsoft Entra ID delegated, OAuth 2.0 authorization code with PKCE; MCP clients discover the auth config through the /.well-known/oauth-protected-resource endpoint. Adding it to an agent in Copilot Studio requires a Microsoft 365 Copilot license.

Official docs: the Work IQ Teams reference and the Work IQ MCP overview.

What's Microsoft Teams API (Microsoft Graph)

The Teams API is the Microsoft Graph REST surface. It exposes teams, channels (standard, private, and shared), chats, channel and chat messages, replies, members, online meetings, shifts and schedules, presence, search, and change notifications. It is versioned by endpoint, v1.0 for GA and beta for preview features, and authenticated with an Authorization: Bearer token issued by Microsoft Entra ID.

Graph supports both delegated permissions (user context) and application permissions (app-only or client credentials, including certificate-based auth), with one important Teams-specific caveat covered below.

Official docs: the Microsoft Graph permissions reference and the Send chatMessage reference.

Comparing Teams MCP vs API where it matters for agents

What your agent can actually do

The Teams MCP server covers the conversational and structural surface well: list teams and channels, read and post messages, reply in threads, manage members, and manage chats.

The gaps appear when the agent needs richer message formatting, real-time change events, or operations the preview surface has not exposed yet.

Capability
Teams MCP (Work IQ Teams)
Microsoft Graph API
List teams and channels
Yes
Yes
Read channel and chat messages
Yes
Yes
Post channel and chat messages
Yes, plain text only
Yes, text or HTML
Reply in a message thread
Yes
Yes
Manage team and channel membership
Yes
Yes
Create, update, delete channels and teams
Yes
Yes
Adaptive Cards and at-mentions in message body
No
Yes
Search messages across teams and channels
No
Yes, via Search API
Online meetings (create, update, delete)
No
Yes
Shifts and schedule management
No
Yes
Presence (set, clear, preferred)
No
Yes
Change notifications and webhooks
No
Yes, via subscriptions

The formatting and search gap

The MCP server posts plain text only, and its reference tool surface has no message search tool. Agents that need formatted Adaptive Cards, at-mentions in the message body, or cross-channel search have to use Graph. Teams message search runs on the Microsoft Search API, which the MCP server does not expose.

The real-time gap

If the agent must react to a new message, a membership change, or a channel update, that requires Graph change notifications: the /subscriptions endpoint paired with a webhook. The MCP server has no event subscription surface. One production constraint to plan for: Graph enforces a per-organization limit of 10,000 active Teams subscriptions, and any further subscription request fails with a 403.

The auth path each one puts you on

This is where the Teams decision diverges most from the rest of the series, so it is worth being precise.

Teams MCP: delegated only

The MCP server runs on Microsoft Entra ID delegated auth, OAuth 2.0 authorization code with PKCE. There is no application-only option. Microsoft's Work IQ documentation states plainly that application-only authentication is not supported and that requests run in the signed-in user's context, with on-behalf-of supported.

A background agent with no user present cannot complete this flow, and the Copilot Studio path also requires a Microsoft 365 Copilot license.

Graph API: delegated and application, with a Teams catch

Graph supports both delegated and application permissions, but the Teams-specific catch matters. Posting channel and chat messages requires delegated, user-context permissions. Application-only message posting is restricted to migration and import scenarios via Teamwork.Migrate.All, not general sending.

App-only client credentials do cover many read operations and change-notification subscriptions, but not message posting. So the usual advice to reach for the direct API when you want clean headless app-only auth is only partly applicable to Teams writes.

The implication for multi-tenant agents

Both paths require per-user credential isolation in a multi-tenant B2B agent. The MCP path gives you a delegated token per user. The Graph delegated path gives you a credential per user. In neither case does the path itself solve storage, rotation, or revocation.

Those are infrastructure problems regardless of which path you choose, and that is where the credential layer, covered below, becomes the real decision.

What you own in production

On the MCP path

Microsoft manages hosting, scaling, tool schemas, and permission enforcement, and centralized governance is built in: admins allow or block servers from the Microsoft 365 admin center. You still own per-user token storage, refresh, revocation on disconnect, and tenant isolation. You also accept preview risk, since tool names and parameters can change and the surface is not production-supported yet.

On the Graph API path

You own endpoint selection, request construction, pagination, error handling, retries, subscription lifecycle, and the full token lifecycle. Subscriptions expire and need renewal, and access tokens must stay refreshed or notifications stop after Graph's retry window. That is more surface area, and more control, with a versioned contract you migrate on your own schedule.

Schema and version stability

MCP tool schemas can shift while the server is in preview. Graph is explicitly versioned across v1.0 and beta. For deterministic production pipelines where an unexpected schema change is an incident, the versioned API is the more predictable dependency today.

When to use MCP, when to use the API

Use Teams MCP when:

  • You are building an interactive, user-present agent inside Copilot Studio, Foundry, or an MCP client where the OAuth consent flow is natural, and you can accept preview status.
  • The agent's job is conversational: read channels and chats, post plain-text updates, and manage membership in natural language.
  • You want Microsoft's admin governance model, allowing or blocking servers from the M365 admin center, without building your own controls.
  • You are validating a Teams agent concept and want Microsoft-maintained tools without writing Graph adapter code.

Use the Microsoft Graph API when:

  • The agent runs headless on a schedule for read or subscription work, where app-only client credentials apply. Note that message posting still needs delegated context.
  • You need capabilities the MCP server does not expose: change notifications, online meetings, shifts, presence, message search, or Adaptive Cards.
  • You need rich message formatting or at-mentions in the message body.
  • You are building a deterministic pipeline where you control endpoint versioning and cannot absorb preview schema changes.

The credential problem that exists on both paths

Same token, different name

Both paths give you a delegated credential per user. Neither gives you a vault, rotation logic, or a revocation flow. In a multi-tenant Teams agent, every user has their own Teams credential, which is N tokens to store encrypted, refresh before expiry, and revoke when a user disconnects or leaves.

The offboarding failure mode

When an employee leaves, disabling their identity in the IdP does not automatically invalidate a delegated Teams token sitting in your own database. An agent on a schedule does not decide to stop using that token. It just does. That is the credential lifecycle problem neither the MCP server nor Graph solves for you.

Where Scalekit fits

Scalekit's Microsoft Teams connector handles the OAuth flow, the vaulted per-user token lifecycle, and per-user scope enforcement for the Graph-backed path, so the MCP vs API decision does not change your auth infrastructure.

How Scalekit fits: Agent Auth, Token Vault, and Virtual MCP

Agent Auth and the Token Vault for Teams

Users authorize Teams once. Scalekit ties the connected account to the user's identity, vaults the token (AES-256, namespaced per tenant), refreshes it automatically, and resolves it server-side at request time, so it never enters the agent runtime or the LLM context.

The agent acts as the authorizing user, which is the correct posture for Teams given that message posting is a delegated operation anyway. What the user can't do, the agent can't do.

Why this matters for multi-tool, multi-tenant agents

A shared service account or bot token gives every user the same Teams surface, the same scope, the same access. In a multi-tenant agent that is both a security failure and an accuracy failure. Per-user connected accounts make correct scoping the default, where scope is a function of identity, not connector configuration.

Every Teams tool call is logged with who triggered it, which resource was touched, and what came back, with a 90-day audit trail tied to the authorizing user rather than a shared bot account. That audit trail is the observability layer that makes a multi-tenant Teams agent answerable to a security review.

Reducing the tool surface

Handing an LLM a full connector catalog degrades tool selection and burns tokens before the agent does any work. list_scoped_tools returns only the Teams tools the current user's connected account is authorized to call, not the catalog. Surface reduction is the lever for tool-calling accuracy and token cost. Model upgrades help. They are not the lever.

The tool surface Scalekit exposes for Teams

The Scalekit Teams connector exposes around 40 tools spanning messaging, channels, teams, members, online meetings, shifts and scheduling, presence, and search. A representative subset, named by the exact strings you pass to execute_tool:

  • microsoftteams_list_teams, microsoftteams_list_channels, microsoftteams_list_channel_messages: read teams, channels, and channel messages
  • microsoftteams_send_channel_message, microsoftteams_send_chat_message, microsoftteams_reply_to_channel_message: post and reply (text or HTML)
  • microsoftteams_search_messages, microsoftteams_create_online_meeting, microsoftteams_set_user_presence: search, meetings, and presence

One integration note worth flagging in advance: the connection_name you pass (for example, microsoftteams) must match the connection name configured in the Scalekit dashboard. This is the single most common integration error. The full input schema for each tool lives in the Teams connector docs.

Connecting Teams through Scalekit

Before the code, the mechanism: the agent does not load a flat Teams catalog. It loads the tools the current user's connected account is authorized to call, then runs the agent loop against that scoped surface. The example below uses list_scoped_tools for discovery, then execute_tool for execution, in a LangChain agent on the Node SDK.

import { ScalekitClient } from "@scalekit-sdk/node"; import { DynamicStructuredTool } from "@langchain/core/tools"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { z } from "zod"; const sk = new ScalekitClient(envUrl, clientId, clientSecret); // Retrieve only the Teams tools this user's connected account is authorized to call const { tools } = await sk.tools.listScopedTools("user_123", { filter: { connectionNames: ["microsoftteams"], toolNames: [ "microsoftteams_list_teams", "microsoftteams_list_channels", "microsoftteams_list_channel_messages", ], }, pageSize: 100, }); const lcTools = tools.map((t) => new DynamicStructuredTool({ name: t.tool.definition.name, description: t.tool.definition.description, schema: z.object({}).passthrough(), func: async (args) => { const { data } = await sk.tools.executeTool({ toolName: t.tool.definition.name, identifier: "user_123", params: args, }); return JSON.stringify(data); }, })); const agent = createReactAgent({ llm, tools: lcTools });

Full setup, including the Azure app and Azure Bot registration the Teams connector needs, is in the Node SDK reference, the Python SDK reference, and the Claude managed agents example.

Virtual MCP Server for Teams

If your team wants an MCP endpoint without standing one up, a Scalekit Virtual MCP server gives the agent a scoped, per-user Teams endpoint that declares exactly which Teams tools it can see and whose credentials it acts with, with no MCP server to deploy, host, or maintain. One server definition serves all users; before each run a short-lived session token is minted, scoped to that user's connected accounts. The endpoint is static; the identity is per-user.

A Scalekit Virtual MCP server URL looks like this:

https://yourcompany.scalekit.com/mcp/v3/servers/<server-id>

To set one up, see Set up your Scalekit account, Configure and connect a virtual MCP server, and the end-to-end Claude managed agent vMCP example.

If a Teams tool you need is not there yet

If Scalekit does not yet expose a Teams tool your agent needs, request it in the Scalekit Slack community or through the Talk to us page.

Which one to build against

  • If your agent is interactive and user-present, and you can accept preview status, the Work IQ Teams MCP server is a fast way to ship conversational Teams functionality inside Copilot Studio or an MCP client.
  • If your agent runs headless, or needs change notifications, meetings, shifts, presence, search, or rich formatting, or simply needs a GA, production-supported contract today, build on Microsoft Graph; just remember that on Teams, message posting needs delegated context even on Graph.

Most production Teams agents will lean on Graph today because the MCP server is still preview, then move user-facing pieces onto the MCP server as it reaches GA. Either way, the per-user credential management problem is the same, and that is what needs production-grade infrastructure.

Browse the Scalekit Microsoft Teams connector.

No items found.
Agent Auth Quickstart
On this page
Share this article
Agent Auth Quickstart

Acquire enterprise customers with zero upfront cost

Every feature unlocked. No hidden fees.
Start Free
$0
/ month
1 million Monthly Active Users
100 Monthly Active Organizations
1 SSO connection
1 SCIM connection
10K Connected Accounts
Unlimited Dev & Prod environments