pdfedit-mcp
Edit text inside existing PDFs: replace, delete, redact, insert, fill forms; original fonts kept.
사용해야 할까요
품질 및 안전성
도구 정의와 프로토콜 준수에 대한 자동 분석을 기반으로 합니다.
컨텍스트 비용
이는 서버의 도구가 모델의 컨텍스트에 로드될 때마다 소비되는 대략적인 토큰 수입니다. 수치가 높을수록 다른 작업에 사용할 수 있는 주의가 줄어듭니다.
설치
원클릭 설치
`claude_desktop_config.json` 파일에 다음을 추가하세요:
{
"mcpServers": {
"pdfedit-mcp": {
"command": "npx",
"args": [
"@niubai/pdfedit-mcp"
]
}
}
}실행 가능한 패키지
0.1.4stdio원격 엔드포인트
https://pdfedit-mcp-remote.niubai-pdfedit-remote-worker.workers.dev/mcpstreamable-http할 수 있는 일
도구 목록
도구 (5)
🟡pdf_edit(file, edits, options, password, output_path)
Edit the text of an existing PDF in place: replace, delete, redact, insert, or fill form fields, 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.
입력 스키마
{
"type": "object",
"properties": {
"file": {
"type": "string",
"minLength": 1,
"description": "The 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."
},
"edits": {
"minItems": 1,
"maxItems": 200,
"type": "array",
"items": {
"type": "object",
"properties": {
"at": {
"anyOf": [
{
"type": "object",
"properties": {
"after": {
"description": "Anchor text to insert after; the first occurrence on the page wins, and the style is inherited from it.",
"type": [
"string",
"null"
]
},
"page": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"placement": {
"type": "string",
"enum": [
"inline",
"below"
],
"description": "With `after`: 'inline' writes one space past the anchor's right edge on its own baseline; 'below' writes at the anchor line's left edge, one leading down. (default: \"inline\")"
},
"units": {
"type": "string",
"enum": [
"pt",
"fraction"
],
"description": "(default: \"pt\")"
},
"x": {
"description": "Baseline origin x. Points from the page's left edge, or a fraction of the page width when units='fraction'.",
"type": [
"number",
"null"
]
},
"y": {
"description": "Baseline origin y: where the first line sits, measured from the page's TOP edge (PDF viewer convention, as every bbox and span origin in this API). A fraction of the page height when units='fraction'.",
"type": [
"number",
"null"
]
}
},
"required": [
"page"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"fields": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "null"
}
]
},
"find": {
"type": [
"string",
"null"
]
},
"fit": {
"type": "string",
"enum": [
"auto",
"reflow",
"strict"
],
"description": "(default: \"auto\")"
},
"flatten": {
"type": "boolean",
"description": "(default: false)"
},
"match": {
"type": "object",
"properties": {
"across_lines": {
"type": "boolean",
"description": "(default: false)"
},
"mode": {
"type": "string",
"enum": [
"exact",
"icase",
"word",
"regex"
],
"description": "(default: \"exact\")"
},
"normalize": {
"type": "boolean",
"description": "(default: true)"
}
},
"additionalProperties": false
},
"op": {
"type": "string",
"enum": [
"replace",
"delete",
"redact",
"insert",
"form"
],
"description": "(default: \"replace\")"
},
"replace": {
"type": [
"string",
"null"
]
},
"scope": {
"type": "object",
"properties": {
"after": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"before": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"layers": {
"type": "array",
"items": {
"type": "string",
"enum": [
"content",
"forms",
"annotations"
]
},
"description": "Page layers to match in. All three are implemented; a match on the 'forms' layer is applied to the field's value, not to the page."
},
"occurrence": {
"anyOf": [
{
"type": "string",
"enum": [
"all",
"first",
"last"
]
},
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
],
"description": "(default: \"all\")"
},
"page_labels": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
},
"pages": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
}
],
"description": "(default: \"all\")"
},
"region": {
"anyOf": [
{
"type": "object",
"properties": {
"units": {
"type": "string",
"enum": [
"fraction",
"pt"
],
"description": "(default: \"fraction\")"
},
"x0": {
"type": "number"
},
"x1": {
"type": "number"
},
"y0": {
"type": "number"
},
"y1": {
"type": "number"
}
},
"required": [
"x0",
"x1",
"y0",
"y1"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"span_ids": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"style": {
"anyOf": [
{
"type": "object",
"properties": {
"color": {
"anyOf": [
{
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$"
},
{
"type": "null"
}
]
},
"font": {
"type": [
"string",
"null"
]
},
"size": {
"anyOf": [
{
"type": "number",
"minimum": 1,
"maximum": 200
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"text": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"description": "The edits to apply, in order, exactly as `POST /v1/edit` takes them."
},
"options": {
"type": "object",
"properties": {
"async": {
"type": "boolean",
"description": "(default: false)"
},
"atomic": {
"type": "boolean",
"description": "(default: true)"
},
"break_signature": {
"type": "boolean",
"description": "(default: false)"
},
"collateral_threshold": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "(default: 8)"
},
"dry_run": {
"type": "boolean",
"description": "(default: false)"
},
"font": {
"type": "object",
"properties": {
"policy": {
"type": "string",
"enum": [
"auto",
"metric_only",
"exact_only"
],
"description": "(default: \"auto\")"
}
},
"additionalProperties": false
},
"ocr": {
"type": "string",
"enum": [
"auto",
"on",
"off"
],
"description": "(default: \"auto\")"
},
"ocr_lang": {
"type": "array",
"items": {
"type": "string",
"enum": [
"zh",
"en"
]
}
},
"preview": {
"type": "string",
"enum": [
"changes",
"pages",
"none"
],
"description": "(default: \"changes\")"
},
"redact_metadata": {
"type": "boolean",
"description": "(default: false)"
},
"redact_style": {
"type": "string",
"enum": [
"box",
"text"
],
"description": "(default: \"box\")"
},
"redact_verify_ocr": {
"type": "boolean",
"description": "(default: true)"
},
"retain": {
"type": "boolean",
"description": "(default: true)"
},
"strict": {
"type": "boolean",
"description": "(default: false)"
},
"tidy": {
"type": "boolean",
"description": "(default: true)"
},
"watermark": {
"type": "string",
"enum": [
"auto",
"on",
"off"
],
"description": "(default: \"auto\")"
},
"webhook_url": {
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 2083,
"format": "uri"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"password": {
"description": "The document open password, when it has one.",
"type": "string"
},
"output_path": {
"description": "Where to write the edited PDF (stdio mode only). Default: `<name>.edited.pdf` next to the input.",
"type": "string"
}
},
"required": [
"file",
"edits"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false
}🟡pdf_batch(file, edits, records, records_url, options, ...)
Apply the same edits to one template PDF once per record, producing one output document per record — a mail merge over an existing PDF. Returns a `job_id`: call `pdf_job` with it for the per-record results. 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.
입력 스키마
{
"type": "object",
"properties": {
"file": {
"type": "string",
"minLength": 1,
"description": "The 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. Used as the template for every record."
},
"edits": {
"minItems": 1,
"maxItems": 200,
"type": "array",
"items": {
"type": "object",
"properties": {
"at": {
"anyOf": [
{
"type": "object",
"properties": {
"after": {
"description": "Anchor text to insert after; the first occurrence on the page wins, and the style is inherited from it.",
"type": [
"string",
"null"
]
},
"page": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"placement": {
"type": "string",
"enum": [
"inline",
"below"
],
"description": "With `after`: 'inline' writes one space past the anchor's right edge on its own baseline; 'below' writes at the anchor line's left edge, one leading down. (default: \"inline\")"
},
"units": {
"type": "string",
"enum": [
"pt",
"fraction"
],
"description": "(default: \"pt\")"
},
"x": {
"description": "Baseline origin x. Points from the page's left edge, or a fraction of the page width when units='fraction'.",
"type": [
"number",
"null"
]
},
"y": {
"description": "Baseline origin y: where the first line sits, measured from the page's TOP edge (PDF viewer convention, as every bbox and span origin in this API). A fraction of the page height when units='fraction'.",
"type": [
"number",
"null"
]
}
},
"required": [
"page"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"fields": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "null"
}
]
},
"find": {
"type": [
"string",
"null"
]
},
"fit": {
"type": "string",
"enum": [
"auto",
"reflow",
"strict"
],
"description": "(default: \"auto\")"
},
"flatten": {
"type": "boolean",
"description": "(default: false)"
},
"match": {
"type": "object",
"properties": {
"across_lines": {
"type": "boolean",
"description": "(default: false)"
},
"mode": {
"type": "string",
"enum": [
"exact",
"icase",
"word",
"regex"
],
"description": "(default: \"exact\")"
},
"normalize": {
"type": "boolean",
"description": "(default: true)"
}
},
"additionalProperties": false
},
"op": {
"type": "string",
"enum": [
"replace",
"delete",
"redact",
"insert",
"form"
],
"description": "(default: \"replace\")"
},
"replace": {
"type": [
"string",
"null"
]
},
"scope": {
"type": "object",
"properties": {
"after": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"before": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"layers": {
"type": "array",
"items": {
"type": "string",
"enum": [
"content",
"forms",
"annotations"
]
},
"description": "Page layers to match in. All three are implemented; a match on the 'forms' layer is applied to the field's value, not to the page."
},
"occurrence": {
"anyOf": [
{
"type": "string",
"enum": [
"all",
"first",
"last"
]
},
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
],
"description": "(default: \"all\")"
},
"page_labels": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
},
"pages": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
}
],
"description": "(default: \"all\")"
},
"region": {
"anyOf": [
{
"type": "object",
"properties": {
"units": {
"type": "string",
"enum": [
"fraction",
"pt"
],
"description": "(default: \"fraction\")"
},
"x0": {
"type": "number"
},
"x1": {
"type": "number"
},
"y0": {
"type": "number"
},
"y1": {
"type": "number"
}
},
"required": [
"x0",
"x1",
"y0",
"y1"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"span_ids": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"style": {
"anyOf": [
{
"type": "object",
"properties": {
"color": {
"anyOf": [
{
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$"
},
{
"type": "null"
}
]
},
"font": {
"type": [
"string",
"null"
]
},
"size": {
"anyOf": [
{
"type": "number",
"minimum": 1,
"maximum": 200
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"text": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"description": "The edits applied to each record, with `{field}` placeholders filled from it."
},
"records": {
"description": "One object per output document.",
"type": "array",
"items": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"records_url": {
"description": "A CSV or JSONL file of records, instead of `records`.",
"type": "string",
"format": "uri"
},
"options": {
"type": "object",
"properties": {
"async": {
"type": "boolean",
"description": "(default: false)"
},
"atomic": {
"type": "boolean",
"description": "(default: true)"
},
"break_signature": {
"type": "boolean",
"description": "(default: false)"
},
"collateral_threshold": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "(default: 8)"
},
"dry_run": {
"type": "boolean",
"description": "(default: false)"
},
"fail_fast": {
"type": "boolean",
"description": "(default: false)"
},
"filename": {
"type": [
"string",
"null"
]
},
"font": {
"type": "object",
"properties": {
"policy": {
"type": "string",
"enum": [
"auto",
"metric_only",
"exact_only"
],
"description": "(default: \"auto\")"
}
},
"additionalProperties": false
},
"ocr": {
"type": "string",
"enum": [
"auto",
"on",
"off"
],
"description": "(default: \"auto\")"
},
"ocr_lang": {
"type": "array",
"items": {
"type": "string",
"enum": [
"zh",
"en"
]
}
},
"output": {
"type": "string",
"enum": [
"zip",
"files"
],
"description": "(default: \"files\")"
},
"preview": {
"type": "string",
"enum": [
"changes",
"pages",
"none"
],
"description": "(default: \"changes\")"
},
"redact_metadata": {
"type": "boolean",
"description": "(default: false)"
},
"redact_style": {
"type": "string",
"enum": [
"box",
"text"
],
"description": "(default: \"box\")"
},
"redact_verify_ocr": {
"type": "boolean",
"description": "(default: true)"
},
"retain": {
"type": "boolean",
"description": "(default: true)"
},
"strict": {
"type": "boolean",
"description": "(default: false)"
},
"tidy": {
"type": "boolean",
"description": "(default: true)"
},
"watermark": {
"type": "string",
"enum": [
"auto",
"on",
"off"
],
"description": "(default: \"auto\")"
},
"webhook_url": {
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 2083,
"format": "uri"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"password": {
"type": "string"
}
},
"required": [
"file",
"edits"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false
}🟢pdf_find(cursor, layers, limit, match, pages, ...)
Read the text of a PDF: every span with its page, position, font and span id, optionally filtered by `query` (the same four `match` modes an edit uses) and `pages`, over the `content`, `forms` and `annotations` layers. Paginated: pass the returned `next_cursor` back as `cursor` for the next page. Use it before `pdf_edit` to check what a document actually says and to pick the `scope` that selects the match you mean.
입력 스키마
{
"type": "object",
"properties": {
"cursor": {
"type": [
"string",
"null"
]
},
"layers": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"enum": [
"content",
"forms",
"annotations"
]
}
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 1000,
"description": "(default: 200)"
},
"match": {
"type": "object",
"properties": {
"across_lines": {
"type": "boolean",
"description": "(default: false)"
},
"mode": {
"type": "string",
"enum": [
"exact",
"icase",
"word",
"regex"
],
"description": "(default: \"exact\")"
},
"normalize": {
"type": "boolean",
"description": "(default: true)"
}
},
"additionalProperties": false
},
"pages": {
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
}
]
},
{
"type": "null"
}
]
},
"query": {
"type": [
"string",
"null"
]
},
"file": {
"type": "string",
"minLength": 1,
"description": "The 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."
},
"password": {
"type": "string"
}
},
"required": [
"file"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false
}🟢pdf_preview(highlight, page, region, scale, file, ...)
Render one page of a PDF as a PNG image block, optionally cropped to `region` and with rectangles drawn over `highlight`. Use it to see a page before editing it, or to check the result afterwards.
입력 스키마
{
"type": "object",
"properties": {
"highlight": {
"anyOf": [
{
"maxItems": 200,
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number"
}
}
},
{
"type": "null"
}
]
},
"page": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "(default: 1)"
},
"region": {
"anyOf": [
{
"minItems": 4,
"maxItems": 4,
"type": "array",
"items": {
"type": "number"
}
},
{
"type": "null"
}
]
},
"scale": {
"anyOf": [
{
"type": "number",
"const": 1
},
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "(default: 2)"
},
"file": {
"type": "string",
"minLength": 1,
"description": "The 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."
},
"password": {
"type": "string"
}
},
"required": [
"file"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false
}🟢pdf_job(job_id, output_path)
The result of an async edit or a batch, by `job_id`: the same body `pdf_edit` returns once the job is done, plus `progress` while it is still queued or running, and `records` for a batch.
입력 스키마
{
"type": "object",
"properties": {
"job_id": {
"type": "string",
"minLength": 1,
"description": "The `job_id` an async edit or a batch returned."
},
"output_path": {
"description": "Where to write the finished document (stdio mode, single-document jobs only).",
"type": "string"
}
},
"required": [
"job_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false
}커뮤니티
증거