m365-mcp-server
A production-ready MCP (Model Context Protocol) server for Microsoft 365, providing secure access to Email, SharePoint, and OneDrive through Azure AD/Entra ID authentication with OAuth 2.1 + PKCE.
Features
- Email Access: List folders, search messages, read email content (including shared mailboxes)
- Calendar Access: List calendars, browse events, expand recurring events with date ranges
- SharePoint/OneDrive: Browse sites, drives, folders, and read file content
- Document Parsing: Extracts readable text from PDF, Word, Excel, PowerPoint, CSV, and HTML files
- OAuth 2.1 + PKCE: Secure authentication via Azure AD/Entra ID
- Delegated Permissions: Users access only their authorized content
- Open WebUI Compatible: Works with native MCP or MCPO proxy
- Production Ready: Docker support, security hardening, structured audit logging
- Token Revocation: RFC 7009 compliant token revocation endpoint
Quick Start
1. Azure AD Setup
Follow docs/entra-app-registration.md to create an Azure AD app registration with these permissions:
openid,offline_access(OIDC)User.Read,Mail.Read,Mail.Read.Shared,Files.Read,Sites.Read.All,Calendars.Read(Microsoft Graph)
2. Configuration
Create a .env file:
# Azure AD / Entra ID (required)
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
AZURE_TENANT_ID=your-tenant-id
# Server
MCP_SERVER_PORT=3000
MCP_SERVER_BASE_URL=http://localhost:3000
SESSION_SECRET=$(openssl rand -hex 32)
# Optional
LOG_LEVEL=info
REDIS_URL=redis://localhost:6379
# OAuth signing keys (required in production)
# OAUTH_SIGNING_KEY_PRIVATE=<base64-encoded PEM>
# OAUTH_SIGNING_KEY_PUBLIC=<base64-encoded PEM>
3. Run Locally
# Install dependencies
npm install
# Development mode
npm run dev
# Production build
npm run build
npm start
4. Authenticate
- Open
http://localhost:3000/auth/loginin a browser - Sign in with your Microsoft 365 account
- Note the session ID returned after login
Docker Deployment
Basic
cd docker
docker-compose up -d m365-mcp-server redis
With Open WebUI
cd docker
docker-compose --profile with-webui up -d
With MCPO Proxy
cd docker
docker-compose --profile with-mcpo up -d
Open WebUI Integration
Option A: Native MCP (Recommended)
- In Open WebUI, go to Admin Settings > Tools
- Add MCP Server:
{ "url": "http://localhost:3000/mcp", "transport": "streamable-http" } - Complete OAuth login when prompted
Option B: Via MCPO Proxy
- Start MCPO with the provided config:
mcpo --config docker/mcpo-config.json --port 8000 - In Open WebUI, add as OpenAPI Tool:
http://localhost:8000/openapi.json
MCP Tools
Email Tools
| Tool | Description |
|---|---|
mail_list_messages | List messages with optional filters (supports shared mailboxes) |
mail_get_message | Get full message details with body (HTML→text), CC/BCC, and attachment metadata |
mail_list_folders | List mail folders or subfolders (supports shared mailboxes) |
mail_get_attachment | Read and parse email attachments (PDF, Word, Excel, PowerPoint, CSV, HTML→text). Max 20MB |
All email tools accept an optional mailbox parameter (email address or user ID) to access shared mailboxes. Omit to use your personal mailbox. Requires Mail.Read.Shared permission with admin consent.
SharePoint/OneDrive Tools
| Tool | Description |
|---|---|
sp_list_sites | Search and list SharePoint sites |
sp_list_drives | List drives (OneDrive/document libraries) |
sp_list_children | List folder contents |
sp_get_file | Get file content with automatic document parsing (PDF, Word, Excel, PowerPoint → text). Max 20MB |
OneDrive Tools
| Tool | Description |
|---|---|
od_my_drive | Get personal OneDrive info including drive ID and storage quota |
od_list_files | List files and folders in personal OneDrive (root or subfolder) |
od_get_file | Get file content by item_id with automatic document parsing (PDF, Word, Excel, PowerPoint). Max 20MB |
od_search | Search for files in personal OneDrive only |
od_recent | List recently accessed files |
od_shared_with_me | List files shared with you by others |
Calendar Tools
| Tool | Description |
|---|---|
cal_list_calendars | List all calendars with metadata |
cal_list_events | List events with optional date range (expands recurring events) |
cal_get_event | Get full event details including body/description |
Requires Calendars.Read permission (no admin consent needed). Provide start_date and end_date to expand recurring events into individual occurrences.
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Health check |
/auth/login | GET | Initiate OAuth login |
/auth/callback | GET | OAuth callback |
/auth/logout | GET | Logout and revoke session |
/auth/status | GET | Check authentication status |
/revoke | POST | Token revocation (RFC 7009) |
/mcp | POST | MCP JSON-RPC endpoint |
/mcp | GET | MCP SSE stream endpoint |
/mcp | DELETE | Terminate MCP session |
Security
- OAuth 2.1 + PKCE: Required for all authentication flows
- Delegated Permissions Only: No app-only access, read-only Graph scopes (
Mail.Read.Sharedrequires admin consent) - Token Encryption: AES-256-GCM encryption for session tokens at rest
- PII Redaction: Sensitive data (tokens, emails, secrets) filtered from logs
- Structured Audit Logging: Security events logged with correlation IDs
- Rate Limiting: 100 req/min general, 5/hour for client registration
- Security Headers: HSTS, CSP (no unsafe-inline), Permissions-Policy, X-Frame-Options via Helmet
- Input Validation: Zod schemas + regex validation for all Graph API resource IDs
- DCR Protection: Redirect URI pattern whitelist, rate limiting, audit logging
- Production Enforcement: Config validation requires Redis, HTTPS, persistent signing keys
See docs/security/threat-model.md for full security analysis.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Open WebUI / Client │
└─────────────────────────────┬───────────────────────────────┘
│ MCP Protocol (Streamable HTTP)
▼
┌─────────────────────────────────────────────────────────────┐
│ m365-mcp-server │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────────────┐ │
│ │ OAuth 2.1 │ │ MCP Handler │ │ Microsoft Graph │ │
│ │ + PKCE │ │ (JSON-RPC) │ │ Client │ │
│ └──────┬──────┘ └─────────────┘ └──────────┬───────────┘ │
└─────────│────────────────────────────────────│──────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌─────────────────────────┐
│ Azure AD / Entra ID │ │ Microsoft Graph API │
│ (Authorization) │ │ (Data Access) │
└──────────────────────┘ └─────────────────────────┘
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
AZURE_CLIENT_ID | Yes | - | Azure AD app client ID |
AZURE_CLIENT_SECRET | Yes | - | Azure AD app client secret |
AZURE_TENANT_ID | Yes | - | Azure AD tenant ID |
SESSION_SECRET | Yes | - | Session encryption key (32+ chars) |
MCP_SERVER_PORT | No | 3000 | Server port |
MCP_SERVER_BASE_URL | No | http://localhost:3000 | Public URL (HTTPS required in production) |
REDIS_URL | Prod | - | Redis URL (required in production) |
OAUTH_SIGNING_KEY_PRIVATE | Prod | - | RSA private key PEM (required in production) |
OAUTH_SIGNING_KEY_PUBLIC | Prod | - | RSA public key PEM (required in production) |
OAUTH_ALLOWED_REDIRECT_PATTERNS | No | - | Comma-separated URI patterns for DCR |
LOG_LEVEL | No | info | Log level (trace/debug/info/warn/error) |
NODE_ENV | No | development | Environment mode |
FILE_PARSE_TIMEOUT_MS | No | 30000 | Document parsing timeout |
FILE_PARSE_MAX_OUTPUT_KB | No | 500 | Max parsed text output size |
Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint
npm run lint
# Type check
npm run typecheck
# Build
npm run build
MCP Registry
This server is published to the MCP Registry. Add to your MCP client:
{
"mcpServers": {
"m365": {
"command": "npx",
"args": ["-y", "@anthropic/m365-mcp-server"],
"env": {
"AZURE_CLIENT_ID": "your-client-id",
"AZURE_CLIENT_SECRET": "your-client-secret",
"AZURE_TENANT_ID": "your-tenant-id",
"SESSION_SECRET": "your-session-secret"
}
}
}
}
Documentation
Supported Document Formats
sp_get_file automatically extracts readable text from these formats:
| Format | Extensions | Library |
|---|---|---|
.pdf | pdf-parse | |
| Word | .docx, .doc | mammoth |
| Excel | .xlsx, .xls | exceljs |
| PowerPoint | .pptx, .ppt | Built-in ZIP/XML |
| CSV | .csv | Built-in |
| HTML | .html | Built-in |
Other binary formats are returned as base64. Parsed text output is limited to 500KB by default.
Known Limitations
- Maximum file download size: 20MB
- Parsed text output capped at 500KB (configurable via
FILE_PARSE_MAX_OUTPUT_KB) - SharePoint site listing requires search query (Graph API limitation)
- Refresh tokens limited to 24 hours for SPA scenarios
- No write operations (read-only by design)
- Access tokens (JWTs) are stateless and cannot be directly revoked (expire naturally)
License
MIT
Contributing
- Fork the repository
- Create a feature branch
- Submit a pull request
Please ensure all tests pass and the code follows the existing style.