Provides unified calendar management for Google Calendar, enabling users to perform CRUD operations on events, check free/busy status, detect scheduling conflicts, and synchronize calendar data across multiple accounts.
Click on "Install 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., "@Calendar MCP ServerShow me my schedule for today and check for conflicts"
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.
Calendar MCP Server
A Model Context Protocol (MCP) server providing unified calendar management across Google Calendar, Microsoft 365, and Exchange On-Premises.
Table of Contents
Features
Multi-Provider Support: Connect to Google Calendar, Microsoft 365 (Graph API), and Exchange On-Premises (EWS)
Multiple Accounts: Support for multiple accounts per provider (e.g., 2+ Exchange accounts)
12 MCP Tools: Comprehensive calendar operations including CRUD, free/busy, conflict detection, and sync helpers
4 MCP Resources: Quick access to calendar summaries, today's events, weekly schedule, and upcoming events
4 MCP Prompts: Pre-built templates for scheduling meetings and daily briefings
NTLM Authentication: Full support for Exchange NTLM authentication via
@ewsjs/xhrUnified Data Model: Consistent event format across all providers
Timezone Support: Configurable timezone for all operations
Quick Start
Installation
Prerequisites
Node.js 18+
npm or yarn
Access to at least one calendar provider (Google, Microsoft 365, or Exchange)
Install Dependencies
Build
This compiles TypeScript to JavaScript in the dist/ directory.
Configuration
The server uses environment variables for configuration. Create a .env file in the project root or pass environment variables directly.
Environment Variables
Server Settings
Variable | Description | Default |
| Server name for identification |
|
| Server version |
|
| Logging level: |
|
| IANA timezone for all operations |
|
| Working hours start (HH:MM) |
|
| Working hours end (HH:MM) |
|
| Working days (comma-separated) |
|
Request Settings
Variable | Description | Default |
| Request timeout in milliseconds |
|
| Maximum retry attempts |
|
| Delay between retries |
|
| Rate limiting |
|
Google Calendar Setup
Variable | Description | Required |
| Enable Google Calendar | Yes |
| Unique identifier for this account | Yes |
| Display name | Yes |
| Google account email | Yes |
| OAuth client ID from Google Cloud Console | Yes |
| OAuth client secret | Yes |
| OAuth redirect URI | Yes |
| Pre-authorized access token | Yes |
| Refresh token for token renewal | Yes |
| Token expiry (ISO 8601) | No |
Getting Google Credentials
Go to Google Cloud Console
Create a new project or select existing
Enable the Google Calendar API
Go to Credentials → Create Credentials → OAuth client ID
Configure consent screen if prompted
Select Desktop app or Web application
Copy Client ID and Client Secret
Use OAuth Playground to get tokens:
Select
https://www.googleapis.com/auth/calendarAuthorize and get access/refresh tokens
Example Google Configuration
Microsoft 365 Setup
Variable | Description | Required |
| Enable Microsoft 365 | Yes |
| Unique identifier for this account | Yes |
| Display name | Yes |
| Microsoft account email | Yes |
| Azure AD app client ID | Yes |
| Azure AD app client secret | Yes |
| Azure tenant ID ( | Yes |
| OAuth redirect URI | Yes |
| Pre-authorized access token | Yes |
| Refresh token | Yes |
| Token expiry (ISO 8601) | No |
Getting Microsoft Credentials
Go to Azure Portal
Navigate to Azure Active Directory → App registrations
Click New registration
Add redirect URI
Go to Certificates & secrets → New client secret
Go to API permissions → Add:
Calendars.ReadWriteUser.Read
Grant admin consent if required
Use Graph Explorer to test
Example Microsoft Configuration
Exchange On-Premises Setup
Variable | Description | Required |
| Enable Exchange provider | Yes |
| Unique identifier for this account | Yes |
| Display name | Yes |
| Exchange email address | Yes |
| EWS endpoint URL | Yes |
| Authentication: | Yes |
For NTLM Authentication (most common for on-premises)
Variable | Description | Required |
| Username (without domain) | Yes |
| Password (quote if special chars) | Yes |
| Active Directory domain | Yes |
For Basic Authentication
Variable | Description | Required |
| Full username or email | Yes |
| Password | Yes |
For OAuth Authentication (Hybrid Exchange)
Variable | Description | Required |
| Azure AD app ID | Yes |
| Client secret | Yes |
| Azure tenant ID | Yes |
| Access token | Yes |
| Refresh token | No |
Finding Your EWS URL
Open Outlook on desktop
Hold Ctrl and right-click the Outlook icon in system tray
Select "Test E-mail AutoConfiguration"
Look for the EWS URL (typically
https://mail.company.com/EWS/Exchange.asmx)
Or ask your Exchange administrator.
Example Exchange Configuration (NTLM)
Note: If your password contains special characters like
!,@,$, wrap it in quotes.
Multiple Exchange Accounts
To configure additional Exchange accounts, use the EXCHANGE_2_, EXCHANGE_3_, etc. prefixes:
Claude Code Integration
Method 1: Using /mcp Command (Recommended)
Open Claude Code in your project directory
Run
/mcpSelect "Add Server"
Configure with:
Restart Claude Code or run
/mcpand reconnect
Method 2: Edit ~/.claude.json Directly
Add to the mcpServers object in your project's configuration:
Verify Connection
After configuring, test with:
Ask Claude: "List my calendars"
Or: "What meetings do I have today?"
Tools Reference
Core Calendar Operations
list_calendars
List all available calendars across connected providers.
Parameter | Type | Description |
| string | Filter by provider: |
Example:
list_events
List events within a time range with optional filters.
Parameter | Type | Required | Description |
| string | Yes | Start of time range (ISO 8601) |
| string | Yes | End of time range (ISO 8601) |
| string[] | No | Filter to specific providers |
| string[] | No | Filter to specific calendar IDs |
| string | No | Text search in subject/body |
| number | No | Maximum results (default: 100, max: 500) |
| string | No | Sort order: |
| boolean | No | Expand recurring events (default: true) |
Example:
get_event
Get detailed information about a specific event.
Parameter | Type | Required | Description |
| string | Yes | The event ID |
| string | Yes | Provider: |
| string | No | Calendar ID (required for some providers) |
Example:
create_event
Create a new calendar event.
Parameter | Type | Required | Description |
| string | Yes | Provider to create event on |
| string | Yes | Event title |
| string | Yes | Start time (ISO 8601) |
| string | Yes | End time (ISO 8601) |
| string | No | Target calendar ID |
| string | No | Event description |
| string | No | Body type: |
| string | No | Physical location |
| array | No | List of attendees with |
| boolean | No | All-day event |
| object | No | Recurrence settings |
| number | No | Reminder before event |
| boolean | No | Create Teams/Meet link |
| string | No |
|
| string | No |
|
| string | No |
|
Example:
update_event
Update an existing event.
Parameter | Type | Required | Description |
| string | Yes | Event ID to update |
| string | Yes | Provider the event belongs to |
| string | No | New title |
| string | No | New start time |
| string | No | New end time |
| string | No | New description |
| string | No | New location |
| array | No | Updated attendee list |
| string | No | For recurring: |
| boolean | No | Notify attendees (default: true) |
Example:
delete_event
Delete a calendar event.
Parameter | Type | Required | Description |
| string | Yes | Event ID to delete |
| string | Yes | Provider the event belongs to |
| string | No | Calendar ID |
| string | No | For recurring: |
| boolean | No | Send cancellation notices |
Example:
Availability & Scheduling
get_free_busy
Get aggregated availability across all calendars.
Parameter | Type | Required | Description |
| string | Yes | Start of time range (ISO 8601) |
| string | Yes | End of time range (ISO 8601) |
| string[] | No | Filter to specific providers |
| string[] | No | Filter to specific calendars |
| number | No | Minimum free slot duration in minutes |
| boolean | No | Only consider working hours |
| object | No | Custom working hours config |
Example:
check_conflicts
Check if a proposed time slot conflicts with existing events.
Parameter | Type | Required | Description |
| string | Yes | Proposed start time (ISO 8601) |
| string | Yes | Proposed end time (ISO 8601) |
| string | No | Event ID to exclude (for rescheduling) |
| string | No | Provider of excluded event |
Example:
respond_to_invite
Respond to a meeting invitation.
Parameter | Type | Required | Description |
| string | Yes | Event ID |
| string | Yes | Provider the event belongs to |
| string | Yes | Response: |
| string | No | Calendar ID |
| string | No | Optional response message |
Example:
Sync Helpers
find_matching_events
Find matching events between two calendars.
Parameter | Type | Required | Description |
| string | Yes | Source calendar provider |
| string | Yes | Target calendar provider |
| string | Yes | Start of time range |
| string | Yes | End of time range |
| string | No | Source calendar ID |
| string | No | Target calendar ID |
| string | No | Match confidence: |
Example:
copy_event
Copy an event from one calendar to another.
Parameter | Type | Required | Description |
| string | Yes | Event ID to copy |
| string | Yes | Source provider |
| string | Yes | Target provider |
| string | No | Source calendar ID |
| string | No | Target calendar ID |
| boolean | No | Include attendees (default: false) |
| boolean | No | Include description (default: true) |
Example:
compare_calendars
Compare two calendars to find matching events, differences, and missing events.
Parameter | Type | Required | Description |
| string | Yes | Source calendar provider |
| string | Yes | Target calendar provider |
| string | Yes | Start of time range |
| string | Yes | End of time range |
| string | No | Source calendar ID |
| string | No | Target calendar ID |
Example:
Resources Reference
MCP Resources provide quick access to calendar data.
URI | Description |
| Overview of all calendars with event counts |
| Today's events across all calendars |
| This week's events grouped by day |
| Next N upcoming events (e.g., |
Usage in Claude Code:
Prompts Reference
MCP Prompts are pre-built conversation templates.
schedule-meeting
Interactive prompt to schedule a new meeting.
Arguments:
title: Meeting titleduration: Duration (e.g., "30 minutes", "1 hour")attendees: Comma-separated email addressesnotes: Additional notes
daily-briefing
Generate a briefing of today's schedule.
Arguments:
timezone: Override default timezoneinclude_details: Include full event details (true/false)
find-meeting-time
Find available time slots for a meeting.
Arguments:
duration: Required meeting durationwithin_days: Number of days to searchattendees: Participants to check availability for
sync-calendars
Compare and sync events between calendars.
Arguments:
source_provider: Source calendar providertarget_provider: Target calendar provideraction:compare,copy_missing, orfull_sync
Usage Examples
Daily Workflow
Finding Time
Managing Events
Multi-Calendar
Troubleshooting
Common Issues
"No calendars found"
Cause: Environment variables not loaded properly.
Solutions:
Verify
EXCHANGE_ENABLED=trueis setCheck that all required variables are present
For Claude Code: ensure
envobject in MCP config has all variablesRestart Claude Code after config changes
"401 Unauthorized" (Exchange NTLM)
Cause: Invalid credentials or wrong username format.
Solutions:
Use just the username, not
domain\userformatPut the domain in
EXCHANGE_DOMAINseparatelyQuote passwords with special characters:
EXCHANGE_PASSWORD="P@ss!word"Verify credentials work by visiting EWS URL in browser
"Failed to connect to Exchange"
Cause: Network or certificate issues.
Solutions:
Verify EWS URL is accessible from your network
Check if VPN is required
For self-signed certs, you may need to set
NODE_TLS_REJECT_UNAUTHORIZED=0
"Property not loaded" errors
Cause: EWS doesn't load all properties by default.
Solution: This is handled internally with safe property access. If you see this, update to latest version.
Google/Microsoft token expired
Cause: Access tokens have limited lifetime.
Solution:
Get new tokens using OAuth flow
Update
ACCESS_TOKENandTOKEN_EXPIRYin configImplement token refresh in your setup
Debug Mode
Run with debug logging:
Testing Connection
Test Exchange connection directly:
Architecture
Key Dependencies
Package | Purpose |
| MCP server implementation |
| Exchange Web Services client |
| NTLM authentication for EWS |
| Microsoft Graph API |
| Google Calendar API |
| Environment variable loading |
| Date manipulation |
| Timezone handling |
License
MIT
Contributing
Fork the repository
Create a feature branch
Make your changes
Run tests:
npm testSubmit a pull request
Support
For issues and feature requests, please open a GitHub issue.