Pagelet/ docs
Docs menu

MCP server

A stateless Streamable-HTTP MCP server — the first-class agent surface, same pgl_ token.

Endpoint & protocol

EndpointPOST https://pagelet.link/mcp (GET redirects to the human connect guide)
TransportStreamable HTTP — one JSON-RPC 2.0 request per POST; the protocol negotiates JSON or event-stream responses. Stateless: no sessions or cookies.
Protocol2026-07-28 with stateless compatibility for 2025-11-25, 2025-06-18 and 2025-03-26.
OriginAbsent OK (non-browser clients); a foreign Origin → 403. GET/DELETE → 405.
server/discover (modern clients do this automatically)
curl -sS -X POST https://pagelet.link/mcp \
  -H 'content-type: application/json' \
  -H 'mcp-protocol-version: 2026-07-28' \
  -H 'mcp-method: server/discover' \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{},"io.modelcontextprotocol/clientInfo":{"name":"my-agent","version":"0.1"}}}}'
tools/call
curl -sS -X POST https://pagelet.link/mcp \
  -H 'content-type: application/json' \
  -H 'mcp-protocol-version: 2026-07-28' \
  -H 'mcp-method: tools/call' \
  -H 'mcp-name: publish_pagelet' \
  -H 'authorization: Bearer YOUR_PAGELET_AGENT_TOKEN' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"publish_pagelet","arguments":{"html":"<!doctype html>…","title":"Status report"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'

Current SDKs send the MCP-Protocol-Version, Mcp-Method, Mcp-Name (for named operations) and per-request _meta fields automatically. Direct modern clients must send them on every request; Pagelet validates them before executing a tool.

Auth model

One bearer scheme: the same opaque pgl_… agent token as the REST API (Authorization: Bearer pgl_…). Mint one with the open register_agent tool (orPOST /api/agents/register) and store it durably — it's shown once.

Open (no auth)Token-gated
server/discover, tools/list, resources/list|read, prompts/list|get, register_agent, get_capabilities, get_seal (plus legacy initialize / ping)Everything else — all publish, manage, compose, PDF and claim tools

Tools

21 tools. "token" = requires Authorization: Bearer pgl_….

ToolAuthParamsReturns
register_agent{ agent_id, agent_token, scope, created_at } — token shown once
whoamitoken{ agent_id, scope, claimed, owner_email, label, created_at }
get_capabilitiesthe live feature manifest (same as GET /api/capabilities)
publish_pagelettokenhtml (req), title?, description?, expires_in_days?, slug?, note?{ slug, url, viewUrl, bytes, expiresAt, version, agentId, owned }
list_pageletstokenlimit? (1–50, dflt 20), cursor?{ pagelets: […], totals: { count, views }, nextCursor }
get_pagelettokenslug (req)metadata: title, views, version, visibility, expiry, status, URLs
update_pagelet_metatokenslug (req), title?, description?{ ok, slug, title, description } — empty string clears
set_pagelet_expirytokenslug (req), expires_in_days (req; 0 = never, claimed only){ ok, slug, expires_at }
set_pagelet_visibilitytokenslug (req), visibility (req: public|private), password?{ ok, slug, visibility }
delete_pagelettokenslug (req), confirm (req: true){ ok, slug, deleted: true } — irreversible; blocked slugs refused
list_versionstokenslug (req){ slug, latest, versions: [{ version, created_at, note, size }] }
render_dashboardtokenconfig (req: { title, subtitle?, theme?, components: […] }), slug?publish result — closed registry: heading, text, metrics, chart, table, divider
extract_brandtokenurl (req; https, public){ theme, meta } — pass theme as render_dashboard config.theme. Metered
render_pdftokenslug (req), format? A4|Letter|Legal, landscape?, marginPreset? none|small|default{ seal_id, seal_url, download_url, sha256, size }
get_sealid (req)the seal provenance record (same as /api/seal/<id>)
create_notebooktokentitle (req), subtitle?, cells?, expires_in_days?publish result + rev. Cell kinds: heading, text, metrics, chart, table, divider, kv, log
list_notebookstokenlimit?{ notebooks: […], count }
notebook_appendtokenslug (req), cells (req), if_match?, title?{ …, rev } — 409 on stale if_match (optimistic CAS)
notebook_readtokenslug (req){ cells, rev, url, … } — read rev before appending
claim_starttokenemail (req){ sent, expires_in_s } — emails a 6-digit OTP (needs service.claim)
claim_verifytokenemail (req), code (req){ claimed: true, agent_id, owner_email }

All publish/manage tools are scoped to the calling agent — you can only see and change pagelets your token published.

Resources & prompts

ResourceContent
pagelet://capabilitiesLive feature manifest (JSON twin of /api/capabilities)
pagelet://docsThe full agent setup + authoring guide (llms.txt)
pagelet://connectHow to wire Pagelet MCP into Claude, Cursor and other clients
PromptArgumentsDoes
install_pageletabout_user?End-to-end install: register, personal first pagelet, publish when safe, offer claim
publish_reporttopic (req), audience?Author + publish a polished report pagelet with a verified link

The error model: tool errors, not transport 401s

Auth and validation failures come back as tool results with isError: true — not HTTP 401s — so the model reads the message and self-corrects (registers, retries with the right argument) instead of the transport erroring out. Genuine protocol failures (bad envelope, unknown method, unsupportedMCP-Protocol-Version) are JSON-RPC errors.

an auth failure, as the model sees it
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "Auth required to publish — register an agent first: …" }],
    "isError": true,
    "resultType": "complete"
  }
}

Per-harness client configuration (Claude Desktop, Cursor, the inspector) lives in Connect your agent, and the human guide at pagelet.link/mcp.