Skip to main content
Glama

lulu-print-mcp

An MCP server for the Lulu Print API. It lets Claude and other AI assistants price, validate, order and track print-on-demand books.

  • Covers the whole API. There is one tool for each of the 22 operations in Lulu's published OpenAPI spec, and a test fails if any operation is missing.

  • Built exactly to the spec. Every input rule and every request is checked against Lulu's own spec in the test suite. The few places where the spec contradicts itself are written up in docs/spec-notes.md.

  • Safe by default. It uses Lulu's sandbox unless you choose production, so you can't place a real order by accident.

  • Ready for Lulu's new product codes. It accepts the dotted pod_package_id format, and the old 27-character format until Lulu retires it on 1 February 2027.

Install

You need Node.js 22 or newer and Lulu API keys. Get your keys from the sandbox developer portal (free test orders) or the production portal (real orders). The two environments use different keys.

Claude Desktop

Add this to claude_desktop_config.json (in Claude Desktop, go to Settings → Developer → Edit Config), then restart Claude Desktop:

{
  "mcpServers": {
    "lulu-print": {
      "command": "npx",
      "args": ["-y", "lulu-print-mcp"],
      "env": {
        "LULU_CLIENT_KEY": "your-client-key",
        "LULU_CLIENT_SECRET": "your-client-secret",
        "LULU_ENVIRONMENT": "sandbox"
      }
    }
  }
}

Claude Code

claude mcp add lulu-print -e LULU_CLIENT_KEY=your-client-key -e LULU_CLIENT_SECRET=your-client-secret -e LULU_ENVIRONMENT=sandbox -- npx -y lulu-print-mcp

Other MCP clients

Run npx -y lulu-print-mcp as a stdio server with the environment variables below.

Related MCP server: Printful MCP Server

Configuration

Variable

Required

Default

Meaning

LULU_CLIENT_KEY

yes

Client key from Lulu's developer portal

LULU_CLIENT_SECRET

yes

Client secret from Lulu's developer portal

LULU_ENVIRONMENT

no

sandbox

sandbox or production

LULU_TIMEOUT_MS

no

30000

Timeout for each request to Lulu, in milliseconds

Production places real orders. In production, create_print_job and reprint_print_job create orders that stay unpaid until you pay for them in Lulu's portal, or that are charged automatically if a card is on file. The server tells the assistant to confirm with you before ordering. Use production_delay to leave time to cancel.

Tools

Tool

Lulu API

What it does

calculate_print_job_cost

POST /print-job-cost-calculations/

Price one or more books, including shipping and tax, without placing an order.

list_print_jobs

GET /print-jobs/

List Print-Jobs (orders), newest first by default, with optional filters and paging.

create_print_job

POST /print-jobs/

Place an order to print and ship books from interior and cover PDF URLs.

reprint_print_job

POST /print-jobs/

Place a new order for books Lulu already has, using each line item's printable_id from an earlier Print-Job, so files don't need to be sent again.

get_print_job_statistics

GET /print-jobs/statistics/

Count Print-Jobs in each status, optionally filtered by date, status or id.

get_print_job

GET /print-jobs/{id}/

Get one Print-Job with its line items, status, costs, shipping address and tracking.

get_print_job_costs

GET /print-jobs/{id}/costs/

Get the cost breakdown of an existing Print-Job: line items, shipping, fees, tax, totals.

get_print_job_status

GET /print-jobs/{id}/status/

Get only the current status of a Print-Job, with any status messages.

cancel_print_job

PUT /print-jobs/{id}/status/

Cancel a Print-Job.

get_shipping_options

POST /shipping-options/

List the shipping levels available for some books to a destination, with price and delivery estimates.

create_webhook

POST /webhooks/

Subscribe a URL to Lulu events.

list_webhooks

GET /webhooks/

List all webhook subscriptions on this Lulu account.

get_webhook

GET /webhooks/{id}/

Get one webhook subscription.

update_webhook

PATCH /webhooks/{id}/

Change a webhook's URL or topics, or switch it on or off.

delete_webhook

DELETE /webhooks/{id}/

Delete a webhook subscription.

test_webhook

POST /webhooks/{id}/test-submission/{topic}/

Ask Lulu to send a sample event of the given topic to a webhook's URL.

list_webhook_submissions

GET /webhook-submissions/

List past webhook deliveries and whether each one succeeded, for troubleshooting.

validate_interior_file

POST /validate-interior/

Start checking an interior PDF.

get_interior_validation

GET /validate-interior/{id}/

Get the result of an interior file validation started with validate_interior_file.

calculate_cover_dimensions

POST /cover-dimensions/

Get the exact cover size (including spine and bleed) needed for a product and page count.

validate_cover_file

POST /validate-cover/

Start checking a cover PDF against a product and page count.

get_cover_validation

GET /validate-cover/{id}/

Get the result of a cover file validation started with validate_cover_file.

A typical order goes like this:

  1. calculate_cover_dimensions to get the cover size for the book.

  2. validate_interior_file and validate_cover_file to check the PDFs.

  3. get_shipping_options to see delivery choices.

  4. calculate_print_job_cost to get the price.

  5. create_print_job to place the order.

  6. get_print_job_status to track it.

Tools that only read data are marked read-only, and cancel_print_job and delete_webhook are marked destructive, so MCP clients can ask before running them.

Use it as a library

import { createLuluServer, LuluClient, loadConfig } from "lulu-print-mcp";

const client = new LuluClient(loadConfig());
const jobs = await client.request({ method: "GET", path: "/print-jobs/", query: { page_size: 10 } });

How it's kept exact

  • spec/openapi_public.yml is a byte-for-byte copy of Lulu's published spec.

  • The rule tests read every required field, length limit, range, enum, type and format from the spec, and check that each tool accepts and rejects exactly the same values. If Lulu changes a rule, the failing test names the field.

  • The contract tests check that:

    • every operation in the spec has exactly one tool;

    • every request each tool sends passes validation against the spec;

    • each tool can send every writable field in the spec;

    • no tool sends a field the spec doesn't document.

  • Live tests run every tool against Lulu's sandbox.

  • A weekly GitHub Action compares our copy with Lulu's live spec and opens an issue if Lulu changes it.

Development

npm install
npm run check

npm run check runs type checking, lint, the tests with coverage, and the build.

To run the live sandbox tests:

LULU_SANDBOX_CLIENT_KEY=... LULU_SANDBOX_CLIENT_SECRET=... npm run test:sandbox

To see whether Lulu has changed its spec:

npm run spec:check

See CONTRIBUTING.md for more.

License

MIT. This project is not affiliated with or endorsed by Lulu Press, Inc.

Available Tools

22 tools
calculate_cover_dimensionsCalculate cover dimensionsA
Read-onlyIdempotent

Get the exact cover size (including spine and bleed) needed for a product and page count.

Inputs: pod_package_id (required), interior_page_count (required), unit.

calculate_print_job_costCalculate print job costA
Read-onlyIdempotent

Price one or more books, including shipping and tax, without placing an order. Returns per-line-item costs, shipping cost, fees and totals.

Inputs: line_items (required), shipping_option (required), shipping_address (required).

cancel_print_jobCancel print jobA
DestructiveIdempotent

Cancel a Print-Job. Only possible before it goes to production (statuses CREATED, UNPAID or PRODUCTION_DELAYED). This cannot be undone.

Inputs: id (required).

create_print_jobCreate print job (place an order)A

Place an order to print and ship books from interior and cover PDF URLs. In production this is a real order: it stays UNPAID until paid in Lulu's developer portal, or is charged automatically if a card is on file. Check the price with calculate_print_job_cost and the files with validate_interior_file / validate_cover_file first. Set production_delay to leave time to cancel.

Inputs: line_items (required), contact_email (required), shipping_level (required), shipping_address (required), +2 more.

create_webhookCreate webhookA

Subscribe a URL to Lulu events. Lulu then POSTs to the URL whenever a subscribed event happens, e.g. PRINT_JOB_STATUS_CHANGED when an order changes status.

Inputs: url (required), topics (required).

delete_webhookDelete webhookB
DestructiveIdempotent

Delete a webhook subscription. This cannot be undone.

Inputs: id (required).

get_cover_validationGet cover validationA
Read-only

Get the result of a cover file validation started with validate_cover_file.

Inputs: id (required).

get_interior_validationGet interior validationB
Read-only

Get the result of an interior file validation started with validate_interior_file.

Inputs: id (required).

get_print_jobGet print jobA
Read-only

Get one Print-Job with its line items, status, costs, shipping address and tracking.

Inputs: id (required).

get_print_job_costsGet print job costsA
Read-only

Get the cost breakdown of an existing Print-Job: line items, shipping, fees, tax, totals. Lulu has no costs until it has processed the job's files, and answers 'No costs are available' before then.

Inputs: id (required).

get_print_job_statisticsCount print jobs by statusA
Read-only

Count Print-Jobs in each status, optionally filtered by date, status or id.

Inputs: id, page, status, ordering, +5 more.

get_print_job_statusGet print job statusA
Read-only

Get only the current status of a Print-Job, with any status messages.

Inputs: id (required).

get_shipping_optionsGet shipping optionsA
Read-onlyIdempotent

List the shipping levels available for some books to a destination, with price and delivery estimates. Only the country is required; a fuller address gives more accurate results.

Inputs: line_items (required), shipping_address (required), currency.

get_webhookGet webhookC
Read-only

Get one webhook subscription.

Inputs: id (required).

list_print_jobsList print jobsB
Read-only

List Print-Jobs (orders), newest first by default, with optional filters and paging.

Inputs: id, page, search, status, +8 more.

list_webhooksList webhooksA
Read-only

List all webhook subscriptions on this Lulu account.

Inputs: no named parameters.

list_webhook_submissionsList webhook deliveriesA
Read-only

List past webhook deliveries and whether each one succeeded, for troubleshooting.

Inputs: page, page_size, is_success, webhook_id, +3 more.

reprint_print_jobReprint (re-order) booksA

Place a new order for books Lulu already has, using each line item's printable_id from an earlier Print-Job, so files don't need to be sent again. Same payment rules as create_print_job.

Inputs: line_items (required), contact_email (required), shipping_level (required), shipping_address (required), +2 more.

test_webhookSend test webhookA

Ask Lulu to send a sample event of the given topic to a webhook's URL. The webhook must be active.

Inputs: id (required), topic (required).

update_webhookUpdate webhookB
Idempotent

Change a webhook's URL or topics, or switch it on or off.

Inputs: id (required), url, topics, is_active.

validate_cover_fileValidate cover fileA

Start checking a cover PDF against a product and page count. Poll get_cover_validation with the returned id until the status is NORMALIZED or ERROR.

Inputs: source_url (required), pod_package_id (required), interior_page_count (required).

validate_interior_fileValidate interior fileA

Start checking an interior PDF. Returns a validation record; poll get_interior_validation with its id until the status is VALIDATED, NORMALIZED or ERROR. With pod_package_id, Lulu also checks the file fits that product.

Inputs: source_url (required), pod_package_id.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 22 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, and the print-job lifecycle is well separated by action. There is some overlap between get_print_job and its narrower variants get_print_job_status and get_print_job_costs, as well as between calculate_print_job_cost and get_print_job_costs, but descriptions clarify the intended use.

    Naming Consistency5/5

    All tool names follow a consistent snake_case verb_noun pattern, such as get_print_job, create_print_job, validate_interior_file, and list_webhooks. There are no mixed conventions or vague standalone verbs.

    Tool Count4/5

    The 22 tools are reasonable for a multi-area API covering print jobs, file validation, pricing/shipping, and webhooks. The count is slightly heavy but each tool maps to a recognizable operation rather than being redundant.

    Completeness4/5

    The surface covers the core print-job lifecycle well: validation, cost calculation, creation, reprint, listing, status, costs, statistics, cancellation, and shipping options. Webhooks also have full CRUD plus testing and delivery history, though product/package discovery before using pod_package_id appears to be a minor gap.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      Provides integration with Lulu Print API for print-on-demand services through Claude Desktop and other MCP clients, enabling users to create and manage print jobs, validate files, calculate costs, and handle shipping for books and printed materials.
      2
      29 npm
      3
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables AI assistants to browse the Printful catalog, retrieve variants and shipping rates, estimate costs, upload print files, generate mockups, and manage sync products through the official Printful REST API. Orders are always saved as drafts and only submitted for fulfillment or payment after an explicit confirmation step.
      16
      20 npm
      MIT