Skip to main content
Glama

teams-reader

Read your own Microsoft Teams chats from the new Teams (v2) desktop app's local cache (and, optionally, the Teams web session) into a searchable SQLite store, and expose them to Claude over MCP — no Microsoft Graph, no admin consent. macOS only. Each user reads only their own chats.

It reads only your own local Teams data. Nothing is uploaded by the tool itself.

How it works

The new Teams app stores chat in a Chromium IndexedDB/LevelDB cache. teams-reader:

  1. locate the work (teams.microsoft.com) LevelDB under the Teams container.

  2. snapshot it (copy, drop LOCK) so Teams can stay running.

  3. dump it to JSONL with dfindexeddb.

  4. parse messages (sender, time, text; reply quotes split out) and chat names.

  5. store them in SQLite with an FTS5 index, idempotently (re-ingest never duplicates).

  6. serve tools to Claude via MCP: list_chats, read_chat, search, recent, ask, chat_profile, and suggest_reply.

Each MCP tool first runs a debounced incremental ingest, so queries always see the latest cached messages without running ingest/daemon by hand.

suggest_reply(chat) returns the recent thread, the chat kind, and a heuristic profile of each participant (language, tone, message length) — Claude uses that to write 2-3 adaptive reply options to copy into the chat. It never sends.

Related MCP server: Apple Messages MCP

Images

Messages reference images by URL on the AMS service; the bytes need the logged-in session. teams-reader records image URLs per message during ingest, then downloads the bytes through the same browser context used for backfill (cookie auth, no CORS). The model reads the downloaded file.

teams-reader fetch-image --chat "Project Sigma" --limit 10

Then, over MCP: list_images("Project Sigma") to see a chat's images, and read_image(msg_id) to get the image inline; the downloaded file is deleted right after it is read.

Full history (browser backfill)

The cache holds only recently synced messages. To pull a chat's full history, teams-reader can read it from the Teams web client's internal chatsvc messages API, reusing your own logged-in session — no Graph, no admin consent.

It drives a real browser (Playwright/Chromium) optionally through a proxy (e.g. a corporate VPN), captures one live chatsvc request (URL + session token), then replays it per conversation and follows the backward-pagination links until history is exhausted. It only reads; nothing is sent.

pip install -e '.[browser]'
python -m playwright install chromium

# If the profile uses a VPN proxy, bring it up first.
teams-reader login                 # one-time: a window opens, log in (MFA)
teams-reader backfill              # sync new/changed chats (real titles from the server)
teams-reader backfill --full       # refetch every chat's history
teams-reader backfill --chat Sigma --max-pages 100

The login persists, so later backfill runs (and the MCP sync_history tool) can reuse the session headless. Set the profile's proxy if Teams is only reachable through a VPN proxy.

Warm browser (MCP server)

The MCP server keeps one headless reader browser open after the first tool call. While the tools are in use it re-syncs changed chats every ~30s in the background (backing off when the VPN or login is unavailable), and sync_history, read_image and read_link reuse it, so they take seconds instead of ~30s. Disable it with live_sync = false in the profile. While it runs it holds that profile's browser, so CLI browser commands for the same profile report "in use" — stop the MCP server first.

Unattended re-login

When the Teams session has expired, user-initiated actions (sync_history, read_image, read_link, CLI login/backfill/fetch-image) sign in again by themselves, using the profile's credentials_env dotenv file and its email_key/password_key (no file configured = never signs in by itself; disable with autologin = false). MFA still needs your phone: the number to enter shows as a macOS notification. A rejected password is never retried. The background sync never signs in, so it cannot spam MFA prompts; it reports login required instead. Try it safely in a throwaway profile: venv/bin/python tools/try_autologin.py.

Requirements

  • macOS, the new Teams app signed into the target account and synced at least once.

  • brew install snappy (the LevelDB reader needs it).

  • Python 3.10+.

Install

macOS with the new Teams desktop app and Homebrew. One command:

curl -fsSL https://raw.githubusercontent.com/dungpham259dev/teams-reader/main/install.sh | bash

It installs snappy and uv if missing, installs the teams-reader CLI, downloads its browser, then runs teams-reader setup, which asks a few questions (profile name, which Teams cache, proxy/VPN, optional automatic re-login, background sync), writes the config, registers the MCP server with Claude Code, and offers to sign in to Teams. Re-run teams-reader setup any time to add or change a profile.

Manual install, if you prefer:

brew install snappy uv
export CPPFLAGS="-I$(brew --prefix snappy)/include" LDFLAGS="-L$(brew --prefix snappy)/lib"
uv tool install --python-preference only-managed --python 3.13 \
  "teams-reader[browser] @ git+https://github.com/dungpham259dev/teams-reader"
teams-reader install-browser
teams-reader setup

The CPPFLAGS/LDFLAGS are needed because a dependency pins python-snappy 0.6.1, which compiles against Homebrew's snappy.

Configuration

Settings live in ~/.config/teams-reader/config.toml as named profiles (see config.example.toml): local cache source, optional proxy (VPN), optional credentials file for unattended re-login, background sync on/off, data folder. Without a config file the default profile reads the work cache, connects directly and never signs in by itself.

teams-reader config                     # show the active profile (no secrets)
teams-reader --profile client-b config  # another profile

Each profile keeps its own store and browser login, and a browser profile can be used by one process at a time (a second one fails fast with "in use"). Register one MCP server per profile so accounts never mix:

claude mcp add teams-reader -- teams-reader mcp                          # default_profile
claude mcp add teams-client-b -- teams-reader --profile client-b mcp

Use

teams-reader setup            # interactive setup: add/change a profile, register with Claude
teams-reader config           # show the active profile's settings
teams-reader locate           # show the Teams cache databases found
teams-reader ingest           # read the cache into the store (one shot)
teams-reader daemon           # keep the store fresh (polls every 45s)
teams-reader login            # one-time browser login for full-history backfill
teams-reader backfill         # sync new/changed chats via the browser session
teams-reader fetch-image      # download chat images via the browser session
teams-reader mcp              # run the MCP server (stdio) for Claude
teams-reader wipe --yes       # delete the store and snapshots

Register the MCP server with Claude Code (see Configuration for profiles):

claude mcp add teams-reader -- teams-reader mcp

Then ask Claude things like "tóm tắt chat Project Sigma" or "tìm tin nhắn về keycloak".

Permissions (macOS)

Cache files live in your own user container, so no admin/sudo is needed. If a run can't read them ("Operation not permitted"), grant your terminal Full Disk Access (System Settings → Privacy & Security → Full Disk Access) and restart it.

Data governance

This stores a local copy of chat content, which may belong to a client. Decide per tenant whether that is acceptable. teams-reader wipe --yes removes the store and all snapshots. The store lives at ~/Library/Application Support/teams-reader/.

Tenant limits

The cache approach depends on the tenant: Conditional Access can block sync on unmanaged devices (empty cache), and Intune app-protection can encrypt the cache (unreadable). Try teams-reader locate and teams-reader ingest on a tenant before relying on it.

Development

PYTHONPATH=. venv/bin/pytest --cov=teams_reader

Tests use synthetic fixtures only — no real chat data is committed.

License

MIT, see LICENSE.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides Claude with read-only access to your WhatsApp chat history entirely on your local machine, enabling natural language search, summarization, and retrieval of messages without sending data to the cloud.
    18 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Lets a Claude Code agent read and post in a fixed allowlist of Microsoft Teams group chats using an ordinary user account, with tools for messaging, replying, editing, deleting, and polling.
    1
    -