ofw-mcp 2.7.1 → 2.9.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +58 -4
- package/dist/bundle.js +1651 -165
- package/dist/cache/store.js +79 -1
- package/dist/config.js +60 -0
- package/dist/extract/document.js +83 -0
- package/dist/extract/index.js +222 -0
- package/dist/extract/inflate.js +55 -0
- package/dist/extract/ooxml.js +58 -0
- package/dist/extract/pdf.js +278 -0
- package/dist/extract/presentation.js +54 -0
- package/dist/extract/spreadsheet.js +258 -0
- package/dist/extract/types.js +4 -0
- package/dist/extract/xml.js +61 -0
- package/dist/extract/zip.js +110 -0
- package/dist/index.js +1 -1
- package/dist/sync.js +11 -2
- package/dist/tools/delivery.js +99 -0
- package/dist/tools/draft-freshness.js +47 -9
- package/dist/tools/lifecycle.js +277 -0
- package/dist/tools/messages.js +571 -177
- package/package.json +1 -1
- package/server.json +14 -2
- package/skills/ofw/SKILL.md +34 -15
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/ofw-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.9.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "ofw-mcp",
|
|
14
|
-
"version": "2.
|
|
14
|
+
"version": "2.9.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
|
@@ -40,6 +40,18 @@
|
|
|
40
40
|
"description": "Set to \"true\" to register calendar write tools (create/update/delete event) in \"drafts\" write mode. Events have no draft stage but are reversible. Never overrides \"none\".",
|
|
41
41
|
"isRequired": false,
|
|
42
42
|
"format": "string"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "OFW_ALLOW_MARK_READ",
|
|
46
|
+
"description": "Default \"true\". Set \"false\" to forbid any tool from marking a message read on OurFamilyWizard - reading a body for the first time stamps a co-parent-visible \"First Viewed\" time that cannot be undone. A ceiling: no per-call argument can raise it.",
|
|
47
|
+
"isRequired": false,
|
|
48
|
+
"format": "string"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "OFW_FETCH_UNREAD_BODIES",
|
|
52
|
+
"description": "Default \"false\". Whether ofw_sync_messages fetches unread inbox bodies by default (each fetch stamps a First Viewed time). Capped by OFW_ALLOW_MARK_READ.",
|
|
53
|
+
"isRequired": false,
|
|
54
|
+
"format": "string"
|
|
43
55
|
}
|
|
44
56
|
]
|
|
45
57
|
}
|
package/skills/ofw/SKILL.md
CHANGED
|
@@ -93,16 +93,17 @@ Always pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter
|
|
|
93
93
|
|------|-------|
|
|
94
94
|
| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |
|
|
95
95
|
| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |
|
|
96
|
-
| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?)` | Cache-backed list. Supports folder ("inbox"/"sent"/"both"), date range, and substring search. |
|
|
97
|
-
| `ofw_get_message(messageId)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: "drafts"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them
|
|
96
|
+
| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder ("inbox"/"sent"/"both"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |
|
|
97
|
+
| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: "drafts"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a "First Viewed" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |
|
|
98
98
|
| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |
|
|
99
|
-
| `ofw_get_unread_sent` | Sent messages your co-parent hasn't read yet (from cache). |
|
|
100
|
-
| `ofw_list_drafts` | List saved drafts (cache-backed). Each draft carries `serverConfirmed` —
|
|
101
|
-
| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. |
|
|
99
|
+
| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as "nothing sent". |
|
|
100
|
+
| `ofw_list_drafts(page?, size?, autoRefresh?)` | List saved drafts (cache-backed). Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying "you have N drafts"**. An empty result from a non-fresh cache is refused. See [Freshness](#freshness). |
|
|
101
|
+
| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. It also returns a `draftKey` that stays the same across every edit — **track that, not the id**. |
|
|
102
102
|
| `ofw_delete_draft(messageId)` | Delete a draft. |
|
|
103
103
|
| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |
|
|
104
|
-
| `ofw_download_attachment(fileId, inline?, saveTo?, force?)` | Download an attachment.
|
|
105
|
-
| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync.
|
|
104
|
+
| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:"1-2"` / a sheet name and `maxChars` on large files. |
|
|
105
|
+
| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |
|
|
106
|
+
| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |
|
|
106
107
|
|
|
107
108
|
### Calendar
|
|
108
109
|
| Tool | Notes |
|
|
@@ -125,18 +126,36 @@ Always pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter
|
|
|
125
126
|
| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |
|
|
126
127
|
| `ofw_create_journal_entry(title, body)` | Create a new entry |
|
|
127
128
|
|
|
128
|
-
## Freshness
|
|
129
|
+
## Freshness, completeness, and lifecycle
|
|
129
130
|
|
|
130
|
-
Message and draft reads come from a local cache, so **a result can be stale without looking stale**.
|
|
131
|
+
Message and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
| Question | Signal |
|
|
134
|
+
|---|---|
|
|
135
|
+
| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |
|
|
136
|
+
| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |
|
|
137
|
+
| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |
|
|
133
138
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- **
|
|
137
|
-
-
|
|
139
|
+
Rules:
|
|
140
|
+
|
|
141
|
+
- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.
|
|
142
|
+
- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as "still sitting unsent" that had already been sent.
|
|
143
|
+
- **`existsOnServer` does not mean "still a draft".** A draft that was SENT still exists on the server. Only `state` distinguishes them.
|
|
144
|
+
- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. "You have 3 drafts" requires `complete: true`.
|
|
145
|
+
- **`serverConfirmed: false` means "remembered, not known."** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.
|
|
146
|
+
- **A refusal is a good outcome.** `result: "UNVERIFIED_EMPTY"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as "nothing found". A wrong "no, that was never sent" is far costlier here than one extra call.
|
|
147
|
+
- **`state: "unknown"` is not "fine".** It means the question was not answered.
|
|
148
|
+
- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. "Nothing changed" and "we didn't look" are otherwise indistinguishable.
|
|
138
149
|
- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never "no changes". Check `notRefreshed`.
|
|
139
150
|
|
|
151
|
+
### Draft identity (`draftKey`)
|
|
152
|
+
|
|
153
|
+
Editing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:
|
|
154
|
+
|
|
155
|
+
- `ofw_status(draftKeys: ["dk_…"])` resolves the key to the chain's **current** id and state.
|
|
156
|
+
- The key keeps resolving after the draft is sent: `state: "sent"` with `sentMessageId` and `sentAt`.
|
|
157
|
+
- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.
|
|
158
|
+
|
|
140
159
|
|
|
141
160
|
## Workflows
|
|
142
161
|
|
|
@@ -166,4 +185,4 @@ Rules for using it:
|
|
|
166
185
|
- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.
|
|
167
186
|
- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.
|
|
168
187
|
- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.
|
|
169
|
-
- **Do not narrate cached state as present fact.**
|
|
188
|
+
- **Do not narrate cached state as present fact.** Before saying what "is" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.
|