diff --git a/src/server.py b/src/server.py index d7c51cd..98a7476 100644 --- a/src/server.py +++ b/src/server.py @@ -105,31 +105,31 @@ def make_server( return wrapper return decorator - @mcp.tool + @mcp.tool() @require_allowed("create_document") def create_document(): """Create a new empty DOCX document""" return provider.create_document() - @mcp.tool + @mcp.tool() @require_allowed("open_document") def open_document(path: str): """Open an existing DOCX document""" return provider.open_document(path) - @mcp.tool + @mcp.tool() @require_allowed("add_paragraph") def add_paragraph(document_id: str, text: str, style: dict | None = None, return_content: bool = False): """Add a paragraph with optional styling to the document""" return provider.add_paragraph(document_id, text, style or {}, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("add_heading") def add_heading(document_id: str, text: str, level: int, return_content: bool = False): """Add a heading to the document""" return provider.add_heading(document_id, text, level, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("add_table") def add_table( document_id: str, @@ -153,7 +153,7 @@ def make_server( return_content=return_content, ) - @mcp.tool + @mcp.tool() @require_allowed("add_section_break") def add_section_break( document_id: str, @@ -167,25 +167,25 @@ def make_server( document_id, page_size, orientation, margins or {}, return_content=return_content ) - @mcp.tool + @mcp.tool() @require_allowed("add_list") def add_list(document_id: str, items: list[str], ordered: bool = False, return_content: bool = False): """Add a bulleted or numbered list to the document""" return provider.add_list(document_id, items, ordered, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("add_list_item") def add_list_item(document_id: str, text: str, level: int = 0, ordered: bool = False, return_content: bool = False): """Add a single list item with a specific level""" return provider.add_list_item(document_id, text, level, ordered, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("add_page_break") def add_page_break(document_id: str, return_content: bool = False): """Add a page break to the document""" return provider.add_page_break(document_id, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("insert_toc") def insert_toc( document_id: str, @@ -199,7 +199,7 @@ def make_server( document_id, from_level, to_level, right_align_dots, return_content=return_content ) - @mcp.tool + @mcp.tool() @require_allowed("insert_bookmark_after_heading") def insert_bookmark_after_heading( document_id: str, @@ -212,19 +212,19 @@ def make_server( document_id, heading_text, name, return_content=return_content ) - @mcp.tool + @mcp.tool() @require_allowed("set_header") def set_header(document_id: str, text: str, return_content: bool = False): """Set the document header""" return provider.set_header(document_id, text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("set_footer") def set_footer(document_id: str, text: str, return_content: bool = False): """Set the document footer""" return provider.set_footer(document_id, text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("set_page_numbering") def set_page_numbering( document_id: str, @@ -235,13 +235,13 @@ def make_server( """Set a simple page numbering text in header or footer""" return provider.set_page_numbering(document_id, location, template, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("embed_page_number_fields") def embed_page_number_fields(document_id: str, return_content: bool = False): """Replace placeholder 'Page {PAGE} of {PAGES}' with Word field codes (best-effort)""" return provider.embed_page_number_fields(document_id, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("add_image") def add_image( document_id: str, @@ -254,19 +254,19 @@ def make_server( """Insert an image into the document""" return provider.add_image(document_id, data_base64, width, height, alt_text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("add_hyperlink") def add_hyperlink(document_id: str, text: str, url: str, return_content: bool = False): """Insert a hyperlink into the document""" return provider.add_hyperlink(document_id, text, url, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("find_and_replace") def find_and_replace(document_id: str, find_text: str, replace_text: str, return_content: bool = False): """Find and replace text in the document""" return provider.find_and_replace(document_id, find_text, replace_text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("find_and_replace_advanced") def find_and_replace_advanced( document_id: str, @@ -282,7 +282,7 @@ def make_server( document_id, pattern, replacement, case_sensitive, whole_word, use_regex, return_content=return_content ) - @mcp.tool + @mcp.tool() @require_allowed("apply_paragraph_format") def apply_paragraph_format( document_id: str, @@ -293,73 +293,73 @@ def make_server( """Apply paragraph formatting to paragraphs matching a simple selector""" return provider.apply_paragraph_format(document_id, contains, format or {}, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("extract_text") def extract_text(document_id: str): """Extract all text content from the document""" return provider.extract_text(document_id) - @mcp.tool + @mcp.tool() @require_allowed("get_tables") def get_tables(document_id: str): """List tables with dimensions, merges, and cell content""" return provider.get_tables(document_id) - @mcp.tool + @mcp.tool() @require_allowed("list_images") def list_images(document_id: str): """List images with width/height and alt text""" return provider.list_images(document_id) - @mcp.tool + @mcp.tool() @require_allowed("list_hyperlinks") def list_hyperlinks(document_id: str): """List hyperlinks in the document""" return provider.list_hyperlinks(document_id) - @mcp.tool + @mcp.tool() @require_allowed("get_fields_summary") def get_fields_summary(document_id: str): """Summarize Word fields (PAGE, NUMPAGES, TOC) in document and headers/footers""" return provider.get_fields_summary(document_id) - @mcp.tool + @mcp.tool() @require_allowed("strip_personal_info") def strip_personal_info(document_id: str): """Remove personal info from metadata and core.xml (best-effort)""" return provider.strip_personal_info(document_id) - @mcp.tool + @mcp.tool() @require_allowed("get_metadata") def get_metadata(document_id: str): """Get document metadata""" return provider.get_metadata(document_id) - @mcp.tool + @mcp.tool() @require_allowed("save_document") def save_document(document_id: str, output_path: str, return_content: bool = True): """Save the document to a specific path and return its content""" return provider.save_document(document_id, output_path, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("close_document") def close_document(document_id: str): """Close the document and free resources""" return provider.close_document(document_id) - @mcp.tool + @mcp.tool() @require_allowed("list_documents") def list_documents(): """List all open documents""" return provider.list_documents() - @mcp.tool + @mcp.tool() @require_allowed("convert_to_pdf") def convert_to_pdf(document_id: str, output_path: str, prefer_external: bool = False, return_content: bool = True): """Convert a DOCX document to PDF and return the file""" return provider.convert_to_pdf(document_id, output_path, prefer_external, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("export_pdf_with_field_refresh") def export_pdf_with_field_refresh( document_id: str, @@ -372,7 +372,7 @@ def make_server( document_id, output_path, prefer_external, return_content=return_content ) - @mcp.tool + @mcp.tool() @require_allowed("convert_to_images") def convert_to_images( document_id: str, @@ -384,7 +384,7 @@ def make_server( """Convert a DOCX document to images (one per page) and return them""" return provider.convert_to_images(document_id, output_dir, format, dpi, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("convert_to_images_with_preference") def convert_to_images_with_preference( document_id: str, @@ -399,43 +399,43 @@ def make_server( document_id, output_dir, format, dpi, prefer_external, return_content=return_content ) - @mcp.tool + @mcp.tool() @require_allowed("merge_documents") def merge_documents(document_ids: list[str], output_path: str, return_content: bool = True): """Merge multiple DOCX documents into one and return the result""" return provider.merge_documents(document_ids, output_path, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("split_document") def split_document(document_id: str, output_dir: str, return_content: bool = True): """Split a document at page breaks and return parts""" return provider.split_document(document_id, output_dir, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("get_document_structure") def get_document_structure(document_id: str): """Get the structural overview of the document (headings, sections, etc.)""" return provider.get_document_structure(document_id) - @mcp.tool + @mcp.tool() @require_allowed("get_outline") def get_outline(document_id: str): """Return heading outline with range_ids""" return provider.get_outline(document_id) - @mcp.tool + @mcp.tool() @require_allowed("get_ranges") def get_ranges(document_id: str, selector: str): """Resolve a selector to range_ids""" return provider.get_ranges(document_id, selector) - @mcp.tool + @mcp.tool() @require_allowed("replace_range_text") def replace_range_text(document_id: str, range_id: dict, text: str, return_content: bool = False): """Replace text in a paragraph/heading by range_id""" return provider.replace_range_text(document_id, range_id, text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("set_table_cell_text") def set_table_cell_text( document_id: str, @@ -448,13 +448,13 @@ def make_server( """Set text in a table cell by indices""" return provider.set_table_cell_text(document_id, table_index, row, col, text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("get_document_properties") def get_document_properties(document_id: str): """Get document properties (title, subject, author, timestamps)""" return provider.get_document_properties(document_id) - @mcp.tool + @mcp.tool() @require_allowed("set_document_properties") def set_document_properties( document_id: str, @@ -466,19 +466,19 @@ def make_server( """Set document properties (title, subject, author)""" return provider.set_document_properties(document_id, title, subject, author, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("insert_after_heading") def insert_after_heading(document_id: str, heading_text: str, text: str, return_content: bool = False): """Insert a paragraph after the first heading that matches text""" return provider.insert_after_heading(document_id, heading_text, text, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("sanitize_external_links") def sanitize_external_links(document_id: str): """Remove external hyperlinks (http/https)""" return provider.sanitize_external_links(document_id) - @mcp.tool + @mcp.tool() @require_allowed("redact_text") def redact_text( document_id: str, @@ -491,61 +491,61 @@ def make_server( """Redact text using regex/whole-word with █ character""" return provider.redact_text(document_id, pattern, use_regex, whole_word, case_sensitive, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("analyze_formatting") def analyze_formatting(document_id: str): """Analyze the formatting used throughout the document""" return provider.analyze_formatting(document_id) - @mcp.tool + @mcp.tool() @require_allowed("get_word_count") def get_word_count(document_id: str): """Get detailed word count statistics for the document""" return provider.get_word_count(document_id) - @mcp.tool + @mcp.tool() @require_allowed("search_text") def search_text(document_id: str, search_term: str, case_sensitive: bool = False, whole_word: bool = False): """Search for text patterns in the document""" return provider.search_text(document_id, search_term, case_sensitive, whole_word) - @mcp.tool + @mcp.tool() @require_allowed("export_to_markdown") def export_to_markdown(document_id: str, output_path: str, return_content: bool = True): """Export document content to Markdown format and return the file""" return provider.export_to_markdown(document_id, output_path, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("export_to_html") def export_to_html(document_id: str, output_path: str, return_content: bool = True): """Export document content to HTML format and return the file""" return provider.export_to_html(document_id, output_path, return_content=return_content) - @mcp.tool + @mcp.tool() @require_allowed("get_security_info") def get_security_info(): """Get information about current security settings and restrictions""" return provider.get_security_info() - @mcp.tool + @mcp.tool() @require_allowed("get_storage_info") def get_storage_info(): """Get information about temporary storage usage""" return provider.get_storage_info() - @mcp.tool + @mcp.tool() @require_allowed("list_templates") def list_templates(): """List available document templates from the templates directory""" return list_templates(TEMPLATES_DIR) - @mcp.tool + @mcp.tool() @require_allowed("open_template") def open_template(name: str): """Open a template document by name from the templates directory""" return provider.open_template(name, TEMPLATES_DIR) - @mcp.tool + @mcp.tool() @require_allowed("generate_from_template") def generate_from_template( template_name: str,