office365-blade-mcp
A token-efficient Microsoft 365 MCP server for email, calendar, and tasks -- all through one connection.
Built on the Model Context Protocol and Microsoft Graph API. Ships 38 tools with pipe-delimited output, field selection, null omission, write-gating, and dual auth. Designed to give LLMs maximum signal per token.
Why This Over Microsoft's Official Graph MCP Servers?
| office365-blade-mcp | Microsoft reference servers | |
|---|---|---|
| Scope | Email + Calendar + Tasks in ONE server | Split across separate repos |
| Output | Pipe-delimited, field-selected, nulls omitted | Raw JSON blobs (10-50x more tokens) |
| Auth | Dual: device code (interactive) + client credentials (headless/CI) | Single flow per server |
| Safety | Write-gated by default, delete confirmation, credential scrubbing | Varies |
| Sync | Delta tokens for incremental email sync | Full re-fetch |
| Convenience | cal_today, cal_week, task_today, task_inbox |
Build your own queries |
| Batch | email_bulk (up to 50 ops), cal_batch (multi-calendar) |
Individual calls |
The output format alone justifies the switch. A 20-email search result that costs ~8K tokens from raw Graph JSON costs ~800 tokens here.
Features
- 38 tools across email, calendar, To Do, and Planner
- Token-efficient output -- pipe-delimited tables with
$selectoptimization and null omission - Write-gated by default -- read-only until you explicitly enable writes
- Dual authentication -- device code flow for interactive use, client credentials for daemons and CI
- Incremental sync -- delta tokens for email change tracking without re-fetching
- Batch operations -- bulk email actions (up to 50), multi-calendar event fetch
- Purpose-built views --
cal_today,cal_week,task_today,task_inboxfor common queries - FastMCP 2.0 -- stdio and HTTP transports
Quick Start
# Install
uvx office365-blade-mcp
# Or clone and install
git clone https://github.com/groupthink-dev/office365-blade-mcp.git
cd office365-blade-mcp
uv sync
# Configure
export O365_TENANT_ID="your-tenant-id"
export O365_CLIENT_ID="your-client-id"
export O365_AUTH_MODE="device_code"
# Run (stdio)
uv run office365-blade-mcp
On first run with device_code auth, you'll be prompted to authenticate in your browser.
Tools
Email -- Meta
| Tool | Description |
|---|---|
o365_info |
Account and tenant info, health check |
email_folders |
List mail folders with unread/total counts |
Email -- Read
| Tool | Description |
|---|---|
email_search |
Search with OData filters and text queries |
email_read |
Full email content with body |
email_thread |
Conversation view -- all messages in a thread |
email_snippets |
Search with context excerpts for quick triage |
Email -- Attachments
| Tool | Description |
|---|---|
email_attachments |
List attachments for an email |
Email -- Sync
| Tool | Description |
|---|---|
email_state |
Get a delta token for current mailbox state |
email_changes |
Incremental changes since a previous delta token |
Email -- Write (gated)
| Tool | Description |
|---|---|
email_send |
Send a new email |
email_reply |
Reply to an email |
email_forward |
Forward an email |
email_flag |
Flag/unflag an email |
email_move |
Move email to a folder |
email_delete |
Delete an email (requires confirmation) |
email_bulk |
Batch operations on up to 50 emails |
Calendar -- Read
| Tool | Description |
|---|---|
cal_calendars |
List available calendars |
cal_events |
Events in a date range |
cal_event |
Full event detail by ID |
cal_search |
Search events by text |
cal_today |
Today's events across all calendars |
cal_week |
This week's events across all calendars |
Calendar -- Write (gated)
| Tool | Description |
|---|---|
cal_freebusy |
Check availability for scheduling |
cal_batch |
Fetch events from multiple calendars in one call |
cal_respond |
Accept, decline, or tentatively accept an invite |
cal_create |
Create a new calendar event |
cal_update |
Update an existing event |
cal_delete |
Delete an event (requires confirmation) |
Tasks -- To Do
| Tool | Description |
|---|---|
task_lists |
List all task lists |
task_list |
Tasks in a specific list |
task_search |
Search tasks by text |
task_today |
Tasks due today |
task_inbox |
Tasks in the default list |
task_create |
Create a task (gated) |
task_update |
Update a task (gated) |
task_complete |
Mark a task complete (gated) |
Tasks -- Planner
| Tool | Description |
|---|---|
planner_plans |
List Planner plans |
planner_tasks |
Tasks in a Planner plan |
Output Format
All read tools return pipe-delimited, field-selected output with null fields omitted. This keeps LLM context tight.
Raw Graph API response (~400 tokens):
{"id": "AAMk...", "subject": "Q3 Review", "from": {"emailAddress": {"name": "Alice", "address": "alice@contoso.com"}}, "receivedDateTime": "2026-03-28T14:30:00Z", "isRead": true, "importance": "normal", "hasAttachments": false, "bodyPreview": "Hi team, please review the attached...", "flag": {"flagStatus": "notFlagged"}, "categories": [], ...}
office365-blade-mcp response (~40 tokens):
AAMk...|Q3 Review|Alice <alice@contoso.com>|2026-03-28 14:30|read|Hi team, please review the attached...
Authentication
Device Code (interactive)
For desktop use and development. Prompts for browser-based login.
export O365_AUTH_MODE="device_code"
export O365_TENANT_ID="your-tenant-id"
export O365_CLIENT_ID="your-client-id"
Client Credentials (headless)
For daemons, CI pipelines, and unattended operation. Requires a client secret and admin-consented app registration.
export O365_AUTH_MODE="client_credentials"
export O365_TENANT_ID="your-tenant-id"
export O365_CLIENT_ID="your-client-id"
export O365_CLIENT_SECRET="your-client-secret"
Security Model
| Layer | Behaviour |
|---|---|
| Write gate | All write/delete tools disabled by default. Enable with O365_WRITE_ENABLED=true |
| Delete confirmation | Delete operations require explicit confirmation parameters |
| Credential scrubbing | Bearer tokens and secrets never appear in tool output or logs |
| Bearer auth | Optional API token for HTTP transport via O365_MCP_API_TOKEN |
| Minimal scopes | Requests use $select to fetch only the fields needed |
Claude Desktop Config
{
"mcpServers": {
"office365": {
"command": "uvx",
"args": ["office365-blade-mcp"],
"env": {
"O365_TENANT_ID": "your-tenant-id",
"O365_CLIENT_ID": "your-client-id",
"O365_AUTH_MODE": "device_code"
}
}
}
}
Claude Code Config
{
"mcpServers": {
"office365": {
"command": "uvx",
"args": ["office365-blade-mcp"],
"env": {
"O365_TENANT_ID": "your-tenant-id",
"O365_CLIENT_ID": "your-client-id",
"O365_AUTH_MODE": "device_code",
"O365_WRITE_ENABLED": "true"
}
}
}
}
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
O365_TENANT_ID |
Yes | -- | Azure AD tenant ID |
O365_CLIENT_ID |
Yes | -- | App registration client ID |
O365_CLIENT_SECRET |
For client_credentials | -- | App registration client secret |
O365_AUTH_MODE |
No | device_code |
device_code or client_credentials |
O365_WRITE_ENABLED |
No | false |
Enable write/delete tools |
O365_MCP_TRANSPORT |
No | stdio |
stdio or http |
O365_MCP_HOST |
No | 127.0.0.1 |
HTTP transport bind address |
O365_MCP_PORT |
No | 8000 |
HTTP transport port |
O365_MCP_API_TOKEN |
No | -- | Bearer token for HTTP transport auth |
Architecture
src/office365_blade_mcp/
├── server.py # FastMCP 2.0 server, 38 @mcp.tool decorators
├── client.py # GraphClient: dual auth, token refresh, $select optimization
├── formatters.py # Token-efficient output: pipe-delimited, null omission, field selection
├── models.py # Config dataclass, write-gate logic, constants
└── auth.py # Device code + client credentials flows, bearer middleware
Development
# Install dependencies
uv sync
# Run locally (stdio)
uv run office365-blade-mcp
# Run with HTTP transport
O365_MCP_TRANSPORT=http uv run office365-blade-mcp
# Lint
uv run ruff check .
# Format
uv run ruff format .
License
MIT
Metadata
Release files for office365-blade-mcp 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| office365_blade_mcp-0.2.0.tar.gz | 32.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| office365_blade_mcp-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.6 kB
Release files / office365_blade_mcp-0.2.0.tar.gz
| Download URL | office365_blade_mcp-0.2.0.tar.gz |
|---|---|
| Size | 32.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d87ffc98c1943dabe6c499dc5f5ad2722a0a7f92bd3074ede0663d67a832a1f6
|
|
BLAKE2b-256 checksum How to use checksums |
b8e5c756ba41cf68b2b3ad6e60458f690b9261fe4b88c63e8f5d40922713daa3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.
Transparency logRelease files / office365_blade_mcp-0.2.0-py3-none-any.whl
| Download URL | office365_blade_mcp-0.2.0-py3-none-any.whl |
|---|---|
| Size | 27.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
96f5a90e1eb7a4bf7b09305c6e393330531c4c5a7925765235f5a9144b62967d
|
|
BLAKE2b-256 checksum How to use checksums |
436309339c49480b6b44984a1899dff1f993a2450ab9e1f16d5fa2bf56483852
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.
Transparency log