circal-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/dist/circal-mcp.mjs +4467 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# circal-mcp
|
|
2
|
+
|
|
3
|
+
A stdio [MCP](https://modelcontextprotocol.io) server that reads and writes
|
|
4
|
+
circal's own mirror file — the `.json` a browser tab keeps in sync on disk
|
|
5
|
+
through the File System Access API (see `src/lib/mirror.ts` and
|
|
6
|
+
`src/lib/mirrorLink.ts`). It imports circal's own domain layer
|
|
7
|
+
(`src/lib/events.ts`, `recur.ts`, `quickadd.ts`, `mutate.ts`, `backup.ts`, …),
|
|
8
|
+
so an agent and the app can never disagree about what a legal event, an
|
|
9
|
+
occurrence, or a recurrence rule is.
|
|
10
|
+
|
|
11
|
+
Built on `@modelcontextprotocol/server` v2, implementing MCP protocol
|
|
12
|
+
revision 2026-07-28.
|
|
13
|
+
|
|
14
|
+
**The browser tab does not need to be open.** The mirror file is the only
|
|
15
|
+
thing this server reads or writes; if circal's tab is open and connected, it
|
|
16
|
+
picks up the change and its own next write moves the file's `rev` forward
|
|
17
|
+
again, the same as any second writer would.
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
A `FileSystemFileHandle` (what the browser hands circal when the mirror is
|
|
22
|
+
turned on) never exposes the full path it came from: that is deliberate
|
|
23
|
+
browser privacy design, so circal cannot print it for you. `--find` searches
|
|
24
|
+
the places a mirror file usually lands and does that work instead.
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npx -y circal-mcp --find
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It prints every mirror file it located (path, event and calendar counts,
|
|
31
|
+
zone, revision) plus a ready-to-paste config block. Paste that block into
|
|
32
|
+
your client below, swap the path if it picked up the wrong file, then
|
|
33
|
+
restart the client.
|
|
34
|
+
|
|
35
|
+
### Claude Desktop
|
|
36
|
+
|
|
37
|
+
Add to `claude_desktop_config.json`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"circal": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "circal-mcp", "--file", "/absolute/path/to/your/calendar.json"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Claude Code
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
claude mcp add circal -- npx -y circal-mcp --file /absolute/path/to/your/calendar.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or in `.mcp.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"circal": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "circal-mcp", "--file", "/absolute/path/to/your/calendar.json"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Cursor
|
|
70
|
+
|
|
71
|
+
Add to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"circal": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["-y", "circal-mcp", "--file", "/absolute/path/to/your/calendar.json"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
No mirror file yet: turn it on from circal's Settings panel, then run
|
|
85
|
+
`--find` again. Run `npx -y circal-mcp --help` for the full flag and
|
|
86
|
+
environment variable list.
|
|
87
|
+
|
|
88
|
+
## From source (contributors)
|
|
89
|
+
|
|
90
|
+
Building from a checkout instead of the published package:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
pnpm install
|
|
94
|
+
pnpm build:mcp
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Produces the same single-file ESM bundle at `mcp/dist/circal-mcp.mjs`.
|
|
98
|
+
`pnpm mcp` builds and runs it directly, for local testing. Point a client's
|
|
99
|
+
`command`/`args` at `node` and the absolute path to that bundle instead of
|
|
100
|
+
`npx`, with the same `env`/`--file` as above.
|
|
101
|
+
|
|
102
|
+
## What it refuses, and why
|
|
103
|
+
|
|
104
|
+
- **No `CIRCAL_FILE` (or `--file <path>`).** The path is never guessed — a
|
|
105
|
+
wrong guess here means writing over the wrong year's calendar. The server
|
|
106
|
+
exits with one line on stderr before it ever connects.
|
|
107
|
+
- **A zone mismatch.** Every day boundary in circal is local time. If the
|
|
108
|
+
file's own recorded zone does not match the zone this process is running
|
|
109
|
+
in, reads go through with a warning line; writes are refused, because a
|
|
110
|
+
write meant for "today" could land on the file's yesterday or tomorrow.
|
|
111
|
+
Override with `CIRCAL_ALLOW_ZONE_MISMATCH=1` if you are certain.
|
|
112
|
+
- **A feed calendar.** A calendar with a subscription attached is a mirror of
|
|
113
|
+
somebody else's ICS feed. Its events are pulled, not written — the same
|
|
114
|
+
read-only rule the event editor already enforces — so no tool here can
|
|
115
|
+
create, edit, delete, or tick an event on one.
|
|
116
|
+
- **A repeating event with no `scope`.** `update_event`, `delete_event` and
|
|
117
|
+
similar ask for `"one"`, `"future"`, or `"all"` before touching a series,
|
|
118
|
+
and name the event in the refusal rather than guessing.
|
|
119
|
+
- **A moved file.** Every mutation reads the file, applies the change,
|
|
120
|
+
re-reads to confirm nothing else wrote in between, then writes `rev + 1`
|
|
121
|
+
through a temp file plus rename (so a crash mid-write cannot truncate the
|
|
122
|
+
file). One retry on a conflicting write, then a refusal naming both
|
|
123
|
+
revisions.
|