Skip to main content
Glama

save_document

Save Markdown documents with configurable validation levels, optional backups, and flexible target paths for secure editing workflows.

Instructions

        Save the document (mainly for validation purposes since auto_save handles most cases).
        
        Args:
            document_path: Path to the source Markdown file
            target_path: Path to save to (if different from source)
            backup: Whether to create a backup before saving
            validation_level: Validation strictness - "STRICT", "NORMAL", or "PERMISSIVE"
        

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
document_pathYes
target_pathNo
backupNo
validation_levelNoNORMAL

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Primary MCP tool handler for 'save_document'. Decorated with @self.mcp.tool() to register and define the tool execution logic. Loads document editor and delegates saving to processor.
    @self.mcp.tool()
    def save_document(document_path: str, target_path: Optional[str] = None,
                     backup: bool = True, validation_level: str = "NORMAL") -> Dict[str, Any]:
        """
        Save the document (mainly for validation purposes since auto_save handles most cases).
        
        Args:
            document_path: Path to the source Markdown file
            target_path: Path to save to (if different from source)
            backup: Whether to create a backup before saving
            validation_level: Validation strictness - "STRICT", "NORMAL", or "PERMISSIVE"
        """
        try:
            validation_map = {"STRICT": ValidationLevel.STRICT, "NORMAL": ValidationLevel.NORMAL, "PERMISSIVE": ValidationLevel.PERMISSIVE}
            validation_enum = validation_map.get(validation_level.upper(), ValidationLevel.NORMAL)
            
            editor = self.processor.load_document(document_path, validation_enum)
            
            # Determine save path
            save_path = target_path if target_path else document_path
            
            # Save the document
            save_result = self.processor.save_document(editor, save_path, backup)
            return save_result
            
        except Exception as e:
            return self.processor.create_error_response(str(e), type(e).__name__)
  • Core helper function in StatelessMarkdownProcessor that implements the actual file saving logic: resolves path, creates directories and backup, serializes editor content, and writes to file.
    @staticmethod
    def save_document(editor: SafeMarkdownEditor, document_path: str, backup: bool = True) -> Dict[str, Any]:
        """Save a document to the specified path."""
        target_path = StatelessMarkdownProcessor.resolve_path(document_path)
        
        # Create parent directories if they don't exist
        target_path.parent.mkdir(parents=True, exist_ok=True)
        
        # Create backup if requested and file exists
        if backup and target_path.exists():
            backup_path = target_path.with_suffix(f"{target_path.suffix}.bak")
            backup_path.write_bytes(target_path.read_bytes())
        
        # Save the document
        content = editor.to_markdown()
        target_path.write_text(content, encoding='utf-8')
        
        return {
            "success": True,
            "message": f"Successfully saved document to {target_path}",
            "file_path": str(target_path),
            "backup_created": backup and Path(str(target_path) + ".bak").exists(),
            "file_size": len(content)
        }
  • Alternative handler for 'save_document' in the enhanced MCP server variant, simpler version delegating to processor.
    def save_document(document_path: str, backup: bool = True) -> Dict[str, Any]:
        """Save document to file (stateless only)."""
        try:
            editor = self.processor.load_document(document_path)
            return self.processor.save_document(editor, document_path, backup)
        except Exception as e:
            return self.processor.create_error_response(str(e), type(e).__name__)
  • Internal registration of save_document handler (_save_document_impl) in the synchronous call_tool_sync method for testing.
    tools = {
        "load_document": self._load_document_impl,
        "list_sections": self._list_sections_impl,
        "get_section": self._get_section_impl,
        "insert_section": self._insert_section_impl,
        "update_section": self._update_section_impl,
        "delete_section": self._delete_section_impl,
        "move_section": self._move_section_impl,
        "get_document": self._get_document_impl,
        "save_document": self._save_document_impl,
        "analyze_document": self._analyze_document_impl,
    }
  • Internal implementation (_save_document_impl) used by synchronous tool calling and registered in call_tool_sync.
    def _save_document_impl(self, document_path: str, target_path: Optional[str] = None, backup: bool = True, validation_level: str = "NORMAL") -> Dict[str, Any]:
        """Implementation for save_document tool."""
        try:
            validation_map = {"STRICT": ValidationLevel.STRICT, "NORMAL": ValidationLevel.NORMAL, "PERMISSIVE": ValidationLevel.PERMISSIVE}
            validation_enum = validation_map.get(validation_level.upper(), ValidationLevel.NORMAL)
            
            editor = self.processor.load_document(document_path, validation_enum)
            
            # Determine save path
            save_path = target_path if target_path else document_path
            
            return self.processor.save_document(editor, save_path, backup)
        except Exception as e:
            return self.processor.create_error_response(str(e), type(e).__name__)
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It mentions validation purposes and backup behavior, which adds useful context. However, it lacks details on permissions needed, error handling, rate limits, or what happens if validation fails. The description doesn't contradict any annotations (none provided).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded: the first sentence states the purpose and context, followed by a clear Args section. Every sentence earns its place with no wasted words. It's appropriately sized for a 4-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema (not shown here), the description doesn't need to explain return values. It covers the purpose, usage context, and parameter semantics adequately. However, as a mutation tool with no annotations, it could benefit from more behavioral details like error conditions or side effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It provides clear explanations for all 4 parameters: 'document_path' (source), 'target_path' (save destination), 'backup' (create backup), and 'validation_level' (strictness with enum values). This adds significant meaning beyond the bare schema, though it could elaborate on default behaviors.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Save') and resource ('the document'), and specifies it's 'mainly for validation purposes since auto_save handles most cases.' This distinguishes it from simple save operations. However, it doesn't explicitly differentiate from sibling tools like 'update_section' or 'move_section' in terms of scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: 'mainly for validation purposes since auto_save handles most cases.' This gives guidance on when to use this tool (for validation) versus relying on auto-save. However, it doesn't explicitly mention alternatives among sibling tools or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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