Sign inSign up

carbone/carbone-mcp

By carbone

•Updated about 5 hours ago

Official MCP for Carbone — Document Generation, Document Conversion, and Universal Templating.

Image
Machine learning & AI
0

10K+

carbone/carbone-mcp repository overview

⁠Carbone MCP Server

Run the official Carbone MCP server yourself: a Streamable HTTP endpoint that lets AI assistants automate production-ready PDF, Word, Excel and PowerPoint documents from templates and JSON, and convert files with 100+ conversions, through the Carbone API.

Upgrading from 1.x? Every 1.x HTTP deployment should upgrade now (security fixes): read the upgrade notes⁠.

⁠Quick start

docker run -d --name carbone-mcp -p 127.0.0.1:3000:3000 carbone/carbone-mcp
curl http://localhost:3000/health
{
  "mcp": { "version": "2.3.0" },
  "carbone": { "version": "5.x.x" }
}

This quick start sets no server key: each MCP client sends its own Carbone key in Authorization: Bearer <key>, and only your machine can reach the port. Get a key at account.carbone.io⁠. The test key generates unlimited watermarked PDFs for free; the production key produces every format without a watermark (details⁠).

Serving other machines: publish the port behind a TLS reverse proxy, keep the server without CARBONE_API_KEY (or set CARBONE_REQUIRE_CLIENT_AUTH_HEADER=true), and list the hostnames of browser-based clients in MCP_ALLOWED_ORIGINS.

⁠Shared-key variant, for one user on one machine
docker run -d --name carbone-mcp -p 127.0.0.1:3000:3000 -e CARBONE_API_KEY=your_api_key_here carbone/carbone-mcp

Warning: every request without a Bearer key then spends your key: anyone who can reach the port uses your Carbone account. The server prints a warning at startup. Never publish this port on a network you don't fully trust, or set CARBONE_REQUIRE_CLIENT_AUTH_HEADER=true to refuse requests that bring no key of their own.

⁠What it does

  • Converts DOCX, XLSX, PPTX, HTML, Markdown and PDF files to PDF, images, CSV and other formats (100+ conversions)
  • Fills Word, Excel, PowerPoint, LibreOffice, HTML and Markdown templates with JSON data, and tells you which data a template expects
  • Adds passwords, watermarks and PDF/A to PDFs, with a choice of converter: LibreOffice, OnlyOffice, Chromium or Carbone ICE
  • Generates up to 100 documents per request, collected by the assistant (async renders) or delivered to your webhook, with translations, time zones and currency conversion
  • Manages a template library: upload, version, categorize, deploy and download templates

⁠Docker Compose

services:
  carbone-mcp:
    image: carbone/carbone-mcp
    ports:
      - 127.0.0.1:3000:3000   # local only; serve other machines through a TLS reverse proxy
    restart: unless-stopped
docker compose up -d

Add any variable below under environment:. Leave CARBONE_API_KEY out so that clients send their own key: setting it gives you the shared-key variant above.

⁠Environment variables

VariableDefaultDescription
CARBONE_API_KEYnoneYour Carbone API key (get one⁠). Optional in HTTP mode: leave it unset so each client sends its own Authorization: Bearer <key>. When set, requests without a Bearer key spend it (see CARBONE_REQUIRE_CLIENT_AUTH_HEADER). Required in stdio mode for the cloud API. Not required for on-premise deployments.
CARBONE_BASE_URLhttps://api.carbone.ioCarbone API URL. Set it to your on-premise instance (no key needed).
CARBONE_TIMEOUT60000Carbone API request timeout in milliseconds. Carbone Cloud's synchronous API has its own 60-second limit.
CARBONE_MAX_FILE_BYTES104857600Maximum size (bytes) of one input file, given as a URL or base64 (100 MB).
MCP_TRANSPORThttpTransport mode: http (image default) or stdio.
MCP_PORT3000HTTP server port.
MCP_PATH/HTTP endpoint path. Cannot be /health.
MCP_MAX_BODY_BYTES62914560Maximum size of one incoming MCP message (60 MB): an HTTP request body (HTTP 413 when exceeded) or one stdio message.
MCP_ALLOWED_ORIGINSnoneBrowser Origin hostnames allowed in addition to localhost, 127.0.0.1 and [::1]: comma-separated, without scheme or port (e.g. app.example.com); <scheme>://* allows a browser-extension scheme. A request with any other Origin gets HTTP 403; requests without one are unaffected. Invalid entries stop the container at startup.
CARBONE_REQUIRE_CLIENT_AUTH_HEADERfalseRequire Authorization: Bearer <key> on every request. Left false, a request with no Bearer key falls back to the server-level CARBONE_API_KEY (a shared-key server: anyone reaching the port can spend it). Set true to require per-client keys. No effect when no server key is set.
CARBONE_ALLOW_PRIVATE_NETWORKfalseAllow user-supplied URLs to resolve to private and internal addresses. Off by default to block SSRF.
MCP_TICKET_SECRETnoneTurns on upload URLs for large templates, and async renders with a job store (below): at least 32 random bytes, base64 (openssl rand -base64 32), the same on every instance.
MCP_PUBLIC_URLnoneWith MCP_TICKET_SECRET: the public https origin of this server (e.g. https://mcp.example.com), where upload URLs and Carbone's webhook point.
MCP_S3_ENDPOINT, MCP_S3_REGION, MCP_S3_BUCKET, MCP_S3_ACCESS_KEY_ID, MCP_S3_SECRET_ACCESS_KEYnoneAsync renders: an S3-compatible bucket shared by every instance. Set all five, or none. The key needs to read, write and list the bucket.
MCP_JOBS_DIRnoneAsync renders, instead of MCP_S3_*: an existing, writable directory every instance shares (one container, or a volume they all mount).

⁠Connect your MCP client (HTTP)

Point the client at http://localhost:3000 (Streamable HTTP) with the header Authorization: Bearer <your Carbone API key>.

Claude Code:

claude mcp add --transport http carbone http://localhost:3000 --header "Authorization: Bearer your_api_key_here"

VS Code (.vscode/mcp.json; VS Code asks for the key once and stores it):

{
  "inputs": [
    { "type": "promptString", "id": "carbone-api-key", "description": "Carbone API key", "password": true }
  ],
  "servers": {
    "carbone": {
      "type": "http",
      "url": "http://localhost:3000",
      "headers": { "Authorization": "Bearer ${input:carbone-api-key}" }
    }
  }
}

Cursor (~/.cursor/mcp.json or .cursor/mcp.json):

{
  "mcpServers": {
    "carbone": {
      "url": "http://localhost:3000",
      "headers": { "Authorization": "Bearer your_api_key_here" }
    }
  }
}

Over HTTP, file inputs must be URLs or base64: the server cannot read the client's local files. A generated PDF or Office file comes back as a one-time download link (valid 1 hour); ask for asAttachment to get the file itself (output and file delivery⁠).

⁠Upload URLs and async renders

Both are off by default. With MCP_TICKET_SECRET and MCP_PUBLIC_URL, upload_template can return an upload URL, so an assistant that runs commands sends a large template with curl instead of base64. Add a job store and render_document accepts async: true for batches and renders over a minute: this server becomes Carbone's webhook, and get_render_result returns the download link.

Both hand out URLs on MCP_PUBLIC_URL, and Carbone calls the webhook there from the internet: run the server behind a TLS reverse proxy that serves that address and forwards to port 3000. Without it, upload URLs fail and async renders stay "still rendering".

# Once: keep this value, every restart and every instance needs the same one.
export MCP_TICKET_SECRET="$(openssl rand -base64 32)"

docker run -d --name carbone-mcp -p 127.0.0.1:3000:3000 \
  -e MCP_TICKET_SECRET \
  -e MCP_PUBLIC_URL=https://mcp.example.com \
  -e MCP_JOBS_DIR=/data/jobs -v carbone-jobs:/data/jobs \
  carbone/carbone-mcp

Here the reverse proxy on the same machine forwards https://mcp.example.com to 127.0.0.1:3000. With several instances, give them the same secret, and an S3-compatible bucket (MCP_S3_*) or a volume they all mount. Details: upload URLs⁠ and async renders⁠.

⁠Claude Desktop (stdio)

Claude Desktop starts local (stdio) servers from its config file (Settings → Developer → Edit Config):

{
  "mcpServers": {
    "carbone": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
               "-e", "CARBONE_API_KEY=your_api_key_here",
               "-e", "MCP_TRANSPORT=stdio",
               "carbone/carbone-mcp"]
    }
  }
}

In this mode, local paths and saved documents refer to the container's filesystem, which --rm deletes: pass URLs or base64 and ask for returnLink, or mount a folder with -v and use paths inside it. The npm package (npx -y carbone-mcp, Node.js 20.3+) reads and writes your own files directly.

From Claude Desktop, the stdio mode above works on every plan. A claude.ai or Claude Desktop custom connector connects from Anthropic's cloud: it can also reach this server once it is published at a public HTTPS URL (not 127.0.0.1), where your organization has Anthropic's Request headers beta, which sends the Bearer key (Anthropic docs⁠). To connect without a key, use Carbone's hosted server https://mcp.carbone.io, which signs you in with your Carbone account.

⁠On-premise Carbone

Point the server at your own Carbone instance; no API key is needed:

docker run -d -p 127.0.0.1:3000:3000 -e CARBONE_BASE_URL=https://your-carbone-server.com carbone/carbone-mcp

⁠Tools

The server exposes 12 tools (13 with async renders) to convert and render documents, inspect templates and manage a template library: see the API reference⁠.

⁠Security and troubleshooting

  • URL inputs: URLs that resolve to a private or internal address (localhost, RFC 1918, cloud metadata) are refused by default. Set CARBONE_ALLOW_PRIVATE_NETWORK=true only on a trusted deployment with internal template hosts. Local paths are always refused over HTTP.
  • Shared key: a server-level CARBONE_API_KEY is spent by every request that brings no key of its own, unless CARBONE_REQUIRE_CLIENT_AUTH_HEADER=true (see the shared-key variant above).
  • HTTP 403 Invalid Origin: a browser-based client served from a host other than localhost. Add its hostname to MCP_ALLOWED_ORIGINS.
  • HTTP 405 when you open the endpoint in a browser: expected, the endpoint only answers MCP POST requests. Check the server with GET /health.
  • Prompt injection: a document or template can carry instructions aimed at the AI. Review tool calls before you confirm them.

More in the Security section of the README⁠.

⁠Tags

TagDescription
latestLatest stable release
2.3.0Specific version
2.2Latest patch of 2.2
2Latest minor of v2

Supported platforms: linux/amd64, linux/arm64

Tag summary

Content type

Image

Digest

sha256:d947a440e…

Size

70.7 MB

Last updated

about 5 hours ago

docker pull carbone/carbone-mcp