ofw-mcp 2.4.4 → 2.6.3

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "OurFamilyWizard tools for Claude Code",
9
- "version": "2.4.4"
9
+ "version": "2.6.3"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -14,7 +14,7 @@
14
14
  "displayName": "OurFamilyWizard",
15
15
  "source": "./",
16
16
  "description": "OurFamilyWizard co-parenting tools for Claude — messages, calendar, expenses, and journal via MCP",
17
- "version": "2.4.4",
17
+ "version": "2.6.3",
18
18
  "author": {
19
19
  "name": "Chris Chall"
20
20
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ofw",
3
3
  "displayName": "OurFamilyWizard",
4
- "version": "2.4.4",
4
+ "version": "2.6.3",
5
5
  "description": "OurFamilyWizard co-parenting tools for Claude — messages, calendar, expenses, and journal via MCP",
6
6
  "author": {
7
7
  "name": "Chris Chall"
package/README.md CHANGED
@@ -124,6 +124,17 @@ Environment variables always take priority over the `.env` file. You can also pa
124
124
  OFW_USERNAME=you@example.com OFW_PASSWORD=yourpass node dist/index.js
125
125
  ```
126
126
 
127
+ ## Hosted connector (Cloudflare Worker)
128
+
129
+ Instead of running `ofw-mcp` locally, you can add it to [claude.ai](https://claude.ai) as a **remote MCP connector** — a hosted Cloudflare Worker you reach from Settings → Connectors on Claude web, desktop, or mobile (connectors sync across all three). The same tool registrars back both targets, so the tools and behaviour are identical to the local stdio install; the Worker just wraps them with [`@chrischall/mcp-connector`](https://www.npmjs.com/package/@chrischall/mcp-connector) (the shared OAuth + streamable-HTTP harness) and a per-user [Durable Object](src/cache/durable.ts) cache in place of the local SQLite file.
130
+
131
+ - **How you connect.** Each person you share the connector URL with logs in through the connector's own OAuth page with their **own** OurFamilyWizard email and password. Those credentials are stored (encrypted at rest) per user because OFW bearer tokens expire after ~6h with no refresh token, so the connector must be able to re-login on its own. One user can never see another's account or cache.
132
+ - **Attachments are inline-only.** The Worker has no local filesystem, so `ofw_download_attachment` always returns bytes as MCP content blocks (`OFW_INLINE_ATTACHMENTS=true`) rather than writing to disk.
133
+ - **Write mode defaults to `all`.** The hosted connector registers every tool by default, configurable per deployment via `OFW_WRITE_MODE` / `OFW_CALENDAR_WRITES` in `wrangler.jsonc` — see [Write protection](#write-protection-ofw_write_mode).
134
+ - **Message sync is bounded and resumable.** To stay under Cloudflare's per-request subrequest cap, `ofw_sync_messages` on the hosted connector caps how many OFW requests one call makes (`OFW_SYNC_MAX_REQUESTS` in `wrangler.jsonc`, default `40`) and resumes across calls, so a large mailbox backfills over multiple `ofw_sync_messages` calls rather than one; the local stdio server is unbounded. See [`docs/DEPLOY-CONNECTOR.md`](docs/DEPLOY-CONNECTOR.md#sync--the-subrequest-limit).
135
+
136
+ Standing this up requires a Cloudflare account and is a manual, one-time process for whoever hosts it (there is no CI/CD path for it) — see [`docs/DEPLOY-CONNECTOR.md`](docs/DEPLOY-CONNECTOR.md) for the full runbook. `wrangler.jsonc` serves the Worker at a custom domain (`https://connector.ofw.nullnet.app/mcp`) plus the account's `*.workers.dev` URL; whoever hosts it uses their own domain. The local stdio / `.mcpb` install above remains the desktop-only alternative if you'd rather run it against just your own account.
137
+
127
138
  ## Available tools
128
139
 
129
140
  Read-only tools run automatically. Write tools ask for your confirmation first. The *Write mode* column shows the minimum `OFW_WRITE_MODE` a tool needs to be available at all — see [Write protection](#write-protection-ofw_write_mode) below.
@@ -144,9 +155,9 @@ Read-only tools run automatically. Write tools ask for your confirmation first.
144
155
  | `ofw_delete_draft` | Delete a draft | Confirm | `drafts` |
145
156
  | `ofw_upload_attachment` | Upload a local file to My Files; returns a fileId to attach via `ofw_send_message`/`ofw_save_draft` | Auto | `drafts` |
146
157
  | `ofw_list_events` | Calendar events in a date range | Auto | any |
147
- | `ofw_create_event` | Create a calendar event | Confirm | `all` |
148
- | `ofw_update_event` | Update a calendar event | Confirm | `all` |
149
- | `ofw_delete_event` | Delete a calendar event | Confirm | `all` |
158
+ | `ofw_create_event` | Create a calendar event | Confirm | `all` (or `drafts` + `OFW_CALENDAR_WRITES`) |
159
+ | `ofw_update_event` | Update a calendar event | Confirm | `all` (or `drafts` + `OFW_CALENDAR_WRITES`) |
160
+ | `ofw_delete_event` | Delete a calendar event | Confirm | `all` (or `drafts` + `OFW_CALENDAR_WRITES`) |
150
161
  | `ofw_get_expense_totals` | Expense summary totals | Auto | any |
151
162
  | `ofw_list_expenses` | Expense history | Auto | any |
152
163
  | `ofw_create_expense` | Log a new expense | Confirm | `all` |
@@ -165,6 +176,10 @@ The "Confirm" permission above is a *hint* to the MCP host — a host configured
165
176
 
166
177
  Unrecognized values fail closed to `none`, with a warning on stderr — a typo never silently grants write access.
167
178
 
179
+ #### Calendar opt-in (`OFW_CALENDAR_WRITES`)
180
+
181
+ Calendar events sit between the two message tiers: they have no draft stage (a created event is immediately visible on the shared record), but unlike a sent message they are reversible — an event can be edited or deleted afterward. If you run in `drafts` mode but are comfortable with direct calendar writes, set `OFW_CALENDAR_WRITES=true` to additionally register `ofw_create_event`, `ofw_update_event`, and `ofw_delete_event`. The flag is redundant in `all` mode and never overrides `none`.
182
+
168
183
  ## Troubleshooting
169
184
 
170
185
  **"0 messages"** — Claude may have read the notification counts rather than the actual messages. Ask explicitly: *"List the messages in my OFW inbox"* or *"Use ofw_list_message_folders then ofw_list_messages"*.
@@ -44,8 +44,15 @@ export async function loginWithPassword(username, password) {
44
44
  }
45
45
  const contentType = response.headers.get('content-type') ?? '';
46
46
  if (!contentType.includes('application/json')) {
47
+ // OFW rejects bad credentials by re-serving its HTML login page (Spring
48
+ // Security re-renders the form rather than returning 401/JSON). Surface a
49
+ // clean, actionable message instead of dumping the HTML page — this is what
50
+ // the hosted connector's login page shows the user on a failed sign-in.
51
+ if (contentType.includes('text/html')) {
52
+ throw new Error('OFW login failed — your OurFamilyWizard email or password was not accepted. Check them and try again.');
53
+ }
47
54
  const body = await response.text();
48
- throw new Error(`OFW login returned unexpected response (${contentType}): ${body.substring(0, 200)}`);
55
+ throw new Error(`OFW login returned unexpected response (${contentType || 'no content-type'}): ${body.substring(0, 200)}`);
49
56
  }
50
57
  const data = (await response.json());
51
58
  return {