outlook-local-mcp
# outlook-local-mcp
Read your local Outlook mailbox from an MCP client. Runs on Windows, attaches to
your existing **classic Outlook** session, and exposes six read-only tools over
standard input/output.
The server is client-independent: use it with local stdio clients such as Codex,
Claude Desktop, Claude Code, Cursor or VS Code. Configuration varies by client;
see [client setup](docs/clients.md) and [tested integrations](docs/status.md).
## Quick start
1. Install [uv](https://docs.astral.sh/uv/getting-started/installation/) once.
No manual Python installation, repository clone or virtual environment is needed.
On Windows, `winget install --id astral-sh.uv --exact` is one option.
2. Open **classic Outlook**, load your profile and resolve any pending dialogs.
New Outlook does not implement the required Object Model.
3. Merge this entry into your MCP client's configuration, preserving other entries:
```json
{
"mcpServers": {
"outlook-local": {
"command": "uvx",
"args": [
"--python", "3.12",
"--constraints", "https://github.com/santiv343/outlook-local-mcp/releases/download/v0.1.0/constraints.txt",
"--from", "https://github.com/santiv343/outlook-local-mcp/releases/download/v0.1.0/outlook_local_mcp-0.1.0-py3-none-any.whl",
"outlook-local-mcp"
]
}
}
}
```
4. Restart the client or reload its MCP servers, then call `outlook_status`.
`uvx` downloads Python and the pinned runtime dependencies on first use. Release
assets come from this repository's GitHub Releases; dependencies come from their
package index. Later starts use uv's cache. Installation and updates need internet.
Run the diagnostic below first if your client has a short startup timeout.
If a desktop client cannot find `uvx`, use its absolute path from
`(Get-Command uvx).Source`. Launch the server on **native Windows**: Linux, WSL,
remote containers and cloud chats cannot directly access this Windows COM session.
## Diagnose and configure
In PowerShell, define the versioned command once:
```powershell
$release = 'https://github.com/santiv343/outlook-local-mcp/releases/download/v0.1.0'
$serverArgs = @(
'--python', '3.12', '--constraints', "$release/constraints.txt",
'--from', "$release/outlook_local_mcp-0.1.0-py3-none-any.whl",
'outlook-local-mcp'
)
uvx @serverArgs doctor
uvx @serverArgs config
```
`doctor` checks the platform, COM registration and running Outlook session with a
deadline. It reports status, version and counts without account names or messages.
The MCP tools perform these same checks lazily. The server still starts and
advertises its tools when Outlook is unavailable.
`config` prints generic JSON with the installed `uvx` path. The optional
`configure-claude` command discovers Claude Desktop's settings, preserves existing
entries, backs up the file and writes atomically. Use `--dry-run` to preview changes.
A conflicting entry requires `--replace`; ambiguous installations require
`--config-path`. Invalid JSON is never overwritten. Restart Claude after updating.
For Codex and other clients, see [client setup](docs/clients.md).
## Tools
| Tool | Purpose |
| --- | --- |
| `outlook_status` | Availability, version and connection diagnosis |
| `list_mailboxes` | Stores accessible through the current Outlook session |
| `list_folders` | Immediate children of a store root or selected folder |
| `recent_emails` | Recent summaries, without bodies |
| `search_emails` | Literal text and metadata filters in one folder |
| `read_email` | Plain text body pages and attachment metadata |
**An empty partial search page does not mean no messages match.** Follow its
cursor and inspect coverage and warnings. See [tool contracts](docs/tools.md).
## Scope and privacy
- Windows 10/11, classic Outlook with a configured profile, CPython 3.11/3.12.
The recommended command provisions Python 3.12 automatically.
- Reads stores, mounted archives and shared stores already available in Outlook.
Does not add accounts, open external PST files or grant access.
- No sending, replying, deleting, moving, saving or marking read. No opening links,
running HTML, fetching remote images or downloading attachments.
- No Azure app registration or stored email credentials. Outlook profile permissions
and corporate Object Model protections still apply.
- The server makes no outbound network connections of its own and has no telemetry.
Outlook itself can synchronize with its provider.
- Logs contain operation, duration, counts and stable error codes only. No message
contents, addresses, mailbox IDs, searches or raw COM exceptions are logged.
- **Returned mail data reaches the requesting AI client.** Local Outlook access
does not make the client's model processing local. Check your client's data policy.
- Mail is untrusted external content. Tool descriptions tell agents to treat its
instructions as data; this does not enforce what an agent does with other tools.
Microsoft documents [classic/new Outlook differences](https://support.microsoft.com/en-us/outlook/getstarted/feature-comparison-between-new-outlook-and-classic-outlook)
and [Object Model security](https://learn.microsoft.com/en-us/office/vba/outlook/security/security-behavior-of-the-outlook-object-model).
## Development
```powershell
uv sync --locked --python 3.12
uv run --locked ruff check .
uv run --locked ruff format --check .
uv run --locked mypy
uv run --locked pytest
uv build --no-sources
```
Tests use synthetic COM objects and real subprocess/MCP transports. Windows CI
checks Python 3.11 and 3.12 without a mailbox. For the real Outlook journey, open
Outlook and run `uv run --locked python scripts/smoke_test.py`. This reads messages
but prints only counts and pass/fail. Never publish mailbox data or personal config.
[Architecture](docs/architecture.md) · [Troubleshooting](docs/troubleshooting.md) ·
[Security](SECURITY.md) · [MIT license](LICENSE)
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose: outlook_status for diagnostics, list_mailboxes/list_folders for navigation, recent_emails vs search_emails for retrieval vs filtered search, and read_email for content. The descriptions explicitly clarify the boundary between browsing (recent_emails) and searching (search_emails) and between folder-level and message-level operations.
Five of six tools follow a consistent verb_noun or noun pattern (list_mailboxes, list_folders, search_emails, read_email, outlook_status). The outlier recent_emails uses an adjective_noun form rather than something like list_recent_emails, a minor deviation within an otherwise readable set.
Six tools is well-scoped for a local Outlook reader, with each tool earning its place across the status, navigation, listing, search, and read stages. Nothing feels padded or missing at the count level.
The read-side lifecycle is well covered: diagnostics, mailbox/folder navigation, listing, searching, and full-body reading with pagination. Gaps remain on the write side (send, reply, move, mark read/unread, attachment download), though for a read-only local reader this is a minor limitation agents can work around by not mutating state.