calendula
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., "@calendulaWhat's on my calendar 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.
calendula
An MCP server that lets Claude Code (or any MCP client) read your Outlook (classic) calendar from WSL.
Read-only: list the events of a day (or several), or look up the event at a given time with its attendees and body
Talks to Outlook on Windows through PowerShell and COM: no Microsoft Graph, no admin consent, no tokens
Keeps what it fetched in memory only; nothing is written to disk (see Caching)
Requirements
Windows with Outlook (classic) running. The new Outlook has no COM interface and does not work
WSL: calendula runs in the Linux distribution and calls
wscript.exeandpowershell.exethrough WSL interopPython 3.11 or later
Related MCP server: Microsoft Calendar MCP Server
Install
uv tool install calendula # or: pipx install calendula
calendula list # prints today's events (checks that Outlook answers)Register it with Claude Code for all your projects:
claude mcp add --scope user calendula -- calendulaOther MCP clients: run calendula as a stdio server.
Then ask things like "What's on my calendar tomorrow afternoon?" or "Who is in the 14:00 meeting?".
To let Claude read the calendar without asking each time, allow the two read-only tools in ~/.claude/settings.json:
{
"permissions": {
"allow": ["mcp__calendula__list_events", "mcp__calendula__get_event"]
}
}Tools
Tool | Arguments | Returns |
|
| Each day's events: time, subject, location |
|
| The event running at that time (or the one starting nearest to it, with a note): location, organizer, attendees, status, body |
| none | Force-quits Outlook and starts it again, to recover a broken COM connection. Unsaved drafts are lost, so the model is told to ask you first |
Every answer starts with the day and the time it was fetched:
2026-11-05 (Thu) fetched 2026-11-05 10:32
09:00-10:00 Weekly sync [Room A]
13:30-14:30 Customer interviewAn event that spans several days (a conference, a meeting past midnight) appears on each day it covers. Bodies are kept whole except for blank lines and the Teams join block.
Caching
Fetching takes a few seconds (PowerShell starts, then Outlook answers over COM), so fetched days are kept in the server's memory:
Today and later are reused for up to 1 hour, then fetched again
Past days fetched after they ended are kept for the life of the server (one Claude Code session)
refresh: truealways fetches; ask for it when the calendar has just changedA request fetches only the days that are missing or stale, in one call
When fetching fails, the error is returned as is; older copies are never shown instead
Nothing is written to disk. Set CALENDULA_TTL_MINUTES to change the 1 hour.
Command line
calendula run the MCP server on stdio (same as `calendula serve`)
calendula list [DATE] [DAYS] print events, fetched from Outlook now
calendula show TIME [--date DATE] print the event at a time
calendula --versionTroubleshooting
CO_E_SERVER_EXEC_FAILURE(0x80080005) and similar COM errors: Outlook's COM connection often breaks after sleep or a network change. Restart Outlook (Claude will ask before callingrestart_outlook)Outlook gave no answer: check that Outlook (classic) is runningcalendula needs WSL ...: calendula only works inside WSL on a Windows PC with Outlook
How it works
For each fetch, calendula writes get_calendar.ps1 (as UTF-16 with a BOM, which Windows PowerShell 5.1 reads correctly) into a temporary directory under /tmp, and runs it hidden through wscript.exe and run_hidden.vbs, using the \\wsl.localhost\... path. The script reads the default calendar folder through Outlook.Application, including recurring events, and writes events.json, which calendula parses.
Development
uv sync
uv run pytest # needs neither Windows nor Outlook
CALENDULA_WINDOWS_TESTS=1 uv run pytest # on WSL: also the PowerShell side, still without Outlook
uv run ruff check && uv run ruff format --checkWhat is tested where, and why, is in docs/test-design.md; the behavior it checks is specified in docs/spec.md.
Releases: bump version in pyproject.toml, then push a tag vX.Y.Z. GitHub Actions tests, builds, publishes to TestPyPI, installs from there, publishes to PyPI (Trusted Publishing), and creates a GitHub release.
License
Available Tools
3 toolsget_eventARead-onlyIdempotent
Details of the event at a time: location, organizer, attendees, status, and the body.
If no event is running at that time, returns the timed event that starts nearest to it (and says so).
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | Day as YYYY-MM-DD (or MM-DD for this year). Default: today. | |
| time | Yes | Time as HH:MM (24-hour). | |
| refresh | No | Fetch from Outlook even if a recent copy is cached. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so the safety profile is covered. The description's real contribution is the fallback rule — if no event is running it returns the nearest upcoming timed event and discloses that fact — which is behavior an agent could not infer from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the returned fields and then the fallback caveat. No filler; only minor awkwardness in phrasing such as 'the body'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, yet it still summarizes the payload. Its main gap is the absence of any pointer to list_events for date-range browsing, but for a three-parameter read tool this is otherwise complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter carries its own format note (YYYY-MM-DD, HH:MM, cache refresh), so the schema does the heavy lifting. The description reinforces the semantics by stressing lookup 'at a time', matching the required time parameter, but adds no new format or constraint detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Details of the event at a time') and enumerates what is returned: location, organizer, attendees, status, body. It is clearly a single-event lookup rather than a listing, so an agent can separate it from list_events without opening either schema, though it never names that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'at a time' — the tool is for pinpointing one event at a moment. There is no explicit statement of when to prefer it over list_events, nor any prerequisite guidance about needing a recent Outlook sync.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_eventsARead-onlyIdempotent
List events (time, subject, location) day by day. Use get_event for attendees and the body.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | Day as YYYY-MM-DD (or MM-DD for this year). Default: today. | |
| days | No | Number of days from `date`. | |
| refresh | No | Fetch from Outlook even if a recent copy is cached. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so the safety profile is covered. The description adds that the listing is per-day and scoped to time/subject/location (no attendees or body), but says nothing about caching, result volume, or ordering beyond what the schema's refresh parameter implies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with zero filler; the core purpose is front-loaded and the sibling redirect is a compact second sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, full parameter documentation, and annotations covering safety, the description covers what the agent needs to select and call the tool. It only lacks a note on calendar scope or result ordering, which is a minor gap given the structured fields.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter already documents its format and default (date YYYY-MM-DD, days 1-31, refresh ignoring cache). The phrase "day by day" loosely echoes the days parameter but adds no syntax or edge-case meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ("List events") and names the fields returned (time, subject, location), so the agent knows exactly what it gets. It also implicitly separates itself from get_event, which covers the detail view.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes the agent: use get_event for attendees and the body. That names the alternative and the condition that selects it, leaving no inference needed for the common choice between the two calendar tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restart_outlookADestructive
Force-quit Outlook (classic) and start it again, to recover a broken COM connection.
Unsaved drafts are lost. Call it only after the user has agreed, and only after a fetch failed with a COM error.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, but the description adds the concrete consequence the annotation cannot express: unsaved drafts are lost. It also discloses the consent requirement and the fact that the restart is a force-quit, which implies abrupt termination rather than graceful shutdown.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and rationale, followed by the risk and the trigger condition. No filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless, side-effecting tool with an output schema present, the description covers action, motivation, data-loss risk, consent requirement, and the exact diagnostic precondition. Nothing an agent needs to decide whether to call it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the schema is trivially complete. Baseline for a parameterless tool applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb pair (force-quit and restart) on a specific resource (Outlook classic) and names the failure mode it addresses (broken COM connection). An agent can immediately tell this apart from sibling read tools like list_events and get_event.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit preconditions: only after the user has agreed, and only after a fetch failed with a COM error. This is a clear when-to-use gate with an implicit when-not (do not call speculatively or without consent).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
get_event - First observed
list_events - First observed
restart_outlook
TDQS
Scored across 3 tools
list_events (day-by-day summaries) and get_event (full details for a specific time) have a clear summary-vs-detail split, and restart_outlook is unmistakably a maintenance operation. The only mild blur is get_event's fallback of returning the nearest starting event, which makes it behave slightly like a lookup rather than a strict fetch, but the description calls this out explicitly.
All three tools follow a clean verb_noun snake_case pattern: list_events, get_event, restart_outlook. No mixed conventions or vague verbs, and the naming maps directly onto the described action.
Three tools is a deliberate, well-scoped surface for a read-only Outlook calendar reader plus one recovery utility; nothing feels redundant. It is on the thin side of the typical 3-15 range, but each tool clearly earns its place.
The surface covers reading a day's events and drilling into one event, but there are notable gaps: no create/update/delete or RSVP/response operations, no cross-calendar search or range queries beyond day-by-day listing, and no way to list available calendars. Agents needing to modify a calendar will hit a dead end.
Maintenance
Related MCP Connectors
A MCP server that works with Outlook Calendar to manage event listing, reading, and updates.
EU-hosted calendar MCP: Google, Outlook, iCloud, GMX, WEB.DE, CalDAV. Read, book, RSVP, sync.
MCP server for Cronofy — read calendars, events and free/busy, and create, update or delete events.
Read Schedule it events, resources, groups and labels; create and update events and resources.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables interaction with Outlook / Microsoft 365 calendar, allowing users to list events, get event details, find meeting times, and access calendar and profile information.377 npm1MIT
- AlicenseAqualityDmaintenanceEnables fetching and managing Microsoft Outlook calendar events within date ranges through natural language, using Azure AD authentication and dual transport support for compatibility with Claude Desktop and other MCP clients.1MIT
- FlicenseNot gradedqualityDmaintenanceEnables interaction with Google Calendar via MCP, allowing users to list, get, search, and create events as well as list accessible calendars.-
- AlicenseAqualityDmaintenanceEnables reading your Microsoft 365 calendar to get today's meetings and availability.214 npmMIT