Skip to main content
Glama
DRITI2906
by DRITI2906

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

Related MCP server: Temporal Cortex MCP

โœจ 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 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

# Clone or navigate to project directory
cd calender-mcp

# Install dependencies
npm install

# Build TypeScript
npm run build

๐Ÿš€ Usage

Running the Server

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):

{
  "mcpServers": {
    "calendar": {
      "command": "node",
      "args": ["C:/path/to/calender-mcp/dist/index.js"]
    }
  }
}

Example Tool Calls

1. Create a Simple Event

{
  "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

{
  "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

{
  "tool": "calendar.list",
  "arguments": {
    "range_start": "2026-01-20T00:00:00Z",
    "range_end": "2026-01-27T00:00:00Z"
  }
}

4. Cancel an Entire Event Series

{
  "tool": "calendar.cancel",
  "arguments": {
    "event_id": "abc-123-def-456"
  }
}

5. Cancel a Specific Instance

{
  "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):

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

Related MCP Connectors

Related MCP Servers