agentic-cal
Provides calendar integration with iCloud, allowing reading of ICS feeds and writing of time blocks via iMIP email invitations.
Provides calendar integration with Proton Calendar, allowing reading of ICS feeds and writing of time blocks via iMIP email invitations.
Click on "Install 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., "@agentic-calShow my available times for tomorrow afternoon."
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.
agentic-cal
Agentic email + calendar hub on Cloudflare Workers. One Worker owns your domain's email surface: a full self-hosted email client with an AI agent, plus a unified calendar that aggregates Proton / Outlook / iCloud into one busy/free model and writes time blocks back to all three, using nothing but standards-compliant email invitations. No OAuth, no CalDAV, no provider APIs.
Forked from cloudflare/agentic-inbox (Apache 2.0) as a chassis: cloned, renamed, owned. Not tracked against upstream.
In one paragraph: the read path polls each provider's secret ICS publish link every 10 minutes (conditional GETs via KV, raw snapshots to R2) and expands everything (recurrence rules, exceptions, timezones) into a unified busy/free model in a Durable Object. The write path is RFC 5546 over RFC 6047: blocking time emails a standards-compliant invitation to each account, the native client renders a normal meeting invite, and the acceptance (METHOD:REPLY) routes back into the same Worker's email() handler where a Cloudflare Workflow tracks per-account acceptance. Clients accept; providers do the writing.
What it does
Full email client. Send and receive via Cloudflare Email Routing; rich text composer, threading, folders, search, attachments. Each mailbox is an isolated Durable Object (SQLite) with R2 for attachments.
Unified calendar (read). Each provider publishes a read-only ICS feed (Proton "share via link", Outlook "publish calendar", iCloud "public calendar"). A cron poller normalizes all of them (RRULE expansion, EXDATE, RECURRENCE-ID overrides, timezones) into one availability model with per-feed staleness warnings.
Calendar write path (iMIP).
block_timeemails an RFC 5546/6047 invitation to each account; native clients render a normal meeting invite; acceptances route back into the same Worker and a Cloudflare Workflow tracks the lifecycle (send, wait, nag, finalize) per block.MCP server.
/mcpbehind Cloudflare Access exposes 20 tools (13 email + 7 calendar:get_availability,find_free_slots,block_time,get_block_status,cancel_block,list_blocks,list_calendars) for external agents such as Claude Code, Hermes, or anything speaking MCP, authenticated with an Access service token.Built-in AI agent. Chat panel with a 16-tool surface (9 email + 7 calendar, overlapping but not identical to the 20 exposed over
/mcp), powered by Workers AI (default@cf/google/gemma-4-26b-a4b-it, swappable via theAGENT_MODELvar) with all model traffic routed through AI Gateway. Auto-drafts replies to inbound email, and checks real availability before answering scheduling emails. Drafts always require explicit confirmation before sending.Calendar UI.
/calendarpage for paste-the-link feed registration, feed health, and per-block acceptance state (✓ ✗ ~ …) with one-click cancel.
Related MCP server: simple-email-mcp
How it works
Three flows carry the whole system. The read path folds three providers into one busy/free model; the write path blocks time using nothing but email; and inbound dispatch routes every message by its content, never by its address.
Read path: three calendars into one busy/free model
Write path: blocking time by email (iMIP, RFC 5546 over RFC 6047)
Inbound dispatch: route on the message, never the address
Stack
Frontend: React 19, React Router v7, Tailwind CSS, Zustand, TipTap,
@cloudflare/kumoBackend: Hono, Workers, Durable Objects (SQLite), Workflows, R2, KV, Email Routing + Email Service, cron triggers
Calendar:
ical.js(parsing/expansion), hand-rolled RFC 5545 authoring,mimetextenvelopesAI: Cloudflare Agents SDK (
AIChatAgent), AI SDK v6, Workers AI via AI Gateway (AGENT_MODEL/AI_GATEWAY_IDvars)Auth: Cloudflare Access JWT validation (fails closed in production)
Deploy
One-click
The Deploy to Cloudflare button above provisions the Worker plus its resources (Durable Objects, the block-time Workflow, R2 buckets, KV namespace, cron trigger, Workers AI) on your account and prompts you for your domain values.
The button cannot do everything. Finish with these manual steps, in order:
Cloudflare Access: enable one-click Access on the Worker; set the
POLICY_AUD+TEAM_DOMAINsecrets from the modal. The app intentionally returns 500 until this is done. Create a service token for any MCP agent.AI Gateway: create a gateway matching the
AI_GATEWAY_IDvar (defaultt9-agentic-cal), or set the var to""to call Workers AI directly.Email Routing: on your domain, add a catch-all rule → this Worker; enable Email Service for sending; add your calendar invite addresses as verified destination addresses.
Vars: set
DOMAINSto your domain andORGANIZER_ADDRtocalendar@<your-domain>. This single address is both the meeting organizer and a normal monitored inbox: dispatch routes RSVPs to the calendar path and everything else to the inbox by payload + UID (never by address), so ordinary mail to it is never swallowed.Feeds: open
/calendarand paste your three ICS publish links (table below).
Manual / local
npm install
npm run dev # local dev (uses .dev.vars, see .dev.vars.example)
npm run typecheck # cf-typegen + tsc, run before every push
npx tsx scripts/smoke-ics.ts && npx tsx scripts/smoke-availability.ts && npx tsx scripts/smoke-imip.tsCloning manually instead of using the button? Create your own KV namespace (wrangler kv namespace create calendar-feed-cache) and R2 buckets (agentic-inbox, calendar-snapshots), and put your KV id in wrangler.jsonc. Then deploy with wrangler deploy.
Registering calendar feeds
Open /calendar (button on the Mailboxes page). One card per provider: paste the publish link, set the invite address, save, hit Poll now:
Provider | Where to generate the link | Recommended detail |
Proton | Proton Calendar → Settings → Share calendar via link | full |
Outlook (M365) | Settings → Calendar → Shared calendars → Publish a calendar → ICS | busy-only (Microsoft caches; feed lags hours) |
iCloud | Apple Calendar → calendar info → Public Calendar → copy | full |
webcal://URLs are converted automatically; stored publish URLs are write-only secrets (only a truncated form is ever echoed).The invite email per feed is where iMIP invitations are sent (usually the account's own address).
The cron repolls every 10 minutes; a failing feed keeps its last good data and surfaces the error on the card and in
feed_warnings.
API equivalents (behind Access): GET/POST /api/v1/calendar/feeds, DELETE /api/v1/calendar/feeds/:id, POST /api/v1/calendar/poll, GET /api/v1/calendar/stats, GET /api/v1/calendar/events, GET /api/v1/calendar/blocks, DELETE /api/v1/calendar/blocks/:uid.
Connecting an agent over MCP
Endpoint: https://<your-worker>/mcp
Auth: CF-Access-Client-Id / CF-Access-Client-Secret (Access service token)All 20 tools are self-describing over MCP (list_tools returns full schemas and usage guidance). Semantics worth knowing up front: block_time is asynchronous; it returns pending immediately (the slot counts as busy right away) and refuses with a conflict list unless force is set; acceptance per account is tracked by a Workflow and read via get_block_status. Tool responses include feed_warnings when a calendar feed is stale or erroring, so agents should hedge availability statements accordingly, and should never state availability without a same-turn tool call.
Trust model
Any principal passing the shared Cloudflare Access policy can access all mailboxes and the calendar, including via /mcp (tools take a mailboxId parameter). There is no per-mailbox authorization; the Access policy is the single trust boundary. The same grant includes setting each mailbox's agent system prompt (Settings → it is fed verbatim to the model), so the Access boundary also governs what the agent is instructed to do. Keep this in mind before putting the app behind a multi-user Access policy.
Troubleshooting Access
Invalid or expired Access token→POLICY_AUDorTEAM_DOMAINsecret is stale. Toggle Access off/on for the Worker to get the modal again, and reset both secrets.Cloudflare Access must be configured in production→ intentional fail-closed behavior; enable Access and set the secrets.
Architecture
License
Apache 2.0. See LICENSE. Derived from cloudflare/agentic-inbox, © Cloudflare, Inc.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/talalakkari/agentic-cal'
If you have feedback or need assistance with the MCP directory API, please join our Discord server