io.github.chrischall/ofw-mcp
NPM · OFW-MCP · SCANNED SEP 20
OurFamilyWizard co-parenting for Claude — messages, calendar, expenses, and journal
Available components
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security100
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 0 of 9 dependencies flagged as unhealthy. View diagnostics → Pass
Provenance & Transparency97
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Cryptographically verified build provenance (signed, bound to chrischall/ofw-mcp). View diagnostics → Pass
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 0 days ago).Pass
- Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability61
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 6615 tokens (~264/item across 25 items; 25 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management93
- Stability observed for 28 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage97
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 90% of tool parameters carry a description.Partial
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 3 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 25 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a current MCP spec version (2026-07-28).Pass
How do I install the io.github.chrischall/ofw-mcp server?
io.github.chrischall/ofw-mcp runs locally as an npm package, launched with npx -y ofw-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · ofw-mcp
claude mcp add chrischall-ofw-mcp -- npx -y ofw-mcp
{
"mcpServers": {
"chrischall-ofw-mcp": {
"command": "npx",
"args": [
"-y",
"ofw-mcp"
]
}
}
} {
"servers": {
"chrischall-ofw-mcp": {
"command": "npx",
"args": [
"-y",
"ofw-mcp"
]
}
}
} codex mcp add chrischall-ofw-mcp -- npx -y ofw-mcp
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"chrischall-ofw-mcp": {
"type": "local",
"command": [
"npx",
"-y",
"ofw-mcp"
],
"enabled": true
}
}
} openclaw mcp add chrischall-ofw-mcp --command npx --arg -y --arg ofw-mcp
mcp_servers:
chrischall-ofw-mcp:
command: "npx"
args: ["-y", "ofw-mcp"] {
"McpServers": {
"chrischall-ofw-mcp": {
"Transport": "stdio",
"Command": "npx",
"Arguments": [
"-y",
"ofw-mcp"
]
}
}
} assistant mcp add chrischall-ofw-mcp -t stdio -c npx -a -y ofw-mcp
{
"mcpServers": {
"chrischall-ofw-mcp": {
"command": "npx",
"args": [
"-y",
"ofw-mcp"
]
}
}
} Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 20 Sept 26 0
- Stability: 0.90 → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Capabilities: pass → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: Schema quality not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. functional
- MCP protocol: Implements a current MCP spec version (2026-07-28). functional
- Package version: 2.17.0 → 2.19.0 functional
- Package version: 2.17.0 → 2.18.0 functional
- 19 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 87 to 90. That category is still filling its 30-day observation window: 26 days of observed history at the previous scan, 27 at this one. The score rises as the window fills, whether or not the server changes.
- 18 Sept 26 +11
- Known CVEs: unverified → pass ▲ security
- Dependency health: unverified → 1.00 ▲ functional
- 17 Sept 26 −13
- Stability: pass → unverified ▼ security
- Known CVEs: pass → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Capabilities: pass → unverified ▼ functional
- Dependency health: 0.87 → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: Schema quality not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. functional
- Stability: pass → 0.83 functional
- Package version: 2.16.3 → 2.17.0 functional
- 16 Sept 26 +16
- Malware scan: unverified → pass ▲ security
- Stability: 0.97 → pass security
- Package version: 2.10.0 → 2.16.3 functional
- 15 Sept 26 +11
- Malware scan: unverified → pass ▲ security
- Known CVEs: unverified → pass ▲ security
- Dependency health: unverified → 0.87 ▲ functional
- Package version: 2.16.2 → 2.16.3 functional
- 14 Sept 26 −25
- Stability: 0.90 → unverified ▼ security
- Malware scan: pass → unverified ▼ security
- Known CVEs: pass → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Capabilities: pass → unverified ▼ functional
- Dependency health: 0.86 → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: Schema quality not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. functional
- Package version: 2.16.1 → 2.16.2 functional
- 12 Sept 26 +16
- Malware scan: unverified → pass ▲ security
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 20 Sept 2026 · Analysed npm/ofw-mcp@2.19.0
Provenance Verified
A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.
| Result | Verified |
|---|---|
| Ecosystem | npm |
| Reason | Verified |
| Discovered via | Registry attestation endpoint |
| Source repo | chrischall/ofw-mcp |
| Certificate issuer | https://token.actions.githubusercontent.com |
| Certificate SAN | https://github.com/chrischall/ofw-mcp/.github/workflows/release-please.yml@refs/heads/main |
| Rekor log index | 2902181909 |
| Predicate type | https://slsa.dev/provenance/v1 |
| Subject digest | sha512:839b5b19bcfbf0156f48772a7d7219afa290805a65109114d00bb854e421aafe2606f215e49bf26a454d1b378074b6b1d8d36b586b8f66ee186fa55be |
Background: How many MCP packages publish verified provenance →
Dependencies 9 packages
| Packages resolved | 9 |
|---|---|
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
ofw_check_freshness ~434
Cheaply confirm whether the local cache still matches OurFamilyWizard, WITHOUT running a full sync. Use this before asserting anything about current state — especially "draft X is still sitting unsent". Costs one OFW request for the folder check plus one per messageId. For each folder it returns the live server count next to the cached count. For each id it returns a LIVE lifecycle `state` — "draft" | "sent" | "received" | "deleted" | "unknown" — alongside `folder`, `sentAt`, `existsOnServer` and a content comparison. `state` is the field that answers "is this still a draft?": a draft that has been SENT still exists on the server, so existsOnServer:true never distinguished the two. A cached draft whose state is no longer "draft" reports inSync:false even when its text is byte-identical. Content is compared by revision hash, because OFW draft timestamps do NOT change when a draft is edited in the web app. Does not fetch bodies into the cache, does not touch attachments, and does not depend on sync state. For draftKeys, or a full live draft inventory, use ofw_status.
| Name | Type | Req | Description |
|---|---|---|---|
| allowMarkRead | boolean | – | Default false. Probing an id whose cached state cannot rule out an unread INBOX message requires fetching its detail, which marks it READ on OurFamilyWizard and stamps a co-parent-visible "First View… |
| folders | array | – | Folders to compare cached vs live counts for. Defaults to all three when messageIds is not given. Must be non-empty if given. |
| messageIds | array | – | Specific ids to verify against OFW (max 25). Ids cached as drafts, as sent messages, or as already-read inbox messages are probed freely — none of those can stamp the record. Anything else is skipped… |
No output schema declared.
No examples provided.
ofw_create_event ~244
Create a calendar event in OurFamilyWizard. Unless privateEvent is true, the event is immediately visible to the co-parent — there is no draft stage.
| Name | Type | Req | Description |
|---|---|---|---|
| allDay | boolean | – | – |
| children | array | – | Child userIds to tag (see ofw_get_profile) |
| dropOffParentId | number | – | userId of the drop-off parent |
| endDate | string | – | End date YYYY-MM-DD (default: startDate) |
| endTime | string | – | End time HH:mm, 24-hour (required unless allDay) |
| eventParentId | number | – | userId of the parent the event is 'for' |
| location | string | – | – |
| notes | string | – | – |
| pickUpParentId | number | – | userId of the pick-up parent |
| privateEvent | boolean | – | true = visible only to you; default false = shared with co-parent |
| reminderMinutes | integer | – | – |
| startDate | string | yes | Start date YYYY-MM-DD |
| startTime | string | – | Start time HH:mm, 24-hour (required unless allDay) |
| title | string | yes | – |
No output schema declared.
No examples provided.
ofw_create_expense ~38
Log a new expense in OurFamilyWizard
| Name | Type | Req | Description |
|---|---|---|---|
| amount | number | yes | Expense amount |
| description | string | yes | Expense description |
No output schema declared.
No examples provided.
ofw_create_journal_entry ~41
Create a new journal entry in OurFamilyWizard
| Name | Type | Req | Description |
|---|---|---|---|
| body | string | yes | Entry text content |
| title | string | yes | Entry title |
No output schema declared.
No examples provided.
ofw_delete_draft ~184
Delete a draft message from OurFamilyWizard. Also removes the draft from the local cache. Before deleting, the draft is re-read from OFW and the delete is REFUSED if it changed since you last read it (the current server body is returned so nothing is lost) — pass expectedRevision to assert which version you mean, or force:true to delete regardless.
| Name | Type | Req | Description |
|---|---|---|---|
| expectedRevision | string | – | The `revision` you got from ofw_list_drafts/ofw_get_message. Asserts you are deleting THAT version; if the draft changed on OFW since, the delete is refused and the current server body returned. |
| force | boolean | – | Default false. Delete even if the draft changed on OurFamilyWizard since you read it. The discarded server version is echoed back in the response. |
| messageId | number | yes | Draft message ID to delete |
No output schema declared.
No examples provided.
ofw_delete_event ~67
Delete an OurFamilyWizard calendar event
| Name | Type | Req | Description |
|---|---|---|---|
| eventId | string | yes | Event id — the `id` from ofw_list_events / eventRecurrenceId from ofw_create_event |
| includeFuture | boolean | – | For repeating events: also delete future occurrences (default false) |
No output schema declared.
No examples provided.
ofw_download_attachment ~698
Download an OFW message attachment by fileId and return content you can actually read. Inline delivery walks a ladder and returns the first rung that works: (1) host-renderable images (PNG/JPEG/GIF/WEBP) come back as ImageContent; (2) .xlsx/.csv/.tsv, .pdf, .docx, .pptx and text files come back as EXTRACTED CONTENT — per-sheet CSV, per-page/slide text, document text — in the response JSON under `extracted`; (3) anything else comes back as an EmbeddedResource blob of the raw bytes. The meta block names the rung as `deliveredVia` and, when it falls through to bytes, lists what was tried in `deliveryAttempts`. Reported mime types are always normalized to a bare media type (no charset/name parameters). In disk mode the bytes are saved to ~/Downloads/ofw-mcp/ and the response carries the absolute path; pass extract:true to ALSO get the extracted content in that response. The default for `inline` can be flipped server-side via the OFW_INLINE_ATTACHMENTS env var. On a hosted deployment with no filesystem, disk mode is unavailable, so inline is forced (forcedInline:true) rather than failing — a saveTo path never costs you the content. fileId comes from attachments[].fileId on ofw_get_message. Override disk destination with OFW_ATTACHMENTS_DIR or saveTo. Re-downloading to the same path is a no-op (disk mode only).
| Name | Type | Req | Description |
|---|---|---|---|
| extract | boolean | – | Whether to extract readable content from the file. Default: on for inline delivery of any non-image type, off in disk mode. Set false to get the raw bytes inline instead of extracted text (e.g. to ha… |
| fileId | number | yes | Attachment file id (from ofw_get_message → attachments[].fileId) |
| force | boolean | – | Re-download even if already on disk. Default false. Ignored when inline:true (inline always fetches fresh bytes, or reuses an on-disk copy if present). |
| inline | boolean | – | If true, return content inline as MCP content blocks and skip the disk write. If false, write to disk and return the path — except on a hosted deployment with no filesystem, where inline is forced (f… |
| maxChars | integer | – | Ceiling on extracted characters (default 50000). Over it, content is clipped on a row/line boundary, `truncated` is set, and anything dropped whole is listed in `extracted.omitted`. |
| parts | string | – | Which sheets / slides / pages to extract, e.g. "1-3,5" (1-based positions) or a sheet name like "2026". A bare number matches either a position or a name. Omit for everything. Unselected parts are li… |
| saveTo | string | – | Absolute path or directory to write to. If a directory, the OFW filename is used. Default: ~/Downloads/ofw-mcp/<fileId>-<filename>. Ignored when inline is in effect. |
No output schema declared.
No examples provided.
ofw_get_expense_totals ~25
Get OurFamilyWizard expense summary totals (owed/paid)
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
ofw_get_message ~396
Get a single OurFamilyWizard message OR draft by ID. Reads from local cache when available; otherwise fetches from OFW — and for an UNREAD INBOX message that fetch marks it read and stamps a "First Viewed" time the co-parent can see, which is part of the record and cannot be undone. Pass allowMarkRead:false to refuse such a fetch instead (cached bodies, sent messages and already-read messages are unaffected, because none of them stamp anything). For ids that match a draft (in the drafts cache), the response carries folder="drafts" and the body/subject/recipients reflect the drafts cache (which ofw_sync_messages keeps fresh) — drafts have no `fromUser`, and `sentAt`/`fetchedBodyAt` mirror the draft's `modifiedAt`. For inbox/sent messages, folder is "inbox" or "sent" as before.
| Name | Type | Req | Description |
|---|---|---|---|
| allowMarkRead | boolean | – | Default true (the long-standing behaviour). Set false to refuse a fetch that would mark an unread INBOX message as READ on OurFamilyWizard — an irreversible, co-parent-visible change to the record. R… |
| messageId | string | yes | Message ID (also accepts draft IDs — drafts are routed via the drafts cache) |
| view | string | – | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact omits OurFamilyWizard's raw `listData` echo, which… |
No output schema declared.
No examples provided.
ofw_get_notifications ~36
Get OurFamilyWizard dashboard summary: unread message count, upcoming events, outstanding expenses. Note: updates your last-seen status.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
ofw_get_profile ~23
Get current user and co-parent profile information from OurFamilyWizard
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
ofw_get_unread_sent ~186
List sent messages that have not been read by one or more recipients. Reads from local cache. Returns `complete` describing whether every sent message was scanned. An empty SENT cache that is not verified-fresh is REFUSED (result:"UNVERIFIED_EMPTY") rather than reported as "nothing sent"; pass autoRefresh:true to sync and answer instead.
| Name | Type | Req | Description |
|---|---|---|---|
| autoRefresh | boolean | – | If the result comes back EMPTY from a cache that is not verified-fresh, sync the backing folders first and answer from the refreshed cache instead of refusing. Defaults to the OFW_AUTO_REFRESH env va… |
| page | integer | – | Page (default 1) |
| size | integer | – | Per page (default 50) |
No output schema declared.
No examples provided.
ofw_healthcheck Verify credentials and upstream reachability ~101
Resolves the credential the way real tools do, then makes one authenticated request to ourfamilywizard.com. Reports which source supplied the credential, whether ourfamilywizard.com accepted it, the round-trip time, and a plain-English hint distinguishing 'no credential' from 'credential rejected' from 'a ourfamilywizard.com-side problem'. Read-only; never returns the credential itself. Call this when a real tool fails and you want to know which hop broke.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
ofw_list_drafts ~423
List draft messages, verified against OurFamilyWizard in ONE call: when the local drafts cache is not verified-fresh, a cheap drafts sync runs first by default (verify:true), so the answer is server-confirmed without a second call. Pass verify:false to answer purely from the cache (no OFW requests). Returns an explicit `complete` boolean describing the RESULT SET: true means "these are ALL the drafts on OurFamilyWizard as of freshness.asOf" — check it before saying "you have N drafts". Each draft carries its `draftKey` (stable across the create-then-delete churn of editing) when one is known. An empty result from a cache that is not verified-fresh is REFUSED (result:"UNVERIFIED_EMPTY"); pass autoRefresh:true to sync and answer instead.
| Name | Type | Req | Description |
|---|---|---|---|
| autoRefresh | boolean | – | If the result comes back EMPTY from a cache that is not verified-fresh, sync the backing folders first and answer from the refreshed cache instead of refusing. Defaults to the OFW_AUTO_REFRESH env va… |
| page | integer | – | Page number (default 1) |
| size | integer | – | Drafts per page (default 50) |
| verify | boolean | – | Default true: when the drafts cache is not verified-fresh, run a drafts sync first (cheap — one list page plus one detail per draft) so the response is server-confirmed in one call. Set false to serv… |
| view | string | – | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact omits OurFamilyWizard's raw `listData` echo, which… |
No output schema declared.
No examples provided.
ofw_list_events ~61
List OurFamilyWizard calendar events in a date range
| Name | Type | Req | Description |
|---|---|---|---|
| detailed | boolean | – | Return full event details (default false) |
| endDate | string | yes | End date YYYY-MM-DD |
| startDate | string | yes | Start date YYYY-MM-DD |
No output schema declared.
No examples provided.
ofw_list_expenses ~125
List OurFamilyWizard expenses. Offset-paged via start/max. The response leads with its paging state — `hasMore` and `nextStart` (null when the list is exhausted) — BEFORE the records, so a truncated or partially-read response still says whether more remain. Never state an expense total or an absence from one page.
| Name | Type | Req | Description |
|---|---|---|---|
| max | integer | – | Max results (default 20) |
| start | integer | – | Start offset, 0-based (default 0). To continue a listing, pass the `nextStart` from the previous response. |
No output schema declared.
No examples provided.
ofw_list_journal_entries ~130
List OurFamilyWizard journal entries. Offset-paged via start/max (1-based). The response leads with its paging state — `hasMore` and `nextStart` (null when the list is exhausted) — BEFORE the records, so a truncated or partially-read response still says whether more remain. Never state an entry count or an absence from one page.
| Name | Type | Req | Description |
|---|---|---|---|
| max | integer | – | Max results (default 10) |
| start | integer | – | Start offset, 1-based (default 1). To continue a listing, pass the `nextStart` from the previous response. |
No output schema declared.
No examples provided.
ofw_list_message_folders ~61
List OurFamilyWizard message folders (inbox, sent, etc.) and their unread counts. Fetched LIVE from OFW, so the counts are current. Returns folder IDs needed to call ofw_list_messages. Does NOT return message content.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
ofw_list_messages ~566
List messages from the local OurFamilyWizard cache. Supports filtering by folder, date range, and a substring query on subject+body. Pagination is offset-based (1-based `page`) but if you know what you want (a date range, a topic), prefer the filters over walking pages — the cache may have 1000+ messages. Results are newest-first by default; `sort:"oldest"` starts at the old end of a range instead of paging to it. Returns an explicit `complete` boolean describing the RESULT SET: true means "this is every message on OurFamilyWizard matching these filters as of freshness.asOf" — check it before asserting a count. An empty result from a cache that is not verified-fresh is REFUSED (result:"UNVERIFIED_EMPTY") rather than reported as an absence; pass autoRefresh:true to sync and answer instead.
| Name | Type | Req | Description |
|---|---|---|---|
| autoRefresh | boolean | – | If the result comes back EMPTY from a cache that is not verified-fresh, sync the backing folders first and answer from the refreshed cache instead of refusing. Defaults to the OFW_AUTO_REFRESH env va… |
| folderId | string | – | Folder name: "inbox", "sent", or "both" (default "both") |
| page | integer | – | Page number (default 1) |
| q | string | – | Substring match on subject AND body (case-insensitive). Use to find messages on a specific topic. |
| since | string | – | ISO date or datetime — only messages with sent_at >= since (inclusive) |
| size | integer | – | Messages per page (default 50) |
| sort | string | – | Result order: "newest" (default, newest first) or "oldest" (oldest first). This decides which end a truncated page keeps — with "newest" page 1 of a wide date range holds its most RECENT slice, with… |
| until | string | – | ISO date or datetime — only messages with sent_at < until (exclusive) |
| view | string | – | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact omits OurFamilyWizard's raw `listData` echo, which… |
No output schema declared.
No examples provided.
ofw_save_draft ~634
Save a message as a draft in OurFamilyWizard. RECIPIENTS: OurFamilyWizard does NOT persist recipients on drafts — recipientIds are accepted but the saved draft comes back with none (documented OFW behavior, noted once in the response, not warned about; supply recipientIds at send time instead). IDENTITY: the response leads with `draftKey`, the stable identity that survives editing — key off it, because the `id` changes on EVERY edit (replacing a draft creates a NEW draft and deletes the old one; OFW's update-in-place endpoint silently no-ops, so we never use it). Pass messageId to replace an existing draft; the response.id will be the NEW id, and a transparency NOTE documents the swap and which fields were carried over. THREADING: if replyToId is provided, the cache may rewrite it to the latest reply in the thread (note included). The threading verdict is read from OFW's full echo (replyToId/inReplyTo/showContext) — a warning appears ONLY when the reply linkage was genuinely dropped or re-targeted, and the response's top-level replyToId/inReplyTo always agree with its listData. Attach files via myFileIDs (from ofw_upload_attachment). After saving, the tool re-fetches the draft from OFW, and the returned `revision` reflects that authoritative state (so it will match on your next edit). SAFETY: because replacing DESTROYS the old draft rather than merging, passing messageId first re-reads that draft from OFW and REFUSES the write if its subject/body/recipients changed since you read it (drafts edited in the OFW web app do not bump any timestamp, so the local cache can be silently behind). A pure replyToId normalization by OFW is NOT treated as a conflict. The refusal returns the current server body under serverBody — merge your edit into it and retry with expectedRevision.
| Name | Type | Req | Description |
|---|---|---|---|
| body | string | yes | Message body text |
| expectedRevision | string | – | With messageId: the `revision` you got from ofw_list_drafts/ofw_get_message for that draft. Asserts you are replacing THAT version. If the draft changed on OFW since, the write is refused and the cur… |
| force | boolean | – | Default false. Overwrite even when the draft changed on OurFamilyWizard since you read it. The discarded server version is echoed back in the response. Only use after showing the user the conflict. |
| messageId | number | – | ID of an existing draft to replace (the new draft will have a new id; the old is deleted) |
| myFileIDs | array | – | Attachment file ids (from ofw_upload_attachment) |
| recipientIds | array | – | Array of recipient user IDs (optional for drafts) |
| replyToId | number | – | ID of the message this draft replies to |
| subject | string | yes | Message subject |
No output schema declared.
No examples provided.
ofw_send_message ~848
Send a message via OurFamilyWizard — the ONE irreversible operation here, so it carries the strongest guard. TO SEND AN EXISTING DRAFT (the safe default): pass draftId (or messageId — same thing). The tool re-reads the draft from OFW and sends the SERVER'S version, so what goes out is what is on OurFamilyWizard, not what this session remembers — subject/body act only as explicit overrides. It is guarded exactly like ofw_save_draft: pass expectedRevision to assert which version you are sending; if the draft changed on OFW since you read it — or no longer exists (it may already have been SENT) — the send is REFUSED with the current server content echoed back, and nothing goes out. RECIPIENTS: OurFamilyWizard does not persist recipients on drafts, so recipientIds is usually still required at send time (ids from ofw_get_profile). After the send is CONFIRMED (OFW returned the new message id and the re-fetched sent record matches what was posted), the source draft is deleted automatically; pass deleteDraftOnSuccess:false to keep it. On ANY failure or ambiguity the draft is never deleted — the response carries draftRetained:true with the reason. TO COMPOSE FROM SCRATCH: supply subject/body/recipientIds with no draftId. If replyToId is provided (or inherited from the draft), the cache may rewrite it to the latest reply in the same thread (a note is included when this happens). ATTACHMENTS: when sending by draftId, the server draft's own attachments carry over automatically; myFileIDs (from ofw_upload_attachment) overrides or attaches files on a fresh compose. The response leads with sentMessageId and the stable draftKey, and reports threaded (whether OFW actually linked the reply) and draftDeleted.
| Name | Type | Req | Description |
|---|---|---|---|
| body | string | – | Message body text. Required unless draftId/messageId is given (then it overrides the server draft's body — omit it to send exactly what is on OurFamilyWizard). |
| deleteDraftOnSuccess | boolean | – | Default true. Delete the source draft after — and ONLY after — the send is confirmed (new message id returned and the re-fetched sent record checks out). Set false to keep the draft. On a failed or u… |
| draftId | number | – | ID of an existing draft to send. The draft is re-read from OurFamilyWizard and its SERVER content is sent; missing subject/body default from it. Guarded: a draft that changed since you read it, or th… |
| expectedRevision | string | – | With draftId: the `revision` from ofw_list_drafts / ofw_get_message / ofw_check_freshness for that draft. Asserts you are sending THAT version; if the draft changed on OFW since, the send is refused… |
| force | boolean | – | Default false. Send even when the draft changed on OurFamilyWizard since you read it, or its current state could not be read. Only use after showing the user the conflict. |
| messageId | number | – | Synonym for draftId (if both are passed they must be equal). |
| myFileIDs | array | – | Attachment file ids (from ofw_upload_attachment) to attach to the message. When sending by draftId, omit it to carry the server draft's own attachments over; passing it overrides them. |
| recipientIds | array | – | Array of recipient user IDs (get from ofw_get_profile). Usually required even when sending a draft: OurFamilyWizard does not persist recipients on drafts. |
| replyToId | number | – | ID of the message being replied to. Defaults to the draft's stored reply target when sending by draftId. |
| subject | string | – | Message subject. Required unless draftId/messageId is given (then it overrides the server draft's subject). |
No output schema declared.
No examples provided.
ofw_status ~418
ONE live call that answers "where does everything stand?". This is the call that should back any status summary about drafts or specific messages — never session memory, and never a cached read alone. With no arguments it returns the FULL current draft inventory, verified against OurFamilyWizard. Pass ids and/or draftKeys to get each one's live lifecycle `state` ("draft" | "sent" | "received" | "deleted" | "unknown") with `sentAt` and `viewedAt`. A draftKey is the stable identity ofw_save_draft returns: editing a draft mints a new OFW id every time (create-then-delete), so the key is the only way to ask "what happened to the thing I was working on?" — it resolves to the chain's current id and keeps resolving after the draft is SENT (state:"sent" with sentMessageId). The top-level `complete` is true ONLY when every part of this snapshot was verified live; if it is false, do not state a draft count or a lifecycle claim from this payload.
| Name | Type | Req | Description |
|---|---|---|---|
| allowMarkRead | boolean | – | Default false. An id whose cached state cannot rule out an unread INBOX message can only be probed by fetching its detail, which marks it READ on OurFamilyWizard — irreversible and co-parent-visible.… |
| draftKeys | array | – | Stable draft keys (from ofw_save_draft / ofw_list_drafts) to resolve to their CURRENT id and state. |
| ids | array | – | Message/draft ids to resolve to a live state (combined with draftKeys, max 25 probes per call). |
| includeDraftInventory | boolean | – | Return the full current draft list, verified against OurFamilyWizard first. Defaults to TRUE when neither ids nor draftKeys is given (so a bare ofw_status() is a complete status snapshot), otherwise… |
No output schema declared.
No examples provided.
ofw_sync_messages ~427
Sync messages from OurFamilyWizard into the local cache. Returns counts per folder and a list of unread inbox messages whose bodies were NOT fetched (to avoid mark-as-read on OFW). Call ofw_get_message(id) on those to read them. EVERY call re-checks the newest page first, so new messages are picked up promptly even while an old-history backfill is still running; only then does it spend what is left of its budget advancing that backfill. Pass deep:true to walk all OFW pages instead of stopping at the first all-cached page (use to backfill suspected gaps). Sync is BOUNDED and RESUMABLE: on hosted deployments a per-call OFW-request budget (env OFW_SYNC_MAX_REQUESTS, or the maxRequests argument) caps how far one call walks; when the budget is hit the response reports done:false with a note — call again with the SAME arguments to resume. done:false means older history is still being backfilled; it does NOT mean recent messages are missing. Local installs are unbounded by default (done is always true).
| Name | Type | Req | Description |
|---|---|---|---|
| deep | boolean | – | If true, walk every OFW page until empty regardless of cache state. Use to backfill gaps. Default false. |
| fetchUnreadBodies | boolean | – | If true, also fetch bodies for unread inbox messages — which marks each one READ on OurFamilyWizard and stamps a co-parent-visible "First Viewed" time that cannot be undone. Defaults to the OFW_FETCH… |
| folders | array | – | Folders to sync (default: all three). Must be non-empty if given — an empty list would sync nothing while reporting success. |
| maxRequests | integer | – | Maximum OFW requests this single call may make before pausing. When hit, the response reports done:false — call again with the same arguments to continue. Omit to use the server default (OFW_SYNC_MAX… |
No output schema declared.
No examples provided.
ofw_update_event ~284
Update an existing OurFamilyWizard calendar event. Fetches the event, applies the given changes, and writes the merged result back (OFW has no partial update).
| Name | Type | Req | Description |
|---|---|---|---|
| allDay | boolean | – | – |
| children | array | – | Child userIds to tag; pass [] to remove all child tags (omit to keep current tags) |
| dropOffParentId | number | – | userId of the drop-off parent |
| endDate | string | – | End date YYYY-MM-DD (default: startDate) |
| endTime | string | – | End time HH:mm, 24-hour (required unless allDay) |
| eventId | string | yes | Event id — the `id` from ofw_list_events / eventRecurrenceId from ofw_create_event |
| eventParentId | number | – | userId of the parent the event is 'for' |
| location | string | – | – |
| notes | string | – | – |
| pickUpParentId | number | – | userId of the pick-up parent |
| privateEvent | boolean | – | true = visible only to you; default false = shared with co-parent |
| reminderMinutes | integer | – | – |
| startDate | string | – | Start date YYYY-MM-DD |
| startTime | string | – | Start time HH:mm, 24-hour (required unless allDay) |
| title | string | – | – |
No output schema declared.
No examples provided.
ofw_upload_attachment ~165
Upload a local file to OurFamilyWizard's "My Files" so it can be attached to a message. Returns the fileId — pass that to ofw_send_message or ofw_save_draft in myFileIDs to attach it. The file is uploaded as PRIVATE (visible only to you) by default; pass shareClass:"SHARED" to share with co-parents directly via the My Files area.
| Name | Type | Req | Description |
|---|---|---|---|
| description | string | – | Description shown in OFW My Files (default: filename) |
| label | string | – | Display label for the file in OFW (default: filename) |
| path | string | yes | Absolute path to the local file to upload. Tilde (~) is expanded. |
| shareClass | string | – | Share class (default PRIVATE) |
No output schema declared.
No examples provided.
What is the io.github.chrischall/ofw-mcp server?
io.github.chrischall/ofw-mcp is listed in the public MCP registry as io.github.chrischall/ofw-mcp. OurFamilyWizard co-parenting for Claude, messages, calendar, expenses, and journal. This page covers its npm package (ofw-mcp).
Is the io.github.chrischall/ofw-mcp server safe to use?
io.github.chrischall/ofw-mcp scores 91 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. It declares no install or post-install scripts. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the io.github.chrischall/ofw-mcp server expose?
io.github.chrischall/ofw-mcp exposes 25 tools: ofw_healthcheck, ofw_get_profile, ofw_get_notifications, ofw_list_message_folders, ofw_list_messages, and 20 more. Their descriptions and schemas cost roughly 6,615 tokens of context every time the server is loaded.
Is the io.github.chrischall/ofw-mcp server still maintained?
io.github.chrischall/ofw-mcp is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the io.github.chrischall/ofw-mcp server under?
io.github.chrischall/ofw-mcp declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.