Skip to content

NextPDF Connect quickstart

This page runs the smallest useful exchange against both transports: Model Context Protocol (MCP) and Representational State Transfer (REST). Each request uses the exact wire format the server implements. You do not need a software development kit (SDK).

Terminal window
composer require nextpdf/server

The MCP transport uses JSON-RPC 2.0 over standard input and output. You must send the sequence in order. First send initialize. Then send the notifications/initialized acknowledgement. Then send tools/list and tools/call. The server reads one JSON message per line. Each line must end with a newline. The server writes one response per line.

The REST transport exposes the same engine capabilities as Hypertext Transfer Protocol (HTTP) operations. A single stateless render is one POST /api/v1/render with an ordered operations array. The response body is the Portable Document Format (PDF) file.

Code sample — Quick start (MCP over stdio)

Section titled “Code sample — Quick start (MCP over stdio)”

Start the server, and pipe the handshake into it. These three requests use the verified method names that the protocol handler routes:

Terminal window
./vendor/bin/nextpdf-mcp <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"quickstart","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
EOF

The initialize response reports the protocol version 2025-06-18, the server name NextPDF Connect, and a capabilities.nextpdf block. That block includes the live tier counts, the runtime tool_count, the risk model version, and hitl_enabled: true. The tools/list response lists the exact tools registered for this installation. The notification line intentionally produces no response.

Now call a safe tool. The diagnostic.doctor tool runs a read-only environment check. It does not need a document or confirmation:

Terminal window
./vendor/bin/nextpdf-mcp <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"quickstart","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"diagnostic.doctor","arguments":{}}}
EOF

Start the REST server, then render a one-line PDF. The server requires an application programming interface (API) key on every non-health endpoint, so define one first:

Terminal window
export NEXTPDF_API_KEYS='npk_live_k8a3b2c1_0123456789abcdef0123456789abcdef:demo:core:default'
./vendor/bin/rr serve -c .rr.yaml

In a second shell, post a render request. The body is a RenderRequest. That request contains an ordered operations array of typed operations.

Terminal window
curl -sS -X POST http://localhost:8080/api/v1/render \
-H 'Authorization: Bearer npk_live_k8a3b2c1_0123456789abcdef0123456789abcdef' \
-H 'Content-Type: application/json' \
-d '{
"page_size": "A4",
"orientation": "portrait",
"operations": [
{ "type": "add_text", "text": "Hello from NextPDF Connect" }
]
}' \
--output hello.pdf

A 200 response body is the PDF (Content-Type: application/pdf) written to hello.pdf. Health probes do not need a key:

Terminal window
curl -sS http://localhost:8080/healthz
  • The handshake order matters. The protocol handler treats a message with no id as a notification and returns nothing. Send initialize with an id, then the initialized notification, then your requests that include an id.

  • A repeated request id is de-duplicated. The handler caches recent responses in a 64-entry circular buffer. For a duplicate id, it returns the cached response without running the tool again. Use fresh ids.

  • A high-risk tool answers with a challenge, not a result. Calling output_pdf with a file_path returns a confirmation challenge instead of running. Re-invoke the tool with the issued _confirmation_token. The base64 output mode, without file_path, does not require confirmation. See /connect/hitl-risk-tiers/.

  • An unauthorized REST request gets 401. A missing or malformed Authorization: Bearer header returns a problem-details body with a WWW-Authenticate: Bearer header. The /healthz and /readyz probes are the only anonymous endpoints.

Both quickstart paths use a single request. The REST path also pays the RoadRunner worker pool’s cold-start cost on the first request after rr serve. Later requests reuse warm workers.

The npk_live_ key above is a throwaway demo value. Generate real keys with sufficient entropy, store them outside source control, and prefer the file-based key store for rotation. The MCP stdio transport has no API key because it is a local subprocess trusted by its launching client under the MCP transport model. See /connect/security-and-operations/.

The wire formats shown match the implemented MCP revision 2025-06-18 and the OpenAPI 3.1 REST contract. Normative protocol and authentication citations are pinned on /transports/mcp/, /transports/rest/, and /connect/security-and-operations/.

  • /transports/mcp/ — the full MCP transport reference
  • /transports/rest/ — the full REST transport reference and OpenAPI rendering
  • /connect/tool-catalog/ — which tools tools/list returns and why
  • /connect/hitl-risk-tiers/ — what a confirmation challenge looks like
  • /connect/configuration/ — restricting the catalog and tuning the server