Authentication, idempotency, error handling, and rate limits for the PDFHaul MCP server.
All requests require an API key issued from the Developer page. Pass it as a Bearer token in every request header.
Authorization: Bearer <your_api_key>
Where to get a key
Sign in to PDFHaul, open the Developer page, and click New key. Each key is shown only once.
Key format
All keys are prefixed ph_mcp_live_ followed by a 64-character hex string.
Revocation
Keys can be revoked instantly from the Developer page. Revoked keys return HTTP 401 immediately.
For applications that connect on behalf of a user without requiring them to copy an API key manually. PDFHaul supports OAuth 2.1 with PKCE (S256). Claude uses this flow automatically when you add the MCP server.
Authorization endpoint
https://pdfhaul.com/oauth/authorize
Token endpoint
https://mcp.pdfhaul.com/oauth/token
Discovery
https://mcp.pdfhaul.com/.well-known/oauth-authorization-server
PKCE required
S256 only. Plain is not supported.
Generate a cryptographically random state value before redirecting the user to the authorization endpoint. Store it locally, then verify it matches the value returned in the callback. Reject the flow if it does not match. This prevents CSRF attacks where a malicious page tricks a user into completing a flow the attacker initiated.
// Before redirecting
const state = crypto.randomUUID();
sessionStorage.setItem('oauth_state', state);
// On callback
const returned = new URLSearchParams(location.search).get('state');
if (returned !== sessionStorage.getItem('oauth_state')) {
throw new Error('State mismatch — possible CSRF attack');
}AI clients sometimes retry a tool call after a timeout even if the server already succeeded. To prevent duplicate files being created, pass a unique idempotencyKey string with every mutation. The server caches the result for 5 minutes — a retry with the same key returns the original result without running the operation again.
{
"name": "merge_pdfs",
"arguments": {
"fileIds": ["abc123", "def456"],
"outputName": "combined.pdf",
"idempotencyKey": "merge-contract-2026-07-21"
}
}Key scope
Keys are scoped per API key — the same idempotencyKey value used by two different accounts will not conflict.
TTL
Cached results expire after 5 minutes. After expiry the operation will run again on the next call.
Errors are not cached
If the operation fails, the result is not cached. Retries with the same key will attempt the operation again.
Read-only tools excluded
list_files and get_file_url are excluded from idempotency caching as they are always safe to repeat.
Errors are returned as MCP tool errors with isError: true in the content. The text field contains a human-readable message. HTTP-level errors (401, 429) are returned before reaching tool execution.
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | The requested file ID does not exist or does not belong to this account. |
| FORBIDDEN | 403 | The API key does not have access to this resource. |
| INVALID_INPUT | 400 | A required parameter is missing or has an invalid value. |
| CORE_API_ERROR | varies | The PDFHaul backend returned an error. The message field contains details. |
| FETCH_ERROR | 400 | upload_from_url could not retrieve the remote PDF (bad URL, non-PDF content type, or HTTP error from origin). |
| UPLOAD_ERROR | 500 | The file was fetched but the upload to storage failed. |
| SSRF_BLOCKED | 400 | upload_from_url was passed a URL that resolves to a private/internal IP address. |
Limits reset on a rolling 1-hour window and apply per API key. Exceeding the limit returns HTTP 429 with a X-RateLimit-Reset header containing the Unix timestamp when the window resets.
| Tool | Limit |
|---|---|
| All tools (default) | 60 calls / hour |
| upload_from_url | 10 calls / hour |
| Max keys per account | 10 keys |
Full parameter tables, types, and response schemas for every MCP tool.