ics-cal-mcp
Reads a Google Calendar feed via its secret iCal address and exposes the events as JSON tools, allowing an assistant to list events overlapping a given day or a date range, with recurring events expanded and time zones handled correctly.
Reads a published iCloud calendar ICS feed (handled by the generic feed profile) and exposes its events as JSON, supporting day and date-range queries with recurrence, exclusion and override expansion.
Reads a published Nextcloud calendar ICS feed (handled by the generic feed profile) and exposes its events as JSON, supporting day and date-range queries with recurrence, exclusion and override expansion.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ics-cal-mcpwhat's on my calendar today?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ics-cal-mcp
A read-only MCP server that turns a published ICS calendar feed into three JSON tools for an AI assistant. MCP (Model Context Protocol) is the standard that AI clients such as Claude Desktop use to call external tools.
You run it with uvx. You do not need Docker. The only tool to install is uv.
This is a Python reimplementation of hromadkom/calendar-ics-mcp, which is written in Rust and runs in Docker. It keeps the same tools, the same output format, and the same test fixtures. It adds feed profiles, so that feeds that do not come from Exchange also give correct results.
What it does
The server downloads the full feed and checks that it is complete. It expands recurring events in the correct time zone, across daylight saving time changes. It returns small, ready-to-use JSON.
A generic web-fetch tool is not enough for a calendar feed, for two reasons:
Fetch tools cut off large responses. A calendar feed is large, so events at the end are lost without a warning. This server checks that the feed ends with
END:VCALENDAR.An ICS file is not a list of events. A weekly meeting is one
VEVENTwith anRRULE(recurrence rule). A cancelled occurrence is anEXDATE(excluded date). A moved occurrence is a separate component with aRECURRENCE-ID. The server applies all of these rules.
Related MCP server: ICS Calendar MCP Server
Tools
Tool | Input | Output |
|
| Events that overlap that local day, sorted by start time. |
|
| The same format, for a date range. |
| None. | Feed diagnostics: size, event count, date range, cache age, the profile in use, and whether the feed is complete. |
Each tool returns its result in structuredContent and as the same JSON text in content[0].text. If a tool fails (the feed is unreachable, the feed is truncated, or an argument is wrong), the result has isError: true. The server does not send a protocol error for these cases.
Example output of get_events:
{
"date": "2026-07-14",
"events": [
{
"all_day": false,
"busy_status": "TENTATIVE",
"description": "Agenda without the Teams dial-in text",
"end": "2026-07-14T14:45:00+02:00",
"is_recurring": true,
"location": "Microsoft Teams Meeting",
"meeting_url": "https://teams.microsoft.com/l/meetup-join/…",
"start": "2026-07-14T14:15:00+02:00",
"summary": "Design review"
}
],
"timezone": "Europe/Brussels"
}Timed events use ISO 8601 with the TZ_DEFAULT offset. All-day events use date-only strings, and the end date is exclusive. A day query returns every event that overlaps the local day. For example, a meeting that runs past midnight shows on both days.
Feed profiles
The server selects a profile from the feed URL. The profile decides which feed-specific rules apply.
If the host is
outlook.office365.com,outlook.office.comoroutlook.live.com, theexchangeprofile applies. If the URL path contains/owa/calendar/, theexchangeprofile also applies. On-premises Exchange servers publish calendars under that path. This profile gives the same results as the Rust original.The
genericprofile applies to all other feeds, for example Google Calendar, iCloud, Fastmail or Nextcloud.
To force a profile, set ICS_PROFILE to exchange or generic.
Rule |
|
|
|
|
|
|
| The description, then the location |
Teams dial-in text in the description | Removed, from the first line of | Kept |
| Ignored, as Exchange does not send it | The event or occurrence is left out |
| Ignored, as Exchange does not send it | Added to the occurrences |
Floating times (no | Read as UTC | Read in the calendar's |
Windows time zone names, for example | Mapped to IANA names | Mapped to IANA names |
| Supported | Supported |
The Windows time zone mapping applies in both profiles. A Windows name can only mean one zone, and Outlook exports that are hosted elsewhere also use these names.
These items are not supported in either profile: RANGE=THISANDFUTURE, RDATE values of type PERIOD, and EXRULE.
Get your ICS URL
For Outlook on the web, do these steps:
Open Settings, then Calendar, then Shared calendars.
Under Publish a calendar, select the calendar and select Can view all details. Lower permissions remove the fields that the tools return.
Select Publish, and copy the ICS link (not the HTML link).
For Google Calendar, open the calendar settings and copy the Secret address in iCal format.
Keep the URL secret, like a password. Anyone who has the URL can read the whole calendar. The URL does not expire. Never commit it to Git, never log it, and never paste it into an issue.
Configure your MCP client
You need uv on your computer. On macOS, you can install it with brew install uv. When the client starts the server for the first time, uv downloads the package and a matching Python version. After that, uv uses its cache.
For Claude Desktop, add this to claude_desktop_config.json:
{
"mcpServers": {
"calendar": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/kspeeckaert/ics-cal-mcp@v1.0.20261005",
"ics-cal-mcp"
],
"env": {
"ICS_URL": "https://outlook.office365.com/owa/calendar/…/calendar.ics",
"TZ_DEFAULT": "Europe/Brussels"
}
}
}
}Notes:
The
@v1.0.20261005suffix pins a release tag. To update, change the tag. If you remove the suffix, uv uses the default branch.Claude Desktop starts commands with a minimal
PATH. If the client cannot finduvx, use the full path. To find it, runwhich uvxin a terminal. With Homebrew on Apple Silicon, the path is usually/opt/homebrew/bin/uvx.Other MCP clients that support stdio servers use the same command, arguments and environment variables.
Configuration
You configure the server with environment variables.
Variable | Required | Default | Description |
| Yes | None | The published ICS feed URL ( |
| No |
| The IANA zone for date queries and for output times. |
| No |
|
|
| No |
| How long the server keeps the downloaded feed in memory. |
| No |
| The timeout for each network step (connect, read) of the download. |
The server ignores the time zone of your computer. The results depend only on TZ_DEFAULT and the feed. The same query gives the same result on any machine.
Security
The server is read-only. It sends one kind of request: a
GETto the configuredICS_URL. It writes nothing and calls no other service.The calendar data stays in memory for at most
CACHE_TTL_SECONDS. There is no telemetry.The URL does not leak. Logs, error messages and tool output show only the scheme and the host (for example
https://outlook.office365.com/…). The tests make sure that the secret part of the URL never appears.If the feed does not end with
END:VCALENDAR, the server treats it as truncated. The event tools then return an error and do not return partial data.feed_infostill answers, so that you can see the problem.TLS certificates are checked against the trust store of your operating system.
Development
You need uv. The commands below install the development tools in a local .venv folder.
git clone https://github.com/kspeeckaert/ics-cal-mcp.git
cd ics-cal-mcp
uv sync
uv run pytest
uv run ruff check .
uv run ruff format --check .To check that the results do not depend on the host time zone, run the tests with another zone:
TZ=Pacific/Kiritimati uv run pytestTo run the server from your local copy against a real feed, without the URL in your shell history:
read -rs ICS_URL && export ICS_URL
uvx --from . ics-cal-mcpCall feed_info first. It must show ends_with_end_vcalendar: true, a plausible vevent_count, and the profile you expect.
Project layout
src/ics_cal_mcp/
├── __main__.py # entry point: configuration, start log line, stdio transport
├── server.py # tool definitions, argument checks, results, MCP wiring
├── config.py # environment variables (the only module that reads them)
├── profile.py # exchange and generic feed profiles, detection from the URL
├── feed.py # download, single-slot TTL cache, END:VCALENDAR check
├── errors.py # error types, URL masking and sanitizing
├── log.py # JSON log lines on stderr (stdout is for JSON-RPC only)
└── ics/
├── tzids.py # line unfolding, Windows to IANA TZID rewrite
├── windows_zones.py # CLDR Windows to IANA table
├── parse.py # ICS content-line parser
├── model.py # parsed event types
├── timeutil.py # instant arithmetic in epoch milliseconds
├── rrule_slots.py # RRULE occurrences from python-dateutil
├── expand.py # RRULE, EXDATE, RDATE and override expansion
└── format.py # output: offsets, busy status, meeting URL, descriptionVersions
Versions use the format major.minor.YYYYMMDD, for example 1.0.20261005. Increase the version in pyproject.toml for each change, and add an entry to CHANGELOG.md. Tag each release as v<version>.
License
MIT. The design, the tool contract and the test fixtures come from hromadkom/calendar-ics-mcp (MIT, © Martin Hromádko). The Windows time zone table comes from the Unicode CLDR project (Unicode License v3).
This server cannot be deployed
Maintenance
Related MCP Connectors
Calendar API for AI agents: events, availability, Google/Microsoft setup, scheduling, and iCal.
Turns one JSON payload into a complete RFC 5545 .ics file — recurrence (RRULE), real IANA time zo...
GDPR-compliant calendar access for AI assistants: read, create, edit, RSVP. Google, MS 365, Apple.
Extracts calendar events from natural-language text, with .ics and calendar links.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA read-only MCP server that exposes iCalendar feeds as queryable tools for LLM agents, enabling calendar event retrieval and filtering.MIT
- AlicenseNot gradedqualityDmaintenanceEnables reading and interacting with ICS calendar feeds (e.g., Outlook, Google Calendar) with recurring event expansion, caching, and timezone support.MIT
- AlicenseAqualityCmaintenanceCalendar API purpose-built for AI agents. Exposes tools to manage agents, calendars, and events, find meeting times, run scheduling proposals, set availability rules, manage webhooks, and subscribe to iCal feeds.5486 npmApache 2.0
- AlicenseNot gradedqualityCmaintenanceProvides read-only access to calendar events from iCal feeds, enabling agents to query schedules, search events, and check availability via natural language.AGPL 3.0