/** * ┌─────────────────────────────────────────────────────────────────────────┐ * │ REPLACE TEXT AT POSITION TOOL - MCP Tool Implementation │ * ├─────────────────────────────────────────────────────────────────────────┤ * │ Filename: replace-text-at-position.tool.ts │ * │ Language: TypeScript │ * │ MCP Server: PDF Operations Server │ * │ │ * │ Purpose: │ * │ Implements an MCP tool that replaces text at specific positions in │ * │ PDF documents. Works in conjunction with detect-text-position tool │ * │ to find and replace text with precise control over positioning. │ * │ │ * │ Why this tool exists: │ * │ - Enables AI to modify text content in PDFs │ * │ - Supports bulk text replacements across documents │ * │ - Provides precise control over text appearance and positioning │ * │ - Essential for PDF content updates and corrections │ * │ │ * │ MCP Tool Information: │ * │ Tool Name: replace-text-at-position │ * │ Category: pdf-operations │ * │ Input: { filePath, replacements, options } │ * │ Output: { outputPath, replacementCount, pagesModified, details } │ * │ │ * │ Key Features: │ * │ - Replace text at precise positions using detect-text-position data │ * │ - Support for single or batch replacements │ * │ - Preserve or override fonts, colors, and styling │ * │ - Automatic coordinate conversion between PDF.js and pdf-lib │ * │ - Handles rotated text correctly │ * │ - Creates backup of original file (optional) │ * │ │ * │ Workflow: │ * │ 1. User calls detect-text-position to find text locations │ * │ 2. User calls this tool with replacement specifications │ * │ 3. Tool covers old text with background rectangles │ * │ 4. Tool draws new text at exact positions │ * │ 5. Tool saves modified PDF and returns details │ * │ │ * │ Use Cases: │ * │ - Replace all occurrences of "Hello" with "Hi" │ * │ - Update year "2023" to "2024" in first occurrence │ * │ - Replace whitespace with underscores │ * │ - Correct typos at specific locations │ * │ - Batch update product names or prices │ * │ │ * │ Dependencies: │ * │ - @modelcontextprotocol/sdk: MCP server SDK │ * │ - zod: Input validation and schema definition │ * │ - pdf-lib: PDF manipulation and modification │ * │ - ../utils/text-replacement-utils: Text replacement functions │ * │ - ../utils/path-resolver: File path resolution │ * │ - ./detect-text-position.tool: Text position detection │ * │ │ * │ Related Tools: │ * │ - detect-text-position: Finds text positions in PDFs │ * │ - extract-pdf-text: Extracts all text from PDFs │ * │ │ * │ Security Considerations: │ * │ - Validates file paths to prevent traversal attacks │ * │ - Validates page numbers within document bounds │ * │ - Sanitizes text content to prevent injection │ * │ - Limits number of replacements to prevent DOS │ * │ │ * │ Author: PDF MCP Team │ * │ Created: 2025-10-31 │ * │ Version: 1.0.0 │ * └─────────────────────────────────────────────────────────────────────────┘ */ import { z } from 'zod'; import type { TextReplacementResult } from '../types.js'; /** * Zod schema for a single text replacement specification */ declare const ReplacementSpecSchema: z.ZodObject<{ pageNumber: z.ZodNumber; originalText: z.ZodString; replacementText: z.ZodString; bounds: z.ZodObject<{ x: z.ZodNumber; y: z.ZodNumber; width: z.ZodNumber; height: z.ZodNumber; }, "strip", z.ZodTypeAny, { x: number; y: number; width: number; height: number; }, { x: number; y: number; width: number; height: number; }>; fontName: z.ZodOptional; fontSize: z.ZodOptional; color: z.ZodOptional>; rotation: z.ZodOptional; backgroundColor: z.ZodOptional>; }, "strip", z.ZodTypeAny, { pageNumber: number; bounds: { x: number; y: number; width: number; height: number; }; originalText: string; replacementText: string; fontSize?: number | undefined; color?: { r: number; g: number; b: number; } | undefined; rotation?: number | undefined; fontName?: string | undefined; backgroundColor?: { r: number; g: number; b: number; } | undefined; }, { pageNumber: number; bounds: { x: number; y: number; width: number; height: number; }; originalText: string; replacementText: string; fontSize?: number | undefined; color?: { r: number; g: number; b: number; } | undefined; rotation?: number | undefined; fontName?: string | undefined; backgroundColor?: { r: number; g: number; b: number; } | undefined; }>; /** * Zod schema for replace-text-at-position tool input validation */ export declare const ReplaceTextAtPositionInputSchema: { filePath: z.ZodString; replacements: z.ZodArray; fontName: z.ZodOptional; fontSize: z.ZodOptional; color: z.ZodOptional>; rotation: z.ZodOptional; backgroundColor: z.ZodOptional>; }, "strip", z.ZodTypeAny, { pageNumber: number; bounds: { x: number; y: number; width: number; height: number; }; originalText: string; replacementText: string; fontSize?: number | undefined; color?: { r: number; g: number; b: number; } | undefined; rotation?: number | undefined; fontName?: string | undefined; backgroundColor?: { r: number; g: number; b: number; } | undefined; }, { pageNumber: number; bounds: { x: number; y: number; width: number; height: number; }; originalText: string; replacementText: string; fontSize?: number | undefined; color?: { r: number; g: number; b: number; } | undefined; rotation?: number | undefined; fontName?: string | undefined; backgroundColor?: { r: number; g: number; b: number; } | undefined; }>, "many">; preserveFonts: z.ZodOptional; preserveColors: z.ZodOptional; outputPath: z.ZodOptional; createBackup: z.ZodOptional; }; /** * Zod schema for replace-text-at-position tool output */ export declare const ReplaceTextAtPositionOutputSchema: { outputPath: z.ZodString; replacementCount: z.ZodNumber; pagesModified: z.ZodNumber; originalPath: z.ZodString; replacements: z.ZodArray; }, "strip", z.ZodTypeAny, { pageNumber: number; originalText: string; replacementText: string; success: boolean; error?: string | undefined; }, { pageNumber: number; originalText: string; replacementText: string; success: boolean; error?: string | undefined; }>, "many">; }; /** * Helper function to find text positions and prepare replacements * * PRECISION TEXT REPLACEMENT - Word-level accuracy! * * This function enables surgical precision text replacement: * - "Ramya" in "Ramya Lakhani" → "Raj Lakhani" ✅ * - "ramya" in "lakhani.ramya.u@gmail.com" → "lakhani.raj.u@gmail.com" ✅ * - Only replaces the exact substring, preserving all surrounding text * * Technical approach: * 1. Uses detect-text-position to find all text items containing search text * 2. Calculates PRECISE partial bounds for each substring match * 3. Uses character-by-character width measurement for accuracy * 4. Creates replacement specs that only affect the target substring * 5. Surrounding text remains completely untouched * * Key improvements over previous version: * - Uses partial bounds instead of full text bounds * - Replaces only the substring, not the entire text item * - Accurate width calculations with character-level precision * - Minimal padding to avoid affecting adjacent text * * @param filePath - Path to PDF file * @param searchText - Text to search for (can be substring) * @param replacementText - Text to replace with * @param pageNumber - Optional page number to search (default: all pages) * @param firstOccurrenceOnly - Only replace first occurrence (default: false) * @param caseSensitive - Case-sensitive search (default: true) * @returns Array of replacement specifications with precise partial bounds */ export declare function findAndPrepareReplacements(filePath: string, searchText: string, replacementText: string, pageNumber?: number, firstOccurrenceOnly?: boolean, caseSensitive?: boolean): Promise>; /** * Replaces text at specific positions in a PDF document * * @param params - Replacement parameters * @returns Complete text replacement result * @throws Error if file cannot be processed or replacements fail */ export declare function replaceTextAtPosition(params: { filePath: string; replacements: Array<{ pageNumber: number; originalText: string; replacementText: string; bounds: { x: number; y: number; width: number; height: number; }; fontName?: string; fontSize?: number; color?: { r: number; g: number; b: number; }; rotation?: number; backgroundColor?: { r: number; g: number; b: number; }; }>; preserveFonts?: boolean; preserveColors?: boolean; outputPath?: string; createBackup?: boolean; }): Promise; /** * Tool handler for replace-text-at-position * Formats the result for MCP protocol */ export declare const replaceTextAtPositionToolHandler: (params: any) => Promise<{ content: { type: "text"; text: string; }[]; structuredContent: TextReplacementResult; }>; export {}; //# sourceMappingURL=replace-text-at-position.tool.d.ts.map