AI-native Microsoft Teams integration — read chats, send messages, search people
AI-native Microsoft Teams integration — read chats, send messages, search people
Valid MCP server (2 strong, 3 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry. Trust signals: 3 highly-trusted packages.
4 files analyzed · 1 issue found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
This plugin requests these system permissions. Most are normal for its category.
Set these up before or after installing:
Environment variable: TEAMS_EMAIL
Environment variable: TEAMS_AUTO
Environment variable: TEAMS_LOGIN
Environment variable: TEAMS_TOKEN
Environment variable: TEAMS_REGION
Environment variable: TEAMS_BEARER_TOKEN
Environment variable: TEAMS_SUBSTRATE_TOKEN
Environment variable: TEAMS_DEBUG
Environment variable: TEAMS_TELEMETRY
Environment variable: TEAMS_TELEMETRY_PATH
Add this to your MCP configuration file:
{
"mcpServers": {
"io-github-maxim-mazurok-teams-api": {
"env": {
"TEAMS_AUTO": "your-teams-auto-here",
"TEAMS_EMAIL": "your-teams-email-here",
"TEAMS_LOGIN": "your-teams-login-here",
"TEAMS_TOKEN": "your-teams-token-here",
"TEAMS_REGION": "your-teams-region-here",
"TEAMS_BEARER_TOKEN": "your-teams-bearer-token-here",
"TEAMS_SUBSTRATE_TOKEN": "your-teams-substrate-token-here"
},
"args": [
"-y",
"teams-api"
],
"command": "npx"
}
}
}From the project's GitHub README.
AI-native Microsoft Teams integration — read conversations, send messages, and manage members via the Teams Chat Service REST API.
Designed for autonomous AI agents that need to interact with Teams: read messages, reply to people, monitor conversations, and participate in team workflows.
[!NOTE] This project was AI-generated using Claude Opus 4.6 with human guidance and review.
teams-api can be used in three ways:
npx, which all MCP and CLI commands use.The quickest way to get started is to click one of the install badges above, or follow the instructions for your editor below.
Option 1 — One-click install:
Option 2 — CLI:
macOS / Linux:
# VS Code
code --add-mcp '{"name":"teams","command":"npx","args":["-y","-p","teams-api@latest","teams-api-mcp"],"env":{"TEAMS_LOGIN":"true"}}'
# VS Code Insiders
code-insiders --add-mcp '{"name":"teams","command":"npx","args":["-y","-p","teams-api@latest","teams-api-mcp"],"env":{"TEAMS_LOGIN":"true"}}'
Windows (PowerShell):
# VS Code
code --add-mcp '{"name":"teams","command":"npx","args":["-y","-p","teams-api@latest","teams-api-mcp"],"env":{"TEAMS_LOGIN":"true"}}'
# VS Code Insiders
code-insiders --add-mcp '{"name":"teams","command":"npx","args":["-y","-p","teams-api@latest","teams-api-mcp"],"env":{"TEAMS_LOGIN":"true"}}'
Windows (CMD):
rem VS Code
code --add-mcp "{\"name\":\"teams\",\"command\":\"npx\",\"args\":[\"-y\",\"-p\",\"teams-api@latest\",\"teams-api-mcp\"],\"env\":{\"TEAMS_LOGIN\":\"true\"}}"
rem VS Code Insiders
code-insiders --add-mcp "{\"name\":\"teams\",\"command\":\"npx\",\"args\":[\"-y\",\"-p\",\"teams-api@latest\",\"teams-api-mcp\"],\"env\":{\"TEAMS_LOGIN\":\"true\"}}"
Option 3 — Manual config:
Add to your VS Code MCP config (.vscode/mcp.json or User Settings):
{
"mcpServers": {
"teams": {
"command": "npx",
"args": ["-y", "-p", "teams-api@latest", "teams-api-mcp"],
"env": {
"TEAMS_LOGIN": "true"
}
}
}
}
Or add to ~/.cursor/mcp.json:
{
"mcpServers": {
"teams": {
"command": "npx",
"args": ["-y", "-p", "teams-api@latest", "teams-api-mcp"],
"env": {
"TEAMS_LOGIN": "true"
}
}
}
}
Add to claude_desktop_config.json (how to find it):
{
"mcpServers": {
"teams": {
"command": "npx",
"args": ["-y", "-p", "teams-api@latest", "teams-api-mcp"],
"env": {
"TEAMS_LOGIN": "true"
}
}
}
}
claude mcp add teams -- npx -y -p teams-api@latest teams-api-mcp
Then set the environment variable TEAMS_LOGIN=true in your shell before starting Claude Code. The server will ask for your email interactively on first use.
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"teams": {
"command": "npx",
"args": ["-y", "-p", "teams-api@latest", "teams-api-mcp"],
"env": {
"TEAMS_LOGIN": "true"
}
}
}
}
[!TIP] On macOS with a FIDO2 passkey, replace
TEAMS_LOGINwithTEAMS_AUTOfor fully unattended auth. See Authentication for details.
You can also use the CLI directly without installing anything:
npx -y -p teams-api@latest teams-api auth --login
npx -y -p teams-api@latest teams-api list-conversations --login --limit 20
If you use the CLI often, a global install is optional:
npm install -g teams-api
teams-api auth --login
Manual token usage, debug-session auth, and programmatic Node.js usage are covered later in this README.
| Feature | macOS | Windows / Linux |
|---|---|---|
| Interactive login | Full support | Full support |
| Auto-login (FIDO2) | Full support | Not supported |
| Debug session | Full support | Full support |
| Direct token | Full support | Full support |
| Token caching | macOS Keychain | Windows DPAPI / Linux secret-tool |
| CLI & MCP server | Full support | Full support |
| Programmatic API | Full support | Full support |
[!NOTE] Windows Defender false positive: Older versions of this package used inline PowerShell to call the Windows DPAPI — a pattern that Windows Defender flags as ransomware-like behavior. This has been replaced with native Windows Credential Manager storage via keytar. If you hit issues on an older version, upgrade and re-run
teams-api auth --login. See SECURITY.md for details.
Most users do not need to manage tokens manually.
If you use interactive login, auto-login, or a Chrome debug session, teams-api captures the full token bundle automatically from Teams web traffic. That includes the base skypeToken plus the extra bearer tokens used for profile resolution and reliable people/chat/channel search.
Those flows also detect the Teams chat region automatically from the intercepted request URLs, so most users do not need to set --region or TEAMS_REGION.
On macOS, prefer auto-login when you have a platform authenticator / FIDO2 passkey set up. On other platforms, use interactive login.
Direct token usage is the advanced/manual path.
| Method | Description | Automation | Platform |
|---|---|---|---|
| Auto-login | Playwright launches system Chrome and captures the full token bundle | Fully unattended | macOS |
| Interactive login | Opens a browser window and captures skype, middle-tier, and Substrate tokens | One-time manual | All |
| Debug session | Connects to a running Chrome instance and captures the full token bundle | Semi-manual | All |
| Direct token | Provide a previously captured token or token bundle explicitly | Manual | All |
Requires macOS with a platform authenticator (e.g. Intune Company Portal) and a FIDO2 passkey enrolled. Fully unattended — no browser window appears.
The easiest cross-platform option. A browser window opens, you log in with any method your organization supports (password, MFA, passkey, etc.), and the token is captured automatically:
teams-api auth --login
Optionally pre-fill your email:
teams-api auth --login --email you@example.com
[!NOTE] Interactive login prefers an installed browser (Edge or Chrome) when available, and falls back to Playwright's bundled Chromium.
Debug session — start Chrome with --remote-debugging-port=9222, navigate to Teams and log in, then run:
teams-api auth --debug-port 9222
Direct token — advanced/manual only. Extract x-skypetoken from browser DevTools (Network tab) and pass it directly:
teams-api list-conversations --token "<paste-token-here>" --region emea
If you want reliable people/chat/channel lookup and profile resolution on the direct-token path, also pass the extra bearer tokens captured from Teams requests:
teams-api find-people \
--token "<paste-skype-token-here>" \
--bearer-token "<paste-api-spaces-skype-bearer-token-here>" \
--substrate-token "<paste-substrate-bearer-token-here>" \
--region emea \
--query "Jane Doe"
[!TIP] Skip this section if you are using
--login,--auto,TEAMS_LOGIN, orTEAMS_AUTO. Those modes capture the full token bundle automatically.
[!TIP] Direct-token mode still needs an explicit region. See API regions below.
Preferred without install:
npx -y -p teams-api@latest teams-api <command> [options]
Optional global install for frequent use:
npm install -g teams-api
teams-api <command> [options]
The examples below use teams-api for readability. If you are not installing globally, replace it with npx -y -p teams-api@latest teams-api.
| Flag | Description |
|---|---|
--login | Interactive browser login (all platforms) |
--auto | Auto-acquire token via FIDO2 passkey (macOS) |
--email <email> | Corporate email (required with --auto, optional otherwise) |
--token <token> | Use an existing skype token (advanced/manual) |
--bearer-token <token> | Optional middle-tier bearer token (advanced/manual) |
--substrate-token <token> | Optional Substrate bearer token (advanced/manual) |
--debug-port <port> | Chrome debug port (default: 9222) |
--region <region> | API region override. Auto-detected for login/debug auth; required with --token |
--format <format> | Output format: concise, detailed |
--output <file> | Export output to file (default format: concise) |
# Acquire a token (interactive — all platforms)
teams-api auth --login
# Acquire a token (auto — macOS with FIDO2)
teams-api auth --auto --email you@example.com
# List conversations
teams-api list-conversations --login --limit 20 --format detailed
# Find a conversation by topic
teams-api find-conversation --auto --email you@example.com --query "Design Review"
# Find a 1:1 chat by person name
teams-api find-one-on-one --auto --email you@example.com --person-name "Jane Doe"
# Read messages (by topic name, person name, or direct ID)
teams-api get-messages --auto --email you@example.com --chat "Design Review"
teams-api get-messages --auto --email you@example.com --to "Jane Doe" --max-pages 5
teams-api get-messages --auto --email you@example.com --conversation-id "19:abc@thread.v2" --format detailed
# Newest-first order (API returns newest-first; default is oldest-first/chronological)
teams-api get-messages --auto --email you@example.com --chat "General" --order newest-first
# Send a message
teams-api send-message --auto --email you@example.com --to "Jane Doe" --content "Hello!"
teams-api send-message --auto --email you@example.com --chat "Design Review" --content "Status update"
# List members
teams-api get-members --auto --email you@example.com --chat "Design Review"
# Get current user info
teams-api whoami --auto --email you@example.com
# Export messages to a file (default format: concise)
teams-api get-messages --auto --email you@example.com --chat "General" --output exports/general.md
# Export as JSON to a file
teams-api get-messages --auto --email you@example.com --chat "General" --format detailed --output exports/general.json
The MCP server exposes Teams operations as tools for AI agents via stdio transport. See Getting Started for editor-specific setup.
Use this only if you already have tokens from another flow or need to avoid browser-based auth entirely:
{
"mcpServers": {
"teams": {
"command": "npx",
"args": ["-y", "-p", "teams-api@latest", "teams-api-mcp"],
"env": {
"TEAMS_TOKEN": "<paste-skype-token-here>",
"TEAMS_BEARER_TOKEN": "<optional-api-spaces-skype-bearer-token>",
"TEAMS_SUBSTRATE_TOKEN": "<optional-substrate-bearer-token>",
"TEAMS_REGION": "emea"
}
}
}
}
[!TIP] If you do use direct tokens,
teams-api auth --loginprints the full token object as JSON. For basic chat operations,skypeTokenis enough. For reliable people/chat/channel search and profile resolution, also passbearerTokenandsubstrateToken.
| Variable | Description |
|---|---|
TEAMS_TOKEN | Pre-existing skype token |
TEAMS_BEARER_TOKEN | Optional middle-tier bearer token |
TEAMS_SUBSTRATE_TOKEN | Optional Substrate bearer token |
TEAMS_REGION | API region override. Required with TEAMS_TOKEN; optional otherwise |
TEAMS_EMAIL | Corporate email. Optional — the server prompts the AI agent if needed |
TEAMS_AUTO | Set to true to enable auto-login (macOS + FIDO2) |
TEAMS_LOGIN | Set to true to enable interactive browser login |
TEAMS_DEBUG_PORT | Chrome debug port (default: 9222) |
TEAMS_EDIT_REPLY_GUARD | Edit reply guard: allow (default), warn, or block. See below |
TEAMS_AGENT_MARKER | Agent marker prefix for sent/edited messages (e.g. Ⓜ). See below |
TEAMS_DELETE_MODE | Delete mode: hard (default), soft, or block. See below |
TEAMS_DELETE_TOMBSTONE | Custom tombstone text for soft-delete mode. See below |
TEAMS_AUDIT_LOG | Audit logging: off (default), stderr, or file:<path>. See below |
TEAMS_PROTECTED_CONVERSATIONS | Comma-separated glob patterns of conversations where edit/delete is blocked. See below |
When an AI agent sends or edits messages on behalf of a user, it can be hard to tell which messages were composed by the agent and which by the human. The TEAMS_AGENT_MARKER environment variable (or --agent-marker CLI flag / agentMarker MCP parameter) automatically prepends a configurable string to message content:
{
"env": {
"TEAMS_AGENT_MARKER": "Ⓜ", // or "🤖", "[Bot]", etc.
},
}
When set, every send-message and edit-message call prepends the marker followed by a space to the content. For example, with TEAMS_AGENT_MARKER=Ⓜ, sending "Hello world" produces "Ⓜ Hello world".
The per-call parameter takes precedence over the environment variable. Pass an empty string to disable the marker for a specific call.
When editing a message that already has replies, the original context can be lost — replies may no longer make sense. The TEAMS_EDIT_REPLY_GUARD environment variable (or --reply-guard CLI flag / replyGuard MCP parameter) controls this:
| Value | Behavior |
|---|---|
allow | Edit proceeds normally (default, backward-compatible) |
warn | Edit proceeds but an annotation is appended: "⚠️ This message was edited after…" |
block | Edit is refused with an error listing the reply count |
The per-call parameter takes precedence over the environment variable.
Hard-deleting messages removes content permanently, which can be problematic for auditability and conversation flow in group chats. The TEAMS_DELETE_MODE environment variable (or --delete-mode CLI flag / deleteMode MCP parameter) controls how message deletion is handled:
| Value | Behavior |
|---|---|
hard | Permanently delete the message (default, current behavior) |
soft | Replace message content with a tombstone marker instead of deleting |
block | Refuse deletion entirely with an error |
When using soft mode, the message content is replaced with ~~This message was removed by an agent~~ by default. Customize the tombstone text with TEAMS_DELETE_TOMBSTONE (or --delete-tombstone / deleteTombstone):
{
"env": {
"TEAMS_DELETE_MODE": "soft",
"TEAMS_DELETE_TOMBSTONE": "🗑️ [removed by automation]",
},
}
The per-call parameters take precedence over environment variables.
State-modifying actions (edit and delete) can emit structured audit events for compliance and traceability. The TEAMS_AUDIT_LOG environment variable controls where events are written:
| Value | Behavior |
|---|---|
off | No audit logging (default) |
stderr | Write JSON Lines to stderr |
file:<path> | Append JSON Lines to the specified file (created on demand) |
{
"env": {
"TEAMS_AUDIT_LOG": "file:/var/log/teams-audit.jsonl",
},
}
Each event is a single JSON line with the following fields:
| Field | Description |
|---|---|
timestamp | ISO 8601 timestamp |
action | "edit", "delete", or "soft-delete" |
conversationId | Conversation thread ID |
conversationLabel | Human-readable conversation label (topic or 1:1 partner name) |
messageId | Target message ID |
content | New content for edits, tombstone text for soft-delete, null for hard delete |
Audit logging is designed to be silent — errors in the audit pipeline never affect tool execution.
Some conversations contain sensitive or compliance-relevant information where accidental edits or deletions could be harmful. The TEAMS_PROTECTED_CONVERSATIONS environment variable (or --protected-conversations CLI flag / protectedConversations MCP parameter) blocks edit and delete actions in matching conversations:
{
"env": {
"TEAMS_PROTECTED_CONVERSATIONS": "Incident *,*compliance*,Architecture Decisions",
},
}
Patterns are comma-separated and support * as a wildcard (matches any characters). Matching is case-insensitive. When a conversation's name matches any pattern, both edit-message and delete-message throw an error before making any changes — the message is left untouched.
The per-call parameter takes precedence over the environment variable, so individual tool invocations can override the configured patterns when needed.
All MCP tools accept an optional format parameter (concise or detailed). Default format is concise.
| Tool | Description |
|---|---|
teams_list_conversations | List available conversations |
teams_find_conversation | Find a conversation by topic or member name |
teams_find_one_on_one | Find a 1:1 chat with a person |
teams_find_people | Search the organization directory |
teams_find_chats | Search chats by name or member |
teams_get_messages | Get messages from a conversation |
teams_send_message | Send a message to a conversation |
teams_get_members | List members of a conversation |
teams_get_transcript | Get a meeting transcript from a recorded conversation |
teams_whoami | Get the authenticated user's display name |
Workflow guidance, tips, and important notes are served automatically via the MCP server's instructions field — no separate skill file needed. For the same content on the CLI, run teams-api guide.
The Teams Chat Service URL varies by region. Login-based and debug-session auth detect it automatically. You only need to set --region or TEAMS_REGION when you are supplying tokens directly or want to force an override:
| Region | Base URL |
|---|---|
apac | https://apac.ng.msg.teams.microsoft.com/v1 |
emea | https://emea.ng.msg.teams.microsoft.com/v1 |
amer | https://amer.ng.msg.teams.microsoft.com/v1 |
--login) instead.findOneOnOneConversation() to resolve names from message history.emotions field in message payloads. Parsing handles both JSON-string and array formats.This is the advanced integration path. Most users should start with MCP or CLI instead.
Install the package in your project:
npm install teams-api
Example:
import { TeamsClient } from "teams-api";
// Interactive login — opens a browser, you log in manually (all platforms)
const client = await TeamsClient.fromInteractiveLogin();
// Or auto-login via platform authenticator (macOS + FIDO2 passkey)
const autoClient = await TeamsClient.fromAutoLogin({
email: "you@example.com",
});
// Advanced/manual: create a client from previously captured tokens
const manualClient = TeamsClient.fromToken("skype-token-here", "emea");
const conversations = await client.listConversations();
const messages = await client.getMessages(conversations[0].id, {
maxPages: 5,
onProgress: (count) => console.log(`Fetched ${count} messages`),
});
await client.sendMessage(conversations[0].id, "Hello from the API!");
const oneOnOne = await client.findOneOnOneConversation("Jane Doe");
const members = await client.getMembers(conversations[0].id);
See CONTRIBUTING.md for development setup, architecture, and implementation notes.
MIT
Be the first to review this server!
by Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
by Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
by mcp-marketplace · Developer Tools
Create, build, and publish Python MCP servers to PyPI — conversationally.
by Microsoft · Content & Media
Convert files (PDF, Word, Excel, images, audio) to Markdown for LLM consumption
by mcp-marketplace · Developer Tools
Scaffold, build, and publish TypeScript MCP servers to npm — conversationally
by mcp-marketplace · Finance
Free stock data and market news for any MCP-compatible AI assistant.