Skip to main content

calendula

License: MIT Python PyPI version

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.exe and powershell.exe through WSL interop
  • Python 3.11 or later

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 -- calendula

Other 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
list_events date (YYYY-MM-DD, default today), days (1-31, default 1), refresh Each day's events: time, subject, location
get_event time (HH:MM), date, refresh The event running at that time (or the one starting nearest to it, with a note): location, organizer, attendees, status, body
restart_outlook 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 interview

An 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: true always fetches; ask for it when the calendar has just changed
  • A 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 --version

Troubleshooting

  • 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 calling restart_outlook)
  • Outlook gave no answer: check that Outlook (classic) is running
  • calendula 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 --check

What 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

MIT

Metadata

Release files for calendula 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for calendula 0.1.0
File Size Uploaded Provenance Actions
calendula-0.1.0.tar.gz 13.8 kB With provenance Details for calendula-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for calendula 0.1.0
File Interpreter ABI Platform Actions
calendula-0.1.0-py3-none-any.whl Python 3 none any Details for calendula-0.1.0-py3-none-any.whl

Total release size: 30.4 kB

Release files / calendula-0.1.0.tar.gz

Download URL calendula-0.1.0.tar.gz
Size 13.8 kB
Tags Source
SHA-256 checksum
How to use checksums
79b6030430de44eb2a2946c38e6044f2794d7a1f23e1933e335f2f8ef7d5f4ad
BLAKE2b-256 checksum
How to use checksums
cd8d2eb0bf5e1f452825763f293e7ec8b32151c10572b88e677245f52b049fe1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Release files / calendula-0.1.0-py3-none-any.whl

Download URL calendula-0.1.0-py3-none-any.whl
Size 16.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
475695dabf9d4d625c9fc74af88fa553712ca6a594f941b76fe8a3b005eeeb5b
BLAKE2b-256 checksum
How to use checksums
0789e60ff15ee7e3f84d60d2dc379decf98bbad0954d91756d155e3d7c57f00c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Security for calendula 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for calendula-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page