ICS Calendar MCP
Reads private Google Calendar ICS subscription feeds to compute merged busy intervals and available free slots without exposing event titles or calendar contents.
Reads private iCloud Calendar ICS subscription feeds to compute merged busy intervals and available free slots without exposing event titles or calendar contents.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Why ICS Calendar MCP
To plan a meeting, an AI assistant needs to know when you're free. Most calendar integrations hand it far more than that: meeting titles, notes, who you're meeting, where, and often write access too.
ICS Calendar MCP gives the assistant only time ranges. It reads the private subscription links that iCloud, Google and most calendar apps can publish, strips every event down to a start and an end, merges your calendars, and returns busy blocks or free slots. Event details and feed URLs never leave the server.
Ask things like "Find me a free hour on Thursday afternoon" or "Am I free Friday between 2 and 4?"
Related MCP server: google-calendar-mcp
The three tools
All three are read-only.
Tool | What it returns |
| Configured calendar IDs, display names and timezones, plus the current time. Never feed URLs or secrets. |
| Merged busy intervals ( |
| Free windows of at least N minutes inside working hours (default 09:00–17:00 on weekdays), with an optional buffer around meetings. |
Timed, all-day, multi-day and overnight events
Recurrence (
RRULE,RDATE,EXDATE), modified and cancelled occurrences, andRANGE=THISANDFUTURESTATUS:CANCELLEDandTRANSP:TRANSPARENTevents are skipped;STATUS:TENTATIVEevents are reported astentativeIANA timezones, embedded
VTIMEZONEdefinitions, floating times (read in the calendar's default timezone) and DST transitionsOverlapping events from any number of calendars are merged
Quick start
You need Node.js 22 or newer (24 recommended; see .nvmrc).
git clone https://github.com/mihirkavi/ics-calendar-mcp.git
cd ics-calendar-mcp
npm install
npm test # 125 tests in the Workers runtime (Miniflare), no network accessnpm run check type-checks and npm run lint runs ESLint. To run the Worker locally, copy .dev.vars.example to .dev.vars, fill it in and run npm run dev. The sign-in cookies need HTTPS, so use wrangler dev --local-protocol https or test sign-in against a deployed Worker.
How it works
MCP client ──OAuth 2.1──▶ Cloudflare Worker
├─ OAuth provider (/authorize, /token, /register, discovery)
│ └─ GitHub sign-in + numeric-ID allowlist
└─ /mcp (stateless Streamable HTTP)
└─ CalendarService
├─ registry (IDs → secret bindings)
├─ fetch policy (HTTPS, exact host, limits)
├─ ICS adapter (ICAL.js → detail-free intervals)
└─ interval merge + free-slot searchThe server stores no event data: each request fetches the feeds live, turns them into bare intervals and throws the rest away.
Privacy by design
No event content. The ICS adapter reads only start, end, duration, recurrence, status and transparency.
Callers can't choose URLs. Feeds come only from an operator-defined registry and Worker secrets. Each fetch needs HTTPS and an exact hostname, rejects embedded credentials, custom ports and redirects, times out after 10 seconds and stops at 5 MiB.
Bounded work. Ranges are capped at 93 days, 10,000 busy occurrences per calendar and 100,000 recurrence candidates.
Locked-down sign-in. PKCE (S256), exact redirect-URI checks, a consent page that can't be framed, single-use browser-bound state, and tokens stored only as hashes in Cloudflare KV. The GitHub token is discarded after the identity check.
Redacted errors. Public errors carry a stable code and a generic message, with URLs, credentials and calendar text scrubbed.
Treat calendar subscription links like passwords. Anyone with the link can read the full calendar. Keep them in Worker secrets, and regenerate them in your calendar app if they're ever exposed.
Deploy your own
One Cloudflare Worker (the free plan is enough to try it), a GitHub account and a GitHub OAuth App.
npx wrangler kv namespace create OAUTH_KV # put the ID in wrangler.jsonc
npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET
npx wrangler secret put ALLOWED_GITHUB_USER_ID # numeric: gh api user --jq .id
npx wrangler secret put CALENDAR_REGISTRY # JSON array, see below
npx wrangler secret put CALENDAR_1_ICS_URL # one per calendar
npm run deployYour MCP endpoint is https://<your-worker-host>/mcp. Set the OAuth App's callback URL to https://<your-worker-host>/callback.
Without configuration, the server uses one synthetic example calendar (example-calendar, read from the CALENDAR_EXAMPLE_ICS_URL secret, host calendar.example.com). To use your own, set CALENDAR_REGISTRY to a JSON array:
[
{
"id": "work",
"name": "Work",
"enabled": true,
"timezone": "America/New_York",
"secretBinding": "CALENDAR_1_ICS_URL",
"allowedHostname": "calendar.example.com"
}
]id: lowercase letters, digits and hyphens. MCP clients pass it ascalendarIds.timezone: an IANA zone, used for all-day and floating events and as the default output zone.secretBinding: the name of a separate Worker secret that holds the feed URL.allowedHostname: the exact host the feed URL must use.
Feed URLs must be https://. If your calendar app gives you a webcal:// link, replace webcal with https.
If you don't want the KV namespace ID in Git, copy wrangler.jsonc to wrangler.local.jsonc (ignored by Git), edit the copy, and pass -c wrangler.local.jsonc to Wrangler. npm run deploy:local does this for you. Each secret put prompts for its value, so secrets never land in your shell history or in files.
OAuth discovery is published at /.well-known/oauth-protected-resource/mcp and /.well-known/oauth-authorization-server, and clients can register dynamically at /register.
ChatGPT: add a custom MCP connector with the
/mcpURL and OAuth, then sign in with GitHub. Whether custom connectors (and connectors in mobile and Voice modes) are available depends on your plan, workspace settings and OpenAI's rollout.MCP Inspector: run
npx @modelcontextprotocol/inspector, choose Streamable HTTP, enter the/mcpURL and complete the OAuth flow.Other clients: any client that supports remote Streamable HTTP servers with OAuth 2.1 discovery and dynamic client registration should work.
Path | Responsibility |
| Worker entry: OAuth provider wiring and the protected |
| Consent page, GitHub sign-in, numeric-ID allowlist |
| Tool schemas, registration and text summaries |
| Registry, service, ICS adapter, interval math, timezone helpers |
| Feed fetch policy and error redaction |
Honest status
v0.1 is an early, read-only foundation. It works end to end and has been verified with a standalone MCP client against one private deployment (record), but it hasn't been tested across many calendar providers, and ChatGPT connector use is not yet verified.
Read-only: no creating, editing or deleting events, and no CalDAV.
One allowed GitHub account per deployment; no multi-user access.
Feeds are fetched live on every request with no cache. A slow or offline provider makes that calendar
unavailable(reported, never silently empty).Published ICS feeds can lag behind the calendar app by several minutes.
Working hours can't cross midnight, and
find_free_slotsreturns at most 100 windows.A calendar that needs more than 100,000 recurrence candidates, or has more than 10,000 busy occurrences in the range, is reported as
unavailablefor that request.Windows-style timezone names such as
Pacific Standard Timework only when the feed includes their definition.
Ideas, not commitments (none implemented): short-lived caching with explicit stale coverage, per-calendar working hours, and CalDAV as another source.
Contributing
See CONTRIBUTING.md and the changelog. Please report vulnerabilities privately as described in SECURITY.md, not in public issues.
License
MIT © 2026 Mihir Kavishwar
This server cannot be deployed
Maintenance
Related MCP Connectors
Merged free/busy, find mutual time, propose bookings with human approval. Never event contents.
Hosted Google Calendar MCP server for AI agents. No self-hosting or Google Cloud setup.
Calendar API for AI agents: events, availability, Google/Microsoft setup, scheduling, and iCal.
Keeper.sh calendar sync: read and book events, RSVP and find free time across synced calendars.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides AI assistants with intelligent access to Google Calendar data, enabling natural language queries about availability, upcoming events, schedule conflicts, and meeting summaries through context-aware calendar integration.-
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to read and manage a user's Google Calendar, including listing calendars, searching, creating, updating, and deleting events, and checking free/busy availability via OAuth 2.0.109 npmMIT
- AlicenseAqualityBmaintenanceEnables privacy-safe calendar availability queries across Outlook, iCloud, and Google ICS feeds, exposing only busy/free intervals and free-slot search without revealing event details.3MIT
- AlicenseNot gradedqualityAmaintenanceEnables assistants and agents to query calendar availability from Google, Outlook, iCloud, or ICS feeds and return free time slots for specified days, date ranges, or pasted messages. It exposes read-only tools for finding availability and checking calendar readability without exposing calendar addresses.23 PyPIApache 2.0