Skip to main content
Glama

skylight_upload_photo

Destructive

Upload a photo or video to a Skylight frame slideshow, with a preview and confirmation before sending.

Instructions

Upload a photo or video to the Skylight frame (it appears in the slideshow). Pass exactly ONE of image_path (a local file — local installs), image_blob_key (on the hosted connector: call skylight_upload_slots first, PUT the file to the returned uploadUrl, then pass its blobKey) or image_inline (base64; small files only). Two-step: signs an S3 upload with temporary credentials, then registers it as a frame message. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token (and the same file) proceeds (see MCP_CONFIRM_MODE). The preview names the file (absolute image_path, or filename and image_blob_key), detected mime, size, SHA-256 and caption; nothing is uploaded until it is confirmed, and a file that changed in between is refused. A blob-store upload is deleted once Skylight accepts the photo (reported as blob.deleted) and kept if the upload fails.

Tool call template

This tool declares no required parameters. Add optional parameters from the input schema as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {},
    "name": "skylight_upload_photo"
  }
}

Input Schema

NameRequiredDescriptionDefault
captionNoCaption shown with the photo.
frameIdNo
frame_idsNoFrame ids to post to; defaults to the resolved frame.
image_pathNoLOCAL installs only: absolute path to an image/video file inside the upload directories (SKYLIGHT_UPLOAD_DIR; by default ~/Pictures and ~/Downloads) (jpg, jpeg, png, heic, gif, webp, mp4, mov; max 200 MiB). Anything else — a file outside those directories, a hidden file, a symlink, or a file whose contents do not match its extension — is refused. Refused on a hosted deployment (the claude.ai connector): use image_blob_key there.
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.
image_inlineNoThe file itself as base64: {filename, contentBase64, mimeType?}. Small files only — the whole file rides inside one tool call (a hosted deployment caps a request at about 9.9 MiB). Same types as image_path; the bytes must match the type.
image_blob_keyNoHosted deployments: the blobKey from skylight_upload_slots, after the file was PUT to its uploadUrl. Same types as image_path, max 200 MiB. The upload is deleted from the blob store once Skylight accepts it, and kept if the upload fails.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv1.6.0
    • addedInput schema / properties / image_blob_key
      Added value: +{
      +  "description": "Hosted deployments: the blobKey from skylight_upload_slots, after the file was PUT to its uploadUrl. Same types as image_path, max 200 MiB. The upload is deleted from the blob store once Skylight accepts it, and kept if the upload fails.",
      +  "type": "string"
      +}
    • addedInput schema / properties / image_inline
      Added value: +{
      +  "description": "The file itself as base64: {filename, contentBase64, mimeType?}. Small files only — the whole file rides inside one tool call (a hosted deployment caps a request at about 9.9 MiB). Same types as image_path; the bytes must match the type.",
      +  "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"
      +}
    • changedInput schema / properties / image_path / description
      Previous value: -"Absolute path to a local image/video file inside the upload directories (SKYLIGHT_UPLOAD_DIR; by default ~/Pictures and ~/Downloads) (jpg, jpeg, png, heic, gif, webp, mp4, mov; max 200 MiB). Anything else — a file outside those directories, a hidden file, a symlink, or a file whose contents do not match its extension — is refused."New value: +"LOCAL installs only: absolute path to an image/video file inside the upload directories (SKYLIGHT_UPLOAD_DIR; by default ~/Pictures and ~/Downloads) (jpg, jpeg, png, heic, gif, webp, mp4, mov; max 200 MiB). Anything else — a file outside those directories, a hidden file, a symlink, or a file whose contents do not match its extension — is refused. Refused on a hosted deployment (the claude.ai connector): use image_blob_key there."
    • removedInput schema / required
      Removed value: -[
      -  "image_path"
      -]
  2. Changed1 schema field changedv1.3.1
    • changedInput schema / properties / image_path / description
      Previous value: -"Absolute path to a local image/video file (jpg, jpeg, png, heic, gif, webp, mp4, mov; max 200 MiB). Anything else — or a symlink, or a file whose contents do not match its extension — is refused."New value: +"Absolute path to a local image/video file inside the upload directories (SKYLIGHT_UPLOAD_DIR; by default ~/Pictures and ~/Downloads) (jpg, jpeg, png, heic, gif, webp, mp4, mov; max 200 MiB). Anything else — a file outside those directories, a hidden file, a symlink, or a file whose contents do not match its extension — is refused."
  3. Changed2 schema fields changedv1.3.0
    • removedInput schema / properties / confirm
      Removed value: -{
      -  "description": "Must be true to proceed. Without this, the tool returns a preview.",
      -  "type": "boolean"
      -}
    • 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"
      +}
  4. Changed1 schema field changedv1.1.3
    • changedInput schema / properties / image_path / description
      Previous value: -"Absolute path to a local image/video file (jpg, png, heic, mp4, …)."New value: +"Absolute path to a local image/video file (jpg, jpeg, png, heic, gif, webp, mp4, mov; max 200 MiB). Anything else — or a symlink, or a file whose contents do not match its extension — is refused."
  5. Changed1 schema field changedv1.0.1
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
  6. Changed2 schema fields changedv0.7.1
    • removedInput schema / properties / frame_ids / items / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "number"
      -  }
      -]
    • addedInput schema / properties / frame_ids / items / type
      Added value: +[
      +  "string",
      +  "number"
      +]
  7. First observedv0.4.6

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only declare destructiveHint/openWorldHint/readOnlyHint=false; the description adds far more: a mandatory user confirmation gate, a preview containing path/filename, mime, size, SHA-256 and caption, refusal of files that changed between preview and confirm, and the blob lifecycle (deleted on success as blob.deleted, kept on failure). These are exactly the behavioral facts an agent needs before a mutating upload.

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?

Purpose and the exclusivity rule are front-loaded, and every clause carries operational meaning (modes, confirmation, blob cleanup). It is a dense single block, though, and the parameter-mode routing could be split into short bullets for faster scanning.

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

Completeness4/5

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

For a 7-parameter mutating tool with a nested object, no required fields and no output schema, the description covers the risky parts well: source selection, size/type limits, confirmation, and cleanup. Minor gaps remain around what the success response contains and how frame_id/frame_ids interact when both are supplied.

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

Parameters4/5

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

Schema coverage is 86%, so the schema already documents each field, but the description supplies a constraint the schema does not encode: "Pass exactly ONE" of the three image sources (there is no oneOf/anyOf in the schema). It also clarifies ordering for image_blob_key and the confirmToken lifecycle. It stops short of explaining frameId vs frame_ids resolution, which the schema only partially covers.

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?

Opens with a specific verb + resource + effect: "Upload a photo or video to the Skylight frame (it appears in the slideshow)." It also distinguishes itself from the sibling skylight_upload_slots by naming it as a prerequisite step rather than an equivalent, so an agent can route between them without opening either schema.

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?

Gives explicit routing rules: exactly one of image_path (local installs), image_blob_key (hosted connector, after skylight_upload_slots + PUT), or image_inline (small files). It also states the confirmation requirement and the two operating modes (elicitation-capable client vs confirmToken fallback), so the agent knows the required call sequence before acting.

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

Deploy Server

Other Tools