Calendar MCP Server
by DRITI2906
README.md
# MCP Calendar Server
A production-quality **Model Context Protocol (MCP)** server for calendar management with robust timezone handling, recurrence support, and idempotency guarantees.
## ๐ฏ What is MCP?
The **Model Context Protocol** is a standardized way for AI agents (like Claude, ChatGPT, etc.) to interact with external tools and data sources. This server exposes calendar operations as MCP tools, allowing AI assistants to:
- Create events with timezone-aware scheduling
- List events with automatic recurrence expansion
- Cancel individual instances or entire event series
## โจ Features
### ๐ Timezone Correctness (Top Priority)
Timezone handling is **notoriously difficult**. Here's how we handle it:
- **Storage**: All events stored in UTC (source of truth)
- **Input**: Accept ISO 8601 datetime + IANA timezone (e.g., `"Asia/Kolkata"`)
- **Output**: Return events in their original timezone
- **DST Handling**: Recurrence expansion happens in local time to preserve wall-clock semantics (e.g., "9 AM daily" stays at 9 AM even across DST transitions)
- **Library**: Uses [Luxon](https://moment.github.io/luxon/) for robust timezone math
**Why UTC Storage?**
- Single source of truth
- No ambiguity during DST transitions
- Easy comparison and sorting
- Portable across systems
**Why Original Timezone Matters?**
- Preserves user intent ("9 AM in Kolkata" not "3:30 AM UTC")
- Correct recurrence expansion (daily meetings stay at same wall time)
### ๐ Recurrence Support
Supports repeating events with:
- **Frequencies**: `daily`, `weekly`, `monthly`
- **Intervals**: Every N days/weeks/months (e.g., "every 2 weeks")
- **End Dates**: `until` parameter (ISO 8601)
**Implementation Design:**
- Recurrence rules stored as JSON in the database
- **Virtual instances** generated on-demand during `calendar.list`
- No duplicate rows for recurring events
- Cancel individual instances via `cancellations` table
- Safety limits: Max 1000 instances per query to prevent DOS
### ๐ Idempotency
Prevents duplicate events from retries:
- Optional `idempotency_key` parameter in `calendar.create`
- If key exists, returns existing event (no duplicate created)
- Unique constraint enforced at database level
### ๐พ Storage
Uses **SQLite** with `better-sqlite3`:
- **Synchronous API**: Simpler, more reliable than async
- **WAL Mode**: Better concurrency
- **Schema**:
- `events`: Core event data (title, start_utc, duration, timezone, recurrence)
- `cancellations`: Tracks cancelled instances of recurring events
- Indexes on `start_utc` and `idempotency_key` for performance
## ๐ฆ Installation
```bash
# Clone or navigate to project directory
cd calender-mcp
# Install dependencies
npm install
# Build TypeScript
npm run build
```
## ๐ Usage
### Running the Server
```bash
npm start
```
The server runs on **stdio** (standard input/output) as per MCP specification.
### Configuring with Claude Desktop
Add to your Claude Desktop config (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"calendar": {
"command": "node",
"args": ["C:/path/to/calender-mcp/dist/index.js"]
}
}
}
```
### Example Tool Calls
#### 1. Create a Simple Event
```json
{
"tool": "calendar.create",
"arguments": {
"title": "Team Standup",
"start": "2026-01-20T09:00:00",
"end": "2026-01-20T09:30:00",
"tz": "Asia/Kolkata"
}
}
```
#### 2. Create a Recurring Event
```json
{
"tool": "calendar.create",
"arguments": {
"title": "Weekly Review",
"start": "2026-01-20T15:00:00",
"end": "2026-01-20T16:00:00",
"tz": "America/New_York",
"recurrence": {
"freq": "weekly",
"interval": 1,
"until": "2026-06-30T23:59:59"
},
"idempotency_key": "weekly-review-2026"
}
}
```
#### 3. List Events
```json
{
"tool": "calendar.list",
"arguments": {
"range_start": "2026-01-20T00:00:00Z",
"range_end": "2026-01-27T00:00:00Z"
}
}
```
#### 4. Cancel an Entire Event Series
```json
{
"tool": "calendar.cancel",
"arguments": {
"event_id": "abc-123-def-456"
}
}
```
#### 5. Cancel a Specific Instance
```json
{
"tool": "calendar.cancel",
"arguments": {
"event_id": "abc-123-def-456",
"instance_start_utc": "2026-01-27T10:00:00.000Z"
}
}
```
## ๐๏ธ Architecture
```
src/
โโโ index.ts # MCP server setup & tool registration
โโโ storage/
โ โโโ db.ts # SQLite schema & connection
โโโ time/
โ โโโ timezone.ts # UTC conversion utilities (Luxon)
โโโ recurrence/
โ โโโ expand.ts # Recurrence expansion logic
โโโ tools/
โโโ create.ts # calendar.create handler
โโโ list.ts # calendar.list handler
โโโ cancel.ts # calendar.cancel handler
```
## ๐งช Testing
Create a test script (`test.mjs`):
```javascript
import { spawn } from 'child_process';
const server = spawn('node', ['dist/index.js']);
// Send MCP request
const request = {
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'calendar.create',
arguments: {
title: 'Test Event',
start: '2026-01-20T10:00:00',
end: '2026-01-20T11:00:00',
tz: 'UTC'
}
}
};
server.stdin.write(JSON.stringify(request) + '\n');
server.stdout.on('data', (data) => {
console.log('Response:', data.toString());
});
```
Run: `node test.mjs`
## ๐ง Known Limitations
1. **No Sync**: Events are stored locally only. No Google Calendar / Outlook sync.
2. **No Notifications**: Server doesn't send reminders or alerts.
3. **Recurrence Complexity**: Only supports simple rules (no "2nd Tuesday of month").
4. **Performance**: Recurrence expansion is brute-force iteration (acceptable for <1000 instances).
5. **No Conflict Detection**: Doesn't prevent overlapping events.
## ๐ฎ Future Extensions
- **Calendar Sync**: Integrate with Google Calendar API, Microsoft Graph
- **Notifications**: Email/SMS reminders via Twilio, SendGrid
- **Search**: Full-text search on event titles/notes
- **Attachments**: Store files/links with events
- **Attendees**: Multi-user support with invitations
- **Conflict Detection**: Warn about overlapping events
- **Advanced Recurrence**: RRULE support (RFC 5545)
## ๐ Design Decisions
### Why Luxon over Moment/Date-fns?
- **Immutable**: Safer API, no accidental mutations
- **IANA Timezone Support**: Built-in, no extra plugins
- **Modern**: Active development, ESM-first
### Why SQLite over JSON Files?
- **ACID Guarantees**: Atomic writes, no corruption
- **Indexes**: Fast lookups on `start_utc`, `idempotency_key`
- **Constraints**: Unique keys enforced at DB level
- **Scalability**: Handles thousands of events efficiently
### Why Virtual Instances for Recurrence?
- **Storage Efficiency**: One row instead of hundreds
- **Flexibility**: Change recurrence rule retroactively
- **Cancellations**: Track exceptions cleanly
## ๐ License
ISC
---
**Built with โค๏ธ for the MCP ecosystem**