Skip to main content
Glama
rauf543
by rauf543

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/xhr

  • Unified Data Model: Consistent event format across all providers

  • Timezone Support: Configurable timezone for all operations


Quick Start

# 1. Clone/navigate to the project cd calendar-mcp # 2. Install dependencies npm install # 3. Build the project npm run build # 4. Configure environment variables (see Configuration section) cp .env.example .env # Edit .env with your credentials # 5. Test the server node dist/index.js

Installation

Prerequisites

  • Node.js 18+

  • npm or yarn

  • Access to at least one calendar provider (Google, Microsoft 365, or Exchange)

Install Dependencies

npm install

Build

npm run 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

MCP_SERVER_NAME

Server name for identification

calendar-mcp

MCP_SERVER_VERSION

Server version

1.0.0

LOG_LEVEL

Logging level: debug, info, warn, error

info

DEFAULT_TIMEZONE

IANA timezone for all operations

UTC

DEFAULT_WORKING_HOURS_START

Working hours start (HH:MM)

09:00

DEFAULT_WORKING_HOURS_END

Working hours end (HH:MM)

18:00

DEFAULT_WORKING_DAYS

Working days (comma-separated)

monday,tuesday,wednesday,thursday,friday

Request Settings

Variable

Description

Default

REQUEST_TIMEOUT

Request timeout in milliseconds

30000

MAX_RETRIES

Maximum retry attempts

3

RETRY_DELAY_MS

Delay between retries

1000

RATE_LIMIT_REQUESTS_PER_MINUTE

Rate limiting

60


Google Calendar Setup

Variable

Description

Required

GOOGLE_ENABLED

Enable Google Calendar

Yes

GOOGLE_PROVIDER_ID

Unique identifier for this account

Yes

GOOGLE_PROVIDER_NAME

Display name

Yes

GOOGLE_EMAIL

Google account email

Yes

GOOGLE_CLIENT_ID

OAuth client ID from Google Cloud Console

Yes

GOOGLE_CLIENT_SECRET

OAuth client secret

Yes

GOOGLE_REDIRECT_URI

OAuth redirect URI

Yes

GOOGLE_ACCESS_TOKEN

Pre-authorized access token

Yes

GOOGLE_REFRESH_TOKEN

Refresh token for token renewal

Yes

GOOGLE_TOKEN_EXPIRY

Token expiry (ISO 8601)

No

Getting Google Credentials

  1. Go to Google Cloud Console

  2. Create a new project or select existing

  3. Enable the Google Calendar API

  4. Go to CredentialsCreate CredentialsOAuth client ID

  5. Configure consent screen if prompted

  6. Select Desktop app or Web application

  7. Copy Client ID and Client Secret

  8. Use OAuth Playground to get tokens:

    • Select https://www.googleapis.com/auth/calendar

    • Authorize and get access/refresh tokens

Example Google Configuration

GOOGLE_ENABLED=true GOOGLE_PROVIDER_ID=google-personal GOOGLE_PROVIDER_NAME=Personal Google Calendar GOOGLE_EMAIL=yourname@gmail.com GOOGLE_CLIENT_ID=123456789.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxx GOOGLE_REDIRECT_URI=http://localhost:3000/oauth/google/callback GOOGLE_ACCESS_TOKEN=ya29.xxxxx GOOGLE_REFRESH_TOKEN=1//xxxxx

Microsoft 365 Setup

Variable

Description

Required

MICROSOFT_ENABLED

Enable Microsoft 365

Yes

MICROSOFT_PROVIDER_ID

Unique identifier for this account

Yes

MICROSOFT_PROVIDER_NAME

Display name

Yes

MICROSOFT_EMAIL

Microsoft account email

Yes

MICROSOFT_CLIENT_ID

Azure AD app client ID

Yes

MICROSOFT_CLIENT_SECRET

Azure AD app client secret

Yes

MICROSOFT_TENANT_ID

Azure tenant ID (common, organizations, or specific)

Yes

MICROSOFT_REDIRECT_URI

OAuth redirect URI

Yes

MICROSOFT_ACCESS_TOKEN

Pre-authorized access token

Yes

MICROSOFT_REFRESH_TOKEN

Refresh token

Yes

MICROSOFT_TOKEN_EXPIRY

Token expiry (ISO 8601)

No

Getting Microsoft Credentials

  1. Go to Azure Portal

  2. Navigate to Azure Active DirectoryApp registrations

  3. Click New registration

  4. Add redirect URI

  5. Go to Certificates & secretsNew client secret

  6. Go to API permissions → Add:

    • Calendars.ReadWrite

    • User.Read

  7. Grant admin consent if required

  8. Use Graph Explorer to test

Example Microsoft Configuration

MICROSOFT_ENABLED=true MICROSOFT_PROVIDER_ID=microsoft-work MICROSOFT_PROVIDER_NAME=Work Microsoft 365 MICROSOFT_EMAIL=yourname@company.com MICROSOFT_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx MICROSOFT_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxx MICROSOFT_TENANT_ID=common MICROSOFT_REDIRECT_URI=http://localhost:3000/oauth/microsoft/callback MICROSOFT_ACCESS_TOKEN=eyJ0eXAiOiJKV1QiLCJ... MICROSOFT_REFRESH_TOKEN=0.xxxxx

Exchange On-Premises Setup

Variable

Description

Required

EXCHANGE_ENABLED

Enable Exchange provider

Yes

EXCHANGE_PROVIDER_ID

Unique identifier for this account

Yes

EXCHANGE_PROVIDER_NAME

Display name

Yes

EXCHANGE_EMAIL

Exchange email address

Yes

EXCHANGE_EWS_URL

EWS endpoint URL

Yes

EXCHANGE_AUTH_METHOD

Authentication: ntlm, basic, or oauth

Yes

For NTLM Authentication (most common for on-premises)

Variable

Description

Required

EXCHANGE_USERNAME

Username (without domain)

Yes

EXCHANGE_PASSWORD

Password (quote if special chars)

Yes

EXCHANGE_DOMAIN

Active Directory domain

Yes

For Basic Authentication

Variable

Description

Required

EXCHANGE_USERNAME

Full username or email

Yes

EXCHANGE_PASSWORD

Password

Yes

For OAuth Authentication (Hybrid Exchange)

Variable

Description

Required

EXCHANGE_OAUTH_CLIENT_ID

Azure AD app ID

Yes

EXCHANGE_OAUTH_CLIENT_SECRET

Client secret

Yes

EXCHANGE_OAUTH_TENANT_ID

Azure tenant ID

Yes

EXCHANGE_OAUTH_ACCESS_TOKEN

Access token

Yes

EXCHANGE_OAUTH_REFRESH_TOKEN

Refresh token

No

Finding Your EWS URL

  1. Open Outlook on desktop

  2. Hold Ctrl and right-click the Outlook icon in system tray

  3. Select "Test E-mail AutoConfiguration"

  4. Look for the EWS URL (typically https://mail.company.com/EWS/Exchange.asmx)

Or ask your Exchange administrator.

Example Exchange Configuration (NTLM)

EXCHANGE_ENABLED=true EXCHANGE_PROVIDER_ID=exchange-work EXCHANGE_PROVIDER_NAME=Work Exchange EXCHANGE_EMAIL=yourname@company.com EXCHANGE_EWS_URL=https://mail.company.com/EWS/Exchange.asmx EXCHANGE_AUTH_METHOD=ntlm EXCHANGE_USERNAME="yourname" EXCHANGE_PASSWORD="YourP@ssword!" EXCHANGE_DOMAIN="COMPANYDOMAIN"

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:

# First Exchange Account EXCHANGE_ENABLED=true EXCHANGE_PROVIDER_ID=exchange-account1 EXCHANGE_PROVIDER_NAME=Account 1 EXCHANGE_EMAIL=user1@company.com EXCHANGE_EWS_URL=https://mail.company.com/EWS/Exchange.asmx EXCHANGE_AUTH_METHOD=ntlm EXCHANGE_USERNAME="user1" EXCHANGE_PASSWORD="password1" EXCHANGE_DOMAIN="DOMAIN" # Second Exchange Account EXCHANGE_2_ENABLED=true EXCHANGE_2_PROVIDER_ID=exchange-account2 EXCHANGE_2_PROVIDER_NAME=Account 2 EXCHANGE_2_EMAIL=user2@company.com EXCHANGE_2_EWS_URL=https://mail.company.com/EWS/Exchange.asmx EXCHANGE_2_AUTH_METHOD=ntlm EXCHANGE_2_USERNAME="user2" EXCHANGE_2_PASSWORD="password2" EXCHANGE_2_DOMAIN="DOMAIN" # Third Exchange Account (if needed) EXCHANGE_3_ENABLED=true # ... and so on

Claude Code Integration

  1. Open Claude Code in your project directory

  2. Run /mcp

  3. Select "Add Server"

  4. Configure with:

{ "type": "stdio", "command": "node", "args": ["/full/path/to/calendar-mcp/dist/index.js"], "env": { "DEFAULT_TIMEZONE": "Your/Timezone", "EXCHANGE_ENABLED": "true", "EXCHANGE_PROVIDER_ID": "your-exchange", "EXCHANGE_PROVIDER_NAME": "Your Exchange", "EXCHANGE_EMAIL": "your@email.com", "EXCHANGE_EWS_URL": "https://mail.company.com/EWS/Exchange.asmx", "EXCHANGE_AUTH_METHOD": "ntlm", "EXCHANGE_USERNAME": "username", "EXCHANGE_PASSWORD": "password", "EXCHANGE_DOMAIN": "DOMAIN" } }
  1. Restart Claude Code or run /mcp and reconnect

Method 2: Edit ~/.claude.json Directly

Add to the mcpServers object in your project's configuration:

{ "projects": { "/path/to/your/project": { "mcpServers": { "calendar": { "type": "stdio", "command": "node", "args": ["/full/path/to/calendar-mcp/dist/index.js"], "env": { "DEFAULT_TIMEZONE": "Asia/Baku", "EXCHANGE_ENABLED": "true", "EXCHANGE_PROVIDER_ID": "exchange-work", "EXCHANGE_PROVIDER_NAME": "Work Calendar", "EXCHANGE_EMAIL": "you@company.com", "EXCHANGE_EWS_URL": "https://mail.company.com/EWS/Exchange.asmx", "EXCHANGE_AUTH_METHOD": "ntlm", "EXCHANGE_USERNAME": "username", "EXCHANGE_PASSWORD": "password", "EXCHANGE_DOMAIN": "DOMAIN" } } } } } }

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

provider

string

Filter by provider: google, microsoft, exchange, or all (default: all)

Example:

List all my calendars

list_events

List events within a time range with optional filters.

Parameter

Type

Required

Description

startTime

string

Yes

Start of time range (ISO 8601)

endTime

string

Yes

End of time range (ISO 8601)

providers

string[]

No

Filter to specific providers

calendarIds

string[]

No

Filter to specific calendar IDs

searchQuery

string

No

Text search in subject/body

maxResults

number

No

Maximum results (default: 100, max: 500)

orderBy

string

No

Sort order: start or updated

expandRecurring

boolean

No

Expand recurring events (default: true)

Example:

Show me all my meetings for tomorrow What events do I have this week? Search my calendar for "standup" meetings

get_event

Get detailed information about a specific event.

Parameter

Type

Required

Description

eventId

string

Yes

The event ID

provider

string

Yes

Provider: google, microsoft, or exchange

calendarId

string

No

Calendar ID (required for some providers)

Example:

Get details for event ID AAMkADA3OWE...

create_event

Create a new calendar event.

Parameter

Type

Required

Description

provider

string

Yes

Provider to create event on

subject

string

Yes

Event title

startTime

string

Yes

Start time (ISO 8601)

endTime

string

Yes

End time (ISO 8601)

calendarId

string

No

Target calendar ID

body

string

No

Event description

bodyType

string

No

Body type: text or html

location

string

No

Physical location

attendees

array

No

List of attendees with email and type

isAllDay

boolean

No

All-day event

recurrence

object

No

Recurrence settings

reminderMinutes

number

No

Reminder before event

createOnlineMeeting

boolean

No

Create Teams/Meet link

onlineMeetingProvider

string

No

teams or meet

sensitivity

string

No

normal, personal, private, confidential

showAs

string

No

free, busy, tentative, oof, workingElsewhere

Example:

Create a meeting called "Project Review" tomorrow at 2pm for 1 hour Schedule a lunch event next Monday from 12-1pm at "Cafe Downtown" Create a weekly team standup every Monday at 9am

update_event

Update an existing event.

Parameter

Type

Required

Description

eventId

string

Yes

Event ID to update

provider

string

Yes

Provider the event belongs to

subject

string

No

New title

startTime

string

No

New start time

endTime

string

No

New end time

body

string

No

New description

location

string

No

New location

attendees

array

No

Updated attendee list

updateScope

string

No

For recurring: single, thisAndFuture, all

sendUpdates

boolean

No

Notify attendees (default: true)

Example:

Move my 2pm meeting to 3pm Change the location of event AAMk... to "Room 201"

delete_event

Delete a calendar event.

Parameter

Type

Required

Description

eventId

string

Yes

Event ID to delete

provider

string

Yes

Provider the event belongs to

calendarId

string

No

Calendar ID

deleteScope

string

No

For recurring: single, thisAndFuture, all

sendCancellation

boolean

No

Send cancellation notices

Example:

Delete my 3pm meeting Cancel all instances of my recurring standup

Availability & Scheduling

get_free_busy

Get aggregated availability across all calendars.

Parameter

Type

Required

Description

startTime

string

Yes

Start of time range (ISO 8601)

endTime

string

Yes

End of time range (ISO 8601)

providers

string[]

No

Filter to specific providers

calendarIds

string[]

No

Filter to specific calendars

slotDuration

number

No

Minimum free slot duration in minutes

workingHoursOnly

boolean

No

Only consider working hours

workingHours

object

No

Custom working hours config

Example:

When am I free tomorrow? Find me a 1-hour free slot this week Show my availability for the next 3 days during working hours

check_conflicts

Check if a proposed time slot conflicts with existing events.

Parameter

Type

Required

Description

startTime

string

Yes

Proposed start time (ISO 8601)

endTime

string

Yes

Proposed end time (ISO 8601)

excludeEventId

string

No

Event ID to exclude (for rescheduling)

excludeProvider

string

No

Provider of excluded event

Example:

Do I have any conflicts tomorrow at 2pm? Check if I can schedule a meeting on Friday from 10-11am

respond_to_invite

Respond to a meeting invitation.

Parameter

Type

Required

Description

eventId

string

Yes

Event ID

provider

string

Yes

Provider the event belongs to

response

string

Yes

Response: accepted, declined, tentative

calendarId

string

No

Calendar ID

message

string

No

Optional response message

Example:

Accept the meeting invite for AAMk... Decline the team lunch with message "I have a conflict" Tentatively accept the project review

Sync Helpers

find_matching_events

Find matching events between two calendars.

Parameter

Type

Required

Description

source_provider

string

Yes

Source calendar provider

target_provider

string

Yes

Target calendar provider

start_time

string

Yes

Start of time range

end_time

string

Yes

End of time range

source_calendar_id

string

No

Source calendar ID

target_calendar_id

string

No

Target calendar ID

min_confidence

string

No

Match confidence: high, medium, low

Example:

Find events that exist in both my Exchange calendars Check for duplicates between Google and Microsoft

copy_event

Copy an event from one calendar to another.

Parameter

Type

Required

Description

source_event_id

string

Yes

Event ID to copy

source_provider

string

Yes

Source provider

target_provider

string

Yes

Target provider

source_calendar_id

string

No

Source calendar ID

target_calendar_id

string

No

Target calendar ID

include_attendees

boolean

No

Include attendees (default: false)

include_body

boolean

No

Include description (default: true)

Example:

Copy event AAMk... from Exchange to Google Calendar

compare_calendars

Compare two calendars to find matching events, differences, and missing events.

Parameter

Type

Required

Description

source_provider

string

Yes

Source calendar provider

target_provider

string

Yes

Target calendar provider

start_time

string

Yes

Start of time range

end_time

string

Yes

End of time range

source_calendar_id

string

No

Source calendar ID

target_calendar_id

string

No

Target calendar ID

Example:

Compare my two Exchange calendars for this week What events are only in my first calendar but not the second?

Resources Reference

MCP Resources provide quick access to calendar data.

URI

Description

calendar://summary

Overview of all calendars with event counts

calendar://today

Today's events across all calendars

calendar://week

This week's events grouped by day

calendar://next/{count}

Next N upcoming events (e.g., calendar://next/5)

Usage in Claude Code:

@calendar://today Show me @calendar://summary What's in @calendar://week

Prompts Reference

MCP Prompts are pre-built conversation templates.

schedule-meeting

Interactive prompt to schedule a new meeting.

Arguments:

  • title: Meeting title

  • duration: Duration (e.g., "30 minutes", "1 hour")

  • attendees: Comma-separated email addresses

  • notes: Additional notes


daily-briefing

Generate a briefing of today's schedule.

Arguments:

  • timezone: Override default timezone

  • include_details: Include full event details (true/false)


find-meeting-time

Find available time slots for a meeting.

Arguments:

  • duration: Required meeting duration

  • within_days: Number of days to search

  • attendees: Participants to check availability for


sync-calendars

Compare and sync events between calendars.

Arguments:

  • source_provider: Source calendar provider

  • target_provider: Target calendar provider

  • action: compare, copy_missing, or full_sync


Usage Examples

Daily Workflow

# Morning check "What's on my calendar today?" # Quick view "Show me my next 5 meetings" # Check availability "Am I free at 3pm today?" # Schedule meeting "Schedule a 30-minute call with john@company.com tomorrow at 2pm"

Finding Time

"When am I free this week for a 1-hour meeting?" "Find me an open slot tomorrow afternoon" "Do I have any conflicts if I book 10-11am on Friday?"

Managing Events

"Move my 2pm meeting to 3pm" "Cancel tomorrow's standup" "Add 'Conference Room A' as the location for my next meeting"

Multi-Calendar

"Compare my two Exchange calendars for this week" "List all calendars I have access to" "Copy the project review from my work calendar to personal"

Troubleshooting

Common Issues

"No calendars found"

Cause: Environment variables not loaded properly.

Solutions:

  1. Verify EXCHANGE_ENABLED=true is set

  2. Check that all required variables are present

  3. For Claude Code: ensure env object in MCP config has all variables

  4. Restart Claude Code after config changes

"401 Unauthorized" (Exchange NTLM)

Cause: Invalid credentials or wrong username format.

Solutions:

  1. Use just the username, not domain\user format

  2. Put the domain in EXCHANGE_DOMAIN separately

  3. Quote passwords with special characters: EXCHANGE_PASSWORD="P@ss!word"

  4. Verify credentials work by visiting EWS URL in browser

"Failed to connect to Exchange"

Cause: Network or certificate issues.

Solutions:

  1. Verify EWS URL is accessible from your network

  2. Check if VPN is required

  3. 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:

  1. Get new tokens using OAuth flow

  2. Update ACCESS_TOKEN and TOKEN_EXPIRY in config

  3. Implement token refresh in your setup

Debug Mode

Run with debug logging:

LOG_LEVEL=debug node dist/index.js

Testing Connection

Test Exchange connection directly:

# Set environment variables export EXCHANGE_ENABLED=true export EXCHANGE_EWS_URL=https://mail.company.com/EWS/Exchange.asmx export EXCHANGE_AUTH_METHOD=ntlm export EXCHANGE_USERNAME=youruser export EXCHANGE_PASSWORD='yourpassword' export EXCHANGE_DOMAIN=YOURDOMAIN # Run test node -e " const { loadConfig, hasConfiguredProviders } = require('./dist/utils/config.js'); console.log('Has providers:', hasConfiguredProviders()); console.log('Config:', JSON.stringify(loadConfig(), null, 2)); "

Architecture

calendar-mcp/ ├── src/ │ ├── index.ts # MCP server entry point │ ├── types/ │ │ └── index.ts # TypeScript interfaces │ ├── providers/ │ │ ├── base.ts # Base provider interface │ │ ├── google/ │ │ │ ├── index.ts # Google Calendar provider │ │ │ └── client.ts # Google API client │ │ ├── microsoft/ │ │ │ ├── index.ts # Microsoft 365 provider │ │ │ └── client.ts # Graph API client │ │ └── exchange/ │ │ ├── index.ts # Exchange EWS provider │ │ ├── client.ts # EWS client with NTLM support │ │ └── auth.ts # Authentication manager │ ├── services/ │ │ ├── calendar-service.ts # Multi-provider orchestration │ │ └── sync-service.ts # Calendar sync logic │ ├── tools/ │ │ ├── index.ts # Tool registration │ │ ├── list-calendars.ts │ │ ├── list-events.ts │ │ ├── get-event.ts │ │ ├── create-event.ts │ │ ├── update-event.ts │ │ ├── delete-event.ts │ │ ├── get-free-busy.ts │ │ ├── check-conflicts.ts │ │ ├── respond-to-invite.ts │ │ ├── find-matching-events.ts │ │ ├── copy-event.ts │ │ └── compare-calendars.ts │ ├── resources/ │ │ └── index.ts # MCP resources │ ├── prompts/ │ │ └── index.ts # MCP prompts │ └── utils/ │ ├── config.ts # Configuration loader │ ├── date.ts # Date utilities │ └── formatting.ts # Output formatting ├── dist/ # Compiled JavaScript ├── .env # Environment configuration ├── .env.example # Example configuration ├── package.json ├── tsconfig.json └── README.md

Key Dependencies

Package

Purpose

@modelcontextprotocol/sdk

MCP server implementation

ews-javascript-api

Exchange Web Services client

@ewsjs/xhr

NTLM authentication for EWS

@microsoft/microsoft-graph-client

Microsoft Graph API

googleapis

Google Calendar API

dotenv

Environment variable loading

date-fns

Date manipulation

date-fns-tz

Timezone handling


License

MIT


Contributing

  1. Fork the repository

  2. Create a feature branch

  3. Make your changes

  4. Run tests: npm test

  5. Submit a pull request


Support

For issues and feature requests, please open a GitHub issue.

-
security - not tested
F
license - not found
-
quality - not tested

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rauf543/calendar-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server