Creating pages
Create a page from HTML or Markdown, update or patch it, and manage large uploads.
A page is a single HTML or Markdown document, hosted at one shareable link. It can be a report, a proposal, a prototype, anything an AI tool or a person produces as a document.
Creating a page
The create_page tool takes exactly one of html or markdown. Markdown is
rendered to HTML server-side. If you omit title, it is inferred from the
document's <title> tag or its first heading. If you give a folder that
doesn't exist yet, it is created. The tool returns the shareable URL.
create_page({
title: "Q3 Report",
markdown: "# Q3 Report\n\n...",
folder: "Reports"
})You can also set visibility and, for password-protected pages, password at
creation time. See Access and sharing for what each visibility
level means.
Markdown rendering
Uploading or passing Markdown (a .md file, or the markdown argument)
renders it to clean, sanitized HTML automatically, no manual formatting
needed:
- GitHub-flavored Markdown (tables, task lists, strikethrough) is supported.
- Code blocks get syntax highlighting.
- Headings get anchor ids, so a heading can be linked to directly.
- Front matter (
title/descriptionat the top of the file) sets the page's title and meta description if present; otherwise the title falls back to the first# heading. - Images must be an absolute
http(s)URL or adata:imageURI; anything else is dropped, since a single Markdown upload has no bundled asset folder to resolve a relative path against. - External links automatically open in a new tab with
rel="noopener noreferrer".
The original Markdown source is preserved and stays downloadable alongside the rendered page, so uploading Markdown never throws away your source of truth.
Same pipeline everywhere
Markdown rendering is identical whether you upload a .md file in the
dashboard or pass markdown through the MCP server (create_page,
update_page, or request_upload_url with format: "markdown").
Updating vs. patching
Two tools change an existing page's content, and they solve different problems:
| Tool | Use it when | Behavior |
|---|---|---|
update_page | You have the full new HTML or Markdown | Replaces the page's content wholesale. Writes a new (reversible) version. |
patch_page | You want to change one part without resending the whole document | Applies a targeted edit: exact find/replace, or insert content after a specific heading. |
patch_page has two mutually exclusive modes:
- Find and replace.
findmust match the current HTML exactly (callget_pageonce to see it, or reuse an inline comment's anchor quote fromlist_comments). By defaultfindmust match exactly once; passexpectedMatchesto change several identical spans at once. - Insert after a heading.
insertAfterHeadingmust exactly match a heading's text fromget_page's outline;insertis placed right before the next heading of the same or higher level (or at the end of the page if there isn't one). This lets you append to a section without ever fetching its contents.
Pass preview: true with either mode to see what would change without
writing a version. Prefer patch_page over update_page for edits to large
pages, since it never requires resending the whole document.
Corrupted-patch guard
If applying a patch would leave the HTML looking truncated (for example, a large inline base64 image got cut off mid-value), the write is aborted and nothing is saved, rather than silently storing broken HTML.
Reading a page
get_page returns a page's current HTML and metadata. For a page you
haven't seen yet, call it with outline: true first: this returns metadata,
size, and a heading outline (with character offsets) instead of the full
HTML. From there, either read a specific range with offset/maxBytes, or
use patch_page to act on one section directly, so a large page never needs
a full fetch.
When a page is large, get_page's response also includes a downloadUrl:
fetch it directly to pull the whole raw HTML to a local file without that
content passing through the model at all.
Images in pages
A page keeps its images as hosted assets and references them by URL, rather than
as giant inline base64 blobs. Drop an HTML file together with its images (or a
whole folder) in the browser and the relative references are rewritten
automatically, or host an image over MCP with add_page_image. See
Images in pages for the full details.
Large-page uploads
Sending a page's whole HTML as a tool argument gets awkward past about 50 KB: it can exceed a model's output-token budget or a client's tool-call size limit, and even under those limits it's slow, since every byte has to be emitted token by token. Two tools move the bytes around that entirely:
request_upload_urlreturns a short-lived URL (valid 15 minutes).PUTthe raw HTML (or Markdown, withformat: "markdown") directly to it, for examplecurl -X PUT --data-binary @page.html '<url>'. Pass an existing page'sidto replace it instead of creating a new one.request_download_urlis the read-side counterpart: it returns a short-lived URL toGETa page's raw stored HTML to a local file.
Your plan's page-size limit still applies to an uploaded file (see the FAQ for the exact limits). If your MCP client can't make an HTTP request itself, the dashboard's page uploader and each page's "Replace content" settings do the same thing from a browser.
See also
- Access and sharing for visibility levels, invites, and passwords.
- MCP tool reference for every page tool's full schema.