Skip to content

MCP tools ​

cicada-mcp (or cicada mcp) serves MCP over stdio. Each tool decodes JSON arguments, runs a cicada-core use case, and returns human-readable content text plus structuredContent JSON. Errors arrive as tool results (isError: true), never protocol errors.

Server options ​

Flag / envDefaultMeaning
--root$CICADA_ROOT, then cwdDirectory cicada.yaml is discovered in
--providerfakefake or google
--fake-file.cicada/fake-provider.jsonFake backend file
--state.cicada/state.yaml, $CICADA_STATERecorded-state file

All tools re-read YAML, state, and the provider per call. from/to window bounds accept today, +Nd, +Nw, YYYY-MM-DD, civil datetimes, or RFC 3339 instants, resolved in each calendar's timeZone.

cicada.calendar.list — read-only ​

Declared calendars with bindings and counts. Takes no arguments.

json
{"calendars": [{"name": "work", "timeZone": "UTC", "provider": "fake",
                "calendarId": "primary", "declaredEvents": 2,
                "recordedEvents": 2}]}

cicada.events.range — read-only ​

Expand occurrences in [from, to) (defaults today, +7d).

ArgTypeMeaning
calendarstringLimit to one declared calendar (default: all)
from, tostringWindow bounds
livebooleanExpand the provider's live events instead of desired YAML
json
{"calendars": [{"calendar": "work", "live": false,
                "occurrences": [ … ]}], "totalOccurrences": 5}

cicada.events.show — read-only ​

One event by stable local id (id, required), plus occurrences (defaults today, +30d).

json
{"calendar": "work", "event": { … }, "occurrences": [ … ]}

cicada.state.drift — read-only ​

Recorded vs live for every recorded calendar.

json
{"calendars": [{"calendar": "work", "calendarId": "primary",
                "drifted": 1,
                "drift": [{"kind": "modified", "localId": "standup",
                           "remoteId": "fake-2", …}]}],
 "totalDrifted": 1}

cicada.state.refresh ​

Fold live into recorded under the state lock. Writes only local state.

json
{"calendars": [{"calendar": "work", "unchanged": 1, "updated": ["standup"],
                "removed": [], "reconciled": [ … ],
                "adoptionCandidates": []}]}

cicada.plan.preview — read-only ​

Plan every declared calendar; issue a session planDigest. Arg: notify (none|externalOnly|all) — must match on apply or the digest goes stale.

json
{"planDigest": "sha256:…", "hasErrors": false, "remoteOps": 2,
 "plans": [ /* cicada/plan-v1 documents */ ]}

cicada.plan.apply — gated write ​

Execute a previewed plan under the state lock.

ArgTypeRequiredMeaning
planDigeststringyesDigest from plan.preview this session
confirmbooleanyesMust be true — explicit approval
forcebooleannoOverwrite out-of-band edits
resumebooleannoSkip already-journaled ops
notifyenumnoNotification override — must match the preview's

Gates, in order: confirm: true → digest issued by plan.preview in this session → server re-plans under the lock and re-derives the digest; a stale digest refuses. Digests are single-use.

json
{"calendars": [{"calendar": "work", "applied": 2, "skipped": 0,
                "failed": 0, "outcomes": [ … ]}],
 "digest": "sha256:…"}

Errors ​

Every error carries its taxonomy class:

json
{"error": {"kind": "fatal|conflict|auth|transient", "message": "…"}}

The write contract ​

There is no events.create — all mutations flow through declared YAML + plan.preview + plan.apply (single write path). This keeps every remote event managed and drift meaningful.