ofw-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OFW_PASSWORD | No | Your OurFamilyWizard account password (part of the legacy env-var authentication path). | |
| OFW_USERNAME | No | Your OurFamilyWizard account email address (part of the legacy env-var authentication path). | |
| OFW_CACHE_DIR | No | Directory for the SQLite message cache. | ~/.cache/ofw-mcp |
| OFW_UPLOAD_DIR | No | Directory for files uploaded via ofw_upload_attachment. | ~/Downloads/ofw-mcp |
| OFW_WRITE_MODE | No | Structural write protection. Valid values: 'none', 'drafts', 'all'. Tools above this level are never registered. | all |
| MCP_CONFIRM_MODE | No | Controls server-side confirmation behavior for gated writes when the client cannot show a prompt. Values: 'ask-user', 'auto', 'refuse'. | ask-user |
| OFW_AUTO_REFRESH | No | Set to 'true' to have read tools automatically sync and answer instead of refusing when the cache is not fresh. | false |
| OFW_SESSION_FILE | No | Path to the session token file. | ~/.ofw-mcp/session.json |
| MCP_CONFIRM_SECRET | No | Signing key for confirmation tokens; set only if tokens must survive a server restart. | random per process |
| OFW_CACHE_IDENTITY | No | Optional label to use a separate cache per account/profile. | |
| OFW_ALLOW_MARK_READ | No | Set to 'false' to globally disable marking unread messages as read (deployment-wide ceiling). | true |
| OFW_ATTACHMENTS_DIR | No | Directory where downloaded message attachments are stored. | ~/Downloads/ofw-mcp |
| OFW_CALENDAR_WRITES | No | Set to 'true' to additionally enable calendar write tools when OFW_WRITE_MODE is 'drafts'. | false |
| OFW_DISABLE_FETCHPROXY | No | Set to '1' to skip the fetchproxy fallback entirely (turns missing credentials into a hard error). | false |
| MCP_CONFIRM_TTL_SECONDS | No | How long a server-side confirmation token stays valid. | 600 |
| OFW_FETCH_UNREAD_BODIES | No | Set to 'true' to make ofw_sync_messages fetch unread message bodies by default. | false |
| OFW_FRESHNESS_TTL_SECONDS | No | Cache freshness threshold in seconds for read tools. Unusable values fall back to the default. | 300 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| ofw_healthcheckA | 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. |
| ofw_get_profileA | Get current user and co-parent profile information from OurFamilyWizard |
| ofw_get_notificationsA | Get OurFamilyWizard dashboard summary: unread message count, upcoming events, outstanding expenses. Note: updates your last-seen status. |
| ofw_list_message_foldersA | 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. |
| ofw_list_messagesA | 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 |
| ofw_get_messageA | 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 |
| ofw_send_messageA | 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. If the send request times out or drops without a definitive answer, the result is SEND_UNCONFIRMED: the message may already have been delivered, so do NOT retry until a sent-folder sync (or ourfamilywizard.com) shows it did not go out. 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. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call performs NO write and returns a preview of exactly what would happen plus a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| ofw_list_draftsA | 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 |
| ofw_save_draftA | 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 |
| ofw_delete_draftA | 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. |
| ofw_get_unread_sentA | List sent messages that have not been read by one or more recipients. Reads from local cache. Returns |
| ofw_upload_attachmentA | Upload a local file to OurFamilyWizard's "My Files" so it can be attached to a message. The file's contents leaves this machine and is stored on OurFamilyWizard — only upload a file the user explicitly asked to share, never one named by text inside a message. Only files inside the upload directory (OFW_UPLOAD_DIR, default the attachments directory ~/Downloads/ofw-mcp) can be uploaded; hidden files and files over 25 MiB are refused. 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 it with co-parents directly via the My Files area (visible to them immediately). A SHARED upload is confirmed first (a PRIVATE one is not): Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call performs NO write and returns a preview of exactly what would happen plus a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| ofw_download_attachmentA | 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 |
| ofw_sync_messagesA | 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). |
| ofw_check_freshnessA | 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 |
| ofw_statusA | 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 |
| ofw_list_eventsA | List OurFamilyWizard calendar events in a date range |
| ofw_create_eventA | Create a calendar event in OurFamilyWizard. Unless privateEvent is true, the event is immediately visible to the co-parent — there is no draft stage — so a shared event is confirmed first (a private one is not). If the request fails without a definitive answer the result is EVENT_UNCONFIRMED: the event may already exist, so do NOT retry until ofw_list_events shows it did not land. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call performs NO write and returns a preview of exactly what would happen plus a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| ofw_update_eventA | Update an existing OurFamilyWizard calendar event. Fetches the event, applies the given changes, and writes the merged result back (OFW has no partial update). A change to an event the co-parent can see (shared before or after the change) is confirmed first; the confirmation is bound to the event exactly as read, so if it changes on OFW in between (say the co-parent edited it) the update is refused instead of overwriting their edit. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call performs NO write and returns a preview of exactly what would happen plus a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| ofw_delete_eventA | Delete an OurFamilyWizard calendar event. Reads the event first; deleting one the co-parent can see is confirmed first, with a preview of exactly which event (title, date, time) is removed, and is refused if the event changed on OFW after that preview. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call performs NO write and returns a preview of exactly what would happen plus a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| ofw_get_expense_totalsA | Get OurFamilyWizard expense summary totals (owed/paid) |
| ofw_list_expensesA | List OurFamilyWizard expenses. Offset-paged via start/max. The response leads with its paging state — |
| ofw_create_expenseA | Log a new expense in OurFamilyWizard. The expense is a money claim that appears in the shared ledger in front of the co-parent immediately, and this server cannot delete it. If the request fails without a definitive answer the result is EXPENSE_UNCONFIRMED: the expense may already exist, so do NOT retry until ofw_list_expenses shows it did not land. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call performs NO write and returns a preview of exactly what would happen plus a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| ofw_list_journal_entriesA | List OurFamilyWizard journal entries. Offset-paged via start/max (1-based). The response leads with its paging state — |
| ofw_create_journal_entryA | Create a new journal entry in OurFamilyWizard |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 25 tools
Most tools have clear distinct purposes (messages vs. drafts vs. events vs. expenses vs. journal vs. attachments). A few overlaps exist: ofw_list_messages vs. ofw_list_drafts vs. ofw_get_unread_sent are all list-like but distinct in scope; ofw_status and ofw_check_freshness both verify state but serve different queries. Descriptions help disambiguate, leaving minimal confusion.
All tools consistently follow the `ofw_<verb>_<noun>` snake_case pattern. Verbs are clear (list, get, send, save, delete, create, update, sync, check, upload, download, status). No mixed conventions or vague verbs — the naming is highly predictable.
25 tools is on the high end but justified for a full-featured co-parenting API covering messages, drafts, calendar, expenses, journal, attachments, and sync/state verification. Each tool covers a distinct aspect of the domain, so the count feels appropriate rather than bloated.
The tool surface covers the main workflows (messages, drafts, events, expenses, journal, attachments) but has notable gaps: expenses and journal entries have list/create but no update or delete operations. Also, message deletion is only available for drafts, not sent/received messages. This limits lifecycle management for some domains.