Fix tool registration: use @mcp.tool decorator without name arg
This commit is contained in:
+383
-494
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user