ofw-mcp 2.19.5 → 2.20.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofw-mcp",
3
- "version": "2.19.5",
3
+ "version": "2.20.0",
4
4
  "license": "MIT",
5
5
  "mcpName": "io.github.chrischall/ofw-mcp",
6
6
  "description": "OurFamilyWizard MCP server for Claude — developed and maintained by AI (Claude Code)",
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.19.5",
9
+ "version": "2.20.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "ofw-mcp",
14
- "version": "2.19.5",
14
+ "version": "2.20.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -64,6 +64,18 @@
64
64
  "description": "Absolute path for the session cache file. Defaults to $MCP_DATA_DIR/.ofw-mcp/session.json.",
65
65
  "isRequired": false,
66
66
  "format": "string"
67
+ },
68
+ {
69
+ "name": "OFW_EXPENSE_ONLY",
70
+ "description": "Set true to register only healthcheck plus expense tools. All profile/dashboard, message, calendar, and journal tools are structurally absent.",
71
+ "isRequired": false,
72
+ "format": "string"
73
+ },
74
+ {
75
+ "name": "OFW_EXPENSE_UPLOAD_ONLY",
76
+ "description": "Set true for strict reimbursement upload mode: only healthcheck, ofw_upload_expense_pdf, ofw_create_expense, and ofw_update_expense register. Implies OFW_EXPENSE_ONLY.",
77
+ "isRequired": false,
78
+ "format": "string"
67
79
  }
68
80
  ]
69
81
  }
@@ -112,12 +112,19 @@ Always pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter
112
112
  | `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |
113
113
  | `ofw_delete_event(eventId)` | Permanent delete |
114
114
 
115
+ ### Restricted expense deployments
116
+
117
+ When `OFW_EXPENSE_ONLY=true`, only the healthcheck and expense tools exist. When `OFW_EXPENSE_UPLOAD_ONLY=true`, only `ofw_healthcheck`, `ofw_upload_expense_pdf`, `ofw_create_expense`, and `ofw_update_expense` exist. Do not suggest message/calendar/journal/profile tools in those deployments; they are structurally unregistered.
118
+
115
119
  ### Expenses
116
120
  | Tool | Notes |
117
121
  |------|-------|
118
122
  | `ofw_get_expense_totals` | Summary of owed/paid totals |
119
- | `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |
120
- | `ofw_create_expense(amount, description)` | Log a new expense |
123
+ | `ofw_list_expenses(page?, size?)` | Paginated (1-based page); default size 20; follow `nextPage` |
124
+ | `ofw_list_expense_categories` | Category ids and split metadata (use the id in create/update) |
125
+ | `ofw_upload_expense_pdf(path \| url, fileName?, label?, description?)` | Upload one receipt PDF to My Files (SHARED, co-parent-visible even on a private expense) for later attachment; confirm-gated; mode `all` only |
126
+ | `ofw_create_expense(title, amount, purchaseDate, categoryId, payerId, children, description?, privateExpense?, receiptFileId?)` | Log a new expense; confirm-gated; optionally private with one receipt |
127
+ | `ofw_update_expense(expenseId, …only the fields to change…)` | Reads the expense and keeps every field you omit; `privateExpense:false` publishes a private expense; `receiptFileId` replaces all receipts, `null` clears it or `description`; refuses as `EXPENSE_FIELDS_UNREADABLE` (naming the fields) rather than erase one it can't read; confirm-gated |
121
128
 
122
129
  ### Journal
123
130
  | Tool | Notes |
@@ -166,7 +173,7 @@ Message and draft reads come from a local cache, so **a result can be stale with
166
173
  |---|---|
167
174
  | How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |
168
175
  | Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |
169
- | If not, how do I get the rest? | `nextPage` (message tools) or `nextStart` (`ofw_list_expenses` / `ofw_list_journal_entries`) — null means there is no more |
176
+ | If not, how do I get the rest? | `nextPage` (message tools and `ofw_list_expenses`) or `nextStart` (`ofw_list_journal_entries`) — null means there is no more |
170
177
  | Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |
171
178
 
172
179
  Rules:
@@ -197,18 +197,72 @@ curl -s -X DELETE "https://ofw.ourfamilywizard.com/pub/v1/calendar/events/${EVEN
197
197
  curl -s 'https://ofw.ourfamilywizard.com/pub/v2/expense/expenses/totals' "${AUTH_HEADERS[@]}" | jq .
198
198
  ```
199
199
 
200
- **List expenses** (offset-based, 0-indexed `start`):
200
+ **List expenses** (page-based, 1-indexed `page`):
201
+
202
+ OFW currently ignores the legacy `start`/`max` query parameters and returns
203
+ page 1 repeatedly. Use `page`/`size` and follow the response metadata's
204
+ `last` flag / `currentPage`.
205
+
206
+ ```sh
207
+ curl -s 'https://ofw.ourfamilywizard.com/pub/v2/expense/expenses?page=1&size=20' "${AUTH_HEADERS[@]}" | jq .
208
+ ```
209
+
210
+ **Upload a receipt PDF** (write to My Files). It must be `SHARED` — that is the
211
+ share class OFW accepts in an expense's `fileIds` — and a SHARED file is
212
+ visible to the co-parent in My Files as soon as it lands:
201
213
 
202
214
  ```sh
203
- curl -s 'https://ofw.ourfamilywizard.com/pub/v2/expense/expenses?start=0&max=20' "${AUTH_HEADERS[@]}" | jq .
215
+ curl -s -X POST 'https://ofw.ourfamilywizard.com/pub/v3/myfiles/multipart' \
216
+ "${AUTH_HEADERS[@]}" \
217
+ -F "file=@/path/to/receipt.pdf;type=application/pdf" \
218
+ -F 'source=expense' \
219
+ -F 'description=receipt.pdf' \
220
+ -F 'label=receipt.pdf' \
221
+ -F 'fileName=receipt.pdf' \
222
+ -F 'shared=true' \
223
+ -F 'shareClass=SHARED' | jq .
204
224
  ```
205
225
 
226
+ Use the returned `fileId` as `receiptFileId` when creating the expense.
227
+
206
228
  **Create an expense** (write):
207
229
 
230
+ The current OFW expense form requires a complete expense record. In addition to
231
+ the amount, send the expense title, purchase date, category id, parent who owes
232
+ (`payerId`), and at least one child user id. Description, visibility, and a
233
+ single receipt file are optional.
234
+
235
+ ```sh
236
+ curl -s -X POST 'https://ofw.ourfamilywizard.com/pub/v2/expense' \
237
+ "${AUTH_HEADERS[@]}" -H 'Content-Type: application/json' \
238
+ --data '{
239
+ "title":"Soccer cleats",
240
+ "amount":45.00,
241
+ "purchaseDate":"2026-09-28",
242
+ "categoryId":1,
243
+ "payerId":<PAYER_USER_ID>,
244
+ "children":[<CHILD_USER_ID>],
245
+ "description":"Cleats for soccer",
246
+ "isPrivate":false,
247
+ "fileIds":[<RECEIPT_FILE_ID>]
248
+ }' | jq .
249
+ ```
250
+
251
+ Use OFW numeric ids, not display labels, for `categoryId`, `payerId`, and
252
+ `children`. For a private expense (visible only to you), send `isPrivate:true`;
253
+ the MCP tools expose this as `privateExpense`. The MCP tools attach at most one
254
+ receipt, sent as a one-element `fileIds` array.
255
+
256
+ **Update an expense** (write; full payload, not a patch — e.g. publish a
257
+ private expense by sending `isPrivate:false`). A field left out of the PUT is
258
+ erased, so GET the expense first and send back every field you are not
259
+ changing (the MCP's `ofw_update_expense` does this for you):
260
+
208
261
  ```sh
209
- curl -s -X POST 'https://ofw.ourfamilywizard.com/pub/v2/expense/expenses' \
262
+ curl -s "https://ofw.ourfamilywizard.com/pub/v2/expense/expenses/${EXPENSE_ID}" "${AUTH_HEADERS[@]}" | jq .
263
+ curl -s -X PUT "https://ofw.ourfamilywizard.com/pub/v2/expense/expenses/${EXPENSE_ID}" \
210
264
  "${AUTH_HEADERS[@]}" -H 'Content-Type: application/json' \
211
- --data '{"amount": 45.00, "description": "Cleats for soccer"}' | jq .
265
+ --data '{ …every current field…, "isPrivate":false }' | jq .
212
266
  ```
213
267
 
214
268
  ## 8. Journal