Skip to main content
Glama

Update site

update_site
Idempotent

Use when the user wants to push the new version, ship the changes they just made, or update the page while keeping the same link. Replaces a site's content in place by id. Accepts the same inputs as publish_site (html, files as text, a bundle, or a single document such as Markdown, .ipynb, PDF, .docx, .pptx, .xlsx, CSV, an image, a video, an audio, a Mermaid diagram or a text file, which is re-rendered; pass filename for a lone non-zip file, and include_original as on publish_site); the detected content_kind may change, and the result warns when html has replaced a site that was rendered from a file. Preserves the URL, visibility, allowlist, link expiry, and view password, and records a new version. Without a shell, a binary the client cannot send as bytes is dropped by the person on the site's own page, https://app.snaphost.ai/sites/<site_id> ("Upload a new version"), never on the drive, which would make a second site. Open viewers are offered a Refresh to the new content (a landing page, framed in the marketing site, shows it on its next load). Like publish_site, the new content is scanned for window.SNAPHOST data usage and any new collections are set up to match how the page uses them (reported in the result), and for external references the site's security policy will block; relay those to the owner and either trust the approved origins (add_external_origins) or vendor the assets. Relative references to files missing from the upload are reported too; include those files and republish.

Input Schema

NameRequiredDescriptionDefault
htmlNoA single self-contained HTML document, as text. The first choice for one page: it needs no encoding, no shell and no network of your own. At most 3.5 MB once JSON-escaped (a control character other than backspace, tab, newline, form feed and carriage return, `<`, `>`, `&` or any non-ASCII character counts 6 bytes, an emoji 12, and `"`, `\` and `/` 2, so non-ASCII text may count three times its size and markup-heavy text up to six): in practice about 3 MB of plain HTML, about 2 MB when tag-dense; the rest of the 4 MB request body is for the call itself. A bigger page: Trim it, split it across more than one site, give the person the text to save as a file and hand it over, or send it through create_bundle_upload, which needs a shell that makes the SnapHost tool calls itself.
filesNoPlain-text files, each `{path, content}`, zipped for you: a page with its own CSS, JS, JSON or SVG files (name the entry `index.html`), or one Markdown, CSV, Mermaid, notebook, code or .tsx/.jsx React component file on its own, rendered as its kind under its path (a component needs a default export and may import only react, react-dom, recharts, lucide-react, d3, framer-motion and @radix-ui/react-*). Paths are relative to the bundle root with forward slashes (`index.html`, `assets/app.js`). Text only: an image, a font, a PDF or any binary is referenced at a URL (add_external_origins) or sent through create_bundle_upload. At most 100 entries and 2 MB of text in total (UTF-8), and 3.5 MB once JSON-escaped (a control character other than backspace, tab, newline, form feed and carriage return, `<`, `>`, `&` or any non-ASCII character counts 6 bytes, an emoji 12, and `"`, `\` and `/` 2, so non-ASCII text may count three times its size and markup-heavy text up to six): in practice about 2 MB of plain English or 1 MB of non-Latin or tag-dense text. The rest of the 4 MB request body is for the call itself. Like `html`, this works from any client, a chat window with no shell included.
site_idYesThe id of the site to update
filenameNoThe uploaded file's own name with its extension (`report.pdf`, `photo.png`, `data.csv`). Give it once, at create_bundle_upload; a name given here as well must match it. Pass it here only for a single non-zip file whose upload was opened without one, so it is rendered as its kind; an upload that no name describes and that is neither a zip nor an HTML page is refused. For a .docx, .pptx or .xlsx sent as `zipBase64`, give its name here: it heads the bar and names the download. Ignored for a .zip bundle. A name SnapHost does not take is refused with the export that would work.
printableNoThe page is built to print (a PDF that keeps the look): the design check asks for print styles, and a plain page gets the viewer's Print action (a report or a deck carries its own Download PDF button instead). Kept on later updates unless given again.
upload_idNoReference a bundle already uploaded via create_bundle_upload (sent with upload_bundle_part, or PUT to its `upload_url`); use this for a large or binary-carrying app (e.g. a built React site with images and fonts) that `html` or `files` cannot hold, or for a single file that is not text (a PDF, an image, a video, an audio, a .docx, .pptx or .xlsx), sent as it is together with `filename`. Sending the bytes needs a shell that makes the SnapHost tool calls itself; without a shell the person drops the file on the dashboard: the drive (https://app.snaphost.ai/) for a new site, or the site's own page (https://app.snaphost.ai/sites/<site_id>, "Upload a new version") to keep an existing link. Mutually exclusive with `html`, `files` and `zipBase64`.
zipBase64NoBase64-encoded .zip bundle (entry HTML + assets), for a multi-file bundle that holds binaries and fits the 4 MB request body once encoded; a .docx, .pptx or .xlsx (zips themselves) or a one-entry zip holding a single PDF, image, video or audio file under its real name also goes here. Text belongs in `html` or `files` instead: base64 has to be reproduced byte for byte and a long string often is not, so this input is rejected outright if the encoding or the archive checksums do not verify. Producing it needs a shell that makes the SnapHost tool calls itself; a client without one sends text as `files` and hands a binary to the person for the dashboard: the drive (https://app.snaphost.ai/) for a new site, or the site's own page (https://app.snaphost.ai/sites/<site_id>, "Upload a new version") to keep an existing link.
workspace_idNoOptional: the workspace to act in, from list_workspaces (the connection reaches the person's personal space and every workspace they are a member of). Required on a write when the connection reaches more than one workspace. Omit to act in the personal space (for an older single-workspace connection, the one workspace it was authorized for).
document_kindNoWhat the site is: a report, a presentation, a dashboard, or a plain page (the default). A publish or content update of such a site runs the design check (`design_warnings`); a presentation may go full screen. Kept on later updates unless given again.
include_originalNoWhether readers may download the uploaded file itself from the page. Applies to a Word, PowerPoint or Excel file only, and is off by default for them, because the file holds what the page does not show: speaker notes, hidden slides, sheets, rows and columns, formulas, comments and tracked changes. Pass true to offer it anyway; on update_site, leave it out to keep the live version's choice. A macro-enabled .docm, .pptm or .xlsm is never offered. A CSV, image, video, audio, PDF, diagram or text file is its page and always downloads; a Markdown file or notebook becomes its page and has no download. The result reports `original_included`, and `render_notices` says what the page could not show (cells shown as formulas when a workbook carries no computed values; a file left out for size). Relay a notice to the user.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changed
    • addedInput schema / properties / files
      Added value: +{
      +  "description": "Plain-text files, each `{path, content}`, zipped for you: a page with its own CSS, JS, JSON or SVG files (name the entry `index.html`), or one Markdown, CSV, Mermaid, notebook, code or .tsx/.jsx React component file on its own, rendered as its kind under its path (a component needs a default export and may import only react, react-dom, recharts, lucide-react, d3, framer-motion and @radix-ui/react-*). Paths are relative to the bundle root with forward slashes (`index.html`, `assets/app.js`). Text only: an image, a font, a PDF or any binary is referenced at a URL (add_external_origins) or sent through create_bundle_upload. At most 100 entries and 2 MB of text in total (UTF-8), and 3.5 MB once JSON-escaped (a control character other than backspace, tab, newline, form feed and carriage return, `<`, `>`, `&` or any non-ASCII character counts 6 bytes, an emoji 12, and `\"`, `\\` and `/` 2, so non-ASCII text may count three times its size and markup-heavy text up to six): in practice about 2 MB of plain English or 1 MB of non-Latin or tag-dense text. The rest of the 4 MB request body is for the call itself. Like `html`, this works from any client, a chat window with no shell included.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "content": {
      +        "description": "The file as UTF-8 text",
      +        "type": "string"
      +      },
      +      "path": {
      +        "description": "Relative path inside the bundle, spelled exactly as the page's own references spell it (two Unicode spellings of one accented name count as one entry)",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "path",
      +      "content"
      +    ],
      +    "type": "object"
      +  },
      +  "maxItems": 100,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • changedInput schema / properties / html / description
      Previous value: -"A single self-contained HTML document"New value: +"A single self-contained HTML document, as text. The first choice for one page: it needs no encoding, no shell and no network of your own. At most 3.5 MB once JSON-escaped (a control character other than backspace, tab, newline, form feed and carriage return, `<`, `>`, `&` or any non-ASCII character counts 6 bytes, an emoji 12, and `\"`, `\\` and `/` 2, so non-ASCII text may count three times its size and markup-heavy text up to six): in practice about 3 MB of plain HTML, about 2 MB when tag-dense; the rest of the 4 MB request body is for the call itself. A bigger page: Trim it, split it across more than one site, give the person the text to save as a file and hand it over, or send it through create_bundle_upload, which needs a shell that makes the SnapHost tool calls itself."
    • changedInput schema / properties / upload_id / description
      Previous value: -"Reference a bundle already uploaded via create_bundle_upload (sent with upload_bundle_part, or PUT to its `upload_url`); use this for a large or multi-file app (e.g. a built React site) that exceeds the inline `html`/`zipBase64` limit, or for a single file that is not a zip (Markdown, a notebook, a PDF, an image, a video, an audio, a CSV, a Mermaid diagram or a text file), sent as it is together with `filename`. Mutually exclusive with `html` and `zipBase64`."New value: +"Reference a bundle already uploaded via create_bundle_upload (sent with upload_bundle_part, or PUT to its `upload_url`); use this for a large or binary-carrying app (e.g. a built React site with images and fonts) that `html` or `files` cannot hold, or for a single file that is not text (a PDF, an image, a video, an audio, a .docx, .pptx or .xlsx), sent as it is together with `filename`. Sending the bytes needs a shell that makes the SnapHost tool calls itself; without a shell the person drops the file on the dashboard: the drive (https://app.snaphost.ai/) for a new site, or the site's own page (https://app.snaphost.ai/sites/<site_id>, \"Upload a new version\") to keep an existing link. Mutually exclusive with `html`, `files` and `zipBase64`."
    • changedInput schema / properties / zipBase64 / description
      Previous value: -"Base64-encoded .zip bundle (entry HTML + assets), for a multi-file bundle small enough to inline; a .docx, .pptx or .xlsx (zips themselves) or a one-entry zip holding a single Markdown, notebook, PDF, CSV, image, video, audio, Mermaid or text file under its real name also goes here. A single HTML document belongs in `html` instead: base64 has to be reproduced byte for byte and a long string often is not, so this input is rejected outright if the encoding or the archive checksums do not verify."New value: +"Base64-encoded .zip bundle (entry HTML + assets), for a multi-file bundle that holds binaries and fits the 4 MB request body once encoded; a .docx, .pptx or .xlsx (zips themselves) or a one-entry zip holding a single PDF, image, video or audio file under its real name also goes here. Text belongs in `html` or `files` instead: base64 has to be reproduced byte for byte and a long string often is not, so this input is rejected outright if the encoding or the archive checksums do not verify. Producing it needs a shell that makes the SnapHost tool calls itself; a client without one sends text as `files` and hands a binary to the person for the dashboard: the drive (https://app.snaphost.ai/) for a new site, or the site's own page (https://app.snaphost.ai/sites/<site_id>, \"Upload a new version\") to keep an existing link."
  2. Changed1 schema field changed
    • changedInput schema / properties / printable / description
      Previous value: -"The page is built to print (a PDF that keeps the look): the viewer then offers Print, and the design check asks for print styles. Kept on later updates unless given again."New value: +"The page is built to print (a PDF that keeps the look): the design check asks for print styles, and a plain page gets the viewer's Print action (a report or a deck carries its own Download PDF button instead). Kept on later updates unless given again."
  3. Changed2 schema fields changed
    • addedInput schema / properties / document_kind
      Added value: +{
      +  "description": "What the site is: a report, a presentation, a dashboard, or a plain page (the default). A publish or content update of such a site runs the design check (`design_warnings`); a presentation may go full screen. Kept on later updates unless given again.",
      +  "enum": [
      +    "page",
      +    "report",
      +    "presentation",
      +    "dashboard"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / printable
      Added value: +{
      +  "description": "The page is built to print (a PDF that keeps the look): the viewer then offers Print, and the design check asks for print styles. Kept on later updates unless given again.",
      +  "type": "boolean"
      +}
  4. Changed4 schema fields changed
    • addedInput schema / properties / filename
      Added value: +{
      +  "description": "The uploaded file's own name with its extension (`report.pdf`, `photo.png`, `data.csv`). Give it once, at create_bundle_upload; a name given here as well must match it. Pass it here only for a single non-zip file whose upload was opened without one, so it is rendered as its kind; an upload that no name describes and that is neither a zip nor an HTML page is refused. For a .docx, .pptx or .xlsx sent as `zipBase64`, give its name here: it heads the bar and names the download. Ignored for a .zip bundle. A name SnapHost does not take is refused with the export that would work.",
      +  "type": "string"
      +}
    • addedInput schema / properties / include_original
      Added value: +{
      +  "description": "Whether readers may download the uploaded file itself from the page. Applies to a Word, PowerPoint or Excel file only, and is off by default for them, because the file holds what the page does not show: speaker notes, hidden slides, sheets, rows and columns, formulas, comments and tracked changes. Pass true to offer it anyway; on update_site, leave it out to keep the live version's choice. A macro-enabled .docm, .pptm or .xlsm is never offered. A CSV, image, video, audio, PDF, diagram or text file is its page and always downloads; a Markdown file or notebook becomes its page and has no download. The result reports `original_included`, and `render_notices` says what the page could not show (cells shown as formulas when a workbook carries no computed values; a file left out for size). Relay a notice to the user.",
      +  "type": "boolean"
      +}
    • changedInput schema / properties / upload_id / description
      Previous value: -"Reference a bundle already uploaded via create_bundle_upload (sent with upload_bundle_part, or PUT to its `upload_url`); use this for a large or multi-file app (e.g. a built React site) that exceeds the inline `html`/`zipBase64` limit. Mutually exclusive with `html` and `zipBase64`."New value: +"Reference a bundle already uploaded via create_bundle_upload (sent with upload_bundle_part, or PUT to its `upload_url`); use this for a large or multi-file app (e.g. a built React site) that exceeds the inline `html`/`zipBase64` limit, or for a single file that is not a zip (Markdown, a notebook, a PDF, an image, a video, an audio, a CSV, a Mermaid diagram or a text file), sent as it is together with `filename`. Mutually exclusive with `html` and `zipBase64`."
    • changedInput schema / properties / zipBase64 / description
      Previous value: -"Base64-encoded .zip bundle (entry HTML + assets), for a multi-file bundle small enough to inline. A single HTML document belongs in `html` instead: base64 has to be reproduced byte for byte and a long string often is not, so this input is rejected outright if the encoding or the archive checksums do not verify."New value: +"Base64-encoded .zip bundle (entry HTML + assets), for a multi-file bundle small enough to inline; a .docx, .pptx or .xlsx (zips themselves) or a one-entry zip holding a single Markdown, notebook, PDF, CSV, image, video, audio, Mermaid or text file under its real name also goes here. A single HTML document belongs in `html` instead: base64 has to be reproduced byte for byte and a long string often is not, so this input is rejected outright if the encoding or the archive checksums do not verify."
  5. Changed1 schema field changed
    • changedInput schema / properties / workspace_id / description
      Previous value: -"Optional: the workspace (the personal space or a Pro workspace) to act in, from list_workspaces. Omit to act in the token owner's own account."New value: +"Optional: the workspace to act in, from list_workspaces (the connection reaches the person's personal space and every workspace they are a member of). Required on a write when the connection reaches more than one workspace. Omit to act in the personal space (for an older single-workspace connection, the one workspace it was authorized for)."
  6. First observed

TDQS

A3.8/5.0
Behavior3/5

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

Well beyond the annotations: it names what is preserved (URL, visibility, allowlist, link expiry, view password), that a new version is recorded, that open viewers get a Refresh, and that content is scanned for `window.SNAPHOST` and external references the security policy will block. However, a great deal of this material (the no-shell fallback, binary handling, size ceilings) is repeated verbatim from the parameter descriptions rather than adding new behavioral disclosure, and the side effect of minting a new version sits in mild tension with idempotentHint=true without being reconciled.

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

Conciseness3/5

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

Front-loaded correctly with the use case, but the body is one sprawling paragraph whose sentences are hard to parse — 'Without a shell, a binary the client cannot send as bytes is dropped by the person on the site's own page, https://app.snaphost.ai/sites/<site_id> ("Upload a new version"), never on the drive, which would make a second site' requires several re-reads. Large chunks duplicate the schema's own parameter text, so length is not fully earned.

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 10-parameter mutation tool with no output schema, the description covers the necessary ground: preserved attributes, version recording, viewer refresh behaviour, security/collection side effects, and warning surfaces such as missing relative files and `html` replacing a file-rendered site. It still does not sketch the result payload (ids, URL, warnings field names) beyond saying things are 'reported in the result', which is the main remaining gap.

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

Parameters3/5

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

Schema coverage is 100% and the property descriptions are already exhaustive, so the baseline is 3. The prose only adds light relational meaning — 'accepts the same inputs as publish_site', `filename` for a lone non-zip file, `include_original` as on publish_site, and that the detected `content_kind` may change — which does not materially exceed the schema.

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?

'Replaces a site's content in place by id' states a specific verb, resource and mechanism, and the opening line ('push the new version, ship the changes they just made, update the page while keeping the same link') separates it from publish_site and rollback_site in the agent's mind. The URL-preservation clause further pins down what distinguishes this from creating a new site.

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

Usage Guidelines4/5

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

Trigger phrases are explicit ('ship the changes they just made', 'keeping the same link') and it points to publish_site as the input-compatible alternative plus the dashboard 'Upload a new version' path when no shell is available. It never states the negative case outright — e.g. that a fresh site must go through publish_site or that reverting belongs to rollback_site — so an agent still has to infer the boundary.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.