Skip to main content
Glama
09-improve-mcp-tool.md•19.6 kB
# MCP Tools Improvement: Document Path Parameter ## Overview This document outlines a comprehensive improvement plan for the SafeMarkdownEditor MCP tools by adding a `document_path` parameter as the first parameter to all document editing tools. This enhancement will enable: - **Stateless operations**: Execute actions on documents without requiring persistent server state - **Multi-document support**: Work with multiple documents simultaneously - **Better scalability**: Reduce memory usage by avoiding persistent document loading - **Improved reliability**: Eliminate race conditions from shared state ## Current Architecture Issues ### State Management Problems 1. **Shared State**: The current server maintains a single `self.editor` instance and `self.current_file_path` 2. **Threading Issues**: While the server uses locks, it creates potential bottlenecks 3. **Memory Usage**: Documents remain loaded in memory until replaced 4. **Concurrency Limitations**: Only one document can be active at a time per server instance ### Current Tool Categories **File Operations (3 tools):** - `load_document(file_path, validation_level)` - `save_document(file_path?, backup)` - `get_file_info()` - `test_path_resolution(path)` **Document Editing (8 tools):** - `insert_section(heading, content, position)` - `delete_section(section_id?, heading?)` - `update_section(section_id, content)` - `move_section(section_id, new_position)` - `get_section(section_id)` - `list_sections()` - `get_document()` - `undo()` ## Proposed Improvements ### Core Design Principle Add `document_path: str` as the **first parameter** to all tools that operate on document content, making operations stateless and enabling one-call document manipulation. ### Tool-by-Tool Enhancement Plan #### 1. File Operations Enhancement **Current:** ```python @mcp.tool() def load_document(file_path: str, validation_level: str = "NORMAL") -> Dict[str, Any]: """Load a Markdown document from a file path.""" ``` **Improved:** ```python @mcp.tool() def load_document(document_path: str, validation_level: str = "NORMAL") -> Dict[str, Any]: """Load and return information about a Markdown document. Args: document_path: Path to the Markdown document to analyze validation_level: Validation strictness - "STRICT", "NORMAL", or "PERMISSIVE" Returns: Document metadata, section count, validation results, and content preview """ ``` **New Capabilities:** - Returns document information without persistent loading - Validates document structure - Provides content preview and statistics - No server state modification #### 2. Document Editing Tools Enhancement **A. Insert Section** **Current:** ```python def insert_section(heading: str, content: str, position: int) -> Dict[str, Any]: ``` **Improved:** ```python def insert_section(document_path: str, heading: str, content: str, position: int, auto_save: bool = True, backup: bool = True, validation_level: str = "NORMAL") -> Dict[str, Any]: """Insert a new section into a document at the specified position. Args: document_path: Path to the target Markdown document heading: The section heading text content: The section content (supports Markdown) position: Insert position (0=beginning, -1=end, or after section N) auto_save: Whether to save changes automatically backup: Whether to create a backup before modifying validation_level: Document validation level Returns: Operation result with new section ID and updated document preview """ ``` **B. Delete Section** **Current:** ```python def delete_section(section_id: Optional[str] = None, heading: Optional[str] = None) -> Dict[str, Any]: ``` **Improved:** ```python def delete_section(document_path: str, section_id: Optional[str] = None, heading: Optional[str] = None, cascade: bool = True, auto_save: bool = True, backup: bool = True) -> Dict[str, Any]: """Delete a section from a document by ID or heading. Args: document_path: Path to the target Markdown document section_id: Unique section identifier (optional) heading: Section heading text to match (optional) cascade: Whether to delete subsections as well auto_save: Whether to save changes automatically backup: Whether to create a backup before modifying Note: Either section_id or heading must be provided """ ``` **C. Update Section** **Current:** ```python def update_section(section_id: str, content: str) -> Dict[str, Any]: ``` **Improved:** ```python def update_section(document_path: str, section_id: str, content: str, preserve_subsections: bool = True, auto_save: bool = True, backup: bool = True, merge_strategy: str = "replace") -> Dict[str, Any]: """Update the content of an existing section. Args: document_path: Path to the target Markdown document section_id: Unique section identifier content: New content for the section preserve_subsections: Whether to keep existing subsections auto_save: Whether to save changes automatically backup: Whether to create a backup before modifying merge_strategy: How to handle content ("replace", "append", "prepend") """ ``` **D. Move Section** **Current:** ```python def move_section(section_id: str, new_position: int) -> Dict[str, Any]: ``` **Improved:** ```python def move_section(document_path: str, section_id: str, new_position: int, auto_save: bool = True, backup: bool = True, adjust_levels: bool = True) -> Dict[str, Any]: """Move a section to a new position within the document. Args: document_path: Path to the target Markdown document section_id: Unique section identifier new_position: Target position (0-based, -1 for end) auto_save: Whether to save changes automatically backup: Whether to create a backup before modifying adjust_levels: Whether to adjust heading levels for better structure """ ``` **E. Get Section** **Current:** ```python def get_section(section_id: str) -> Dict[str, Any]: ``` **Improved:** ```python def get_section(document_path: str, section_id: Optional[str] = None, heading: Optional[str] = None, include_subsections: bool = False, format: str = "markdown") -> Dict[str, Any]: """Retrieve a section's content and metadata from a document. Args: document_path: Path to the target Markdown document section_id: Unique section identifier (optional) heading: Section heading to match (optional) include_subsections: Whether to include nested subsections format: Output format ("markdown", "plain", "html") Note: Either section_id or heading must be provided """ ``` **F. List Sections** **Current:** ```python def list_sections() -> Dict[str, Any]: ``` **Improved:** ```python def list_sections(document_path: str, include_content_preview: bool = False, max_depth: Optional[int] = None, filter_pattern: Optional[str] = None) -> Dict[str, Any]: """List all sections in a document with their metadata. Args: document_path: Path to the target Markdown document include_content_preview: Whether to include content preview for each section max_depth: Maximum heading depth to include (None for all) filter_pattern: Regex pattern to filter section headings """ ``` **G. Get Document** **Current:** ```python def get_document() -> Dict[str, Any]: ``` **Improved:** ```python def get_document(document_path: str, format: str = "markdown", include_metadata: bool = False, sections_only: bool = False) -> Dict[str, Any]: """Retrieve the complete document content and metadata. Args: document_path: Path to the target Markdown document format: Output format ("markdown", "html", "plain", "json") include_metadata: Whether to include document metadata sections_only: Whether to return only section structure """ ``` #### 3. New Advanced Tools **A. Batch Operations** ```python def batch_operations(document_path: str, operations: List[Dict[str, Any]], auto_save: bool = True, backup: bool = True, atomic: bool = True) -> Dict[str, Any]: """Execute multiple operations on a document atomically. Args: document_path: Path to the target Markdown document operations: List of operations to execute auto_save: Whether to save changes automatically backup: Whether to create a backup before modifying atomic: Whether to rollback all changes if any operation fails Example operations: [ {"action": "insert_section", "heading": "New Section", "content": "...", "position": 1}, {"action": "update_section", "section_id": "sec_123", "content": "..."}, {"action": "delete_section", "section_id": "sec_456"} ] """ ``` **B. Document Analysis** ```python def analyze_document(document_path: str, analysis_types: List[str] = ["structure", "content", "links"]) -> Dict[str, Any]: """Perform comprehensive analysis of a document. Args: document_path: Path to the target Markdown document analysis_types: Types of analysis to perform - "structure": Heading hierarchy and document structure - "content": Word count, reading time, language detection - "links": Internal/external links analysis - "images": Image references and accessibility - "tables": Table structure and formatting - "code": Code blocks and syntax highlighting """ ``` **C. Document Transformation** ```python def transform_document(document_path: str, transformations: List[Dict[str, Any]], output_path: Optional[str] = None, backup: bool = True) -> Dict[str, Any]: """Apply structural transformations to a document. Args: document_path: Path to the source Markdown document transformations: List of transformation rules output_path: Path for the transformed document (None to overwrite) backup: Whether to create a backup before modifying Example transformations: [ {"action": "normalize_headings", "start_level": 1}, {"action": "add_toc", "position": 1, "max_depth": 3}, {"action": "auto_number_sections", "format": "1.1.1"}, {"action": "reorder_sections", "order": ["introduction", "methods", "results"]} ] """ ``` #### 4. Multi-Document Operations **A. Document Comparison** ```python def compare_documents(document_path_1: str, document_path_2: str, comparison_type: str = "structure", output_format: str = "diff") -> Dict[str, Any]: """Compare two documents and return differences. Args: document_path_1: Path to the first document document_path_2: Path to the second document comparison_type: Type of comparison ("structure", "content", "both") output_format: Format for differences ("diff", "json", "markdown") """ ``` **B. Document Merging** ```python def merge_documents(document_paths: List[str], output_path: str, merge_strategy: str = "sequential", conflict_resolution: str = "manual") -> Dict[str, Any]: """Merge multiple documents into one. Args: document_paths: List of paths to documents to merge output_path: Path for the merged document merge_strategy: How to merge ("sequential", "interleaved", "by_section") conflict_resolution: How to handle conflicts ("manual", "first_wins", "last_wins") """ ``` ### Implementation Architecture #### 1. Core Engine Modification **Current State Manager:** ```python class MarkdownMCPServer: def __init__(self): self.editor: Optional[SafeMarkdownEditor] = None self.current_file_path: Optional[Path] = None self.lock = threading.RLock() ``` **Proposed Stateless Engine:** ```python class StatelessMarkdownProcessor: """Stateless processor for Markdown operations.""" @staticmethod def load_and_process(document_path: str, operation: Callable, validation_level: ValidationLevel = ValidationLevel.NORMAL, **kwargs) -> Dict[str, Any]: """Load a document, perform an operation, and optionally save.""" @staticmethod def create_editor(document_path: str, validation_level: ValidationLevel) -> SafeMarkdownEditor: """Create a temporary editor instance for a document.""" @staticmethod def save_if_requested(editor: SafeMarkdownEditor, document_path: str, auto_save: bool, backup: bool) -> Dict[str, Any]: """Save document if auto_save is enabled.""" ``` #### 2. Backward Compatibility **Legacy Mode Support:** ```python class MarkdownMCPServer: def __init__(self, legacy_mode: bool = True): self.legacy_mode = legacy_mode if legacy_mode: # Keep existing stateful behavior for backward compatibility self.editor = None self.current_file_path = None ``` **Parameter Detection:** ```python def _is_legacy_call(self, **kwargs) -> bool: """Detect if this is a legacy call without document_path.""" return 'document_path' not in kwargs def _handle_legacy_operation(self, operation_name: str, **kwargs): """Handle operations in legacy mode with shared state.""" ``` #### 3. Enhanced Error Handling **Comprehensive Error Types:** ```python class DocumentOperationError(Exception): """Base class for document operation errors.""" class DocumentNotFoundError(DocumentOperationError): """Document file not found or not accessible.""" class ValidationError(DocumentOperationError): """Document validation failed.""" class SectionNotFoundError(DocumentOperationError): """Requested section not found in document.""" class PermissionError(DocumentOperationError): """Insufficient permissions for operation.""" ``` **Error Response Format:** ```python { "success": False, "error": { "type": "DocumentNotFoundError", "message": "Document not found: /path/to/file.md", "code": "DOC_NOT_FOUND", "details": { "path": "/path/to/file.md", "resolved_path": "/absolute/path/to/file.md", "exists": False, "parent_exists": True } }, "suggestions": [ "Check that the file path is correct", "Ensure you have read permissions for the file", "Use test_path_resolution to verify path expansion" ], "recovery_options": [ { "action": "create_document", "description": "Create a new document at this path", "parameters": {"document_path": "/path/to/file.md"} } ] } ``` ### Benefits of the Proposed Changes #### 1. **Scalability Improvements** - **Memory Efficiency**: Documents are loaded only during operations - **Concurrency**: Multiple documents can be processed simultaneously - **Resource Management**: Automatic cleanup after operations #### 2. **Developer Experience** - **Simpler API**: One call to perform any operation on any document - **Better Debugging**: Each operation is self-contained and traceable - **Flexibility**: Choose between stateful and stateless operations #### 3. **Use Case Examples** **Before (Current):** ```python # Multi-step process with state management await client.call_tool("load_document", {"file_path": "doc1.md"}) await client.call_tool("insert_section", {"heading": "New Section", "content": "...", "position": 1}) await client.call_tool("save_document", {}) # Need to load another document await client.call_tool("load_document", {"file_path": "doc2.md"}) await client.call_tool("delete_section", {"heading": "Old Section"}) await client.call_tool("save_document", {}) ``` **After (Improved):** ```python # Single call per operation, no state management await client.call_tool("insert_section", { "document_path": "doc1.md", "heading": "New Section", "content": "...", "position": 1, "auto_save": True }) await client.call_tool("delete_section", { "document_path": "doc2.md", "heading": "Old Section", "auto_save": True }) ``` **Batch Operations:** ```python # Process multiple operations atomically await client.call_tool("batch_operations", { "document_path": "complex_doc.md", "operations": [ {"action": "insert_section", "heading": "Introduction", "content": "...", "position": 0}, {"action": "update_section", "section_id": "sec_123", "content": "Updated content"}, {"action": "move_section", "section_id": "sec_456", "new_position": 2} ], "atomic": True, "auto_save": True }) ``` ### Migration Strategy #### Phase 1: Add New Parameters (Non-Breaking) - Add `document_path` as an optional first parameter to all tools - Maintain backward compatibility with existing stateful behavior - Default to legacy mode when `document_path` is not provided #### Phase 2: Encourage New Pattern - Update documentation to showcase new stateless approach - Add deprecation warnings for stateful operations - Provide migration examples and tools #### Phase 3: Full Transition - Make `document_path` required parameter - Remove stateful server instance variables - Provide legacy compatibility layer for existing users ### Testing Strategy #### 1. **Compatibility Testing** - Ensure all existing tests pass with legacy mode enabled - Test new parameter handling with and without `document_path` - Verify error handling for mixed old/new calling patterns #### 2. **Performance Testing** - Compare memory usage between stateful and stateless operations - Measure operation latency for repeated document access - Test concurrent operations on multiple documents #### 3. **Integration Testing** - Test with Claude Desktop using new parameter format - Verify VSCode MCP integration works with enhanced tools - Test batch operations and error recovery scenarios ### Conclusion Adding `document_path` as the first parameter to all MCP tools represents a significant architectural improvement that: 1. **Eliminates State Management Complexity**: No more shared state or threading concerns 2. **Enables True Concurrency**: Multiple documents can be processed simultaneously 3. **Improves Reliability**: Each operation is self-contained and atomic 4. **Enhances User Experience**: One call to perform any operation on any document 5. **Supports Advanced Features**: Batch operations, document analysis, and multi-document workflows The proposed changes maintain backward compatibility while providing a clear migration path to a more scalable and reliable architecture. This improvement positions the SafeMarkdownEditor MCP server as a powerful tool for complex document manipulation workflows. --- **Next Steps:** 1. Review and refine the proposed API changes 2. Implement Phase 1 with backward compatibility 3. Create comprehensive test suite for new functionality 4. Update documentation with examples and migration guide 5. Gather user feedback and iterate on the design

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/quantalogic/quantalogic_markdown_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server