Calendar MCP server with atomic booking, conflict prevention, deterministic RRULE expansion, and TOON token compression for AI agents
Temporal Cortex MCP
The complete temporal stack for AI agents. Context. Computation. Calendars. Correct.
The Problem
LLMs get date and time tasks wrong roughly 60% of the time (AuthenHallu benchmark). Ask "What time is it?" and the model hallucinates. Ask "Schedule for next Tuesday at 2pm" and it picks the wrong Tuesday. Ask "Am I free at 3pm?" and it checks the wrong timezone. Then it double-books your calendar.
Every other Calendar MCP server is a thin CRUD wrapper that passes these failures through to Google Calendar — no temporal awareness, no conflict detection, no safety net.
What's Different
- Temporal awareness — Agents call
get_temporal_contextto know the actual time and timezone.resolve_datetimeturns"next Tuesday at 2pm"into a precise RFC 3339 timestamp. No hallucination. - Atomic booking — Lock the time slot, verify no conflicts exist, then write. Two agents booking the same 2pm slot? Exactly one succeeds. The other gets a clear error. No double-bookings.
- Computed availability — Merges free/busy data across multiple calendars into a single unified view. The AI sees actual availability, not a raw dump of events to misinterpret.
- Deterministic RRULE expansion — Handles DST transitions,
BYSETPOS=-1(last weekday of month),EXDATEwith timezones, leap year recurrences, andINTERVAL>1withBYDAY. Powered by Truth Engine, not LLM inference. - Token-efficient output — TOON format compresses calendar data to ~40% fewer tokens than standard JSON, reducing costs and context window usage.
Prerequisites
- Node.js 18+ (for
npxto download and run the binary) or Docker - At least one calendar provider:
- Google Calendar — requires Google OAuth credentials
- Microsoft Outlook — requires Azure AD app registration (
MICROSOFT_CLIENT_ID) - CalDAV (iCloud, Fastmail, etc.) — requires an app-specific password
Quick Start
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"temporal-cortex": {
"command": "npx",
"args": ["-y", "@temporal-cortex/cortex-mcp"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"TIMEZONE": "America/New_York"
}
}
}
}
Cursor
Add to Cursor's MCP settings (~/.cursor/mcp.json):
{
"mcpServers": {
"temporal-cortex": {
"command": "npx",
"args": ["-y", "@temporal-cortex/cortex-mcp"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"TIMEZONE": "America/New_York"
}
}
}
}
Windsurf
Add to Windsurf's MCP config (~/.codeium/windsurf/mcp_config.json):
{
"mcpServers": {
"temporal-cortex": {
"command": "npx",
"args": ["-y", "@temporal-cortex/cortex-mcp"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"TIMEZONE": "America/New_York"
}
}
}
}
Docker
docker run --rm -i \
-e GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com" \
-e GOOGLE_CLIENT_SECRET="your-client-secret" \
-e TIMEZONE="America/New_York" \
-v ~/.config/temporal-cortex:/root/.config/temporal-cortex \
cortex-mcp
Build the image first: docker build -t cortex-mcp . (or build directly from the repo: docker build -t cortex-mcp https://github.com/billylui/temporal-cortex-mcp.git).
Need Google OAuth credentials? See docs/google-cloud-setup.md for a step-by-step guide. For Outlook, add
MICROSOFT_CLIENT_ID. For CalDAV (iCloud/Fastmail), no env vars needed — runauth caldavand enter your app-specific password.
First-Time Setup
On first run, the server needs calendar provider credentials. Run the auth flow for each provider you want to connect:
# Google Calendar (default)
npx @temporal-cortex/cortex-mcp auth google
# Microsoft Outlook
npx @temporal-cortex/cortex-mcp auth outlook
# CalDAV (iCloud, Fastmail, or custom server)
npx @temporal-cortex/cortex-mcp auth caldav
# Docker (interactive auth — needs terminal + browser)
docker run --rm -it \
-e GOOGLE_CLIENT_ID="your-id" -e GOOGLE_CLIENT_SECRET="your-secret" \
-p 8085:8085 \
-v ~/.config/temporal-cortex:/root/.config/temporal-cortex \
cortex-mcp auth google
Each auth flow saves credentials to ~/.config/temporal-cortex/credentials.json and registers the provider in ~/.config/temporal-cortex/config.json. You can connect multiple providers — the server discovers all configured providers on startup and merges their calendars into a unified view.
During auth, the server guides you through interactive setup:
- Timezone — auto-detects your system timezone and opens a fuzzy-search picker with all 597 IANA timezones (type to filter, arrow keys to navigate)
- Week start — arrow-key selection between Monday (ISO standard) and Sunday
- Telemetry — optional anonymous usage data (default: off)
All preferences are stored in ~/.config/temporal-cortex/config.json and used by all temporal tools. You can override them per-session with the TIMEZONE and WEEK_START env vars.
After authentication, verify it works by asking your AI assistant: "What time is it?" — the agent should call get_temporal_context and return your current local time.
Available Tools (11)
Layer 1 — Temporal Context
| Tool | Description |
|------|-------------|
| get_temporal_context | Current time, timezone, UTC offset, DST status, day of week. Call this first. |
| resolve_datetime | Resolve human expressions ("next Tuesday at 2pm", "tomorrow morning", "+2h") to RFC 3339. |
| convert_timezone | Convert any RFC 3339 datetime between IANA timezones. |
| compute_duration | Duration between two timestamps (days, hours, minutes, human-readable). |
| adjust_timestamp | DST-aware timestamp adjustment ("+1d" across spring-forward = same wall-clock). |
Layer 2 — Calendar Operations
| Tool | Description |
|------|-------------|
| list_events | List calendar events in a time range. Supports provider-prefixed IDs (google/primary). Output in TOON (~40% fewer tokens) or JSON. |
| find_free_slots | Find available time slots in a calendar. Supports provider-prefixed IDs. Computes actual gaps between events. |
| expand_rrule | Expand recurrence rules into concrete instances. Handles DST, BYSETPOS, leap years. |
| check_availability | Check if a specific time slot is available against events and active locks. |
Layer 3 — Availability
| Tool | Description |
|------|-------------|
| get_availability | Merged free/busy view across multiple calendars with privacy controls. |
Layer 4 — Booking
| Tool | Description |
|------|-------------|
| book_slot | Book a calendar slot safely. Lock → verify → write with Two-Phase Commit. |
See docs/tools.md for full input/output schemas and usage examples.
The RRULE Challenge
Most AI models and calendar tools silently fail on recurrence rule edge cases. Run the challenge to see the difference:
npx @temporal-cortex/cortex-mcp rrule-challenge
5 cases where LLMs consistently fail
1. "Third Tuesday of every month" across DST (March 2026, America/New_York)
The third Tuesday is March 17. Spring-forward on March 8 shifts UTC offsets from -05:00 to -04:00. LLMs often produce the wrong UTC time or skip the month entirely.
2. "Last Friday of every month" (BYSETPOS=-1)
RRULE:FREQ=MONTHLY;BYDAY=FR;BYSETPOS=-1 — LLMs frequently return the first Friday instead of the last, or fail to handle months with 4 vs 5 Fridays.
3. "Every weekday except holidays" (EXDATE with timezone)
EXDATE values with explicit timezone offsets require exact matching against generated instances. LLMs often ignore EXDATE entirely or apply it to the wrong date.
4. "Biweekly on Monday, Wednesday, Friday" (INTERVAL=2 + BYDAY)
RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE,FR — The INTERVAL=2 applies to weeks, not individual days. LLMs frequently generate every-week occurrences instead of every-other-week.
5. "February 29 yearly" (leap year recurrence)
RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=29 — Should only produce instances in leap years (2028, 2032...). LLMs often generate Feb 28 or Mar 1 in non-leap years.
Truth Engine handles all of these deterministically using the RFC 5545 specification. No inference, no hallucination.
How It Works
The MCP server is a single Rust binary distributed via npm and Docker. It runs locally on your machine and communicates with MCP clients over stdio (standard input/output) or streamable HTTP.
- Truth Engine handles all date/time computation: temporal resolution, timezone conversion, RRULE expansion, availability merging, conflict detection. Deterministic, not inference-based.
- TOON (Token-Oriented Object Notation) compresses calendar data for LLM consumption — fewer tokens, same information.
- Two-Phase Commit ensures booking safety: acquire lock, verify the slot is free, write the event, release lock. If any step fails, everything rolls back.
Stdio vs HTTP Transport
Transport mode is auto-detected — set HTTP_PORT to switch from stdio to HTTP.
- Stdio (default): Standard MCP transport for local clients (Claude Desktop, VS Code, Cursor). The server reads/writes JSON-RPC messages over stdin/stdout.
- HTTP (when
HTTP_PORTis set): Streamable HTTP transport per MCP 2025-11-25 spec. The server listens onhttp://{HTTP_HOST}:{HTTP_PORT}/mcpwith SSE streaming, session management (Mcp-Session-Idheader), and Origin validation. Requests with an invalidOriginheader are rejected with HTTP 403.
# HTTP mode example
HTTP_PORT=8009 npx @temporal-cortex/cortex-mcp
Local Mode vs Platform Mode
Mode is auto-detected — there is no configuration flag.
- Local Mode (default): No infrastructure required. Uses in-memory locking and local file credential storage. Supports multiple calendar providers (Google, Outlook, CalDAV) with multi-calendar availability merging. Designed for individual developers.
- Platform Mode (activated when
REDIS_URLSis set): Uses Redis-based distributed locking (Redlock) for multi-process safety. Designed for production deployments with multiple concurrent agents.
Configuration
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| GOOGLE_CLIENT_ID | For Google | — | Google OAuth Client ID from Cloud Console |
| GOOGLE_CLIENT_SECRET | For Google | — | Google OAuth Client Secret |
| GOOGLE_OAUTH_CREDENTIALS | No | — | Path to Google OAuth JSON credentials file (alternative to CLIENT_ID + CLIENT_SECRET) |
| MICROSOFT_CLIENT_ID | For Outlook | — | Azure AD application (client) ID for Outlook calendar access |
| TIMEZONE | No | auto-detected | IANA timezone override (e.g., America/New_York). Overrides stored config and OS detection. |
| WEEK_START | No | monday | Week start day: monday (ISO 8601) or sunday. Affects "start of week", "next week", etc. |
| REDIS_URLS | No | — | Comma-separated Redis URLs. When set, activates Platform Mode with distributed locking. |
| TENANT_ID | No | auto-generated | UUID for tenant isolation |
| LOCK_TTL_SECS | No | 30 | Lock time-to-live in seconds |
| OAUTH_REDIRECT_PORT | No | 8085 | Port for the local OAuth callback server |
| HTTP_PORT | No | — | Port for HTTP transport. When set, enables streamable HTTP mode instead of stdio. |
| HTTP_HOST | No | 127.0.0.1 | Bind address for HTTP transport. Use 0.0.0.0 only behind a reverse proxy. |
| ALLOWED_ORIGINS | No | — | Comma-separated allowed Origin headers for HTTP mode (e.g., http://localhost:3000). All cross-origin requests rejected if unset. |
At least one calendar provider must be configured. See docs/google-cloud-setup.md for Google setup. CalDAV providers (iCloud, Fastmail) use app-specific passwords configured via cortex-mcp auth caldav.
Troubleshooting
| Problem | Solution |
|---------|----------|
| "No credentials found" | Run npx @temporal-cortex/cortex-mcp auth google (or outlook / caldav) to authenticate |
| OAuth error / "Access blocked" | Verify GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET (or MICROSOFT_CLIENT_ID for Outlook) are correct. Ensure the OAuth consent screen is configured. |
| Port 8085 already in use | Set OAUTH_REDIRECT_PORT to a different port (e.g., 8086) |
| Server not appearing in MCP client | Ensure Node.js 18+ is installed (node --version). Check your MCP client's logs for errors. |
| Provider not discovered on startup | Verify the provider is registered in ~/.config/temporal-cortex/config.json (run auth again if needed) |
See docs/google-cloud-setup.md for detailed Google OAuth troubleshooting.
Telemetry
We'd love your help making Temporal Cortex better! During setup, an interactive prompt asks if you'd like to share anonymous usage data (default: off).
Collected: tool names, success/error counts, platform, version. Never collected: calendar data, events, or personal info.
Non-interactive sessions (MCP stdio) auto-opt-out. Change your choice anytime:
export TEMPORAL_CORTEX_TELEMETRY=off
Ready for More?
The open-source MCP server gives you full multi-calendar intelligence: connect Google, Outlook, and CalDAV simultaneously, with unified availability merging and conflict-free booking. When you're ready for more:
Managed Cloud (Free) — Zero-setup hosting with managed OAuth and dashboard UI. Up to 3 connected calendars, 50 bookings/month, all 11 tools. → Sign up for early access
Open Scheduling (Pro) — Let external agents and people book time with you. Shareable availability, inbound booking API, caller-based policies, and unlimited calendar connections. → Request Early Access
Enterprise — Self-hosted platform deployment, SSO/SAML, audit log export, data residency, and compliance documentation. → Contact us
Agent Skill
The calendar-scheduling Agent Skill teaches AI agents the correct workflow for using these tools — from temporal orientation through conflict-free booking. Install it to give your agent procedural knowledge for calendar operations:
# Claude Code
cp -r temporal-cortex-skill/calendar-scheduling ~/.claude/skills/
The skill follows the Agent Skills specification and works with Claude Code, OpenAI Codex, Google Gemini, GitHub Copilot, Cursor, and 20+ other platforms.
Built on Temporal Cortex Core
The computation layer is open source:
- temporal-cortex-core — Truth Engine (temporal resolution, RRULE expansion, availability merging, timezone conversion) + TOON (token compression)
- Available on crates.io, npm, and PyPI
- 510+ Rust tests, 42 JS tests, 30 Python tests, ~9,000 property-based tests
Contributing
Bug reports and feature requests are welcome. See CONTRIBUTING.md.