Fix tool registration: use @mcp.tool decorator without name arg

This commit is contained in:
2026-06-13 16:16:42 +00:00
parent fc58fd59ac
commit d910c1a817
+383 -494
View File
@@ -3,7 +3,6 @@ from __future__ import annotations
import json import json
import logging import logging
import os import os
import sys
from typing import Any from typing import Any
from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp import FastMCP
@@ -95,52 +94,55 @@ def make_server(
templates_dir=TEMPLATES_DIR, templates_dir=TEMPLATES_DIR,
) )
def wrap(fn, name: str): def require_allowed(tool_name: str):
def wrapper(**kwargs): def decorator(fn):
if not is_command_allowed(name, security_config): def wrapper(*args, **kwargs):
raise ValueError(f"Command '{name}' not allowed by security policy") if not is_command_allowed(tool_name, security_config):
return fn(**kwargs) raise ValueError(f"Command '{tool_name}' not allowed by security policy")
return fn(*args, **kwargs)
wrapper.__name__ = fn.__name__ wrapper.__name__ = fn.__name__
wrapper.__doc__ = fn.__doc__
return wrapper return wrapper
return decorator
# Core document operations @mcp.tool
mcp.tool()( @require_allowed("create_document")
wrap(lambda: provider.create_document(), "create_document"), def create_document():
name="create_document", """Create a new empty DOCX document"""
description="Create a new empty DOCX document", return provider.create_document()
)
mcp.tool()( @mcp.tool
wrap(lambda path: provider.open_document(path), "open_document"), @require_allowed("open_document")
name="open_document", def open_document(path: str):
description="Open an existing DOCX document", """Open an existing DOCX document"""
) return provider.open_document(path)
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_paragraph")
lambda document_id, text, style=None, return_content=False: provider.add_paragraph( def add_paragraph(document_id: str, text: str, style: dict | None = None, return_content: bool = False):
document_id, text, style or {}, return_content=return_content """Add a paragraph with optional styling to the document"""
), return provider.add_paragraph(document_id, text, style or {}, return_content=return_content)
"add_paragraph",
),
name="add_paragraph",
description="Add a paragraph with optional styling to the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_heading")
lambda document_id, text, level, return_content=False: provider.add_heading( def add_heading(document_id: str, text: str, level: int, return_content: bool = False):
document_id, text, level, return_content=return_content """Add a heading to the document"""
), return provider.add_heading(document_id, text, level, return_content=return_content)
"add_heading",
),
name="add_heading",
description="Add a heading to the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_table")
lambda document_id, rows, headers=None, border_style=None, col_widths=None, cell_shading=None, merges=None, return_content=False: provider.add_table( def add_table(
document_id: str,
rows: list[list[str]],
headers: list[str] | None = None,
border_style: str | None = None,
col_widths: list[int] | None = None,
cell_shading: str | None = None,
merges: list[dict] | None = None,
return_content: bool = False,
):
"""Add a table to the document"""
return provider.add_table(
document_id, document_id,
rows, rows,
headers=headers, headers=headers,
@@ -149,524 +151,411 @@ def make_server(
cell_shading=cell_shading, cell_shading=cell_shading,
merges=merges, merges=merges,
return_content=return_content, return_content=return_content,
),
"add_table",
),
name="add_table",
description="Add a table to the document",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_section_break")
lambda document_id, page_size=None, orientation=None, margins=None, return_content=False: provider.add_section_break( def add_section_break(
document_id: str,
page_size: str | None = None,
orientation: str | None = None,
margins: dict | None = None,
return_content: bool = False,
):
"""Insert a section break with optional page setup"""
return provider.add_section_break(
document_id, page_size, orientation, margins or {}, return_content=return_content document_id, page_size, orientation, margins or {}, return_content=return_content
),
"add_section_break",
),
name="add_section_break",
description="Insert a section break with optional page setup",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_list")
lambda document_id, items, ordered=False, return_content=False: provider.add_list( def add_list(document_id: str, items: list[str], ordered: bool = False, return_content: bool = False):
document_id, items, ordered, return_content=return_content """Add a bulleted or numbered list to the document"""
), return provider.add_list(document_id, items, ordered, return_content=return_content)
"add_list",
),
name="add_list",
description="Add a bulleted or numbered list to the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_list_item")
lambda document_id, text, level=0, ordered=False, return_content=False: provider.add_list_item( def add_list_item(document_id: str, text: str, level: int = 0, ordered: bool = False, return_content: bool = False):
document_id, text, level, ordered, return_content=return_content """Add a single list item with a specific level"""
), return provider.add_list_item(document_id, text, level, ordered, return_content=return_content)
"add_list_item",
),
name="add_list_item",
description="Add a single list item with a specific level",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_page_break")
lambda document_id, return_content=False: provider.add_page_break(document_id, return_content=return_content), def add_page_break(document_id: str, return_content: bool = False):
"add_page_break", """Add a page break to the document"""
), return provider.add_page_break(document_id, return_content=return_content)
name="add_page_break",
description="Add a page break to the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("insert_toc")
lambda document_id, from_level=1, to_level=3, right_align_dots=True, return_content=False: provider.insert_toc( def insert_toc(
document_id: str,
from_level: int = 1,
to_level: int = 3,
right_align_dots: bool = True,
return_content: bool = False,
):
"""Insert a Table of Contents placeholder"""
return provider.insert_toc(
document_id, from_level, to_level, right_align_dots, return_content=return_content document_id, from_level, to_level, right_align_dots, return_content=return_content
),
"insert_toc",
),
name="insert_toc",
description="Insert a Table of Contents placeholder",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("insert_bookmark_after_heading")
lambda document_id, heading_text, name, return_content=False: provider.insert_bookmark_after_heading( def insert_bookmark_after_heading(
document_id: str,
heading_text: str,
name: str,
return_content: bool = False,
):
"""Insert a bookmark immediately after the first matching heading"""
return provider.insert_bookmark_after_heading(
document_id, heading_text, name, return_content=return_content document_id, heading_text, name, return_content=return_content
),
"insert_bookmark_after_heading",
),
name="insert_bookmark_after_heading",
description="Insert a bookmark immediately after the first matching heading",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("set_header")
lambda document_id, text, return_content=False: provider.set_header(document_id, text, return_content=return_content), def set_header(document_id: str, text: str, return_content: bool = False):
"set_header", """Set the document header"""
), return provider.set_header(document_id, text, return_content=return_content)
name="set_header",
description="Set the document header",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("set_footer")
lambda document_id, text, return_content=False: provider.set_footer(document_id, text, return_content=return_content), def set_footer(document_id: str, text: str, return_content: bool = False):
"set_footer", """Set the document footer"""
), return provider.set_footer(document_id, text, return_content=return_content)
name="set_footer",
description="Set the document footer",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("set_page_numbering")
lambda document_id, location="footer", template=None, return_content=False: provider.set_page_numbering( def set_page_numbering(
document_id, location, template, return_content=return_content document_id: str,
), location: str = "footer",
"set_page_numbering", template: str | None = None,
), return_content: bool = False,
name="set_page_numbering", ):
description="Set a simple page numbering text in header or footer", """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
wrap( @require_allowed("embed_page_number_fields")
lambda document_id, return_content=False: provider.embed_page_number_fields(document_id, return_content=return_content), def embed_page_number_fields(document_id: str, return_content: bool = False):
"embed_page_number_fields", """Replace placeholder 'Page {PAGE} of {PAGES}' with Word field codes (best-effort)"""
), return provider.embed_page_number_fields(document_id, return_content=return_content)
name="embed_page_number_fields",
description="Replace placeholder 'Page {PAGE} of {PAGES}' with Word field codes (best-effort)",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("add_image")
lambda document_id, data_base64, width=None, height=None, alt_text=None, return_content=False: provider.add_image( def add_image(
document_id, data_base64, width, height, alt_text, return_content=return_content document_id: str,
), data_base64: str,
"add_image", width: int | None = None,
), height: int | None = None,
name="add_image", alt_text: str | None = None,
description="Insert an image into the document", return_content: bool = False,
) ):
"""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
wrap( @require_allowed("add_hyperlink")
lambda document_id, text, url, return_content=False: provider.add_hyperlink( def add_hyperlink(document_id: str, text: str, url: str, return_content: bool = False):
document_id, text, url, return_content=return_content """Insert a hyperlink into the document"""
), return provider.add_hyperlink(document_id, text, url, return_content=return_content)
"add_hyperlink",
),
name="add_hyperlink",
description="Insert a hyperlink into the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("find_and_replace")
lambda document_id, find_text, replace_text, return_content=False: provider.find_and_replace( def find_and_replace(document_id: str, find_text: str, replace_text: str, return_content: bool = False):
document_id, find_text, replace_text, return_content=return_content """Find and replace text in the document"""
), return provider.find_and_replace(document_id, find_text, replace_text, return_content=return_content)
"find_and_replace",
),
name="find_and_replace",
description="Find and replace text in the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("find_and_replace_advanced")
lambda document_id, pattern, replacement, case_sensitive=False, whole_word=False, use_regex=False, return_content=False: provider.find_and_replace_advanced( def find_and_replace_advanced(
document_id: str,
pattern: str,
replacement: str,
case_sensitive: bool = False,
whole_word: bool = False,
use_regex: bool = False,
return_content: bool = False,
):
"""Find/replace with regex, case, whole-word, preserving runs"""
return provider.find_and_replace_advanced(
document_id, pattern, replacement, case_sensitive, whole_word, use_regex, return_content=return_content document_id, pattern, replacement, case_sensitive, whole_word, use_regex, return_content=return_content
),
"find_and_replace_advanced",
),
name="find_and_replace_advanced",
description="Find/replace with regex, case, whole-word, preserving runs",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("apply_paragraph_format")
lambda document_id, contains=None, format=None, return_content=False: provider.apply_paragraph_format( def apply_paragraph_format(
document_id, contains, format or {}, return_content=return_content document_id: str,
), contains: str | None = None,
"apply_paragraph_format", format: dict | None = None,
), return_content: bool = False,
name="apply_paragraph_format", ):
description="Apply paragraph formatting to paragraphs matching a simple selector", """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
wrap( @require_allowed("extract_text")
lambda document_id: provider.extract_text(document_id), def extract_text(document_id: str):
"extract_text", """Extract all text content from the document"""
), return provider.extract_text(document_id)
name="extract_text",
description="Extract all text content from the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_tables")
lambda document_id: provider.get_tables(document_id), def get_tables(document_id: str):
"get_tables", """List tables with dimensions, merges, and cell content"""
), return provider.get_tables(document_id)
name="get_tables",
description="List tables with dimensions, merges, and cell content",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("list_images")
lambda document_id: provider.list_images(document_id), def list_images(document_id: str):
"list_images", """List images with width/height and alt text"""
), return provider.list_images(document_id)
name="list_images",
description="List images with width/height and alt text",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("list_hyperlinks")
lambda document_id: provider.list_hyperlinks(document_id), def list_hyperlinks(document_id: str):
"list_hyperlinks", """List hyperlinks in the document"""
), return provider.list_hyperlinks(document_id)
name="list_hyperlinks",
description="List hyperlinks in the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_fields_summary")
lambda document_id: provider.get_fields_summary(document_id), def get_fields_summary(document_id: str):
"get_fields_summary", """Summarize Word fields (PAGE, NUMPAGES, TOC) in document and headers/footers"""
), return provider.get_fields_summary(document_id)
name="get_fields_summary",
description="Summarize Word fields (PAGE, NUMPAGES, TOC) in document and headers/footers",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("strip_personal_info")
lambda document_id: provider.strip_personal_info(document_id), def strip_personal_info(document_id: str):
"strip_personal_info", """Remove personal info from metadata and core.xml (best-effort)"""
), return provider.strip_personal_info(document_id)
name="strip_personal_info",
description="Remove personal info from metadata and core.xml (best-effort)",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_metadata")
lambda document_id: provider.get_metadata(document_id), def get_metadata(document_id: str):
"get_metadata", """Get document metadata"""
), return provider.get_metadata(document_id)
name="get_metadata",
description="Get document metadata",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("save_document")
lambda document_id, output_path, return_content=True: provider.save_document( def save_document(document_id: str, output_path: str, return_content: bool = True):
document_id, output_path, return_content=return_content """Save the document to a specific path and return its content"""
), return provider.save_document(document_id, output_path, return_content=return_content)
"save_document",
),
name="save_document",
description="Save the document to a specific path and return its content",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("close_document")
lambda document_id: provider.close_document(document_id), def close_document(document_id: str):
"close_document", """Close the document and free resources"""
), return provider.close_document(document_id)
name="close_document",
description="Close the document and free resources",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("list_documents")
lambda: provider.list_documents(), def list_documents():
"list_documents", """List all open documents"""
), return provider.list_documents()
name="list_documents",
description="List all open documents",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("convert_to_pdf")
lambda document_id, output_path, prefer_external=False, return_content=True: provider.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
@require_allowed("export_pdf_with_field_refresh")
def export_pdf_with_field_refresh(
document_id: str,
output_path: str,
prefer_external: bool = True,
return_content: bool = True,
):
"""Embed page fields then export to PDF (hi-fidelity when available)"""
return provider.export_pdf_with_field_refresh(
document_id, output_path, prefer_external, return_content=return_content document_id, output_path, prefer_external, return_content=return_content
),
"convert_to_pdf",
),
name="convert_to_pdf",
description="Convert a DOCX document to PDF and return the file",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("convert_to_images")
lambda document_id, output_path, prefer_external=True, return_content=True: provider.export_pdf_with_field_refresh( def convert_to_images(
document_id, output_path, prefer_external, return_content=return_content document_id: str,
), output_dir: str,
"export_pdf_with_field_refresh", format: str = "png",
), dpi: int = 150,
name="export_pdf_with_field_refresh", return_content: bool = True,
description="Embed page fields then export to PDF (hi-fidelity when available)", ):
) """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
wrap( @require_allowed("convert_to_images_with_preference")
lambda document_id, output_dir, format="png", dpi=150, return_content=True: provider.convert_to_images( def convert_to_images_with_preference(
document_id, output_dir, format, dpi, return_content=return_content document_id: str,
), output_dir: str,
"convert_to_images", format: str = "png",
), dpi: int = 150,
name="convert_to_images", prefer_external: bool = True,
description="Convert a DOCX document to images (one per page) and return them", return_content: bool = True,
) ):
"""Convert DOCX to images, preferring external hi-fidelity path"""
mcp.tool()( return provider.convert_to_images_with_preference(
wrap(
lambda document_id, output_dir, format="png", dpi=150, prefer_external=True, return_content=True: provider.convert_to_images_with_preference(
document_id, output_dir, format, dpi, prefer_external, return_content=return_content document_id, output_dir, format, dpi, prefer_external, return_content=return_content
),
"convert_to_images_with_preference",
),
name="convert_to_images_with_preference",
description="Convert DOCX to images, preferring external hi-fidelity path",
) )
mcp.tool()( @mcp.tool
wrap( @require_allowed("merge_documents")
lambda document_ids, output_path, return_content=True: provider.merge_documents( def merge_documents(document_ids: list[str], output_path: str, return_content: bool = True):
document_ids, output_path, return_content=return_content """Merge multiple DOCX documents into one and return the result"""
), return provider.merge_documents(document_ids, output_path, return_content=return_content)
"merge_documents",
),
name="merge_documents",
description="Merge multiple DOCX documents into one and return the result",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("split_document")
lambda document_id, output_dir, return_content=True: provider.split_document( def split_document(document_id: str, output_dir: str, return_content: bool = True):
document_id, output_dir, return_content=return_content """Split a document at page breaks and return parts"""
), return provider.split_document(document_id, output_dir, return_content=return_content)
"split_document",
),
name="split_document",
description="Split a document at page breaks and return parts",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_document_structure")
lambda document_id: provider.get_document_structure(document_id), def get_document_structure(document_id: str):
"get_document_structure", """Get the structural overview of the document (headings, sections, etc.)"""
), return provider.get_document_structure(document_id)
name="get_document_structure",
description="Get the structural overview of the document (headings, sections, etc.)",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_outline")
lambda document_id: provider.get_outline(document_id), def get_outline(document_id: str):
"get_outline", """Return heading outline with range_ids"""
), return provider.get_outline(document_id)
name="get_outline",
description="Return heading outline with range_ids",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_ranges")
lambda document_id, selector: provider.get_ranges(document_id, selector), def get_ranges(document_id: str, selector: str):
"get_ranges", """Resolve a selector to range_ids"""
), return provider.get_ranges(document_id, selector)
name="get_ranges",
description="Resolve a selector to range_ids",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("replace_range_text")
lambda document_id, range_id, text, return_content=False: provider.replace_range_text( def replace_range_text(document_id: str, range_id: dict, text: str, return_content: bool = False):
document_id, range_id, text, return_content=return_content """Replace text in a paragraph/heading by range_id"""
), return provider.replace_range_text(document_id, range_id, text, return_content=return_content)
"replace_range_text",
),
name="replace_range_text",
description="Replace text in a paragraph/heading by range_id",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("set_table_cell_text")
lambda document_id, table_index, row, col, text, return_content=False: provider.set_table_cell_text( def set_table_cell_text(
document_id, table_index, row, col, text, return_content=return_content document_id: str,
), table_index: int,
"set_table_cell_text", row: int,
), col: int,
name="set_table_cell_text", text: str,
description="Set text in a table cell by indices", return_content: bool = False,
) ):
"""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
wrap( @require_allowed("get_document_properties")
lambda document_id: provider.get_document_properties(document_id), def get_document_properties(document_id: str):
"get_document_properties", """Get document properties (title, subject, author, timestamps)"""
), return provider.get_document_properties(document_id)
name="get_document_properties",
description="Get document properties (title, subject, author, timestamps)",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("set_document_properties")
lambda document_id, title=None, subject=None, author=None, return_content=False: provider.set_document_properties( def set_document_properties(
document_id, title, subject, author, return_content=return_content document_id: str,
), title: str | None = None,
"set_document_properties", subject: str | None = None,
), author: str | None = None,
name="set_document_properties", return_content: bool = False,
description="Set document properties (title, subject, author)", ):
) """Set document properties (title, subject, author)"""
return provider.set_document_properties(document_id, title, subject, author, return_content=return_content)
mcp.tool()( @mcp.tool
wrap( @require_allowed("insert_after_heading")
lambda document_id, heading_text, text, return_content=False: provider.insert_after_heading( def insert_after_heading(document_id: str, heading_text: str, text: str, return_content: bool = False):
document_id, heading_text, text, return_content=return_content """Insert a paragraph after the first heading that matches text"""
), return provider.insert_after_heading(document_id, heading_text, text, return_content=return_content)
"insert_after_heading",
),
name="insert_after_heading",
description="Insert a paragraph after the first heading that matches text",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("sanitize_external_links")
lambda document_id: provider.sanitize_external_links(document_id), def sanitize_external_links(document_id: str):
"sanitize_external_links", """Remove external hyperlinks (http/https)"""
), return provider.sanitize_external_links(document_id)
name="sanitize_external_links",
description="Remove external hyperlinks (http/https)",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("redact_text")
lambda document_id, pattern, use_regex=False, whole_word=False, case_sensitive=False, return_content=False: provider.redact_text( def redact_text(
document_id, pattern, use_regex, whole_word, case_sensitive, return_content=return_content document_id: str,
), pattern: str,
"redact_text", use_regex: bool = False,
), whole_word: bool = False,
name="redact_text", case_sensitive: bool = False,
description="Redact text using regex/whole-word with █ character", return_content: bool = False,
) ):
"""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
wrap( @require_allowed("analyze_formatting")
lambda document_id: provider.analyze_formatting(document_id), def analyze_formatting(document_id: str):
"analyze_formatting", """Analyze the formatting used throughout the document"""
), return provider.analyze_formatting(document_id)
name="analyze_formatting",
description="Analyze the formatting used throughout the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_word_count")
lambda document_id: provider.get_word_count(document_id), def get_word_count(document_id: str):
"get_word_count", """Get detailed word count statistics for the document"""
), return provider.get_word_count(document_id)
name="get_word_count",
description="Get detailed word count statistics for the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("search_text")
lambda document_id, search_term, case_sensitive=False, whole_word=False: provider.search_text( def search_text(document_id: str, search_term: str, case_sensitive: bool = False, whole_word: bool = False):
document_id, search_term, case_sensitive, whole_word """Search for text patterns in the document"""
), return provider.search_text(document_id, search_term, case_sensitive, whole_word)
"search_text",
),
name="search_text",
description="Search for text patterns in the document",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("export_to_markdown")
lambda document_id, output_path, return_content=True: provider.export_to_markdown( def export_to_markdown(document_id: str, output_path: str, return_content: bool = True):
document_id, output_path, return_content=return_content """Export document content to Markdown format and return the file"""
), return provider.export_to_markdown(document_id, output_path, return_content=return_content)
"export_to_markdown",
),
name="export_to_markdown",
description="Export document content to Markdown format and return the file",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("export_to_html")
lambda document_id, output_path, return_content=True: provider.export_to_html( def export_to_html(document_id: str, output_path: str, return_content: bool = True):
document_id, output_path, return_content=return_content """Export document content to HTML format and return the file"""
), return provider.export_to_html(document_id, output_path, return_content=return_content)
"export_to_html",
),
name="export_to_html",
description="Export document content to HTML format and return the file",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_security_info")
lambda: provider.get_security_info(), def get_security_info():
"get_security_info", """Get information about current security settings and restrictions"""
), return provider.get_security_info()
name="get_security_info",
description="Get information about current security settings and restrictions",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("get_storage_info")
lambda: provider.get_storage_info(), def get_storage_info():
"get_storage_info", """Get information about temporary storage usage"""
), return provider.get_storage_info()
name="get_storage_info",
description="Get information about temporary storage usage",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("list_templates")
lambda: list_templates(TEMPLATES_DIR), def list_templates():
"list_templates", """List available document templates from the templates directory"""
), return list_templates(TEMPLATES_DIR)
name="list_templates",
description="List available document templates from the templates directory",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("open_template")
lambda name: provider.open_template(name, TEMPLATES_DIR), def open_template(name: str):
"open_template", """Open a template document by name from the templates directory"""
), return provider.open_template(name, TEMPLATES_DIR)
name="open_template",
description="Open a template document by name from the templates directory",
)
mcp.tool()( @mcp.tool
wrap( @require_allowed("generate_from_template")
lambda template_name, output_path, fields=None, return_content=True: provider.generate_from_template( def generate_from_template(
template_name: str,
output_path: str,
fields: dict | None = None,
return_content: bool = True,
):
"""Generate a new document from a template and return the file"""
return provider.generate_from_template(
template_name, output_path, fields or {}, return_content=return_content template_name, output_path, fields or {}, return_content=return_content
),
"generate_from_template",
),
name="generate_from_template",
description="Generate a new document from a template and return the file",
) )
return mcp return mcp