Skip to main content
Glama
OurFamilyWizard MCP

OurFamilyWizard MCP

by chrischall

ofw_upload_attachment

Destructive

Uploads a file to OurFamilyWizard's My Files so you can attach it to a message or draft. Returns file IDs to pass into send-message or save-draft calls.

Instructions

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:

  • uploadSlots (hosted deployments — the way to send photos and other real files): uploadSlots:[{filename}] returns a signed upload URL per file plus a ready curl command; PUT each file's bytes to its URL, then call this tool again with blobKeys:[…] to upload them. The copies in the upload store are deleted once OFW has them.

  • inline: {filename, contentBase64, mimeType?} or an array of them — the bytes, base64, inside the call. Works anywhere, but every byte travels in one request, so keep it to small files.

  • path: a file on the SERVER's own disk, inside the upload directory (OFW_UPLOAD_DIR, default ~/Downloads/ofw-mcp) — local installs only. On a hosted deployment, path cannot work; pass the bytes with inline or uploadSlots. Up to 10 files per call; each must be non-empty and at most 25 MiB, with a bare filename (no path, no leading dot). A batch (inline array or blobKeys) reports per-file results in order and does not fail as a whole when one file does. Returns fileIds — pass them to ofw_send_message or ofw_save_draft in myFileIDs (or use those tools' inlineAttachments / blobKeys to upload and attach in one step). Files are uploaded as PRIVATE (visible only to you) by default; pass shareClass:"SHARED" to share ONE file with co-parents directly via My Files (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).

Input Schema

NameRequiredDescriptionDefault
pathNoLocal installs only: path to a file inside the upload directory. A relative path is resolved against that directory; tilde (~) is expanded. Refused on a hosted deployment, whose disk you cannot reach.
labelNoDisplay label for the file(s) in OFW (default: filename)
inlineNoThe file bytes, base64: one {filename, contentBase64, mimeType?} or an array of up to 10. Best for small files.
blobKeysNoHosted deployments: the blobKey of each slot whose file you PUT. Each file is uploaded to OFW, then deleted from the upload store.
shareClassNoShare class (default PRIVATE). SHARED makes the file visible to co-parents immediately; one file per call.
descriptionNoDescription shown in OFW My Files (default: filename)
uploadSlotsNoHosted deployments: request signed upload URLs, one per file. Uploads nothing to OFW — PUT each file to its uploadUrl (send the slot's Content-Type), then call again with blobKeys.
confirmTokenNoONLY for the two-step confirmation fallback (a client without MCP elicitation). The confirmToken from this same tool's phase-1 "confirmation-required" response, passed back ONLY after the user has seen that preview and explicitly approved it in chat — never on the first call, never invented, never reused. Call again with the same arguments. Ignored when the client supports elicitation.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changedv2.27.2
    • addedInput schema / properties / blobKeys
      Added value: +{
      +  "description": "Hosted deployments: the blobKey of each slot whose file you PUT. Each file is uploaded to OFW, then deleted from the upload store.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "maxItems": 10,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • addedInput schema / properties / inline
      Added value: +{
      +  "anyOf": [
      +    {
      +      "properties": {
      +        "contentBase64": {
      +          "description": "The file's bytes, standard base64 (line breaks and a \"data:<type>;base64,\" prefix are tolerated).",
      +          "type": "string"
      +        },
      +        "filename": {
      +          "description": "Filename the upstream will show — a bare name, no path, not starting with a dot. Its extension sets the MIME type when mimeType is omitted.",
      +          "type": "string"
      +        },
      +        "mimeType": {
      +          "description": "MIME type, e.g. \"image/jpeg\". Default: inferred from the filename extension.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "filename",
      +        "contentBase64"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "items": {
      +        "properties": {
      +          "contentBase64": {
      +            "description": "The file's bytes, standard base64 (line breaks and a \"data:<type>;base64,\" prefix are tolerated).",
      +            "type": "string"
      +          },
      +          "filename": {
      +            "description": "Filename the upstream will show — a bare name, no path, not starting with a dot. Its extension sets the MIME type when mimeType is omitted.",
      +            "type": "string"
      +          },
      +          "mimeType": {
      +            "description": "MIME type, e.g. \"image/jpeg\". Default: inferred from the filename extension.",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "filename",
      +          "contentBase64"
      +        ],
      +        "type": "object"
      +      },
      +      "maxItems": 10,
      +      "minItems": 1,
      +      "type": "array"
      +    }
      +  ],
      +  "description": "The file bytes, base64: one {filename, contentBase64, mimeType?} or an array of up to 10. Best for small files."
      +}
    • changedInput schema / properties / label / description
      Previous value: -"Display label for the file in OFW (default: filename)"New value: +"Display label for the file(s) in OFW (default: filename)"
    • changedInput schema / properties / path / description
      Previous value: -"Path to the local file to upload, inside the upload directory. A relative path is resolved against that directory; tilde (~) is expanded."New value: +"Local installs only: path to a file inside the upload directory. A relative path is resolved against that directory; tilde (~) is expanded. Refused on a hosted deployment, whose disk you cannot reach."
    • changedInput schema / properties / shareClass / description
      Previous value: -"Share class (default PRIVATE). SHARED makes the file visible to co-parents immediately."New value: +"Share class (default PRIVATE). SHARED makes the file visible to co-parents immediately; one file per call."
    • addedInput schema / properties / uploadSlots
      Added value: +{
      +  "description": "Hosted deployments: request signed upload URLs, one per file. Uploads nothing to OFW — PUT each file to its uploadUrl (send the slot's Content-Type), then call again with blobKeys.",
      +  "items": {
      +    "properties": {
      +      "filename": {
      +        "description": "Filename the upstream will show — a bare name, no path, not starting with a dot.",
      +        "type": "string"
      +      },
      +      "mimeType": {
      +        "description": "MIME type. Default: inferred from the filename extension. The PUT must send exactly this Content-Type.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "filename"
      +    ],
      +    "type": "object"
      +  },
      +  "maxItems": 10,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • removedInput schema / required
      Removed value: -[
      -  "path"
      -]
  2. Changed1 schema field changedv2.19.4
    • addedInput schema / properties / confirmToken
      Added value: +{
      +  "description": "ONLY for the two-step confirmation fallback (a client without MCP elicitation). The confirmToken from this same tool's phase-1 \"confirmation-required\" response, passed back ONLY after the user has seen that preview and explicitly approved it in chat — never on the first call, never invented, never reused. Call again with the same arguments. Ignored when the client supports elicitation.",
      +  "type": "string"
      +}
  3. Changed2 schema fields changedv2.19.3
    • changedInput schema / properties / path / description
      Previous value: -"Absolute path to the local file to upload. Tilde (~) is expanded."New value: +"Path to the local file to upload, inside the upload directory. A relative path is resolved against that directory; tilde (~) is expanded."
    • changedInput schema / properties / shareClass / description
      Previous value: -"Share class (default PRIVATE)"New value: +"Share class (default PRIVATE). SHARED makes the file visible to co-parents immediately."
  4. Changed1 schema field changedv2.17.0
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
  5. First observedv2.8.0

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructive/openWorld annotations it discloses the consequences that matter: bytes leave the machine and are stored on OFW, the upload-store copies are deleted once OFW has them, PRIVATE is the default while SHARED is immediately visible to co-parents, and a SHARED upload is gated behind confirmation. It also explains the two-phase uploadSlots → PUT → blobKeys choreography and that a batch reports per-file results and 'does not fail as a whole when one file does'. Nothing here contradicts the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded and the three sources are cleanly bulleted, so the structure serves the reader well. It is nonetheless long, and the trailing block on confirmation prompts is dense enough that the actionable rule ('first call performs NO write and returns a preview plus confirmToken') has to be dug out of a single run-on sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still tells the agent what comes back (fileIds, per-file ordered results) and what to do with them. Combined with the size limits, share-class semantics, partial-failure behavior, and the confirmation fallback, an agent has everything needed to invoke an 8-parameter, three-mode tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3, but the description adds semantics the schema cannot express: the 'Pass EXACTLY ONE source' rule, which the schema does not enforce (there is no oneOf among path/inline/uploadSlots), plus limits (10 files, 25 MiB, bare non-dot filename) and the meaning of confirmToken as valid only on a repeat call after explicit user approval. It also clarifies that fileIds are the hand-off key to myFileIDs on the message tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and destination resource: 'Upload a file to OurFamilyWizard's "My Files" so it can be attached to a message.' It distinguishes this from the downstream siblings by naming ofw_send_message and ofw_save_draft and explaining that this tool only stages files that those tools then attach. An agent can identify the tool's role without opening the schema, though the near-neighbour ofw_upload_expense_pdf is never explicitly excluded.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit decision tree over the three modes: uploadSlots for hosted deployments and 'the way to send photos and other real files', inline for small files that 'work anywhere', and path for local installs only, with an explicit statement that path 'cannot work' on a hosted deployment. It also states when to bypass this tool entirely by using the other tools' inlineAttachments / blobKeys instead, which is exactly the alternative-routing guidance the dimension asks for.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.