POST /v1/render and POST /v1/render/validate): billing, plan limits, rate limits, fonts, and rendering diagnostics all stay consistent with everything else you build on Blink PDF.
The MCP server is hosted by Blink PDF — there is nothing to install or run. Authenticate with an API key or OAuth, then point any MCP-capable client at the endpoint. See Connect a Client for the setup steps.
Endpoint and transport
The server speaks Streamable HTTP, so any client that supports remote HTTP MCP servers — Claude Code, Codex, and others — connects directly. stdio-only clients connect through a bridge such as
mcp-remote; see Connect a Client.
Auth and discovery
Remote connectors that speak OAuth use OAuth 2.1 authorization code + PKCE against Blink PDF’s authorization server. The MCP resource ishttps://mcp.blinkpdf.io/mcp; the authorization server is https://identity.blinkpdf.io with scopes pdf:render and optional offline_access (refresh tokens only when that scope is granted). After consent, the BFF issues a user-scoped Bearer access token; MCP verifies it and calls REST via internal delegation so the API key never leaves the platform.
IDE and CLI clients that do not support remote OAuth use the same bp_* API keys as the REST API, presented as Authorization: Bearer bp_* (preferred) or x-api-key.
Public, unauthenticated discovery documents (read-only):
There is no anonymous render path — every tool call requires a credential (OAuth Bearer or API key).
Tools
The server exposes six tools:
The render tools accept the same body fields; only
markdown is required. Blink PDF’s defaults already produce publication-grade output, so in most cases only markdown is needed.
The
render_pdf tool description is intentionally compact — it carries a single inline example and points to the reference resources for richer payloads, keeping the agent’s context small. The fields below document the full surface for reference.render_pdf
Renders Markdown and returns a signed download URL plus usage and diagnostics — never the raw PDF bytes (a rendered document can be megabytes and would flood the agent’s context). Every call pre-validates through POST /v1/render/validate before rendering; validation failures return structured issues and do not consume render quota.
string
required
The Markdown source to render. GitHub-flavored — supports tables, task lists, GFM alerts, fenced code, and images (
data: or http(s): URLs). Prefer https:// image URLs; large data: base64 often exceeds body limits.string
Document title for the PDF metadata. Must not be blank. Defaults to the first heading when omitted.
string
A curated design preset (default
report-clean). Call list_themes for the catalog. See Themes.object | string
Page layout and appearance:
size (named preset or [width, height] in points), orientation, margin, and optional full-sheet background. JSON object or JSON string.array | string
Presentation rules that
select Markdown nodes and set properties on them — surgical styling over standard Markdown nodes. See Styling Rules or blinkpdf://reference/styles. JSON array or JSON string.object | string
Font roles: assign
body/heading families, declare a Google Fonts pool, bind custom named roles, and tune per-family weights. See Fonts & Typography. JSON object or JSON string.object | string
Heading auto-numbering. Opt in with
enabled: true, then set depthRange, all/byDepth formats, and trailingSeparator. JSON object or JSON string.string
A Google Fonts URL whose first family becomes the body/heading typeface (CSS API, specimen, or share form). Up to 4 families per URL.
object | string
Running headers and footers (six-slot grid), optional
watermark, decorations, cover/closing overrides (omitFirstPage, firstPage, omitLastPage, lastPage), and pageOverrides. See Headers & Footers or blinkpdf://reference/furniture. JSON object or JSON string.object | string
PDF outline (bookmarks). Omit for the default depth range
[1, 6], pass depthRange to constrain depths, or set enabled: false to suppress. Do not pass depthRange together with enabled: false. JSON object or JSON string.boolean
default:"false"
When
true, each remote http(s):// image is fetched once and reused for up to 24 hours, so repeat renders of the same request stay byte-identical even if the origin changes. Scoped per credential. See Document Options.What render_pdf returns
Every successful call returns three things:
- A download URL of the form
GET /d/:token— a compact signed link the agent can hand straight to you. - The PDF byte size and the link’s expiry timestamp (24 hours out).
- A usage summary (render units this period, with the billing outcome) plus render status (
okordegraded), whether the PDF rendered as requested, and an actionable diagnostics list when the renderer raised warnings or errors (same semantics as the RESTX-Render-*response headers).
validate_render_pdf
Dry-run the same TypeBox schema and cross-field semantic checks as render_pdf, mapped to POST /v1/render/validate. No PDF is generated, no render quota is consumed, and no download link is returned. Use it when iterating on rules, typography, furniture, or other advanced options before calling render_pdf.
validate_render_pdf accepts the same parameters as render_pdf (see above).
What validate_render_pdf returns
- Valid body — confirmation that the request would render.
render_pdfruns this check automatically before every render. - Invalid body — structured validation feedback: allowed keys per path, did-you-mean hints, and relocation suggestions. Fix the reported paths and call again, or proceed to
render_pdfonce validation passes. - A
limitsblock so an agent can decide between inlining,upload_image, and an external URL:{ bodyBytes, bodyLimitBytes (Free 128 KiB / Pro 2 MiB / Business 5 MiB), withinLimit, perImageUploadBytes (5 MiB), maxAssetsPerRender (Free 32 / Pro 128 / Business 256) }. typographyNotesadvisories, which can includegoogle_font_axis_ignored(anopsz/wdth/custom Google Fonts axis was accepted but ignored) andgoogle_font_weight_snapped(an off-grid weight was snapped to a valid 100-step endpoint).staticWarnings, which can includefurniture_fragment_empty(asectionTitle/sectionIndexat a heading depth that doesn’t exist, or adocumentTitlewhen no title resolves).
blinkpdf://reference/path-index.
upload_image
Stages an image so it can be referenced from Markdown (or imageSequence) as a blink://asset/<sha256> handle, instead of inlining a large data: URL. The bytes are fetched at render time, so they do not count toward your input-size limit.
PUT, and no outbound network — the whole upload rides the tool call itself, so it works sandboxed or offline. The server hashes the bytes for you, so no client-side sha256 precompute is needed.
A small image goes in one call: pass its raw bytes as a base64 string with its mime.
Larger images are sent as ordered parts. A single tool call can only carry so much base64 before it hits the model’s per-message output limit, so split the image and send it part by part. Pass part (1-based) and totalParts (2–128); each non-final reply is status: "awaiting" and spells out the exact next call — the session token to echo, the next part index, and the max base64 length per part. The final part assembles and content-addresses the whole image, returning the same handle a single call would — so chunked and single-call uploads of the same image dedupe against each other. State is held server-side between parts, so nothing is lost if a part is retried.
string
required
The image’s raw bytes, base64-encoded. For a chunked upload this is one part’s slice.
string
required
One of
image/png, image/jpeg, image/gif, image/tiff, image/webp, image/avif, image/svg+xml.integer
Chunked upload only: the 1-based index of this part. Omit to send a small image in a single call.
integer
Required with
part: the total number of parts the image is split into (2–128). Send the same value on every part.string
Required from part 2 on: the continuation token returned by the previous call. Absent on part 1 (the server mints it).
blink://asset/<sha256> handle to reference as  or from imageSequence. Assets are content-addressed: identical bytes dedupe and return a dup flag instead of re-storing. The assembled image is capped at a flat 5 MiB on every tier — a single call is limited further by what the model can emit in one message, which is why anything larger is chunked (or referenced by an https:// URL). A per-credential in-process limit of 30 uploads/min and 4 concurrent applies — a chunked sequence counts once, not per part — and over-limit calls return a rate_limited tool error. Assets are scoped per credential, so a handle staged with one API key resolves in any render_pdf or POST /v1/render call made with the same key. To stage several images, call upload_image again for each one.
list_themes
Returns the theme catalog as { version, default, themes[] } — each theme’s slug, category, useWhen tagline, and isDefault flag. Mirrors GET /v1/themes. Read-only, unmetered.
list_fonts and describe_style_targets
list_fonts returns the hosted font catalog and Google Fonts limits for your key (mirrors GET /v1/fonts). describe_style_targets returns the machine-readable rules vocabulary — selectors and settable properties (mirrors GET /v1/style-targets). Both are read-only and unmetered.
Reference resources
Beyond the tools, the server publishes read-only MCP resources so the tool schemas stay small while agents can still discover advanced options:
Most clients expose these under a “Resources” panel; an agent can read them on its own when it needs fine-grained control.
Download links and retention
Because an agent can’t receive raw bytes, the MCP server stores each rendered PDF briefly so it can return a link. This is the one place Blink PDF holds output bytes, so it’s worth understanding precisely:- The render itself still runs through the zero-retention REST pipeline — your Markdown input is never persisted.
- The rendered PDF output is stored and served through a signed download link (
GET /d/:token). - Both the link and the stored object follow the flat 24-hour retention window applied to every output on every plan, then are purged automatically.
- After the link expires, the agent simply renders again to get a fresh one.
Retries are safe. If a render succeeds but the download link can’t be saved, the tool reports a distinct “rendered but not stored — safe to retry” error, and the retry is not billed again (the server sends an idempotency key the REST API dedupes on).
MCP vs. the REST API
Both reach the same renderer. Choose based on how you’re building:Connect a Client
Wire up Claude Code, Codex, or any MCP client in three steps.
AI & LLM Workflows
Pipe OpenAI and Claude output straight into Blink PDF over REST.