Airpdf docs

Airpdf MCP — Tool reference

All 8 tools the Airpdf MCP server exposes. Every tool is dispatched via the standard MCP tools/call JSON-RPC envelope:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": { "name": "<tool>", "arguments": { … } }
}

Endpoint: POST https://airpdf.app/mcp with Authorization: Bearer <mcp_live_…>.

Errors always come back in agent-friendly form:

{ "ok": false, "errors": [ { "path": "/some/field", "code": "…", "message": "…", "suggestion": "…" } ] }

Conventions

  • All tools are per-workspace. The bearer token's McpConnection row carries the tenant_code, and every Ash query runs in that tenant's schema. Cross-tenant access is impossible.
  • state on a template is one of :draft | :active | :archived. list_templates returns :draft + :active only.
  • Mustache placeholders in template bodies always use {{path.to.value}}. Values are HTML-escaped server-side.

Authoring flow

author_guide        # read the prompt + constraints once
   ↓
create_template     # save as DRAFT
   ↓
preview_render      # iterate until the output looks right
   ↓
validate_data       # schema-check sample data quickly
   ↓
update_template     # patch the draft as needed
   ↓
publish_template    # promote DRAFT → LIVE + snapshot version

Tools

list_templates

List templates visible to this MCP connection (draft + active; archived excluded).

Arg Type Required Notes
(none)

Returns: array of {slug, name, engine, state, inserted_at, updated_at}.


get_template

Fetch one template by slug.

Arg Type Required Notes
slug string yes from list_templates

Returns: the template record with both live and draft snapshot fields (html_template, schema, variables_schema, default_sample_data, draft_* counterparts, timestamps).


create_template

Save a new template as a draft. Never writes to live.

Arg Type Required Notes
name string yes display name
draft_engine "html" | "react_pdf" yes which renderer
draft_html_template string when engine = "html" HTML body
draft_schema object when engine = "react_pdf" JSON tree
draft_variables_schema object recommended JSON Schema for data
default_sample_data object recommended seed for preview_render

Returns: {slug, draft_updated_at}.


update_template

Patch a draft. Live snapshot remains untouched.

Arg Type Required Notes
slug string yes which template
draft_html_template string no
draft_schema object no
draft_variables_schema object no
default_sample_data object no

Returns: {slug, draft_updated_at}.


publish_template

Promote the draft to live state and snapshot a TemplateVersion. Call only when the user explicitly asks to publish.

Arg Type Required
slug string yes

Returns: {slug, live_updated_at, version_number}.

Failure modes:

  • no_draft — template has no draft to promote.
  • forbidden — connection scope doesn't allow publish.

preview_render

Render a watermarked PDF preview. Does NOT consume quota.

Arg Type Required Notes
slug string yes which template
version "draft" | "live" no default "draft"
data object no falls back to default_sample_data

Returns:

{
  "pdf_base64": "JVBERi0…",
  "engine": "html",
  "render_ms": 412,
  "byte_size": 18742,
  "watermarked": true
}

pdf_base64 is a standard base64 string (decoder hint: Base.decode64! in Elixir / atob in JS). The watermark cannot be disabled.


validate_data

Quick JSON-Schema check of sample data against the template's variables_schema. No render.

Arg Type Required
slug string yes
data object yes
version "draft" | "live" no

Returns: {ok: true} or {ok: false, errors: [{path, code, message}]}.


author_guide

Static prompt + engine constraints. Call this BEFORE drafting a new template — it tells the LLM which tags, props, and node types are allowed, plus best-practice tips.

Arg Type Required Notes
engine "html" | "react_pdf" no default "html"

Returns:

{
  "version": "2026-05-19-v1",
  "guide": "You are authoring an Airpdf …",
  "engine_constraints": { … },
  "best_practices": [ "…", "…" ]
}

Rate limits

Limit Default
Tool calls per minute, per McpConnection 120
preview_render calls counted toward daily_usage.previews_count (no billing) unbounded
publish_template audited via tenant_audit_log every call
Access token TTL 1 hour
Refresh token TTL 30 days (single-use, rotated on every refresh)

Versioning

The MCP protocol version is currently 2025-03-26, which adds the OAuth Authorization spec (PKCE, Authorization Server Metadata, Dynamic Client Registration, refresh-token rotation — all of which Airpdf implements) and Streamable HTTP transport. Older clients that request 2024-11-05 still work because protocol negotiation happens in the JSON-RPC initialize exchange. We'll bump to 2025-06-18 once ash_ai ships support for it. Tool schemas follow semver — additive changes are minor, breaking changes get a major bump and a 30-day deprecation notice.

Spotted a typo or stale claim? Open an issue or ping us in the workspace — docs are versioned with the product.