Skip to main content
Glama

Edit a PDF

pdf_edit
Idempotent

Edit an existing PDF in place: replace, delete, redact or insert text, fill form fields, stamp an image (a signature, a chop) into a box or remove one, keeping the original layout, fonts and everything you did not point at. edits[] is taken exactly as the API takes it (op, scope, match, fit), and the result carries up to 3 before/after previews of the pages that changed. To change text on one page only, set scope.pages; to pick one of several identical matches, use scope.after with nearby text or scope.occurrence. Use op: 'redact' when the text must be unrecoverable.

Input Schema

NameRequiredDescriptionDefault
fileYesThe PDF: an absolute (or ~) local path, which this server uploads for you, an https:// URL the API fetches, or an `f_…` file id from an earlier call.
editsYesThe edits to apply, in order, exactly as `POST /v1/edit` takes them.
optionsNo
passwordNoThe document open password, when it has one.
output_pathNoWhere to write the edited PDF (stdio mode only). Default: `<name>.edited.pdf` next to the input, or `<name>.edited.2.pdf`, `.3.pdf`, ... when that exists; an earlier result is never overwritten.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / edits / items / properties / op / enum
      Previous value: -[
      -  "replace",
      -  "delete",
      -  "redact",
      -  "insert",
      -  "form",
      -  "stamp"
      -]New value: +[
      +  "replace",
      +  "delete",
      +  "redact",
      +  "insert",
      +  "form",
      +  "stamp",
      +  "remove_image"
      +]
  2. Changed3 schema fields changed
    • addedInput schema / properties / edits / items / properties / box
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "h": {
      +          "description": "Height in points.",
      +          "maximum": 14400,
      +          "type": "number"
      +        },
      +        "page": {
      +          "maximum": 9007199254740991,
      +          "minimum": 1,
      +          "type": "integer"
      +        },
      +        "w": {
      +          "description": "Width in points.",
      +          "maximum": 14400,
      +          "type": "number"
      +        },
      +        "x": {
      +          "description": "Left edge, points from the page's left.",
      +          "minimum": 0,
      +          "type": "number"
      +        },
      +        "y": {
      +          "description": "Top edge, points from the page's TOP.",
      +          "minimum": 0,
      +          "type": "number"
      +        }
      +      },
      +      "required": [
      +        "h",
      +        "page",
      +        "w",
      +        "x",
      +        "y"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / edits / items / properties / image
      Added value: +{
      +  "description": "The image to place: PNG, JPEG, GIF, BMP or WebP, as base64 (a `data:` URL is accepted). JPEG is stored as sent; PNG keeps its transparency.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • changedInput schema / properties / edits / items / properties / op / enum
      Previous value: -[
      -  "replace",
      -  "delete",
      -  "redact",
      -  "insert",
      -  "form"
      -]New value: +[
      +  "replace",
      +  "delete",
      +  "redact",
      +  "insert",
      +  "form",
      +  "stamp"
      +]
  3. Changed2 schema fields changed
    • addedInput schema / properties / options / properties / webhook_url / description
      Added value: +"Called with POST when the job finishes: the body is the job's result (what GET /v1/jobs/{id} returns) plus `event` (job.done, job.failed, batch.done ...) and `job_id`, signed in `X-Signature` (hex HMAC-SHA256 of the raw body with the account's webhook secret). Non-2xx answers are retried after 1, 5 and 30 minutes. https only."
    • changedInput schema / properties / output_path / description
      Previous value: -"Where to write the edited PDF (stdio mode only). Default: `<name>.edited.pdf` next to the input."New value: +"Where to write the edited PDF (stdio mode only). Default: `<name>.edited.pdf` next to the input, or `<name>.edited.2.pdf`, `.3.pdf`, ... when that exists; an earlier result is never overwritten."
  4. First observed

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds real context beyond annotations: the original layout and fonts are preserved, the result returns up to 3 before/after page previews, and redaction is explicitly unrecoverable. That last point sits in mild tension with destructiveHint=false, but the tool writes to a separate output_path and never overwrites a prior result, so the annotation is defensible rather than contradicted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the operation inventory, then progressively narrows to scoping and redaction guidance. Dense but nearly every clause carries information; the 'taken exactly as the API takes it' phrasing is slightly opaque jargon that costs a little clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, deeply nested, mutation tool with no output schema, the description covers the essentials: what gets modified, what is preserved, that previews come back, and that writes go to a separate file. It does not touch the options object (async, dry_run, atomic, webhook), which is left entirely to schema descriptions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 80%, and the description still adds meaning on the hardest parameter: edits[] is passed through exactly as the API takes it, with which sub-keys matter (op, scope, match, fit) called out. It also explains the scope.after / scope.occurrence disambiguation, which the schema alone leaves implicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (edit an existing PDF in place) and enumerates the exact operation families it covers: text replace/delete/redact/insert, form fill, image stamp/remove. This is clearly distinguishable from pdf_find (search) and pdf_preview (render) siblings without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete selection guidance for the ambiguous cases: scope.pages for single-page targeting, scope.after / scope.occurrence to disambiguate identical matches, and op:'redact' when text must be unrecoverable. It does not explicitly say when to prefer this over pdf_batch or pdf_preview, so it stops short of full when/when-not coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.