pdfporter
README.md
# pdfporter
Files in, PDFs out — and PDFs reshaped. pdfporter is a
client for the conv2pdf conversion service: it takes the
path of a file on your computer, sends it for conversion,
and writes the result back next to the original. Office
documents, spreadsheets, presentations, images, e-books,
PostScript and HTML files become PDFs; PDFs become Word
documents or per-page images; and PDFs can be merged,
split, page-extracted, rotated, numbered, watermarked,
compressed, password-protected and unlocked.
## Configuration
- `CONV2PDF_API_KEY` (required for calls) — created in
the conv2pdf dashboard, Developer tab. It is sent on
every request as `Authorization: Bearer <key>`. Without
a key the server still starts and lists its tools; any
tool call fails with a message explaining how to set
the key.
- `CONV2PDF_API_URL` (optional) — API base URL. Defaults
to `https://api.conv2pdf.com/v1`.
- `CONV2PDF_TIMEOUT_MS` (optional) — per-request timeout
in milliseconds. Defaults to `120000`, because a
conversion may legitimately take up to about a minute.
## Tools
- `convert_to_pdf` — convert a file to PDF, chosen from
its extension: Word, Excel, PowerPoint, OpenDocument,
Apple Pages, RTF, TXT and CSV files go through
office-to-pdf; PNG, JPG, WebP, GIF and TIFF images
through image-to-pdf; HEIC/HEIF photos through
heic-to-pdf; EPUB through epub-to-pdf; PS/EPS through
ps-to-pdf; HTML through html-to-pdf. An unknown
extension fails locally, with no request made.
- `convert_url_to_pdf` — render a public web page to
PDF from its address. It always takes an
`output_path`, because there is no input file to write
next to.
- `convert_heic_to_jpg` — an iPhone HEIC or HEIF photo
as a JPG.
- `convert_pdf_to_word` — a PDF with real text as an
editable DOCX document. Pass `password` to open a
protected PDF.
- `convert_pdf_to_images` — one PNG (default) or JPG
per page, delivered in a ZIP file.
- `merge_pdfs` — combine 2 to 20 PDFs into one, in the
order given in `paths`.
- `extract_pdf_pages` — copy the pages listed in
`ranges` (such as `1-5,7,10-12`) into a new PDF, in
the order written.
- `split_pdf` — one PDF per page, in a ZIP file.
- `rotate_pdf` — turn every page by `rotation`: 90, 180
or 270 degrees.
- `add_page_numbers` — number the pages, as "3 / 12"
(`format: "full"`, the default) or "3"
(`format: "simple"`), at `position` bottom-center
(default), bottom-left or bottom-right.
- `add_watermark` — stamp a `text` of up to 50
characters on every page.
- `compress_pdf` — reduce the size, with `quality`
low, medium (default) or high, keeping images at 72,
150 or 300 DPI.
- `protect_pdf` — set a new `password` (6 to 64
characters), with `prevent_print` and `prevent_copy`
to forbid printing or copying.
- `unlock_pdf` — remove a password you know (pass it as
`password`), or the printing and copying restrictions.
- `get_quota` — the plan, usage and limits of the API
key, returned verbatim.
Most PDF-reading tools accept an optional `password`
that opens a protected PDF; the result has no password.
## How a conversion behaves
1. The input file is read locally and POSTed as
multipart/form-data to `<base>/convert/<api-tool>`,
the file in the `file` field plus the tool's fields
as string fields.
2. On HTTP 429 or 503 the server waits for the delay
the API gives (the `Retry-After` header, else the
body's `retry_after` seconds) and retries, at most
twice and only for delays of 30 seconds or less.
3. The convert response carries a `job_id` and a
relative `download_url`; the result is downloaded
from the API origin, written to disk, and the job is
then deleted from the service on a best-effort basis.
Results are never overwritten. By default the output
sits next to the input: a conversion swaps the
extension (`report.docx` gives `report.pdf`), a PDF
operation adds a suffix (`report.pdf` gives
`report-compressed.pdf` for `compress_pdf`,
`report-images.zip` for `convert_pdf_to_images`, and so
on), and a merge writes `merged.pdf` next to the first
input. When the target name is taken, ` (2)`, ` (3)`,
... is appended before the extension until a free name
is found. With an explicit `output_path`, an existing
file there is refused before anything is sent.
A successful conversion answers with a JSON summary:
`{"job_id": ..., "output_path": ..., "size_bytes": ...}`,
plus the `quota` object copied from the convert
response when the service sends one. `get_quota`
returns the service's response body verbatim.
Errors: a non-2xx reply fails with
`conv2pdf error: <error>` when the body carries an
`error` code, else `conv2pdf error: HTTP <status>`; an
unreachable API fails with `conv2pdf unreachable`.
## CLI
Each tool is a subcommand taking one JSON argument
string:
```bash
npx @reneturcios/pdfporter convert_to_pdf '{"path":"report.docx"}'
npx @reneturcios/pdfporter convert_url_to_pdf '{"url":"https://example.com/article","output_path":"article.pdf"}'
npx @reneturcios/pdfporter convert_heic_to_jpg '{"path":"IMG_0001.heic"}'
npx @reneturcios/pdfporter convert_pdf_to_word '{"path":"report.pdf"}'
npx @reneturcios/pdfporter convert_pdf_to_images '{"path":"report.pdf","format":"jpg"}'
npx @reneturcios/pdfporter merge_pdfs '{"paths":["a.pdf","b.pdf"]}'
npx @reneturcios/pdfporter extract_pdf_pages '{"path":"report.pdf","ranges":"1-5,7,10-12"}'
npx @reneturcios/pdfporter split_pdf '{"path":"report.pdf"}'
npx @reneturcios/pdfporter rotate_pdf '{"path":"scan.pdf","rotation":90}'
npx @reneturcios/pdfporter add_page_numbers '{"path":"report.pdf","position":"bottom-right"}'
npx @reneturcios/pdfporter add_watermark '{"path":"contract.pdf","text":"CONFIDENTIAL"}'
npx @reneturcios/pdfporter compress_pdf '{"path":"big.pdf","quality":"low"}'
npx @reneturcios/pdfporter protect_pdf '{"path":"confidential.pdf","password":"secret123","prevent_print":true}'
npx @reneturcios/pdfporter unlock_pdf '{"path":"protected.pdf","password":"secret123"}'
npx @reneturcios/pdfporter get_quota '{}'
npx @reneturcios/pdfporter --version
```
Exit codes: `0` on success, `1` on a runtime error,
`2` on a usage error.
## MCP server
```bash
npx -y @reneturcios/pdfporter mcp
```
MCP client config:
```json
{
"mcpServers": {
"pdfporter": {
"command": "npx",
"args": ["-y", "@reneturcios/pdfporter", "mcp"],
"env": {
"CONV2PDF_API_KEY": "<your key>"
}
}
}
}
```
## Docker
```bash
docker run -i ghcr.io/cloudcorprecords/pdfporter
docker run --rm ghcr.io/cloudcorprecords/pdfporter get_quota '{}'
```
## Development
```bash
npm install
npm run build # tsc -> dist/
npm test # tsx --test test/*.test.ts (fake fetch only, no network)
npm run dev # run the CLI from source
```
## License
MIT — Copyright (c) 2026 Rene Turcios
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues