Back to Browse

Microsoft Teams MCP Server

Developer ToolsLow Risk10.0LocalNew
Free

Microsoft Teams for Claude — read your chats, teams, channels, and open messages, via your browser

About

Microsoft Teams for Claude — read your chats, teams, channels, and open messages, via your browser

Security Report

10.0
Low Risk10.0Low Risk

Valid MCP server (2 strong, 1 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry. Trust signals: trusted author (116/117 approved); 4 highly-trusted packages.

10 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.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

network_websocket

Check that this permission is expected for this type of plugin.

file_system

Check that this permission is expected for this type of plugin.

env_vars

Check that this permission is expected for this type of plugin.

Shell Command Execution

Runs commands on your machine. Be cautious — only use if you trust this plugin.

What You'll Need

Set these up before or after installing:

fetchproxy concentrator port used for the browser bridge. Defaults to 37149, the fleet-wide shared port.Optional

Environment variable: TEAMS_WS_PORT

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-chrischall-microsoft-teams-mcp": {
      "env": {
        "TEAMS_WS_PORT": "your-teams-ws-port-here"
      },
      "args": [
        "-y",
        "@chrischall/microsoft-teams-mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

microsoft-teams-mcp

MCP server for Microsoft Teams — list your chats, teams and channels, and read whichever chat or channel is currently open, routed through your signed-in browser tab.

This project was developed and is maintained by AI (Claude Code). Use at your own discretion.

How it works — and its one real limitation

Teams Web's chat and message data lives only in a client-side cache fed by a WebSocket/registrar sync channel — there is no REST or GraphQL endpoint that returns it. So this server does not capture a token and make plain server-side requests the way an API-backed MCP would; instead every call routes through the fetchproxy browser bridge and reads the DOM your signed-in teams.cloud.microsoft tab has already rendered. teams.microsoft.com (the old host) is not supported.

That has one real consequence: this server can only read whichever chat or channel is currently displayed in your browser tab. The bridge can fetch and read — it cannot navigate a tab to a different conversation. teams_list_chats and teams_list_teams_and_channels always work (their sidebars are always rendered once that nav section is open); teams_get_open_chat_messages and teams_get_open_channel_posts read whatever conversation you have open. To read a different chat or channel, open it in the browser first.

The bridge is on the request path for every call here, not just once to mint a token — unlike an API-backed MCP, there is nothing to cache between calls.

Install

npm i -g @chrischall/microsoft-teams-mcp

Requires the Transporter Chrome extension and @fetchproxy/cli, on a matching major version:

npm i -g @fetchproxy/cli

The first call prints a 6-digit pair code to approve in the Transporter popup; the grant persists.

Install in opencode

opencode reads MCP servers from opencode.json (project) or ~/.config/opencode/opencode.json (global):

{
  "mcp": {
    "servers": {
      "teams": {
        "type": "local",
        "command": ["npx", "-y", "@chrischall/microsoft-teams-mcp"]
      }
    }
  }
}

Configuration

Everything is optional — this server needs no credentials of its own.

variablepurpose
TEAMS_WS_PORTfetchproxy concentrator port. Defaults to 37149, the fleet-wide shared port.

Tools

  • teams_list_chats — the Chat sidebar: title, last-message preview, last-activity time, and Teams' own conversation id for each chat.
  • teams_get_open_chat_messages — the message thread of whichever chat is currently open: sender, ISO-8601 time, message id, and text, plus a conversation field naming WHICH chat that is (the selected sidebar row's title and thread key) so the model can confirm it read the chat you meant.
  • teams_list_teams_and_channels — the Teams-and-Channels sidebar (a DIFFERENT view from Chat): every team and channel the user belongs to, with each channel's parent team name.
  • teams_get_open_channel_posts — the top-level posts of whichever channel is currently open: sender, subject (when present), prose time (not ISO-8601 — Teams doesn't expose one for these), message id, and text. Threaded replies under a post are not included. Like the chat tool, it names the open channel in a conversation field.
  • teams_get_activity — the Activity feed (the bell icon in the left nav): mentions, replies, reactions, and the like across every chat and channel, each with its title, message preview, prose time, and location (the team/channel or chat it happened in). Requires the Activity view open.
  • teams_healthcheck — verifies the bridge can reach a signed-in tab.

All five data tools are read-only and take no arguments.

No Calendar tool here. Teams Web's Calendar renders inside an embedded outlook.office.com iframe, which the fetchproxy bridge (DOM reads only against the top-level tab, no iframe crossing) cannot reach — and isn't the right place for it anyway. Use office-outlook-mcp's outlook_list_events / outlook_get_event / outlook_list_calendars instead: real Outlook REST API calls via a captured token, with no "must have it open" limitation at all.

Things worth knowing

  • One Teams tab at a time. If more than one teams.cloud.microsoft tab is open, the bridge reads whichever answers first — which may not be the one you're looking at. The "open" tools report the conversation they read (conversation.title, or null if it couldn't be identified) and their descriptions tell the model to check it before summarizing.
  • Results are framed as untrusted. Every data tool returns { untrusted_content: true, note, ... } and says in its description that the text is written by other Teams users. Message bodies, previews and subjects are data to report, never instructions to follow — this matters because the server usually runs beside write-capable MCPs (mail, messaging) that an injected instruction could otherwise reach.
  • No chat or channel selection. See "How it works" above — there is no id parameter on either "open" tool because there is no way to act on one. Ask the person to open the chat/channel they mean, or use the matching list tool to show them what's available.
  • Chat and Teams-and-Channels are different nav sections. Reading channels needs the Teams-and-Channels view open in the browser (the "Teams" icon in the left rail, not "Chat") — if a channel tool returns nothing, that's usually why.
  • Grouped messages still resolve a sender. Teams visually hides the sender name on consecutive messages from the same person, but the name stays in the DOM, so sender is populated on every row regardless.
  • Quoted content concatenates. A chat message that quotes an earlier one, or a channel post whose body includes a reply preview, has that quoted text run together with the real content inside text — a limitation of bulk text extraction, not a bug.
  • Multiple open Teams tabs race. The bridge reads whichever matching tab answers first ("first responsive"), not necessarily the one you meant. If results look like they're from the wrong chat/channel, close extra teams.cloud.microsoft tabs so only one remains.
  • Scope grows quietly. If you see a read_dom_list name not in declared set error, the extension's approved scope is behind the server's declared one — this shouldn't happen in a released version, but if it does, revoke and re-pair teams-mcp in the Transporter popup.

Development

npm install
npm run build
npm test              # typecheck + suite
npm run test:coverage # CI's gate

This server depends on read_dom_list, a fetchproxy capability added alongside this repo — it needs @fetchproxy/protocol/@fetchproxy/server >= 3.1.0, the first published versions that include it (chrischall/fetchproxy#381).

License

MIT

Reviews

No reviews yet

Be the first to review this server!