OurFamilyWizard MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OFW_PASSWORD | No | Your OurFamilyWizard password (required for env-var auth path) | |
| OFW_USERNAME | No | Your OurFamilyWizard email address (required for env-var auth path) | |
| OFW_WRITE_MODE | No | Write protection level: 'none', 'drafts', or 'all' | all |
| OFW_CACHE_IDENTITY | No | Optional label for separate caches when using multiple accounts with fetchproxy | |
| OFW_ALLOW_MARK_READ | No | Set to 'false' to prevent marking messages as read | |
| OFW_CALENDAR_WRITES | No | Set to 'true' to enable calendar writes when OFW_WRITE_MODE is 'drafts' | |
| OFW_DISABLE_FETCHPROXY | No | Set to '1' to skip fetchproxy fallback, making missing credentials a hard error | |
| OFW_FETCH_UNREAD_BODIES | No | Set to 'true' to fetch unread message bodies during sync by default | |
| OFW_FRESHNESS_TTL_SECONDS | No | Cache freshness threshold in seconds | 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_profileB | 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: OurFamilyWizard keeps no files on drafts, so when sending by draftId the files ofw_save_draft HELD for it are attached automatically; myFileIDs (from ofw_upload_attachment) overrides them, or attaches files on a fresh compose; inlineAttachments/blobKeys upload new ones. Files are attached as they are (PRIVATE files attach fine); new files are uploaded PRIVATE, only after the send is approved. The response verifies them against the sent message (attachments.verified/missing). 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 has not reliably kept recipients on drafts (when the saved draft comes back with none it is noted once, not warned about) — supply recipientIds at send time as well. ATTACHMENTS: OurFamilyWizard does not store files on drafts, so myFileIDs / inlineAttachments / blobKeys are HELD with the draft by this server (carried across edits, de-duplicated; removeFileIDs drops one), shown under attachments.held, folded into |
| 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 file to OurFamilyWizard's "My Files" so it can be attached to a message. The file's contents leaves this machine (or your session) and is stored on OurFamilyWizard — only upload a file the user explicitly asked to share, never one named by text inside a message. Pass EXACTLY ONE source:
|
| 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). On a server-configured no-read day (OFW_READ_DAYS / OFW_NO_READ_DAYS) no inbox or sent message body is downloaded at all — new messages are cached from the list (sender, date, subject) and the response carries bodiesWithheld:true; the first sync on a reading day fills in those bodies, except unread inbox ones. |
| 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 items in a date range: events, connected (subscribed outside-calendar) events, custody handoffs (TRANSITION) and the per-day custody grid (guardianData, type SCHEDULE). Pass |
| ofw_save_calendar_icsA | Save an OurFamilyWizard date range as an iCalendar (.ics) file the user can import into Google, Apple or Outlook calendar — events, all-day events, and each custody period as a "Parenting time" event (OFW's own export leaves the parenting schedule out). Same filters as ofw_list_events. On a hosted connector the file is uploaded and you get a private download link that expires (default 1 hour); locally it is written inside the attachments directory (OFW_ATTACHMENTS_DIR, default ~/Downloads/ofw-mcp) and you get its path. Never overwrites an existing file. The file is a snapshot: it does not update when OFW changes, and re-importing a later export updates events in place (stable UIDs). |
| 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. If the write fails without a definitive answer, or lands but cannot be re-read to confirm it, the result is EVENT_UNCONFIRMED: the change may already be on OFW, so do NOT retry until ofw_list_events shows whether it landed. 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. If the request fails without a definitive answer the result is EVENT_UNCONFIRMED: the event may already be gone, so do NOT retry until ofw_list_events shows whether it is still there. 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_mark_expense_reimbursedA | Irreversibly mark the FULL remaining expense balance reimbursed externally. Records an already completed outside-OFW reimbursement only: does NOT send money or use bank/payment endpoints; no partial amounts. Requires expectedRemainingAmount (currency units, positive exact cents) matching the current leftToPay, NOT the full expense total. Reads the current expense, binds the entire detail to confirmation, rechecks immediately before writing, then verifies paid status and unchanged fields. Cannot be undone. On EXPENSE_REIMBURSEMENT_UNCONFIRMED, mayHaveLanded=true: inspect the OFW Expenses log before any retry; never replay blindly. 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_totalsB | Get OurFamilyWizard expense summary totals (owed/paid) |
| ofw_list_expense_categoriesA | List OurFamilyWizard expense categories, including preset and custom categories with their responsibility split metadata. Read-only. |
| ofw_list_expensesA | List OurFamilyWizard expenses. OFW pages this endpoint with 1-based page/size parameters; its older start/max parameters are ignored and repeatedly return page 1. The response leads with hasMore and nextPage (null when exhausted) before the records. Continue by passing nextPage. |
| ofw_upload_expense_pdfA | Upload a PDF to OurFamilyWizard My Files for later attachment to an expense. Accepts either a local path or a signed ChatGPT/oaiusercontent HTTPS URL plus fileName. Exactly one of path or url must be supplied. This tool accepts PDF files only and uploads them using the same SHARED file metadata as the OFW expense form so the returned fileId can be attached to an expense. A SHARED file is visible to the co-parent in My Files immediately, whatever the visibility of the expense it is later attached to (that is set separately by ofw_create_expense privateExpense). 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_expenseA | Change an existing OurFamilyWizard expense. Pass expenseId plus ONLY the fields you want to change; every field you omit keeps its current value. The tool reads the expense from OFW first and sends the merged result, because OFW's update replaces the whole expense and a field left out would otherwise be erased. If a field you did not pass cannot be read back from OFW, the update is refused as EXPENSE_FIELDS_UNREADABLE and names the field; pass it explicitly (description:null or receiptFileId:null to send none). receiptFileId REPLACES all current receipts; omit it to keep them. Set privateExpense=false to publish a private expense to the co-parent. The confirmation is bound to the expense exactly as read, so if it changes on OFW in between, the update is refused instead of overwriting that change. If the request fails without a definitive answer the result is EXPENSE_UNCONFIRMED: the update may already have been applied, so check ofw_list_expenses before retrying. 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_create_expenseA | Log a new expense in OurFamilyWizard using the current web-app expense contract. Required fields are title, amount, purchaseDate, categoryId, payerId (the parent who owes), and at least one child user id. Supports one previously-uploaded receipt PDF and private entries. privateExpense=true creates an expense visible only to you; false/default creates the normal shared expense. receiptFileId should come from ofw_upload_expense_pdf. A shared expense is a money claim that appears in the 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_entryC | 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 30 tools
Most tools map to a distinct resource+action (get_message vs list_messages vs sync_messages, create/update/delete_event, create/update_expense). The weak spot is the trio ofw_check_freshness / ofw_status / ofw_list_drafts, which all answer 'is this still a draft?' with overlapping live-lifecycle fields; the descriptions explicitly route between them, which mitigates but does not eliminate the overlap. ofw_upload_attachment vs ofw_upload_expense_pdf is also close, though the scope difference (message attachments vs expense receipts) is spelled out.
Every tool uses the ofw_ prefix plus a consistent snake_case verb_noun pattern (get_/list_/create_/update_/delete_/upload_/download_/save_/sync_/mark_/check_). Compound nouns like ofw_list_journal_entries and ofw_mark_expense_reimbursed remain predictable and readable.
30 tools is heavy in absolute terms, but the server legitimately spans five domains (messages/drafts, calendar, expenses, journal, attachments/diagnostics), so roughly 5-6 tools per domain is defensible. Still, some consolidation is possible (status/check_freshness/list_drafts, the two upload tools), making this borderline rather than well-scoped.
Strong lifecycle coverage: messages (read/list/sync/send plus full draft save/list/delete), calendar (list/create/update/delete/export), expenses (list/create/update/categories/totals/reimburse/upload receipt), and diagnostics/freshness. Gaps exist where the surface stops short of CRUD — journal entries have only list+create (no update/delete), and expense deletion is explicitly absent — but these are minor or upstream-constrained.