owa-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., "@owa-mcp list my calendar events for this week"
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.
owa-mcp
A Model Context Protocol (MCP) server that gives Claude Code full access to your Microsoft Outlook calendar and email — without requiring an Azure app registration.
How it works
The server drives a dedicated, persistent Google Chrome browser via chrome-devtools-mcp, using its own Chrome profile (kept separate from your daily-driver Chrome) so the login session survives across restarts. It navigates that browser to Outlook Web (outlook.office.com) and watches the network requests it makes. When Outlook Web loads, it issues Bearer tokens for its own internal API calls; this server intercepts those tokens and reuses them against the outlook.office.com/api/v2.0 REST endpoint.
The result: full Calendars.ReadWrite and Mail.ReadWrite scope with no OAuth app registration, no client ID, and no IT involvement — as long as you can sign in to Microsoft 365 in the automation browser.
Tokens expire after ~80 minutes. Rather than relaunching a browser for every refresh, the server keeps a single chrome-devtools-mcp connection (and its browser) alive across acquisitions and simply re-navigates to Outlook Web to trigger a fresh token request. The Chrome window is visible (never headless) from the moment the browser first starts, so it's there for you to sign in whenever needed. If no active session is found within 60 seconds, the request fails with a message asking you to sign in and retry — because the connection stays alive, you can take as long as you need (MFA included) and just retry once done, without losing the browser session.
Related MCP server: Outlook MCP Server
Why this approach
Many enterprise Microsoft 365 tenants enforce Conditional Access policies that block third-party OAuth flows (e.g., Azure CLI, custom app registrations) on managed devices. The browser-session interception approach works because it piggybacks on an authentication flow that already satisfies those policy requirements — the same one used by Outlook Web itself. This has been confirmed working with Chrome SSO in at least one Conditional-Access-enforced corp environment; whether it works in yours depends on your organization's specific policies.
Prerequisites
macOS (tested on macOS 15)
Google Chrome installed
chrome-devtools-mcp available via
npx— verify withnpx chrome-devtools-mcp@latest --version; the server spawns it automatically on first use, no manual setup neededSigned in to Microsoft 365 (the first token request opens a visible Chrome window — sign in there if prompted)
Node.js 20+
Installation
claude mcp add owa -s user -- npx owa-mcpThat's it. Restart Claude Code — you should see calendar tools available.
git clone https://github.com/benpeter/owa-mcp
cd owa-mcp
npm install
npm run build
claude mcp add owa -s user -- node /absolute/path/to/owa-mcp/dist/index.jsAvailable Tools
get_calendar_events
Returns calendar events in a time range.
Parameter | Type | Required | Description |
| string | yes | ISO 8601 start |
| string | yes | ISO 8601 end |
| number | no | Max events (default 50, max 100) |
| string | no | IANA timezone (default UTC) |
create_calendar_event
Create a new event. Adding attendees auto-sends invitations.
Parameter | Type | Required | Description |
| string | yes | Event title |
| string | yes | Local datetime without offset |
| string | yes | Local datetime without offset |
| string | no | Windows timezone name (default "W. Europe Standard Time") |
| string | no | Event description |
| string | no | Location name |
| array | no |
|
| boolean | no | All-day event |
| string | no | Free, Tentative, Busy, Oof, WorkingElsewhere |
| boolean | no | Create as Teams meeting |
| boolean | no | Hide attendee list from other attendees (default false) |
| boolean | no | Request RSVPs from attendees (default true) |
| number | no | Reminder minutes before start. Omit for Outlook default, 0 to disable |
| object | no | Make this a recurring event. See Recurrence below |
update_calendar_event
Update fields on an existing event. Only include fields to change.
Parameter | Type | Required | Description |
| string | yes | Event ID |
| string | no | New title |
| string | no | New start time |
| string | no | New end time |
| string | no | Timezone for start/end |
| string | no | New body (caution: overwrites Teams join link) |
| string | no | New location |
| string | no | New show-as status |
| boolean | no | Mark as private |
| boolean | no | Hide attendee list from other attendees |
| boolean | no | Request RSVPs from attendees |
| number | no | Reminder minutes before start. 0 to disable |
| object | no | Change the recurrence pattern. Only applies to series master events. See Recurrence below |
cancel_calendar_event
Cancel a meeting you organized. Sends cancellation with reason to attendees. Supports recurring series operations.
Parameter | Type | Required | Description |
| string | yes | Event ID |
| string | no | Cancellation reason sent to attendees |
| string | no |
|
delete_calendar_event
Remove an event from your calendar silently (no notification sent). Supports recurring series operations.
Parameter | Type | Required | Description |
| string | yes | Event ID |
| string | no |
|
respond_to_calendar_event
RSVP to a meeting: accept, tentatively accept, or decline. Uses OWA's internal service.svc API when possible, which works even when the organizer has disabled response requests (ResponseRequested: false). Falls back to the standard REST API if the internal API can't resolve the event.
Parameter | Type | Required | Description |
| string | yes | Event ID |
| string | yes |
|
| string | no | Message to organizer |
| boolean | no | Notify organizer (default true) |
| string | no | Propose alternative start (tentative/decline only) |
| string | no | Propose alternative end |
follow_calendar_event
Track an event on your calendar without RSVPing. Shows as Free, organizer not notified.
Parameter | Type | Required | Description |
| string | yes | Event ID |
| string | no | Optional message included in the follow notification to the organizer |
| string | no | Timezone for returned event |
get_series_master
Inspect the master event of a recurring series. Returns recurrence pattern, cancelled occurrences, and full event details. Accepts any event ID from the series.
Parameter | Type | Required | Description |
| string | yes | Any event ID from the series (resolved automatically) |
| string | no | IANA timezone (default UTC) |
list_series_instances
List all occurrences of a recurring series within a date range. Accepts any event ID from the series.
Parameter | Type | Required | Description |
| string | yes | Any event ID from the series (resolved automatically) |
| string | yes | ISO 8601 start |
| string | yes | ISO 8601 end |
| string | no | IANA timezone (default UTC) |
list_mail_folders
List all mail folders in the mailbox, or child folders of a specific folder.
Parameter | Type | Required | Description |
| string | no | List children of this folder. If omitted, lists top-level folders |
get_emails
Get emails from a specific mailbox folder with optional filtering.
Parameter | Type | Required | Description |
| string | no | Folder ID or well-known name (Inbox, Drafts, SentItems, DeletedItems). Default: Inbox |
| string | no |
|
| number | no | Max results (default 20, max 500) |
| string | no | Pagination token from previous response |
search_emails
Search emails using full-text query OR structured filters (mutually exclusive).
Parameter | Type | Required | Description |
| string | no | Full-text search query. Cannot combine with structured filters |
| string | no | Filter by sender email |
| string | no | Filter by subject (contains) |
| string | no | ISO 8601 datetime |
| string | no | ISO 8601 datetime |
| string | no | Scope search to folder |
| number | no | Max results (default 20, max 500) |
get_email
Read a single email with full body content and attachment metadata.
Parameter | Type | Required | Description |
| string | yes | Message ID |
| string | no |
|
get_attachment
Download an email attachment to disk.
Parameter | Type | Required | Description |
| string | yes | Message ID |
| string | yes | Attachment ID from get_email response |
send_email
Compose and send a new email in one step. For more control, use create_draft + update_draft + send_draft.
Parameter | Type | Required | Description |
| array | yes |
|
| string | yes | Subject line |
| string | yes | Body content |
| string | no |
|
| array | no | CC recipients |
| array | no | BCC recipients |
| string | no | Low, Normal (default), High |
| boolean | no | Save to Sent Items (default true) |
create_draft
Create a new email draft saved to Drafts folder.
Parameter | Type | Required | Description |
| array | yes |
|
| string | yes | Subject line |
| string | yes | Body content |
| string | no |
|
| array | no | CC recipients |
| array | no | BCC recipients |
| string | no | Low, Normal (default), High |
create_reply_draft
Create a draft reply to the sender. Returns draft with pre-filled recipients, quoted body, "RE:" subject.
Parameter | Type | Required | Description |
| string | yes | Message ID |
create_reply_all_draft
Create a draft reply-all. Returns draft with all original recipients, quoted body, "RE:" subject.
Parameter | Type | Required | Description |
| string | yes | Message ID |
create_forward_draft
Create a draft forward. Returns draft with quoted body, "FW:" subject, no To recipients.
Parameter | Type | Required | Description |
| string | yes | Message ID |
update_draft
Modify a draft before sending. Can change subject, body, recipients, importance.
Parameter | Type | Required | Description |
| string | yes | Draft message ID |
| string | no | New subject |
| string | no | New body content |
| string | no |
|
| array | no | Replace all To recipients |
| array | no | Replace all CC recipients |
| array | no | Replace all BCC recipients |
| string | no | Low, Normal, High |
send_draft
Send a draft message. Moves from Drafts to Sent Items.
Parameter | Type | Required | Description |
| string | yes | Draft message ID |
move_email
Move a message to a different folder. Returns the moved message (with updated ID).
Parameter | Type | Required | Description |
| string | yes | Message ID |
| string | yes | Folder ID or well-known name (Inbox, Drafts, SentItems, DeletedItems, Archive) |
delete_email
Delete a message (moves to Deleted Items).
Parameter | Type | Required | Description |
| string | yes | Message ID |
update_email
Update email properties: mark as read/unread, flag/unflag.
Parameter | Type | Required | Description |
| string | yes | Message ID |
| boolean | no | Set read (true) or unread (false) |
| string | no |
|
Example prompts:
"What meetings do I have next week?"
"Create a 30-minute meeting with Jane tomorrow at 2pm"
"Decline the ECCN sync with a note that I'm on vacation"
"Follow the Analytics Tech Call so I can see it on my calendar"
"Cancel all future occurrences of the weekly sync starting from next week"
"What's the recurrence pattern for the Monday standup?"
"Create a weekly team sync every Tuesday at 10am for the next 3 months"
"Show me unread emails from today"
"Reply to that email from Sarah and add Bob to CC"
"Forward the Q3 report to the finance team"
"Mark all emails from the newsletter as read"
Recurrence Object
Used by create_calendar_event and update_calendar_event to define recurring events.
{
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": ["Monday", "Wednesday", "Friday"]
},
"range": {
"type": "endDate",
"startDate": "2026-04-07",
"endDate": "2026-07-07"
}
}
}Pattern types: daily, weekly, absoluteMonthly, relativeMonthly, absoluteYearly, relativeYearly
Pattern Field | Type | Description |
| string | Required. Pattern type |
| number | Required. Interval between occurrences (1 = every, 2 = every other) |
| string[] | Days for weekly/relative patterns |
| number | Day of month for absoluteMonthly/absoluteYearly |
| number | Month (1-12) for yearly patterns |
| string | Week index for relative patterns: first, second, third, fourth, last |
| string | First day of week (default Sunday) |
Range types: endDate, numbered, noEnd
Range Field | Type | Description |
| string | Required. How the series ends |
| string | Required. Series start (YYYY-MM-DD) |
| string | End date (required for |
| number | Count (required for |
| string | Timezone for recurrence dates |
Troubleshooting
Token acquisition times out / no active session found The automation Chrome window is already open (it becomes visible as soon as the browser starts, not just on timeout) and has navigated to Outlook Web. Switch to it and sign in there (MFA included) at your own pace, then simply retry the request — the browser connection is kept alive, so the same session is reused and you won't need to sign in again on subsequent calls.
ErrorAccessDenied on calendar API
The intercepted token didn't carry calendar scope. This is rare; try quitting any Chrome windows using the automation profile (~/Library/Application Support/owa-mcp/chrome-profile) and retrying — the server will relaunch it automatically.
License
Apache 2.0 — see LICENSE.
Available Tools
24 toolscancel_calendar_eventA
Cancel a meeting you organized. Sends a cancellation notice with your reason to all attendees. Only works if you are the organizer.
Inputs: eventId (required), scope, reason.
create_calendar_eventA
Create a new calendar event in Microsoft Outlook. Adding attendees automatically sends meeting invitations.
Inputs: subject (required), endDateTime (required), startDateTime (required), body, +12 more.
create_draftA
Create a new email draft (saved to Drafts folder). Use update_draft to modify, then send_draft to send.
Inputs: to (required), body (required), subject (required), cc, +3 more.
create_forward_draftA
Create a draft forward of a message. Returns the draft with quoted body and "FW:" subject but no To recipients. Use update_draft to set recipients, then send_draft to send.
Inputs: messageId (required).
create_reply_all_draftA
Create a draft reply-all to all recipients of a message. Returns the draft with pre-filled recipients, quoted body, and "RE:" subject. Use update_draft to modify, then send_draft to send.
Inputs: messageId (required).
create_reply_draftA
Create a draft reply to the sender of a message. Returns the draft with pre-filled recipients, quoted body, and "RE:" subject. Use update_draft to modify, then send_draft to send.
Inputs: messageId (required).
delete_calendar_eventA
Remove an event from your calendar without sending any notification. Use this to remove events you did not organize, or to silently delete your own events.
Inputs: eventId (required), scope.
delete_emailA
Delete a message (moves to Deleted Items).
Inputs: messageId (required).
follow_calendar_eventA
Follow a calendar event without formally RSVPing. The event appears on your calendar with ShowAs=Free. The organizer is NOT notified. Emulates New Outlook's "Follow this event" feature.
Inputs: eventId (required), comment, timezone.
get_attachmentA
Download an email attachment to disk. Returns the file path.
Inputs: messageId (required), attachmentId (required).
get_calendar_eventsA
Retrieve calendar events from Microsoft Outlook. Returns events between startDateTime and endDateTime.
Inputs: endDateTime (required), startDateTime (required), timezone, maxResults.
get_emailA
Read a single email with full body content and attachment metadata.
Inputs: messageId (required), format.
get_emailsA
Get emails from a specific mailbox folder with optional filtering.
Inputs: limit, filter, folderId, pageToken.
get_series_masterA
Inspect the master event of a recurring series. Returns recurrence pattern, cancelled occurrences, and full event details. Accepts any event ID from the series (occurrence, exception, or master).
Inputs: eventId (required), timezone.
list_mail_foldersA
List all mail folders in the mailbox, or child folders of a specific folder.
Inputs: parentFolderId.
list_series_instancesA
List all occurrences of a recurring series within a date range. Accepts any event ID from the series (resolved to master automatically).
Inputs: eventId (required), endDateTime (required), startDateTime (required), timezone.
move_emailA
Move a message to a different folder. Returns the moved message (with updated ID).
Inputs: messageId (required), destinationId (required).
respond_to_calendar_eventA
RSVP to a meeting invitation: accept, tentatively accept, or decline. Optionally include a comment and/or propose an alternative time.
Inputs: eventId (required), response (required), comment, sendResponse, +3 more.
search_emailsA
Search emails using full-text query OR structured filters (mutually exclusive). Use query for natural search, or structured filters for precise field matching.
Inputs: from, limit, query, subject, +3 more.
send_draftA
Send a draft message. The draft is moved from Drafts to Sent Items.
Inputs: messageId (required).
send_emailA
Compose and send a new email in one step. For more control (edit before sending), use create_draft + update_draft + send_draft instead.
Inputs: to (required), body (required), subject (required), cc, +4 more.
update_calendar_eventA
Update an existing calendar event. Only include fields you want to change. If you are the organizer, updates are sent to attendees automatically.
Inputs: eventId (required), body, showAs, subject, +9 more.
update_draftA
Modify a draft message before sending. Can change subject, body, recipients, and importance. Use with create_draft, create_reply_draft, create_reply_all_draft, or create_forward_draft.
Inputs: messageId (required), body, subject, bodyType, +4 more.
update_emailB
Update email properties: mark as read/unread, flag/unflag.
Inputs: messageId (required), isRead, flagStatus.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 24 tools
Each tool targets a distinct resource-action pair. Calendar tools clearly separate create/update/delete/cancel/respond/follow and series operations, while mail tools distinguish send, draft flows, search/get, and message management. Even similar tools like cancel vs delete and reply vs reply-all have descriptions that remove ambiguity.
All tool names follow a consistent verb_noun snake_case pattern. Verbs are specific (create, get, update, send, move, delete) and nouns identify the resource (calendar_event, email, draft). The use of plural for list operations (get_emails, get_calendar_events) and singular for single-item retrieval (get_email) follows a clear convention.
24 tools is on the heavier side but justified by the server's dual scope covering both calendar and mail operations. Each tool contributes to a complete workflow without redundancy. While slightly above the typical 3-15 range, the breadth of Outlook functionality warrants this count.
Calendar coverage includes full lifecycle with recurring series handling. Mail coverage includes sending, multi-step drafting, reply/forward, attachments, folder management, and message state updates. No critical operations appear missing for the domain.
Maintenance
Related MCP Connectors
Mac & Windows: let ChatGPT, Claude & Cursor use your email, calendar, iMessage, Teams, files.
Connect any mailbox to Claude, ChatGPT & AI: read, send, reply, schedule & search emails.
Give your AI assistant its own private email. Create mailboxes in seconds, send and schedule messages, and let the agent wait for incoming emails to pick up verification codes and confirmation links — without exposing your personal address. Works with Claude, ChatGPT, Cursor and VS Code: just sign in with your GhosterMail account. Requires GhosterMail Full Access.
Your Telegram, WhatsApp, Instagram, mail and calendar in Claude or ChatGPT. Never sends messages.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceConnects Claude with Microsoft Outlook through the Graph API, providing comprehensive email, calendar, folder management, and rules creation capabilities.19MIT
- AlicenseNot gradedqualityDmaintenanceConnects Claude to Microsoft Outlook through the Microsoft Graph API, enabling email management (list, search, read, send) and calendar operations (list, create, accept, decline, delete events) via OAuth 2.0 authentication.1MIT
- FlicenseAqualityBmaintenanceEnables Claude to manage Outlook calendar events and Microsoft To Do tasks for a specific mailbox via Microsoft Graph API.7-
- AlicenseAqualityCmaintenanceGives Claude Code access to Outlook Mail, Calendar, and Contacts via Microsoft Graph, with safety-first defaults (no sending, no hard deletes, every mutation logged). Supports multiple Microsoft accounts through a PKCE OAuth flow.21MIT