A Page is an exact static file bundle at a stable URL, with immutable versions and human comments. Validate your HTML before publishing; SecondPage serves the files you supply.
Choose the input
Use exactly one content mode per create_page or update_page call:
The server does not render, rewrite, or autofix the submitted source. Decks receive a separate bounded compatibility assessment after publication; that assessment does not repair source or make malformed files safe.
- One self-contained HTML document: pass
htmlas plain text, at most 512 KiB of UTF-8 bytes. It becomesindex.html; inline CSS and JavaScript are allowed. No encoding or model-generated assets are needed. - Several files, with HTTP available: pass
upload_fileswith path, content_type, byte_size and SHA-256 per file. PUT only files markedupload_requiredto their returned URLs with the required headers. Complete using the same tool andupload_session_id. - Several files, without HTTP available: pass the complete
filesarray with a relativepath,content_base64containing each file's original bytes, and optionalcontent_type. Encode text files as UTF-8 before base64 encoding; preserve binary bytes.
Never mix html, files, upload_files, or upload_session_id. A manifest is optional for the default index.html route; supply one for custom entrypoints or multiple routes. File paths cannot start with /, contain .., backslashes, or control characters. Load topic: "publishing" for upload and export details.
Create or revise
Use list_pages with query to find Pages by title or slug; follow next_cursor with the same query until has_more is false. Confirm the organization with get_organization_context if uncertain.
Use create_page for new work. Target matching runs before upload URLs are issued. target_review_required means nothing was uploaded: use the returned evidence to identify the existing Page, or retry target_choice: "create_separate" only when the user confirms a separate Page. Do not invent another match score.
For every revision:
read_page({ page_id })gives the currentbase_version_idand metadata.- If
file_bundleis null, useexport_page({ page_id, export_type: "html" }). Read every returned file according to its encoding (utf8, base64, or reference). Verify reference bytes against the returned sha256; on mismatch re-export. Use the exported version_id as your base and preserve its manifest (entrypoint and routes) in both upload calls. Custom routes require upload mode; hand off the upload if your client cannot PUT files. - Edit the complete bundle and call
update_pagewithpage_id, requiredbase_version_id, one content mode, and a usefulupdate_reason.
Updates replace every file, never patch a subset. html also replaces the whole bundle with index.html. A concurrent change returns version_conflict: read/export again, reapply the intended edit, and retry with the fresh base. Do not retry old files under a new base without reconciling the intervening change.
Upload completion must retain the original title/create intent or page_id/update base and metadata. Never attach a new base to an old update upload session. no_change means the effective content and requested Page state already match; return the existing URL. A rename with identical files is still a real update.
Visibility and handoff
New Pages default to organization (workspace members); use public for external sharing or private for a draft. MCP agents cannot change an existing Page's visibility, including with OAuth. For revisions, omit visibility or repeat its current value; direct the human to Sharing to change it.
Return the Page URL and who can see it. If publishing returns warnings, resolve them before calling the Page finished.
Errors and pending work
Check isError and branch on the stable JSON error code. Follow recovery when present, or the existing next_action. Do not match message wording. Fix invalid fields; wait for retry_after_seconds for throttles. Reopen expired upload sessions. Shrink bundles that exceed returned limits. Do not blindly retry permanent failures.
For newly authored slides, call prepare_deck with the title, ordered { id, html } slides, optional shared CSS/assets, and optional canvas. It returns a normal inline bundle and does not publish, call a model, or prove readiness. Publish the returned bundle with presentation: { "intent": "deck" }; assemble larger decks locally and use signed uploads.
For an existing deck export, preserve its files and publish them directly with deck intent. Publication and presentation readiness are separate: only ready verifies controls for that exact version. Follow pending presentation_follow_up guidance with a compact version-bound read_page, and stop on a terminal status. Creation may set presentation policy; updates preserve policy, which a Page manager changes in Share settings.
Queued uploads or refreshes are pending, not completed. For live data load topic: "live-data-connections": configure a spec, keep its revision identity, and preview that revision only when ready. CSV is refreshed by human upload.
Comments and decks
Read a specific Page's queue with read_comments({ page_id, queued_only: true }). Read/export its latest bundle, revise it, then reply with add_comment to close the loop. Use read_page_analytics when readership evidence would help.
Only slide-based documents use <html data-sp-document-type="deck"> and stable data-sp-frame attributes on slide roots. Ordinary scrolling Pages do not use deck markers. When generating new markup, give major editable regions stable id and data-review-target-id values. Preserve exact user-supplied files when that was requested. Report publishing warnings and, for decks, the separate presentation status; a live URL proves publication, while ready proves presentation compatibility.