MCP server exposing GroupDocs.Watermark for .NET as AI-callable tools (AddWatermark, AddImageWatermark, SearchWatermarks, RemoveWatermarks, GetDocumentInfo) for Claude, Cursor, GitHub Copilot, and other MCP agents.
Five tools with complete input schemas and detailed descriptions. All tools have verb-noun naming (AddWatermark, SearchWatermarks, etc.) and descriptions 150-400 chars explaining WHAT, WHEN, and error behavior. Parameters include types, descriptions, and sensible defaults (fontSize=36, rotation=-45, opacity=0.5). Output schemas documented in descriptions (JSON with count/watermarks, fileType/pageCount, etc.). However, no tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite clear risk levels (WRITE, DESTRUCTIVE, READ_ONLY). Error handling describes failure message format but lacks recovery guidance. No enum constraints for password-protected documents or file formats. Descriptions are verbose and include implementation details ('response text starts with...') rather than user-focused guidance.
Adds an image watermark (e.g. company logo, signature scan, stamp) to a document and saves the watermarked file. Supports PDF, DOCX, XLSX, PPTX, PNG, JPG, and 50+ more document and image formats as the target. The watermark source image can be PNG, JPG, BMP, or TIFF, resolved from the same storage as the target. Call this tool whenever the user asks to add an image / logo / stamp watermark, or to overlay an image on a document. Do NOT pre-check whether files exist — just pass the filenames the user provided. Returns a saved-path message ('Added image watermark from "<image>" to "<file>"') and the download URL or storage path. On failure, the response text starts with 'Image watermarking failed for' followed by the underlying exception type, message, and inner-exception chain.
Adds a text watermark to a document and saves the watermarked file to storage. Supports PDF, DOCX, XLSX, PPTX, PNG, JPG, and 50+ more document and image formats. Call this tool immediately whenever the user asks to add a watermark, stamp text onto a document, or mark a document as draft/confidential. Do NOT pre-check whether files exist — just pass the filename the user provided. Returns a saved-path message ('Added text watermark "<text>" to "<file>"') and the download URL or storage path. On failure, the response text starts with 'Watermarking failed for' followed by the underlying exception type, message, and inner-exception chain.
Returns the file type, page count, and format-specific properties of a document as JSON. Supports PDF, DOCX, XLSX, PPTX, PNG, JPG, and 50+ more document and image formats. Call this tool whenever the user asks about the structure of a document — page count, dimensions, file type — without modifying it. Useful as a precondition check before AddWatermark / SearchWatermarks (e.g. 'how many pages does this PDF have?'). Do NOT pre-check whether the file exists — just pass the filename the user provided. Returns a JSON object with fields `fileType` (engine-reported format name), `fileFormat` (extension), `size` (bytes), `pageCount`, and `pages` (array of `{ number, width, height }` per page). On failure, the response text starts with 'Document-info lookup failed for' followed by the underlying exception type, message, and inner-exception chain.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite explicit risk levels. RemoveWatermarks is DESTRUCTIVE but lacks annotation; SearchWatermarks is READ_ONLY but unmarked. LLMs cannot infer safety constraints from risk labels alone.
Error handling describes failure message format ('response text starts with...') but provides no recovery guidance. LLMs cannot determine whether to retry, ask user, or abort. E.g., 'Watermarking failed for [exception]' tells agent nothing actionable.
Descriptions include implementation details ('response text starts with', 'underlying exception type, message, and inner-exception chain') instead of user-focused guidance. Verbose and technical; should focus on WHEN to call and WHAT to expect.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | <=2025-11-25 | v2 |
Removes existing watermarks from a document and saves the cleaned copy as '<name>_unwatermarked.<ext>'. Supports PDF, DOCX, XLSX, PPTX, PNG, JPG, and 50+ more document and image formats. Call this tool whenever the user asks to remove / strip / clean / delete watermarks from a document. If `textFilter` is supplied, only watermarks whose text contains that substring (case-insensitive) are removed; otherwise ALL watermarks are removed. Do NOT pre-check whether the file exists — just pass the filename the user provided. Returns a saved-path message ('Removed <N> watermark(s) from "<file>"') and the download URL or storage path. If no matching watermarks are found, the original document is saved unchanged with a message starting 'No matching watermarks found in'. On failure, the response text starts with 'Watermark removal failed for' followed by the underlying exception type, message, and inner-exception chain.
Searches for watermarks in a document and returns their details as JSON. Supports PDF, DOCX, XLSX, PPTX, PNG, JPG, and 50+ more document and image formats. Call this tool immediately whenever the user asks to search for watermarks, find watermarks, list watermarks, or check if a document has watermarks. Do NOT pre-check whether files exist — just pass the filename the user provided. Returns a JSON object with fields `count` (number of watermarks found) and `watermarks` (array with `type` ("text"|"image"), `text`, `page`, `x`, `y`, `width`, `height`, `rotateAngle` per watermark). On failure, the response text starts with 'Search failed for' followed by the underlying exception type, message, and inner-exception chain.
Password parameter is nullable but no guidance on when it is required vs optional. Descriptions say 'Password for protected documents' but do not clarify: Is it required only if document is encrypted? What error occurs if omitted for a protected file?
RemoveWatermarks textFilter parameter is optional but behavior differs: omit to remove ALL watermarks vs supply substring to filter. This conditional logic is documented but not enforced via schema. LLMs may misuse.