outlook-ews-mcp
Secure MCP server for on-prem Microsoft Exchange (EWS) with tools for email, calendar, contacts, folders, attachments, and free/busy availability.
Install / Use
claude mcp add viartemev -- npx -y github:viartemev/outlook-ews-mcpIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
AutomationSupported Platforms
Our assessment of outlook-ews-mcp
outlook-ews-mcp scores 84/100 on our quality scale, 2110th of 2,881 Automation skills we index.
Its MCP Server is 22 KB long, well organised into 22 sections with 8 code examples: a thorough specification that gives an agent plenty to work with.
It has 10 GitHub stars, so there is little community track record yet; judge it on its content.
Maintenance, license and trust
- The repository was last updated 11 days ago, so outlook-ews-mcp is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 97/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
outlook-ews-mcp compared with similar skills
All 4 of these similar skills score higher than outlook-ews-mcp; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| outlook-ews-mcp (this skill)by viartemev | 84 | 10 | 11d ago | MCP Server |
| Agent-Reachby Panniantong | 100 | 97.0k | 5d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 75.2k | today | CLAUDE.md |
| CowAgentby zhayujie | 100 | 47.4k | today | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 87.3k | today | MCP Server |
Frequently asked questions
- How do I install outlook-ews-mcp?
- Run
claude mcp add viartemev -- npx -y github:viartemev/outlook-ews-mcp. The install tabs above show the steps for each supported agent. - Which AI agents does outlook-ews-mcp work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is outlook-ews-mcp safe to use?
- It is MIT-licensed and scores 97/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is outlook-ews-mcp still maintained?
- The repository was last updated 11 days ago, so outlook-ews-mcp is actively maintained.
Skill content
View source on GitHuboutlook-ews-mcp
<p align="right"><b>English</b> · <a href="README.ru.md">Русский</a></p>
outlook-ews-mcp is an MCP server for on-prem Microsoft
Exchange via EWS (exchangelib). It gives
MCP-compatible clients (Claude Desktop, Claude Code, and any other MCP client) access to
email, calendar, contacts, folders, attachments, and availability data through a single,
testable Python service — no direct mailbox scripting required.
Renamed from
outlook-mcp. That name was already taken on PyPI by an unrelated project, so the distribution and CLI name are nowoutlook-ews-mcp. The Python import path is unchanged. Until the first tagged PyPI release, install from this repository as shown below.
Contents
- Highlights
- Tool catalog
- Typical use cases
- Security notes
- Quick start
- Configuration
- Request queue
- Claude Desktop example
- Smoke check
- Docker
- CI/CD
- Development
- Project notes
- Contributing
- License
Highlights
- Email — list, search (substring or Advanced Query Syntax), read, send, reply, forward, move, copy, delete, mark, categorize, bulk actions, raw MIME export, attachment add/delete
- System — Inbox Rules, Out-of-Office (automatic replies), read-only delegate listing
- Calendar — list, create, update, delete, respond to invites, find free slots, view a shared/delegate mailbox's calendar, Room Finder, bulk actions
- Contacts — search, read, create, update, delete
- Folders & attachments — folder CRUD and attachment download
- Auth —
NTLMandBasicagainst on-prem Exchange - Transport —
stdioandSSE - Architecture — centralized error mapping through a single
ExchangeClientabstraction (see Project notes) - Safety — a privacy-safer smoke check by default (see Smoke check)
- Ops — Docker image plus GitHub and GitLab CI/CD pipelines included
Tool catalog
Every tool below is registered in tool_specs.py, the
single source of truth for its name, description, and schema. Read-only marks tools
that never modify the mailbox — they get more concurrency (see
Request queue) and are safe to call speculatively.
System
| Tool | Description | Read-only |
| --- | --- | --- |
| ping_exchange | Check connectivity to Exchange | ✅ |
| get_mailbox_info | Get mailbox metadata | ✅ |
| list_delegates | List mailbox delegates and their folder permission levels — read-only because exchangelib has no delegate write support | ✅ |
| list_inbox_rules | List server-side inbox rules | ✅ |
| create_inbox_rule | Create a server-side inbox rule, e.g. "from this sender → move to folder" | |
| update_inbox_rule | Enable/disable a rule or change its priority (other fields aren't updatable here) | |
| delete_inbox_rule | Delete a server-side inbox rule by id | |
| get_out_of_office | Get the out-of-office (automatic reply) settings | ✅ |
| set_out_of_office | Turn automatic replies off, on, or schedule a start/end window | |
⚠️
create_inbox_rule/update_inbox_rule/delete_inbox_rulemanage rules over EWS, which removes the client-side rule blob desktop Outlook keeps — this can wipe rules a user created in Outlook itself. This is documented EWS behavior, not a bug here.
| Tool | Description | Read-only |
| --- | --- | --- |
| list_emails | List emails in a folder | ✅ |
| get_email | Get a full email by id | ✅ |
| get_email_mime | Export a message's raw RFC 822 MIME content, base64-encoded | ✅ |
| get_thread | Get every message of a conversation in order, bodies included | ✅ |
| search_emails | Search by substring (subject/body/sender) or server-side Advanced Query Syntax | ✅ |
| send_email | Send a new email | |
| reply_email | Reply to an email | |
| forward_email | Forward an email | |
| move_email | Move an email to another folder | |
| copy_email | Copy an email to another folder | |
| move_emails | Bulk move, with per-item results — one bad id doesn't fail the rest | |
| copy_emails | Bulk copy, with per-item results | |
| delete_emails | Bulk delete, with per-item results (soft-deletes unless hard_delete) | |
| delete_email | Delete an email | |
| mark_email | Update read state, importance, or the follow-up flag | |
| categorize_email | Set, add, or remove Outlook categories (the coloured labels) | |
| mark_emails | Bulk version of mark_email, with per-item results | |
| categorize_emails | Bulk version of categorize_email, with per-item results | |
| list_categories | List categories in use with counts, sampled from recent messages (not the mailbox master category list) | ✅ |
| list_folders | List mailbox folders | ✅ |
| create_folder | Create a mailbox folder | |
| rename_folder | Rename a folder — refuses built-in folders (Inbox, Sent Items, Calendar, ...) | |
| delete_folder | Delete a folder and everything in it — refuses built-in folders | |
| create_draft | Create an email draft | |
| create_reply_draft | Create a reply-all draft in the original conversation, with additional recipients, mentions and attachments; does not send | |
| update_draft | Update a draft; omitted fields are left unchanged, attachments (if given) replaces the whole set | |
| send_draft | Submit a draft and confirm its copy in Sent Items | |
| add_attachment | Attach a local file to a message, typically a draft — the file must live under EXCHANGE_ATTACHMENT_ROOT | |
| delete_attachment | Remove one attachment from a message by id | |
| get_attachment | Save an attachment to disk | ✅ |
Calendar
| Tool | Description | Read-only |
| --- | --- | --- |
| list_events | List calendar events in a time range; pass mailbox for a colleague's default calendar (needs delegate/impersonation access, not combinable with calendar_id) | ✅ |
| get_event | Get a calendar event by id; pass mailbox for a colleague's calendar | ✅ |
| create_event | Create a calendar event | |
| update_event | Update a calendar event | |
| delete_event | Delete a calendar event | |
| respond_to_invite | Accept, decline, or tentatively respond to an invite | |
| find_free_slots | Find open meeting time slots | ✅ |
| delete_events | Bulk delete events, with per-item results | |
| respond_to_invites | Bulk respond to invites, with per-item results | |
| get_my_availability | Get free/busy slots; pass mailbox for a colleague's calendar | ✅ |
| list_calendars | List calendars | ✅ |
| list_room_lists | List Room Finder room lists (groups of meeting rooms) | ✅ |
| list_rooms | List the meeting rooms in a Room Finder room list | ✅ |
Contacts
| Tool | Description | Read-only |
| --- | --- | --- |
| search_contacts | Search contacts | ✅ |
| get_contact | Get a contact by id | ✅ |
| create_contact | Create a personal contact | |
| update_contact | Update a personal contact | |
| delete_contact | Delete a personal contact | |
Typical use cases
- Connect Claude Desktop or another MCP client to on-prem Exchange
- Search inbox messages and fetch full email content
- Send or draft emails from AI workflows
- Inspect calendars and create meetings
- Check free/busy windows for scheduling
- Search personal contacts or the Global Address List
- Expose Exchange operations through a controlled MCP boundary instead of direct mailbox scripting
Security notes
What the current code does:
| | |
| --- | --- |
| Scoped connectivity | Connects only to the Exchange/EWS endpoint configured in EXCHANGE_SERVER |
| No telemetry | Contains no telemetry, analytics, or third-party data export logic |
| Secrets stay local | Keeps secrets in environment variables / .env, ignored by .gitignore (.env, .env.*, while keeping .env.example) |
| Clean error payloads | Structured MCP error responses never include raw Exchange exception text, message bodies, attachment contents, or passwords; successful tools return only the mailbox data they were asked for |
| Clean logs | LOG_LEVEL only controls the app's own outlook_mcp.* loggers; exchangelib's SOAP XML loggers — which would otherwise dump full request/response XML, even at ERROR level on transport errors — are always force-silenced |
| Clean Docker builds | .dockerignore excludes .env, tests, caches, and VCS metadata from the build context |
What you should still be careful with:
EXCHANGE_VERIFY_SSL=falsedisables TLS certificate verification — trusted internal/self-signed environments only.EXCHANGE_AUTH_TYPE=Basicsends credentials in the clear, so the server refuses to start against anhttp://EXCHANGE_SERVER; only override withEXCHANGE_ALLOW_INSECURE_BASIC_AUTH=truefor a local/test server you control.get_attachmentwrites files to disk, andsend_email/reply_email/forward_email/create_draftread local files (viaattachments) and attach their contents to outgoing mail. Combined with untrusted email content, this is a plausible path for prompt-injected exfiltration of any file readable by the process. Local file access is refused by default and only works onceEXCHANGE_ATTACHMENT_ROOTis set to an absolute directory, which then confines bothattachmentspaths andget_attachment'ssave_pathto that directory tree (an unsetsave_pathstill falls back to the system temp directory).outlook-ews-mcp-smokeis privacy-safe by default and prints only masked mailbox info plus counts; setOUTLOOK_MCP_SMOKE_INCLUDE_DATA=trueonly if you explicitly want real inbox/event data in stdout.- If you enable file logging with
LOG_FILE, protect that file with OS permissions. - If you publish Docker images from CI, protect GitLab/GitHub project access and registry permissions.
Quick start
uv venv
source .venv/bin/activate
uv pip install -e .[dev]
cp .env.example .env
outlook-ews-mcp
By default the server runs in stdio mode. Set MCP_TRANSPORT=sse to start an HTTP
server instead.
Configuration
Minimal .env to get started — everything else below has a working default:
EXCHANGE_SERVER=https://mail.company.com/EWS/Exchange.asmx
EXCHANGE_USERNAME=DOMAIN\username
EXCHANGE_PASSWORD=secret
EXCHANGE_EMAIL_ADDRESS=user@company.com
EXCHANGE_AUTH_TYPE=NTLM
A fully commented copy of every variable lives in .env.example.
| Variable | Default | Description |
| --- | --- | --- |
| EXCHANGE_SERVER | (required) | EWS endpoint URL, e.g. https://mail.company.com/EWS/Exchange.asmx |
| EXCHANGE_USERNAME | (required) | DOMAIN\username or a UPN. Exactly one backslash — dotenv does not process escape sequences |
| EXCHANGE_PASSWORD | (required) | Account password |
| EXCHANGE_EMAIL_ADDRESS | unset | SMTP address; set when EXCHANGE_USERNAME isn't one |
| EXCHANGE_AUTH_TYPE | NTLM | NTLM or Basic |
| EXCHANGE_ALLOW_INSECURE_BASIC_AUTH | false | Allow Basic auth over http:// — local/test servers only |
| EXCHANGE_VERIFY_SSL | true | Verify the server's TLS certificate; false only for trusted internal/self-signed setups |
| EXCHANGE_VERSION | unset (auto-detected) | Exchange server version, e.g. EXCHANGE_2016 |
| EXCHANGE_TIMEZONE_FALLBACK | Europe/Moscow | Used only when Exch
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
97.0kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
75.2kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.4kOpen-source personal AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
Scrapling
87.3k🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
