teams-chat-mcp
# teams-chat-mcp
Let Claude (or any MCP client) read **your own** Microsoft Teams chats — group chats, 1:1 chats and team posts, full history — and prepare reply drafts. A small Chrome extension does the work inside your signed-in Teams web session; a local MCP server exposes it as tools.
It **cannot send messages**. `draft_message` types text into the Teams compose box and stops; you review and press send.
[中文说明](#中文说明)
```
MCP client ──stdio──▶ teams-chat-mcp ──WebSocket 127.0.0.1──▶ Chrome extension ──▶ Teams chat service
(Python, local) (pairing code) (holds the token)
```
## Why
Microsoft Graph needs an admin to grant chat permissions, which most school and many work accounts never get. The Teams web app, however, already talks to its chat service with a token in your browser. This project reuses that session, read-only, on your machine.
## Tools
| Tool | What it does |
|---|---|
| `list_conversations(match?)` | Your chats with ids, newest first |
| `get_messages(conversation, since?, limit?)` | Messages from one chat (id, exact name or unique part of the name) |
| `search_messages(query, since?, conversation_match?, limit?)` | Regex / text search across chats (default: last 90 days) |
| `draft_message(conversation, text)` | Opens the chat in a new Teams tab and types a draft. **Never sends.** |
| `export_chats(directory, formats?, since?, conversation_match?)` | Writes `chats.txt` / `chats.md` / `chats.json` locally |
Example prompts: *"Which of my Teams chats mentioned final grades this month?"*, *"Summarize what my teacher posted in the course group since Monday"*, *"Draft a polite reply to the last message from Ms. A asking when grades go online."*
## Setup
Requirements: Chrome (or another Chromium browser) 116+, Python 3.10+.
1. **Install the server**
```bash
git clone https://github.com/hanshengcc/teams-chat-mcp
cd teams-chat-mcp
python3 -m venv .venv && .venv/bin/pip install -e .
```
2. **Load the extension**: open `chrome://extensions`, turn on *Developer mode*, click *Load unpacked*, choose the `extension/` folder.
3. **Pair them**
```bash
.venv/bin/teams-chat-mcp pair
```
Paste the pairing code (and port, if you changed it) into the extension popup and click *Save & connect*. The code lives in `~/.config/teams-chat-mcp/config.json` (mode 600).
4. **Add the server to your MCP client**, e.g. Claude Code:
```bash
claude mcp add teams-chat -- /absolute/path/to/teams-chat-mcp/.venv/bin/teams-chat-mcp
```
or Claude Desktop (`claude_desktop_config.json`):
```json
{ "mcpServers": { "teams-chat": { "command": "/absolute/path/to/teams-chat-mcp/.venv/bin/teams-chat-mcp" } } }
```
5. Open <https://teams.cloud.microsoft> in Chrome and sign in. The popup should show *Signed in* and *Connected*.
6. *(Optional, Claude Code)* Install the skill, which teaches Claude the workflows (catching up on announcements, finding deadlines, drafting replies) and the safety rules for untrusted chat content:
```bash
ln -s "$PWD/skills/teams-chat" ~/.claude/skills/teams-chat
```
## How it works
- **Token**: the extension watches the Teams web app's own requests to `/api/chatsvc/…` and keeps their `Authorization` header and regional host in `chrome.storage.session` (memory only, cleared when the browser closes). If it has not seen one yet, it reads the token the web app stores in the Teams tab's `localStorage`. The token is never sent to the MCP server.
- **Data**: the extension calls the same chat service endpoints the web app uses and follows `backwardLink` pages back in time. Only message data (author, time, subject, HTML content) goes to the server, which converts it to text.
- **Bridge**: the server listens on `127.0.0.1:47615`. It refuses WebSocket connections whose `Origin` is not a `chrome-extension://` origin (so web pages cannot connect), then requires the pairing code in the first message (constant-time compare).
## Security and privacy
- **Prompt injection**: message text is written by other people. Tool output is prefixed with a notice telling the model to treat it as data. That lowers the risk but does not remove it, which is the main reason this project has no send tool. Drafts are typed only into an empty compose box, in a tab you can see.
- **Your data goes to your model provider**: whatever the tools return is sent to the LLM you use. Chats contain other people's messages; follow your organization's rules.
- **Local only**: no telemetry, no third-party servers. The extension's host permissions are limited to `teams.cloud.microsoft` and `teams.microsoft.com`.
- **Unofficial**: the chat service API is undocumented and may change or break at any time. Using it may be against your organization's policy. Not affiliated with or endorsed by Microsoft.
## Limitations
- Work / school accounts on Teams web (`teams.cloud.microsoft`, `teams.microsoft.com`). Personal Teams (`teams.live.com`) is not supported.
- Teams: posts in the General channel are included; other channels may not appear in the conversation list.
- Text only. Attachments, images and system events are skipped (emoji `alt` text is kept).
- One MCP server instance owns the port. A second instance reports that the port is busy; pair it on another port with `teams-chat-mcp pair --reset --port <n>` if you really need two.
## Bonus: macOS CLI without the extension
`teams-chat-export` exports chats via AppleScript, no extension needed:
```bash
.venv/bin/teams-chat-export --since 2026-09-01 -f md -o my-chats
```
It requires Chrome's **View → Developer → Allow JavaScript from Apple Events**. That switch lets any app with Automation permission run JavaScript in *all* your tabs, so prefer the extension and turn the switch off when done.
## Development
```bash
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest # Python: server, bridge, tools, CLI
node --test tests/js/*.test.js # JS: chat service client, protocol, drafts
```
`extension/chatsvc.js` is the single source of the chat service client; `src/teams_chat/chatsvc.js` is a copy for the CLI (`cp extension/chatsvc.js src/teams_chat/`; a test fails if they differ).
## License
[MIT](LICENSE)
---
## 中文说明
让 Claude(或任何 MCP 客户端)读取**你自己**的 Microsoft Teams 聊天记录(群聊、私聊、团队帖子,完整历史),并帮你起草回复。Chrome 扩展在你已登录的 Teams 网页版里干活,本地 MCP 服务器把它包装成工具。
**它不能发消息**:`draft_message` 只把文字填进 Teams 输入框,由你检查后自己点发送。
**为什么需要它**:走微软 Graph 读聊天要管理员授权,学校账号和很多公司账号拿不到;Teams 网页版本身已经在浏览器里用令牌访问聊天服务,本项目只在你自己电脑上、只读地复用这个登录状态。
**安装**:见上面的 Setup。概括为:装 Python 包 → `chrome://extensions` 加载 `extension/` 文件夹 → 运行 `teams-chat-mcp pair`,把配对码粘到扩展弹窗 → 把 `teams-chat-mcp` 加到 MCP 客户端 → 在 Chrome 打开并登录 Teams 网页版。Claude Code 用户可以再把 `skills/teams-chat` 链接到 `~/.claude/skills/`,让 Claude 知道怎么汇总通知、找截止日期、起草回复,以及怎么对待别人消息里的内容。
**安全**:
- 令牌只在扩展里(`chrome.storage.session`,只在内存中),不会交给 MCP 服务器。
- 本地端口只接受浏览器扩展来源的连接,还要校验配对码,普通网页连不上。
- 群消息是别人写的,可能包含诱导模型的内容(提示注入),所以不提供发送工具,草稿也只填进空的输入框。
- 工具返回的内容会发给你使用的大模型;聊天里有别人的消息,请遵守学校或公司的规定。
- 使用的是微软未公开的接口,可能随时失效;本项目与微软无关。
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose: listing conversations, reading messages from one conversation, searching across conversations, drafting a message, and exporting history. There is no overlap in scope or action. An agent can easily select the right tool based on the user's intent.
All five tools follow a consistent snake_case verb_noun pattern: list_conversations, get_messages, search_messages, draft_message, export_chats. There are no deviations or mixed conventions. The naming is predictable and readable.
Five tools is well within the ideal 3–15 range and each tool covers a distinct core operation for a Teams chat assistant. The set is tightly scoped without redundant or filler tools. No obvious missing tool forces an awkward count.
The surface covers listing, reading, searching, drafting, and exporting chats, which is strong for a read-and-draft focused server. However, there is no programmatic send or reply tool, and no way to fetch conversation metadata or members; these are minor gaps that agents can work around by using draft_message and asking the user to send manually.