Skip to main content
Glama
marc-hanheide

PDF Redaction MCP Server

save_redacted_pdf

Apply redaction annotations to PDF documents and save the secured version, automatically generating output files with '_redacted' suffix when no custom path is specified.

Instructions

Apply all redactions and save the redacted PDF.

This tool applies all pending redaction annotations to the PDF and saves it. By default, it saves to a new file with '_redacted' appended to the original filename.

Args: pdf_path: Path to the PDF file (must be already loaded) output_path: Optional custom output path. If not provided, saves as '<original_name>_redacted.pdf' ctx: MCP context for logging

Returns: Path to the saved redacted PDF

Raises: ToolError: If the PDF is not loaded or save fails

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
output_pathNoOptional output path. If not provided, appends '_redacted' to the original filename
pdf_pathYesPath to the loaded PDF file

Implementation Reference

  • The core handler function for the 'save_redacted_pdf' tool. It applies all redaction annotations to the loaded PDF using PyMuPDF's apply_redactions() method on each page, determines the output path (defaulting to appending '_redacted' to the input filename), saves the document, and returns a confirmation message with the save location and number of pages with redactions.
    @mcp.tool async def save_redacted_pdf( pdf_path: Annotated[str, Field(description="Path to the loaded PDF file")], output_path: Annotated[str | None, Field( description="Optional output path. If not provided, appends '_redacted' to the original filename" )] = None, ctx: Context = None ) -> str: """Apply all redactions and save the redacted PDF. This tool applies all pending redaction annotations to the PDF and saves it. By default, it saves to a new file with '_redacted' appended to the original filename. Args: pdf_path: Path to the PDF file (must be already loaded) output_path: Optional custom output path. If not provided, saves as '<original_name>_redacted.pdf' ctx: MCP context for logging Returns: Path to the saved redacted PDF Raises: ToolError: If the PDF is not loaded or save fails """ try: path = Path(pdf_path).resolve() path_str = str(path) await ctx.info(f"Saving redacted PDF: {path}") # Check if PDF is loaded if path_str not in _loaded_pdfs: raise ToolError( f"PDF not loaded. Please load it first using load_pdf: {path}" ) doc = _loaded_pdfs[path_str] # Determine output path if output_path: out_path = Path(output_path).resolve() else: # Append '_redacted' to the original filename out_path = path.parent / f"{path.stem}_redacted{path.suffix}" # Count total redactions before applying total_redactions = 0 for page in doc: # Apply redactions on this page redact_count = page.apply_redactions() if redact_count: total_redactions += 1 # Note: apply_redactions returns True if any were applied # Save the document doc.save(str(out_path)) await ctx.info(f"Saved redacted PDF to: {out_path}") return ( f"Successfully applied redactions and saved to: {out_path}\n" f"Redactions applied on {total_redactions} page(s)." ) except ToolError: raise except Exception as e: await ctx.error(f"Failed to save redacted PDF: {str(e)}") raise ToolError(f"Failed to save redacted PDF: {str(e)}")
  • The @mcp.tool decorator registers the save_redacted_pdf function as an MCP tool with FastMCP, automatically generating schema from type annotations.
    @mcp.tool
  • Input schema defined via Pydantic Annotated fields and type hints: required pdf_path (str), optional output_path (str|None), optional ctx (Context).
    pdf_path: Annotated[str, Field(description="Path to the loaded PDF file")], output_path: Annotated[str | None, Field( description="Optional output path. If not provided, appends '_redacted' to the original filename" )] = None, ctx: Context = None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marc-hanheide/redact_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server