Skip to main content
Glama
ReinforceZwei

trilium-calendar-mcp

trilium-calendar-mcp

Calendar events as MCP tools for AI agents, stored as notes in Trilium.

It is a drop-in replacement for the Nextcloud Calendar MCP (nc_calendar_*): the tool names and arguments are deliberately the same shape (calendar_*), so an agent that already knows how to write calendar events only needs the tool prefix changed — no relearning, no new prompt structure.

AI agent  ──MCP──▶  trilium-calendar-mcp  ──ETAPI──▶  Trilium notes
                                                         │
                                      CalDAV facade ─────┘──▶ Apple Calendar / DAVx⁵ / Thunderbird

Notes carrying #startDate are calendar events in Trilium's own calendar view, and the same notes can be served over CalDAV by a facade (see Interoperability), so one set of notes feeds the agent, the Trilium UI and standard calendar clients.

Why not let the agent drive the Trilium MCP directly?

The generic Trilium MCP has no calendar semantics: creating one event means create_note plus one set_attribute call per label, the agent has to know every label name, the inclusive-#endDate convention and the timezone rules, and mistakes fail silently — a note labelled #startdate simply never appears in the calendar, with no error. Those rules live in code here, and every event is validated on the way in.

Related MCP server: dav-mcp

Quickstart

docker run --rm -i \
  -e TRILIUM_URL=https://trilium.example.com \
  -e TRILIUM_ETAPI_TOKEN=your-etapi-token \
  -e TRILIUM_CALENDARS=0hq1wCTuDBjA:Gaming \
  ghcr.io/reinforcezwei/trilium-calendar-mcp:latest

That runs over stdio. For an HTTP (streamable) endpoint — what a remote agent infrastructure usually needs — add:

docker run --rm -p 127.0.0.1:8102:8102 \
  -e MCP_TRANSPORT=streamable-http -e MCP_HOST=0.0.0.0 -e MCP_PORT=8102 \
  -e TRILIUM_URL=https://trilium.example.com \
  -e TRILIUM_ETAPI_TOKEN=your-etapi-token \
  -e TRILIUM_CALENDARS=0hq1wCTuDBjA:Gaming \
  ghcr.io/reinforcezwei/trilium-calendar-mcp:latest
# MCP endpoint: http://host:8102/mcp

docker-compose.yml wires the same thing up with an .env file.

HTTP and Host headers. The MCP SDK rejects requests whose Host header is not allow-listed (DNS-rebinding protection, 421 Invalid Host header) — a check whose SDK default depends on the bind address and has historically rejected every hostname in containers (python-sdk#1798). This server decides it explicitly instead, so no configuration is needed:

MCP_HOST

protection

behaviour

0.0.0.0 (container/VM default)

off

any Host is accepted; the network/proxy is the boundary

127.0.0.1 / localhost

on

localhost and 127.0.0.1 names accepted — protects a loopback-only server from a browser on the same machine

any bind + MCP_ALLOWED_HOSTS

on

only the listed host:port values are accepted

The startup log states which mode is active. Set MCP_ALLOWED_HOSTS (and optionally MCP_ALLOWED_ORIGINS) only when a loopback-bound server is reached under another name — e.g. a reverse proxy on the same host forwarding to 127.0.0.1:8102.

Client configuration (stdio)

{
  "mcpServers": {
    "trilium-calendar": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "--env-file", "/path/.env",
               "ghcr.io/reinforcezwei/trilium-calendar-mcp:latest"]
    }
  }
}

Configuration

Variable

Required

Default

Meaning

TRILIUM_URL

yes

—

Trilium base URL (no /etapi suffix)

TRILIUM_ETAPI_TOKEN

yes

—

ETAPI token (Trilium → Options → ETAPI)

TRILIUM_CALENDARS

yes

—

Calendars to expose — see below

TRILIUM_TIMEZONE

no

Asia/Shanghai

Timezone used to interpret naive datetimes

MCP_TRANSPORT

no

stdio

stdio, streamable-http (alias http) or sse

MCP_HOST / MCP_PORT / MCP_PATH

no

0.0.0.0 / 8102 / /mcp

HTTP binding

MCP_ALLOWED_HOSTS

no

—

Optional host:port allowlist; enables the DNS-rebinding check for binds where it is otherwise off (see the note above)

MCP_ALLOWED_ORIGINS

no

derived

Optional Origin allowlist to accompany MCP_ALLOWED_HOSTS

TRILIUM_VERIFY_SSL

no

true

Set false for a self-signed instance

TRILIUM_CA_BUNDLE

no

—

Custom CA bundle path

TRILIUM_TIMEOUT

no

30

Per-request timeout (seconds)

TRILIUM_SEARCH_LIMIT

no

5000

Max notes fetched per calendar scan

LOG_LEVEL

no

INFO

Log verbosity (logs go to stderr)

Calendars and their names

TRILIUM_CALENDARS is a comma-separated list of Trilium note ids, each optionally named:

TRILIUM_CALENDARS=0hq1wCTuDBjA:Gaming,kf8Xq2vLpZ1a:Personal
# or, without aliases (the note's own title is then used as the name)
TRILIUM_CALENDARS=0hq1wCTuDBjA,kf8Xq2vLpZ1a
  • The name after the colon (or =) is the calendar_name the agent uses. Without an alias the calendar note's Trilium title is used instead, so "Gaming" works either way once the note is titled that.

  • calendar_list_calendars returns every calendar with name, note_id, title, timezone, color and event_count — that is how the agent resolves "put it in Gaming".

  • All tools accept calendar_name; it matches the name/alias, the note title, or the note id, case-insensitively. The first configured calendar is the default when calendar_name is omitted.

  • An unknown name is an error that lists the valid ones, so the agent can self-correct.

Tools

Tool

Purpose

calendar_list_calendars

List calendars with their names/ids/timezones — call this first

calendar_list_events

Events in a date range; filters on title, categories, location

calendar_get_event

One event by uid, including description

calendar_create_event

Create an event (returns its uid)

calendar_update_event

Patch an event; only the arguments you pass change

calendar_delete_event

Delete by uid (unknown uid = success, safe retries)

calendar_get_upcoming_events

Events starting in the next N days

calendar_upsert_events

Bulk create-or-update, keyed on uid

calendar_delete_events

Bulk delete by uid

Migrating an agent from the Nextcloud MCP

Rename the tool prefix; arguments keep their names:

Nextcloud MCP

this server

nc_calendar_list_calendars

calendar_list_calendars

nc_calendar_list_events

calendar_list_events

nc_calendar_get_event

calendar_get_event

nc_calendar_create_event

calendar_create_event

nc_calendar_update_event

calendar_update_event

nc_calendar_delete_event

calendar_delete_event

nc_calendar_get_upcoming_events

calendar_get_upcoming_events

nc_calendar_bulk_operations

calendar_upsert_events / calendar_delete_events

Point the prompt's calendar name at a configured name (e.g. Gaming) and the switch is done. calendar_create_event also accepts event_uid: pass an existing uid to update instead of creating a duplicate, which makes unattended re-runs idempotent.

Semantics the agent can rely on

  • Dates — start_datetime takes YYYY-MM-DD (all-day) or an ISO datetime. Naive datetimes are read in the timezone argument, else the calendar's timezone; Z/offset values are converted. Either way, what is stored is the wall clock in the calendar's timezone.

  • All-day ranges — end_datetime is the last day of the event, inclusive ("until the 28th" means the 28th). This differs from Nextcloud's DTEND, which is the day after: a Nextcloud all-day event ending 2026-07-28 covered 7/8–7/27. Re-check any all-day ranges in the old prompt when you migrate.

  • Times — timed events get #startTime/#endTime; an event with no end time is open-ended.

  • Identity — every event carries a stable #caldavUID. New events get a UUID; pass event_uid (or use calendar_upsert_events) to update in place.

  • Descriptions — plain text, line breaks preserved. Markdown syntax is not interpreted.

  • Response fields — every response reflects what is actually stored. An update that does not include description returns the stored body (never an empty string), so it is safe to trust the response instead of re-fetching.

  • End fields — end is the ISO end (or null when a timed event has no end time), and end_date is the event's last day whenever it has an end. For a same-day timed event (15:00–15:30) end_date is therefore that same day, not null. Note that the #endDate label is only written when an event spans days (Trilium's convention, which the CalDAV facade understands), so if you inspect the notes directly, expect fewer labels than response fields.

  • Not stored — status, priority, privacy, attendees, url, reminders/alarms. These arguments are accepted so an existing prompt does not break, and echoed back in ignored_fields so the agent can see they had no effect.

  • Recurrence — pass an RRULE in recurrence_rule (FREQ=WEEKLY;BYDAY=MO), optionally bounded with recurrence_end_date; recurring=False or recurrence_rule="" removes it.

How events are stored

Trilium label

Meaning

#startDate

YYYY-MM-DD, always present (this is what makes it an event)

#endDate

last day, inclusive

#startTime / #endTime

HH:MM, timed events only, naive wall clock

#caldavUID

stable identity / idempotency key

#tags

categories, comma-separated

#location, #color, #recurrence

passthrough fields

Notes are created as normal Trilium text notes with the event description as their body, so they read naturally in the note tree and the calendar view.

Interoperability with a CalDAV facade

The labels above match the mapping used by the Trilium CalDAV facade (#endDate inclusive → DTEND +1 day, #caldavUID → UID, #tags → CATEGORIES), so events written by an agent are served correctly to Apple Calendar, DAVx⁵ and Thunderbird by the same facade. Nothing here requires the facade, and the facade does not require this server.

Limitations

  • No reminders/alarms, attendees, or event status — Trilium notes have no equivalent.

  • No todos/VTODO — event notes only (Trilium's #todoDate task notes are a follow-up).

  • Timezones are per calendar, not per event — a single calendar has one timezone; events from several zones are normalised into it.

  • Listing scans the calendar's children (one ETAPI search) and filters locally; fine for the thousands-of-events scale, not for millions.

  • No ETags/conflict detection — last write wins, which is fine for an agent-owned calendar.

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"

pytest tests/test_event.py            # unit tests, no server needed
TRILIUM_URL=https://... TRILIUM_ETAPI_TOKEN=... pytest   # + integration tests against a live instance

Integration tests create a temporary calendar note under root, exercise create/list/update/ upsert/delete against it, and delete it afterwards (cascading to the events they made). No existing notes are touched.

Releasing

./release.sh 0.2.0          # bump version, commit, tag
./release.sh 0.2.0 --push   # ... and push the commit + tag

Pushing a v* tag runs the test suite, then builds and publishes ghcr.io/<owner>/trilium-calendar-mcp (0.2.0, 0.2, latest) for linux/amd64 and linux/arm64, and opens a GitHub release.

License

MIT

Available Tools

9 tools
calendar_create_eventA

Create a calendar event.

Args: title: Event title. start_datetime: YYYY-MM-DD for an all-day event, or an ISO datetime such as 2026-07-08T11:00:00 (naive = calendar timezone) / 2026-07-08T03:00:00Z (converted to calendar timezone). calendar_name: Calendar to create in; omit for the default calendar. end_datetime: ISO datetime end, or for all-day events the LAST day (inclusive). Empty = same day / no end. all_day: Force an all-day event (times are ignored). description: Plain text; line breaks are preserved. location: Free text location. categories: Comma-separated categories/tags. timezone: IANA timezone used to interpret naive datetimes. color: Colour name or hex. recurrence_rule: RRULE body, with or without the RRULE: prefix. recurrence_end_date: YYYY-MM-DD that bounds the series (writes UNTIL). recurring: Set False to force a non-recurring event. event_uid: Reuse an existing uid (updates that event instead of creating a duplicate) — use it to make retries idempotent. status, priority, privacy, attendees, url, reminder_minutes, reminder_email, reminders: accepted for compatibility but NOT stored by Trilium; they are echoed back in ignored_fields.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNo
colorNo
titleYes
statusNo
all_dayNo
privacyNo
locationNo
priorityNo
timezoneNo
attendeesNo
event_uidNo
recurringNo
remindersNo
categoriesNo
descriptionNo
end_datetimeNo
calendar_nameNo
reminder_emailNo
start_datetimeYes
recurrence_ruleNo
reminder_minutesNo
recurrence_end_dateNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: naive-vs-Z timezone interpretation, all-day semantics with inclusive end day, the UNTIL write for recurrence_end_date, and the transparent note that status/priority/privacy/attendees/url/reminders are NOT stored but echoed in ignored_fields. It omits return-shape and permission/auth details, but the destructive/side-effect behavior is well explained.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The per-argument list is long but tightly front-loaded with the action line and never wastes words; length is justified by 22 parameters, though grouping the ignored compatibility fields together is handled efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 22-param tool with 0% schema coverage, no annotations, and no output schema, the description covers required formats, defaults, and the critical ignored-fields behavior. Missing auth/prerequisite and return-value notes, but it is otherwise complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and does: it gives formats for start_datetime and end_datetime, defines calendar_name omission default, explains empty end_datetime, and clarifies the debasement of ignored fields — far beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Create a calendar event') that is unambiguous among siblings like calendar_update_event, calendar_upsert_events, and calendar_delete_event.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It documents the idempotent retry path via event_uid ('use it to make retries idempotent'), which is genuine usage guidance, but it never says when to prefer calendar_upsert_events or how it differs from calendar_update_event.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_delete_eventB

Delete an event by uid. Deleting an unknown uid succeeds (safe retries).

Args: event_uid: Uid of the event to delete. calendar_name: Calendar holding the event; omit to search all calendars.

ParametersJSON Schema
NameRequiredDescriptionDefault
event_uidYes
calendar_nameNo

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden, and it does disclose one valuable trait: deleting an unknown uid succeeds, so retries are safe (idempotency). It still omits permission requirements, whether deletion is soft/reversible, and side effects such as attendee notifications, leaving meaningful gaps for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and the idempotency caveat, followed by a compact Args block. Every sentence adds signal and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and no output schema, most of what an agent needs is present (target, calendar scoping, retry safety), but permission requirements, confirmation/reversibility semantics, and error behavior are all absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it largely does: event_uid is identified as the event's uid and calendar_name is explained with the non-obvious behavior 'omit to search all calendars'. That adds real meaning the bare schema lacks.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (delete) and resource (event) keyed by uid, so the core action is unambiguous. It does not, however, distinguish itself from the sibling calendar_delete_events (plural), which an agent could easily confuse with this single-event tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no prerequisites, and never names an alternative such as calendar_delete_events. Usage is only implied by the verb itself, matching the calibration case that scored 2 for 'no when-to-use, no prerequisites'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_delete_eventsA

Delete many events by uid in one call.

Args: event_uids: Uids to delete; unknown uids are reported, not an error. calendar_name: Calendar to delete from; omit to search all calendars.

ParametersJSON Schema
NameRequiredDescriptionDefault
event_uidsYes
calendar_nameNo

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full burden. It usefully discloses the partial-success behavior (unknown uids are reported, not an error) and the default scope of calendar_name, but says nothing about the destructive/irreversible nature of deletion, permissions required, or the shape of the report.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One summary sentence followed by a tight Args block; no filler, and the core action is front-loaded before the parameter detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter destructive tool with no annotations and no output schema, the description covers parameter behavior and partial-failure handling, but omits irreversibility/confirmation expectations and what the 'report' of unknown uids actually looks like.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: it defines event_uids semantics (unknown ones are reported, not fatal) and calendar_name's default 'all calendars' behavior. Both parameters gain meaning beyond their bare names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Delete'), resource ('events'), and scope ('many ... by uid in one call'), which implicitly distinguishes it from the singular calendar_delete_event sibling. It never names the alternative explicitly, so a 5 is not warranted, but the bulk-by-uid framing is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The Args block gives real operating context — unknown uids are reported rather than erroring, and omitting calendar_name searches all calendars — which implies when the tool is appropriate. It offers no explicit when-not guidance or named alternatives, so usage is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_get_eventA

Get one event by its uid, including its description.

Args: calendar_name: Calendar to look in; omit to search all calendars. event_uid: The event's uid (from calendar_list_events).

ParametersJSON Schema
NameRequiredDescriptionDefault
event_uidNo
calendar_nameNo

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses that the return includes the event description and that omitting calendar_name searches all calendars. It does not state that this is strictly a read-only operation, nor does it cover error behavior (e.g., event not found) or permission requirements, leaving gaps for a tool with zero annotation support.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, followed by tightly formatted argument notes. Every sentence earns its place with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and no output schema, the description adequately covers both parameters and notes the return includes the event description. It omits error-handling and permission context, but for a simple single-event read tool it is largely sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds meaning for both parameters: calendar_name ('Calendar to look in; omit to search all calendars') and event_uid ('The event's `uid` (from calendar_list_events)'). This is helpful, though it could go further by describing the uid format or any constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Get') and resource ('one event by its uid'), clearly distinguishing it from list or multi-event siblings. However, it does not explicitly contrast itself with calendar_get_upcoming_events or calendar_list_events, so sibling differentiation is only implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives parameter-level guidance ('omit to search all calendars') and references calendar_list_events as the source of the uid, implying usage context. But it never states when to choose this tool over list_events or get_upcoming_events, leaving the agent to infer the single-event retrieval scenario.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_get_upcoming_eventsB

List events starting between today and N days ahead.

Args: calendar_name: Calendar to read; omit for all calendars. days_ahead: How many days ahead to include (today counts as day 0). limit: Maximum number of events to return.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
days_aheadNo
calendar_nameNo

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. 'List' implies a read, and the window semantics are clarified (today = day 0), but there is no mention of result ordering, timezone handling, recurring-event expansion, or whether the read has any side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One front-loaded summary sentence followed by a compact Args block; every line conveys needed information with no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-param read tool with no annotations and no output schema, the description covers the parameters well but omits return-shape essentials: ordering, timezone basis for 'today', and recurring-event behavior. Adequate but with clear gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and largely does: it explains that omitting calendar_name reads all calendars, defines days_ahead's day-0 convention, and states that limit is a maximum count. Defaults and types remain only in the schema, but the semantics are meaningfully enriched.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (events) scoped to a time window starting today through N days ahead. This distinguishes it from calendar_list_events by the windowing semantics, though it never explicitly contrasts with that sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implied usage (get upcoming events within a horizon) is clear from the description, and it notes that omitting calendar_name reads all calendars. However, it never states when to prefer this over calendar_list_events or calendar_get_event, leaving routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_list_calendarsA

List the calendars this server exposes.

Returns each calendar's name (use this as calendar_name in other tools), its Trilium note_id, note title, timezone, colour and the current number of events. Start here: calendar names are how the user refers to calendars (e.g. "Gaming"), and they are what the other tools accept.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations and no output schema, the description carries the behavioral burden and largely meets it by disclosing the return fields (name, note_id, title, timezone, colour, event count) and implying a non-mutating read via 'List'. It omits auth requirements, pagination, and cost characteristics, which are minor for a zero-parameter listing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then the payload, then the call-to-action. The 'Start here' sentence and the closing clause about names being how the user refers to calendars overlap somewhat, but the text is short and each sentence is nearly load-bearing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description's enumeration of return fields is exactly the right compensation, and the identifier hand-off to other tools is explained. Nothing essential is missing for a zero-parameter, read-only list; only secondary details like pagination are absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so the baseline is 4; the description goes slightly beyond by explaining that the returned `name` is the `calendar_name` identifier consumed by sibling tools, which is useful cross-tool semantics rather than schema restatement.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the calendars this server exposes') and enumerates the returned fields, so an agent can immediately distinguish this discovery tool from the event CRUD siblings. The purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Start here' gives explicit sequencing guidance, and the note that calendar names are what the other tools accept tells the agent how to chain this call into siblings. It does not name exclusions or alternatives, but for a single list-calendars tool that would be artificial.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_list_eventsA

List events, optionally filtered by date range and text.

Args: calendar_name: Calendar to read; omit to use the default calendar. start_date: Earliest day to return, YYYY-MM-DD (events overlapping the range are included). end_date: Latest day to return, YYYY-MM-DD. limit: Maximum number of events to return (0 = no limit). title_contains: Only events whose title contains this text. categories: Comma-separated categories; matches events carrying any of them. location_contains: Only events whose location contains this text. include_descriptions: Fetch event bodies (one extra request per event). search_all_calendars: Search every configured calendar instead of one.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
end_dateNo
categoriesNo
start_dateNo
calendar_nameNo
title_containsNo
location_containsNo
include_descriptionsNo
search_all_calendarsNo

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It does disclose useful behavior: overlapping events are included in the date range, and include_descriptions costs one extra request per event. However, it says nothing about permissions, pagination, or what the returned records look like.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded purpose sentence followed by a tight, scannable Args block. Every line is necessary given 0% schema coverage; no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nine-parameter, zero-annotation, no-output-schema tool, the description covers parameters and key behaviors well. It omits any indication of the return shape or result ordering, but the core invocation information is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does for all nine parameters: formats (YYYY-MM-DD), defaults-by-omission (default calendar), sentinel values (limit 0 = no limit), and matching semantics (overlap for dates, contains for text, any-of for categories). This adds real meaning beyond the bare schema titles and types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a clear verb+resource ('List events') and names the two filtering axes (date range, text). It is distinguishable from mutating siblings, but it does not explicitly differentiate itself from close read siblings like calendar_get_upcoming_events or calendar_get_event.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use guidance or routing to alternatives. The reader must infer that this is the broad listing tool versus calendar_get_upcoming_events or calendar_get_event. No prerequisites or exclusions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_update_eventA

Update an existing event. Only the arguments you pass are changed.

The returned event reflects what is now stored: if you do not pass description, the response carries the existing body (not an empty string), so you do not need to re-fetch to confirm it survived.

Args: event_uid: Uid of the event to update. calendar_name: Calendar holding the event; omit to search all calendars. (other arguments as in calendar_create_event; end_datetime="" clears the end, location="" clears the location, recurrence_rule="" or recurring=False removes the recurrence.)

ParametersJSON Schema
NameRequiredDescriptionDefault
colorNo
titleNo
all_dayNo
locationNo
timezoneNo
event_uidYes
recurringNo
categoriesNo
descriptionNo
end_datetimeNo
calendar_nameNo
start_datetimeNo
recurrence_ruleNo
recurrence_end_dateNo

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose meaningful behavior: updates are partial, omitted fields retain existing values, and specific empty-string values clear fields. It also explains that the returned event reflects stored data. It still lacks auth, error, and rate-limit behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and uses a clear Args block. The returned-event paragraph is somewhat long but earns its place by explaining omission behavior and avoiding a re-fetch. Overall it is well structured with minor verbosity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 14-parameter mutation tool with no annotations and no output schema, the description is not complete enough. It cannot document all parameters, auth requirements, error cases, or return structure, so an agent still lacks important context despite the useful partial-update explanation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for 14 parameters, so the description must compensate. It documents event_uid and calendar_name and gives clearing semantics for end_datetime, location, recurrence_rule, and recurring, but defers most other fields to calendar_create_event without describing them, leaving substantial gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Update an existing event') and immediately clarifies partial-update semantics ('Only the arguments you pass are changed'). It implicitly distinguishes from calendar_create_event by saying 'existing event', though it does not name siblings or address overlap with calendar_upsert_events.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides useful update behavior and operational details, such as omitting calendar_name to search all calendars and clearing values with empty strings. However, it gives no explicit when-to-use guidance versus alternatives like calendar_create_event or calendar_upsert_events, nor any prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calendar_upsert_eventsA

Create or update many events at once, keyed on uid (or on key).

Use this for bulk work (a release calendar for a whole season). Each entry is created if its identity is new and updated if it already exists, so re-running the same list updates in place instead of duplicating. Identity comes from event_uid/uid, or from key: a short stable slug ("wuwa-3.7-banner-1") that is hashed into a uid, so a scheduled agent can re-publish its list without storing uids.

Args: events: List of event objects. Each accepts the arguments of calendar_create_event (title, start_datetime, end_datetime, all_day, description, location, categories, color, recurrence_rule) plus the identity fields event_uid/uid or key. calendar_name may be set per entry to spread the list across calendars. Entries with no identity always create new events. calendar_name: Default calendar for entries that do not name one.

ParametersJSON Schema
NameRequiredDescriptionDefault
eventsYes
calendar_nameNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does well: it discloses upsert semantics (create if new, update if existing), deduplication on identity, identity derivation via `event_uid`/`uid` or a hashed `key`, and that entries with no identity always create new events. It omits auth/rate-limit and response/error behavior, but the critical upsert mechanics are explicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is front-loaded with the core purpose before mechanics and an Args section, and every sentence contributes. It is somewhat long, but the length is justified by the complex upsert semantics and the 0% schema coverage it must offset.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter bulk upsert tool with no annotations, no output schema, and 0% schema description coverage, the description is nearly complete: it covers identity, upsert behavior, per-entry calendar spreading, and parameter fields. Minor gaps remain around partial-failure behavior, conflict resolution within a single list, and permission requirements.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and does: it documents the `events` list as accepting all `calendar_create_event` fields plus identity fields, explains `calendar_name` per-entry override, and clarifies that `calendar_name` at the top level is the default calendar. This adds substantial meaning beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Create or update many events at once, keyed on `uid` (or on `key`).' It clearly distinguishes this bulk upsert tool from the single-event siblings `calendar_create_event` and `calendar_update_event`, which it explicitly references as the source of per-entry arguments.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context for use: 'Use this for bulk work (a release calendar for a whole season).' and explains the idempotent re-run benefit. It names `calendar_create_event` as the argument reference but does not explicitly state when not to use this tool or contrast it directly with single-event siblings, so it falls short of fully explicit routing.

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.

  1. 9 tool updatesv0.1.2
    • First observedcalendar_create_event
    • First observedcalendar_delete_event
    • First observedcalendar_delete_events
    • First observedcalendar_get_event
    • First observedcalendar_get_upcoming_events
    • First observedcalendar_list_calendars
    • First observedcalendar_list_events
    • First observedcalendar_update_event
    • First observedcalendar_upsert_events

TDQS

A4/5.0

Scored across 9 tools

Disambiguation4/5

Most tools have clearly distinct actions (list, get, create, update, delete, upcoming, bulk upsert/delete). Slight overlap exists between calendar_get_upcoming_events and calendar_list_events with a date range, and between calendar_create_event's event_uid idempotency and calendar_upsert_events, but descriptions clarify the intended distinctions.

Naming Consistency5/5

All nine tools follow a consistent calendar_verb_noun pattern with snake_case throughout. Verb choices (list, get, create, update, delete, upsert) are predictable and parallel, including the plural bulk variants.

Tool Count5/5

Nine tools is well-scoped for a calendar server, covering single-event CRUD plus bulk operations and an upcoming shortcut without redundancy. Each tool earns its place.

Completeness5/5

Full CRUD lifecycle is covered (list, get, create, update, delete) plus bulk upsert/delete, upcoming events, and recurrence support. No obvious calendar operations are missing.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    F
    maintenance
    Enables interaction with any CalDAV-compatible calendar server (Yandex, Google, Nextcloud, iCloud, etc.) to list calendars, create/manage events with reminders and attendees, search events, and handle recurring events through natural language.
    14
    -
  • A
    license
    A
    quality
    A
    maintenance
    Turn any calendar, contact book, or task list into an AI-orchestrated system. Platform-independent via CalDAV/CardDAV works with Nextcloud, Baikal, Fastmail, and any standards-compliant DAV server. 26 tools with field-agnostic updates.
    27
    173 npm
    35
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Provider-agnostic CalDAV calendar MCP server that connects any CalDAV calendar to AI assistants, enabling calendar operations like listing, creating, updating, and deleting events.
    AGPL 3.0