Upload, edit, compress, protect, redact, and compare PDFs with KDAN PDF in Claude and ChatGPT.
The com.kdandoc.mcp/kdan-pdf-mcp server enables PDF workflows with KDAN PDF in Claude and ChatGPT. It supports operations to upload, edit, compress, protect, redact, and compare PDFs, making these tasks available through an MCP interface.
ð ïļ Key Features
Upload PDFs
Edit PDFs
Compress PDFs
Protect PDFs
Redact PDFs
Compare PDFs
ð Use Cases
Preparing documents for sharing by uploading and editing PDFs
Reducing file size via PDF compression
Applying protection and redaction for sensitive content
Comparing PDF versions to identify differences
⥠Developer Benefits
Integrates KDAN PDF capabilities into Claude and ChatGPT-driven workflows
Centralizes multiple PDF actions (upload/edit/compress/protect/redact/compare)
â ïļ Limitations
Only describes KDAN PDF-related operations; no other file types or broader document tooling are specified.
MANDATORY for all document comparison requests. Compare two PDFs side-by-side.
When the user asks to compare, diff, or find differences between two PDFs, you MUST
call this tool â NEVER attempt to compare documents using text analysis.
Displays an interactive side-by-side visual diff widget with colored highlights:
red = deleted, yellow = replaced, green = inserted.
The widget IS the comparison result â do NOT re-summarize the differences after calling.
Before calling, confirm both job_ids exist via check_upload_status.
Parameters3
session_id
string
required
Session ID that both jobs belong to.
job_id_a
string
required
Job ID for the first (original) PDF.
job_id_b
string
required
Job ID for the second (modified) PDF.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that both jobs belong to."
},
"job_id_a": {
"type": "string",
"description": "Job ID for the first (original) PDF."
},
"job_id_b": {
"type": "string",
"description": "Job ID for the second (modified) PDF."
}
},
"required": [
"session_id",
"job_id_a",
"job_id_b"
],
"additionalProperties": false
}
compress_pdf
Compress a PDF to reduce its file size and return a new versioned file.
MANDATORY: Before calling this tool, call 'check_upload_status' with the
session_id to confirm the file exists and retrieve the latest job_id.
Skipping this check and calling compress_pdf directly is FORBIDDEN.
Each call creates a NEW job_id (with parent_job_id linking to the source).
The original PDF version is preserved unchanged â previous versions remain accessible.
After compression completes, call 'view_pdf' with the new job_id to display the result.
Parameters2
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the PDF to compress (use the latest job_id from check_upload_status).
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the PDF to compress (use the latest job_id from check_upload_status)."
}
},
"required": [
"session_id",
"job_id"
],
"additionalProperties": false
}
delete_pdf_page
Delete one or more pages from a PDF and return a new versioned file.
MANDATORY: Before calling this tool, call 'check_upload_status' with the
session_id to confirm the file exists and retrieve the latest job_id.
Skipping this check and calling delete_pdf_page directly is FORBIDDEN.
Each call creates a NEW job_id (with parent_job_id linking to the source).
The original PDF version is preserved unchanged â previous versions remain accessible.
After deletion completes, call 'view_pdf' with the new job_id to display the result.
Parameters3
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the PDF to modify (use the latest job_id from check_upload_status).
page_numbers
array
required
1-based page numbers to delete. Duplicates are ignored.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the PDF to modify (use the latest job_id from check_upload_status)."
},
"page_numbers": {
"items": {
"type": "integer"
},
"type": "array",
"description": "1-based page numbers to delete. Duplicates are ignored."
}
},
"required": [
"session_id",
"job_id",
"page_numbers"
],
"additionalProperties": false
}
set_password
Add password protection to an unprotected PDF file.
Creates a NEW job_id (with parent_job_id linking to the source). After the operation
completes, call 'view_pdf' with the new job_id to display the result. Do NOT call
this on an already-protected PDF â use change_password instead.
Parameters4
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the unprotected PDF to protect (use the latest job_id).
owner
string
required
Owner password (grants full PDF permissions).
password
string
required
User password (required to open the PDF).
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the unprotected PDF to protect (use the latest job_id)."
},
"owner": {
"type": "string",
"description": "Owner password (grants full PDF permissions)."
},
"password": {
"type": "string",
"description": "User password (required to open the PDF)."
}
},
"required": [
"session_id",
"job_id",
"owner",
"password"
],
"additionalProperties": false
}
change_password
Change the password of an already-protected PDF file.
Creates a NEW job_id (with parent_job_id linking to the source). After the operation
completes, call 'view_pdf' with the new job_id to display the result. Do NOT call
this on an unprotected PDF â use set_password instead.
Parameters5
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the password-protected PDF (use the latest job_id).
old_password
string
required
The current user password needed to unlock the PDF.
owner
string
required
New owner password.
password
string
required
New user password.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the password-protected PDF (use the latest job_id)."
},
"old_password": {
"type": "string",
"description": "The current user password needed to unlock the PDF."
},
"owner": {
"type": "string",
"description": "New owner password."
},
"password": {
"type": "string",
"description": "New user password."
}
},
"required": [
"session_id",
"job_id",
"old_password",
"owner",
"password"
],
"additionalProperties": false
}
list_redactable_line_text
Return per-page, per-line text for identifying redaction targets.
Read-only: does not modify job state. ALWAYS call this before redact_by_text_range.
The returned 'text' field for each line is the source of truth â you MUST use it
to count exact character positions. Character positions within each line are 0-based
from the start of that line.
Parameters2
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the PDF to inspect (use the latest job_id).
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the PDF to inspect (use the latest job_id)."
}
},
"required": [
"session_id",
"job_id"
],
"additionalProperties": false
}
redact_by_text_range
Redact PDF text by specifying the exact text to remove on each line.
MANDATORY WORKFLOW â follow every step in order before calling this tool:
Step 1 â Retrieve line text:
Call list_redactable_line_text and note the exact 'text' string
and 'line_index' for every line you intend to redact.
Step 2 â Identify the text to redact:
Provide the exact substring to remove. The value must appear verbatim
in the line's 'text' field.
- Non-CJK text (e.g. English): whole-word matching is enforced.
"the" will NOT redact text inside "then", "there", or "either".
- CJK text (e.g. Chinese): substring matching â "įåΧæ" will match
wherever it appears in the line.
Step 3 â Build the content payload:
Group redaction targets by page. Each page entry contains a list of
{ line_index, text } pairs.
Example:
content = [
{
"page_index": 1,
"lines": [
{"line_index": 3, "text": "John Doe"},
{"line_index": 7, "text": "confidential"}
]
}
]
Step 4 â Verify and re-redact if needed:
After this tool returns, you MUST call list_redactable_line_text again
with the NEW job_id to verify that all intended targets have been removed.
If any target text still appears in the result, call redact_by_text_range
again immediately with the remaining targets. Repeat until all targets
are gone â do NOT report success until the verification confirms zero
remaining targets.
Creates a NEW job_id (with parent_job_id linking to the source). After redaction
completes, call 'view_pdf' with the new job_id to display the result.
Parameters3
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the PDF to redact (use the latest job_id).
content
array
required
List of pages to redact. Each item must include:
- page_index (int): 1-based page number.
- lines (list): each entry contains:
- line_index (int): line index from list_redactable_line_text.
- text (str): exact text to redact from that line.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the PDF to redact (use the latest job_id)."
},
"content": {
"items": {
"description": "æåŪæé äļčĶéŪč―įčĄčæåã",
"properties": {
"page_index": {
"type": "integer"
},
"lines": {
"items": {
"description": "æåŪåŪčĄäļčĶéŪč―įæåã",
"properties": {
"line_index": {
"type": "integer"
},
"text": {
"type": "string"
}
},
"required": [
"line_index",
"text"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"page_index",
"lines"
],
"type": "object"
},
"type": "array",
"description": "List of pages to redact. Each item must include:\n- page_index (int): 1-based page number.\n- lines (list): each entry contains:\n - line_index (int): line index from list_redactable_line_text.\n - text (str): exact text to redact from that line."
}
},
"required": [
"session_id",
"job_id",
"content"
],
"additionalProperties": false
}
upload_pdf
Upload a PDF from a ChatGPT file attachment (download URL).
MANDATORY WORKFLOW â follow EVERY step in order:
1. ALWAYS call check_upload_status FIRST â even if you think the file is new.
2. If a job with the same filename already exists, reuse its job_id â do NOT call upload_pdf.
3. Only call upload_pdf if the file is confirmed absent from check_upload_status.
Skipping step 1 and calling upload_pdf directly is FORBIDDEN.
Use this when the user provides a file attachment in ChatGPT. The tool downloads
the PDF from the signed URL in the pdf_file parameter and stores it immediately.
Returns session_id and job_id for use in all subsequent tool calls.
For MCP clients where no file attachment is available (e.g. Claude), use
create_upload_page instead to display an upload widget.
Parameters2
pdf_file
any
required
File object from ChatGPT containing download_url (and optionally
name/filename). Passed automatically from the file attachment.
session_id
any
optional
Existing session ID to group this file with previous uploads.
If omitted, a new session is created. Always pass the same session_id
throughout the entire conversation.
Raw schema
{
"type": "object",
"properties": {
"pdf_file": {
"description": "File object from ChatGPT containing download_url (and optionally\nname/filename). Passed automatically from the file attachment."
},
"session_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Existing session ID to group this file with previous uploads.\nIf omitted, a new session is created. Always pass the same session_id\nthroughout the entire conversation."
}
},
"required": [
"pdf_file"
],
"additionalProperties": false
}
batch_upload_pdf
Upload multiple PDF files from ChatGPT file attachments (download URLs).
Use this when the user provides multiple file attachments in ChatGPT.
Downloads each PDF from its signed URL and stores it.
Returns session_id and a list of job_ids.
MANDATORY WORKFLOW before calling this tool:
1. ALWAYS call check_upload_status FIRST â even if you think the files are new.
2. Only include files confirmed absent from check_upload_status. If ALL files are already
uploaded, skip batch_upload_pdf entirely and reuse the existing job_ids.
3. Reuse job_ids from already_uploaded â do NOT re-upload those files.
Skipping step 1 and calling batch_upload_pdf directly is FORBIDDEN.
After batch_upload_pdf completes: if the user requested a comparison, call
'compare_pdfs' with the returned job_ids immediately.
Parameters2
pdf_files
array
required
List of file objects from ChatGPT, each containing download_url
(and optionally name/filename).
session_id
any
optional
Existing session ID to group these files.
If omitted, a new session is created.
Raw schema
{
"type": "object",
"properties": {
"pdf_files": {
"items": {},
"type": "array",
"description": "List of file objects from ChatGPT, each containing download_url\n(and optionally name/filename)."
},
"session_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Existing session ID to group these files.\nIf omitted, a new session is created."
}
},
"required": [
"pdf_files"
],
"additionalProperties": false
}
create_upload_page
Display an interactive PDF upload widget directly in the chat.
Use this when the user wants to upload a local PDF file from their device.
This is the standard upload method for MCP clients (e.g. Claude) where
file attachments with download URLs are not available.
Do NOT call upload_pdf when using this tool â the widget handles the upload automatically.
The widget renders inline and the PDF viewer appears after the user selects a file.
Do NOT call view_pdf after this tool; the widget manages the UI.
Never tell the user the file is still uploading; the widget handles the spinner.
After the user uploads via the widget and notifies you, call
check_upload_status(session_id=<session_id>) to discover the uploaded file
and its job_id before proceeding with any operation.
Parameters1
session_id
any
optional
Existing session ID to continue an ongoing workflow.
If omitted, a new session is created. Always pass the same session_id
throughout the entire conversation to keep all files grouped together.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Existing session ID to continue an ongoing workflow.\nIf omitted, a new session is created. Always pass the same session_id\nthroughout the entire conversation to keep all files grouped together."
}
},
"additionalProperties": false
}
check_upload_status
Check existing uploads and determine which files still need uploading.
Call this BEFORE upload_pdf or create_upload_page to avoid duplicate uploads.
Also call it after the user uploads via the widget to discover the new file
and its job_id.
Returns 'session_id' (always â store it!), plus:
- 'already_uploaded': files found in this session with reusable job_ids
- 'needs_upload': files not yet in this session (must be uploaded)
You MUST call this tool before any upload, and you MUST act on its result immediately:
- 'needs_upload' is non-empty â call upload_pdf (single) or batch_upload_pdf (multiple)
with ONLY the files listed in 'needs_upload'. Pass the same session_id.
Do NOT upload files in 'already_uploaded'.
- 'needs_upload' is empty â skip uploading entirely; use the job_ids from 'already_uploaded'.
When pending_filenames is omitted, returns all jobs currently in the session.
Parameters2
session_id
any
optional
Session ID from a previous upload_pdf or create_upload_page call.
If omitted, a new session_id is generated and ALL pending files are
treated as needs_upload (new workflow).
pending_filenames
any
optional
Bare filenames to check, e.g. ['FileA.pdf', 'FileB.pdf'].
Never include directory paths like '/mnt/data/FileA.pdf'.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Session ID from a previous upload_pdf or create_upload_page call.\nIf omitted, a new session_id is generated and ALL pending files are\ntreated as needs_upload (new workflow)."
},
"pending_filenames": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Bare filenames to check, e.g. ['FileA.pdf', 'FileB.pdf'].\nNever include directory paths like '/mnt/data/FileA.pdf'."
}
},
"additionalProperties": false
}
view_pdf
Display an already-uploaded PDF in an interactive viewer widget.
Call this after delete_pdf_page, set_password, change_password, redact_pii, and
redact_by_text_range to show the updated PDF. Also call when the user explicitly
asks to (re-)display a specific PDF.
Do NOT call this after upload_pdf (the widget handles it automatically).
Before calling, confirm the job_id exists via check_upload_status.
MANDATORY after this tool returns:
1. Render a markdown download link so the user can save the file:
[Download {filename}]({download_url})
2. Follow cta_instruction and append cta_text at the end of your reply.
Parameters2
session_id
any
optional
Session ID that the job belongs to.
job_id
string
optional
Job ID of the PDF to display (use the latest job_id).
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Session ID that the job belongs to."
},
"job_id": {
"default": "",
"type": "string",
"description": "Job ID of the PDF to display (use the latest job_id)."
}
},
"additionalProperties": false
}
get_pdf_status
Return current status of a PDF viewer job. Used internally by the viewer widget.
Parameters2
session_id
any
optional
Session ID of the job.
job_id
string
optional
Job ID of the PDF to check.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Session ID of the job."
},
"job_id": {
"default": "",
"type": "string",
"description": "Job ID of the PDF to check."
}
},
"additionalProperties": false
}
get_pdf_info
Use this when you need to read the text content of each page to decide which pages to delete. Returns page count and a text preview of every page. Use for text-based identification: table of contents, blank pages, cover page, etc. For visual content (logos, images, photos), use get_pdf_page_images instead.
Parameters2
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the PDF to inspect.
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the PDF to inspect."
}
},
"required": [
"session_id",
"job_id"
],
"additionalProperties": false
}
get_pdf_page_images
Use this when you need to visually inspect PDF pages to identify content that cannot be detected from text alone â for example, pages containing a logo, a photograph, a watermark, a QR code, or any visual element. Returns rendered JPEG screenshots as images you can see. Returns at most 10 pages per call. ALWAYS start from start_page=1 and paginate through the ENTIRE document: check 'has_more' in structuredContent â if true, call again with start_page=next_start_page. Repeat until has_more is false. You must finish scanning all pages before answering the user's question or performing any action (e.g. deletion). Requires: pip install pymupdf
Parameters4
session_id
string
required
Session ID that the job belongs to.
job_id
string
required
Job ID of the PDF to render.
start_page
integer
optional
1-based page number to start from (default 1).
count
integer
optional
Number of pages to render per call (capped at MAX_IMAGE_PAGES).
Raw schema
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Session ID that the job belongs to."
},
"job_id": {
"type": "string",
"description": "Job ID of the PDF to render."
},
"start_page": {
"default": 1,
"type": "integer",
"description": "1-based page number to start from (default 1)."
},
"count": {
"default": 10,
"type": "integer",
"description": "Number of pages to render per call (capped at MAX_IMAGE_PAGES)."
}
},
"required": [
"session_id",
"job_id"
],
"additionalProperties": false
}
KDAN PDF MCP is a remote MCP server that lets users prepare PDFs with natural-language instructions. In supported AI assistants such as Claude or ChatGPT, users can ask KDAN PDF MCP to compress large files, remove selected pages, redact sensitive information, compare document versions, or add or update password protection before documents are shared, submitted, or reviewed.
What is MCP? (Plain-English version)
Think of an AI assistant like Claude as very capable, but with no hands â on its own it can only talk about your PDF. MCP (Model Context Protocol) is an open standard that gives the AI a real pair of hands: it can now actually open your file, edit it, and save a new copy for you. KDAN PDF MCP is the connector that plugs KDAN PDF's editing tools into that assistant.
No code, no installation, no account. You paste one link into your AI assistant once, and from then on you just type what you want in plain language.
What is MCP
Why KDAN PDF MCP
One sentence, done. Replace the download â open another tool â find the right button â re-upload routine with a single message.
Free & unlimited. No account, no credit card, no usage caps, no upsell.
True redaction. Sensitive data is permanently removed, not hidden under a black box â built for compliance.
Stays in your conversation. Compare, redact, protect and deliver without switching apps.
How it works
Pull a file from wherever it lives, let KDAN PDF MCP + your AI assistant do the work, and send the result straight to where your team already is.
How it works
Setup on Claude
Works on free accounts. Steps are the same for both Claude Desktop and claude.ai.
Click your account icon â Settings
Select Connectors â Add Connector
Paste the following URL:
code
https://mcp.kdandoc.com/mcp
Claude will walk you through the authorization flow to grant access.
Once connected, just tell Claude what you want â for example: "Help me compress this PDF and remove page 3."
Add KDAN PDF to Claude
Setup on ChatGPT
May require a paid plan.
Go to chatgpt.com, click your account icon â Settings
Select Connectors â Add Connector
Paste the following URL:
code
https://mcp.kdandoc.com/mcp
Complete the authorization flow to finish setup.
What You Can Do
Once connected, try asking your AI assistant:
"Upload this PDF."
"Show me a preview."
"Compress this PDF and tell me how much smaller it got."
"Delete page 3 from this PDF."
"Add a password to protect this contract."
"Change the password of this PDF."
"Redact the customer's email address on page 2."
"Compare these two PDFs and highlight the differences side by side."
"Give me a download link for the final file."
Tips for best results
Attach the PDF in the same message as your request.
Be specific about pages and targets â e.g. "redact emails and ID numbers on pages 2â4."
For multi-step jobs, chain them in one sentence: "Compare v1 and v2, redact the names, then password-protect the result."
Ask for a download link when you want the finished file.
Built for every team
The same connector fits seven everyday workflows:
Team
Typical job
One-sentence example
Legal
Compare contract versions, strip internal notes, protect before sending
"Compare v1 and v2, redact comments, then set a password."
Finance
One report, audience-specific versions with figures masked
"Mask the internal figures for the investor version."
HR
Remove PII from resumes; hide salary bands on offer letters
"Black out names, IDs and phone numbers on this resume."
Procurement
Compare vendor proposals with pricing masked; issue decisions
"Compare these three proposals and mask the pricing."
Marketing & Sales
Compress decks, protect proposals before sharing externally
"Compress this deck and password-protect it."
Project Management
Clean up specs, remove draft pages, share final copies
"Delete the draft pages and give me a clean copy."
Engineering
Redact credentials from logs/specs before distribution
"Redact any keys or emails in this document."
See team workflow examples (Legal · Finance · HR · Procurement)
KDAN PDF MCP applies true PDF redaction â targeted content is permanently removed, not masked with an overlay, so it cannot be recovered from the output file. KDAN Mobile operates under GDPR, Taiwan PDPA and CCPA. For full details see KDAN's Security, Privacy Policy and GDPR Compliance pages.
FAQ
Q1: Is KDAN PDF MCP free?
A: Yes â completely free and unlimited, with no upsell and no credit card required.
Q2: Can it redact PII in a PDF?
A: Yes. Once national IDs, credit cards, emails and phone numbers are detected, KDAN PDF MCP applies permanent, compliance-ready redaction.
Q3: How is this different from Claude's built-in PDF reading?
A: On its own, an AI assistant can only read a PDF. KDAN PDF MCP adds full editing â encrypt, delete pages, redact and save new copies â all through chat.
Q4: Which AI assistants are supported?
A: Claude (web and desktop) and ChatGPT. Setup steps for each are above.
Q5: Do I need a KDAN account?
A: No. There's no sign-up â paste the connector URL once and start using it.
Q6: Can I use it on a free Claude plan?
A: Yes, KDAN PDF MCP works on free Claude accounts. ChatGPT may require a paid plan to add connectors.
Q7: Does redaction actually remove the data, or just cover it?
A: It removes it. KDAN PDF MCP applies true redaction rather than a visual black box, so the underlying text can't be copied or recovered.
Q8: What PDF tasks are supported?
A: Compress, delete pages, password-protect / change password, redact PII, compare two versions, preview, and generate a download link.
Q9: What languages can I give instructions in?
A: You can chat in the language your AI assistant supports; instructions work in natural language.
Troubleshooting
Connector doesn't appear? Restart Claude Desktop after adding it, then check Settings â Connectors.
Authorization didn't complete? Remove the connector and re-add the URL https://mcp.kdandoc.com/mcp.
Assistant only reads the PDF? Confirm KDAN PDF MCP shows as connected, and mention "KDAN PDF" in your request.
Large file is slow? Bigger PDFs take longer to process â let it finish before sending the next instruction.