outlook-triage-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@outlook-triage-mcp Give me my daily briefing for the last 48 hours."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
outlook-triage-mcp
MCP server for Microsoft 365 mail — search, classify, and triage your inbox from Claude via Microsoft Graph: daily-briefing digest, idempotent inbox-rule provisioning, attachment extraction. Device-code auth, read-only by default.
🇺🇸 English
Your inbox, triaged by Claude — without handing anyone your password. This MCP server connects Claude (Code or Desktop) to a Microsoft 365 mailbox through Microsoft Graph, using device-code sign-in and a local token cache. It classifies mail with deterministic keyword heuristics (no LLM calls at runtime, no message content leaving your machine beyond what you ask Claude to read), builds a morning briefing, and can — only if you explicitly opt in — provision inbox rules idempotently.
Features
Daily briefing — classifies the last N hours of inbox mail into
urgent/action_needed/fyi/newsletterand renders a Markdown digest. Heuristics are deterministic and configurable (env vars or a JSON file); messages you already read are never flagged as pending.Search & read — Graph
$search/$filtermessage search in any folder; full plain-text bodies; local text extraction from PDF / DOCX / XLSX attachments (pypdf, python-docx, openpyxl — parsing is 100% local).Idempotent inbox rules —
ensure_inbox_ruleconverges mailbox state: an already-correct rule triggers zero write calls, a divergent one is patched, a missing one is created (folder included). Run it a hundred times, get one rule.Device-code auth — MSAL public-client flow: the
auth_statustool hands you a URL and a code; sign in from any browser. Tokens are cached in~/.local/share/outlook-triage-mcp/(never in the repo,0600permissions) and refreshed silently.Read-only by default — the server requests only
Mail.Read/MailboxSettings.Readscopes unless you setOUTLOOK_MCP_ENABLE_WRITE=1.Retry/backoff — Graph calls honor
Retry-Afteron 429 and back off exponentially on 5xx.
⚠️ Write access
ensure_inbox_rule is the ONLY tool that writes to your mailbox. Every other tool is strictly read-only (and annotated as such in the MCP tool metadata). Rule provisioning is disabled by default: the tool refuses to run until you start the server with OUTLOOK_MCP_ENABLE_WRITE=1 and re-authenticate with write scopes. The server never sends, deletes, moves, or marks messages.
Tools
Tool | Access | Description |
| read-only | Token state; starts device-code sign-in and returns the URL + code when login is needed |
| read-only | Search (KQL) or list messages; |
| read-only | Full body + metadata; optionally extracts text from PDF/DOCX/XLSX attachments locally |
| read-only | Markdown digest classified into urgent / action_needed / fyi / newsletter |
| read-only | Inventory of inbox rules with conditions and actions |
| WRITE | Idempotently converge one rule (sender contains X → move to folder Y); creates the folder if missing |
Example prompts once connected:
"Give me my daily briefing for the last 48 hours." "Search my inbox for messages about the Q3 invoice and read the newest one, including attachments." "Make sure there's a rule moving everything from recruiting@ to a Recruiters folder." (requires write mode)
How it works
flowchart LR
subgraph Claude["Claude (Code / Desktop)"]
C[MCP client]
end
subgraph Server["outlook-triage-mcp (local)"]
T[FastMCP tools]
H[Heuristic classifier<br/>deterministic, no LLM]
A[MSAL device-code auth<br/>token cache ~/.local/share]
G[Graph client<br/>retry + backoff]
X[Attachment extraction<br/>PDF / DOCX / XLSX, local]
end
M[(Microsoft Graph<br/>Microsoft 365 mailbox)]
C <-->|stdio JSON-RPC| T
T --> H
T --> X
T --> G
G --> A
G <-->|HTTPS, delegated scopes| MInstall
git clone https://github.com/giuseppeferretti/outlook-triage-mcp
cd outlook-triage-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[attachments]" # attachments extra enables PDF/DOCX/XLSX parsingConfigure Claude
Claude Code:
claude mcp add outlook-triage -- /path/to/.venv/bin/outlook-triage-mcpClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"outlook-triage": {
"command": "/path/to/.venv/bin/outlook-triage-mcp",
"env": {
"OUTLOOK_MCP_USER_EMAIL": "you@yourcompany.com"
}
}
}
}First use: ask Claude to call auth_status, open the verification URL it returns, type the code, done. The token is cached locally; you will rarely need to sign in again.
Configuration (env vars)
Variable | Default | Purpose |
| Microsoft Graph CLI public client ( | Azure AD app registration. The default is Microsoft's own Graph CLI public client, which is pre-authorized for delegated mail scopes on most tenants (the older Azure CLI client is blocked for |
|
| Restrict sign-in to a specific tenant |
| — | Your address; used to pick the cached account and to classify self-sent mail |
|
| Set |
|
| Token cache location |
| — | JSON file overriding heuristic keyword lists |
| built-in lists | Comma-separated overrides for individual heuristic lists |
|
| Attachments larger than this are listed, not parsed |
Classification file example (classify.json):
{
"urgent_keywords": ["urgent", "asap", "outage"],
"action_keywords": ["please review", "sign off"],
"vip_senders": ["ceo@yourcompany.com"],
"newsletter_sender_patterns": ["noreply@", "digest@"]
}Development
pip install -e ".[dev]"
pytest # all offline: fixture JSON + fake Graph + stdio smoke test
OUTLOOK_MCP_LIVE_TESTS=1 pytest tests/test_graph_live.py # optional, real GraphThe test suite requires no Microsoft account: classification and rule-idempotency tests run against fake Graph responses, and the MCP smoke test boots the real stdio server with the official SDK client and verifies the tool list and graceful auth-required behavior.
Provenance
This server was extracted from a production Microsoft 365 automation system — a daily-briefing robot and idempotent inbox-rule provisioner that runs every morning for a real controllership workflow. The battle-tested parts were kept (device-code auth with token cache, Graph retry/backoff, write-free classification, converge-don't-duplicate rule provisioning) and the client-specific heuristics were genericized into configurable keyword lists. Case study at portfolio.iterlabs.com.br.
Related MCP server: m365-mcp
🇧🇷 Português
Servidor MCP para e-mail Microsoft 365 — busque, classifique e faça triagem da sua caixa de entrada pelo Claude via Microsoft Graph. Autenticação por device-code (sem senha no servidor), token em cache local, somente leitura por padrão.
Recursos
Briefing diário: classifica as últimas N horas em
urgent/action_needed/fyi/newslettercom heurísticas determinísticas (sem LLM em runtime), configuráveis por env ou arquivo JSON. Mensagens já lidas nunca aparecem como pendentes.Busca e leitura: pesquisa Graph em qualquer pasta, corpo completo em texto e extração local de texto de anexos PDF / DOCX / XLSX.
Regras idempotentes:
ensure_inbox_ruleconverge o estado da caixa — regra já correta gera zero chamadas de escrita; nunca duplica regra nem pasta.Retry/backoff nas chamadas Graph (respeita
Retry-Afterem 429).
⚠️ Escrita
ensure_inbox_rule é a ÚNICA ferramenta que escreve na caixa. Todas as outras são somente leitura. Escrita fica desabilitada até você definir OUTLOOK_MCP_ENABLE_WRITE=1 e autenticar novamente com escopos de escrita. O servidor nunca envia, exclui, move ou marca mensagens.
Instalação e uso
git clone https://github.com/giuseppeferretti/outlook-triage-mcp
cd outlook-triage-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[attachments]"
claude mcp add outlook-triage -- /caminho/para/.venv/bin/outlook-triage-mcpNo primeiro uso, peça ao Claude para chamar auth_status: ele devolve uma URL e um código — abra no navegador, digite o código e pronto. O token fica em cache em ~/.local/share/outlook-triage-mcp/ (nunca no repositório).
Configuração principal: OUTLOOK_MCP_CLIENT_ID (padrão: client público do Microsoft Graph CLI; registre seu próprio app se o tenant bloquear), OUTLOOK_MCP_TENANT_ID, OUTLOOK_MCP_USER_EMAIL, OUTLOOK_MCP_ENABLE_WRITE e as listas de palavras-chave OUTLOOK_MCP_*_KEYWORDS / OUTLOOK_MCP_VIP_SENDERS.
Testes: pytest roda 100% offline (fixtures JSON + Graph falso + smoke test MCP stdio com o SDK oficial). Testes contra o Graph real são opcionais: OUTLOOK_MCP_LIVE_TESTS=1.
Origem
Extraído de um sistema de automação Microsoft 365 em produção (robô de briefing diário + provisionamento idempotente de regras), com as heurísticas do cliente genericizadas em listas configuráveis. Case em portfolio.iterlabs.com.br.
Built with AI-assisted development; designed, verified, and operated by Giuseppe Ferretti.
Available Tools
6 toolsauth_statusARead-only
Check Microsoft 365 auth state; start device-code sign-in if needed.
When sign-in is required, returns a verification URL and a user code — relay both to the user, then call this tool again to confirm completion.
Inputs: no named parameters.
daily_briefingARead-only
Classified digest of recent inbox mail. Read-only, no LLM calls.
Groups messages from the last N hours into: urgent, action_needed, fyi, newsletter — using deterministic keyword heuristics (configurable via OUTLOOK_MCP_* env vars or a JSON rules file). Returns Markdown.
Inputs: hours. Returns: result
ensure_inbox_ruleAIdempotent
Idempotently provision one inbox rule. THE ONLY WRITE TOOL.
Creates (or converges) a rule: messages whose sender matches
from_contains are moved to folder move_to_folder (created if
missing). Safe to run repeatedly — an already-correct rule results in
zero write calls; never duplicates rules or folders.
Disabled unless the server runs with OUTLOOK_MCP_ENABLE_WRITE=1 (which also requires re-consenting to write scopes on next sign-in).
Args: name: Rule display name — the idempotency key. from_contains: Substring matched against the sender address/name. move_to_folder: Target folder display name.
Inputs: name (required), from_contains (required), move_to_folder (required).
get_messageARead-only
Fetch one message: full plain-text body plus metadata. Read-only.
Args: message_id: Graph message id (from search_messages or daily_briefing). include_attachments: Also download attachments and extract text locally from PDF / DOCX / XLSX (other types are listed only).
Inputs: message_id (required), include_attachments.
list_inbox_rulesARead-only
List all inbox message rules (name, state, conditions, actions). Read-only.
Inputs: no named parameters.
search_messagesARead-only
Search or list mail messages. Read-only.
Args: query: Free-text search (Graph $search / KQL, e.g. 'invoice', 'from:alice subject:report'). Empty = list newest first. folder: Well-known folder (inbox, archive, drafts, sentitems, deleteditems, junkemail, outbox) or a custom folder display name. top: Max messages to return (1-100). since: Only messages received after this point. ISO 8601 ('2026-07-01T00:00:00Z') or relative ('24h', '7d').
Inputs: top, query, since, folder.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
Each tool has a clear and distinct purpose: auth_status for authentication, daily_briefing for digest, ensure_inbox_rule for rule creation, get_message for fetching a single message, list_inbox_rules for listing rules, and search_messages for searching. No two tools overlap in functionality.
While most names follow a verb_noun pattern (e.g., ensure_inbox_rule, get_message), some deviate: daily_briefing is a noun phrase, and auth_status is noun_noun. This inconsistency, though not severe, prevents a higher score.
Six tools is an appropriate scope for an Outlook triage server, covering authentication, inbox digest, rule management, message retrieval, rule listing, and message search. None seem redundant or missing for the stated purpose.
The server covers reading (search, get, digest) and rule creation, but lacks message actions (delete, move, mark as read) and rule deletion. This is a notable gap for a triage tool, as users cannot act on individual messages beyond reading.
Maintenance
Related MCP Connectors
Hosted Mailchimp MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
MCP server for Nylas — read email, calendars, events and contacts, and send email or create events.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for Claude to access Outlook data via Microsoft Graph API2089 npm1MIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that gives Claude Code (or any MCP client) controlled access to Microsoft 365 through the Microsoft Graph API: mail, calendar, contacts, files, notes, tasks, Teams, SharePoint, and the full tenant-admin surface.33 npm1MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that enables Claude to manage Outlook emails, including reading, sending, organizing, drafting, and bulk operations via Microsoft Graph API.15 npm1MIT
- AlicenseAqualityDmaintenanceA local MCP server that connects Claude Desktop to a personal Hotmail/Outlook.com mailbox via Microsoft Graph API, enabling email management, rule handling, and composing messages.25MIT