Skip to main content
Glama

submit_document

Submit documents in Frappe by changing docstatus from 0 to 1 with validation, error handling, and clear feedback for corrective action.

Instructions

    Submit a document in Frappe (change docstatus from 0 to 1).
    
    This tool handles document submission using Frappe's submission workflow,
    including proper validation and error handling to provide clear feedback
    for corrective action.
    
    Args:
        doctype: DocType name
        name: Document name (case-sensitive)
        
    Returns:
        Success message if submitted, or detailed error information if submission
        fails due to validation errors or missing required fields.
    

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
doctypeYes
nameYes

Implementation Reference

  • The core handler function for the 'submit_document' MCP tool. Decorated with @mcp.tool(), it implements the logic to submit a Frappe document by retrieving the document, validating its status, using Frappe's savedocs API with 'Submit' action, and providing detailed error messages for common issues like validation errors, permissions, and missing fields.
    @mcp.tool()
    async def submit_document(
        doctype: str,
        name: str
    ) -> str:
        """
        Submit a document in Frappe (change docstatus from 0 to 1).
        
        This tool handles document submission using Frappe's submission workflow,
        including proper validation and error handling to provide clear feedback
        for corrective action.
        
        Args:
            doctype: DocType name
            name: Document name (case-sensitive)
            
        Returns:
            Success message if submitted, or detailed error information if submission
            fails due to validation errors or missing required fields.
        """
        try:
            client = get_client()
            
            # First, get the current document to check its status and get full data
            try:
                doc_response = await client.get(f"api/resource/{doctype}/{name}")
                doc_data = doc_response.get("data", {})
                current_docstatus = doc_data.get("docstatus", None)
                
                if current_docstatus is None:
                    return f"Error: Could not retrieve document {doctype} '{name}'. Document may not exist."
                    
                if current_docstatus == 1:
                    return f"Document {doctype} '{name}' is already submitted."
                    
                if current_docstatus == 2:
                    return f"Document {doctype} '{name}' is cancelled and cannot be submitted."
                    
                if current_docstatus != 0:
                    return f"Document {doctype} '{name}' has unexpected status (docstatus={current_docstatus}). Only draft documents (docstatus=0) can be submitted."
                    
            except Exception as get_error:
                return f"Error retrieving document for submission: {get_error}"
            
            # Prepare document for submission by setting docstatus to 1
            submit_doc = doc_data.copy()
            submit_doc['docstatus'] = 1
            
            # Use Frappe's savedocs method which handles the submission workflow
            response = await client.post(
                "api/method/frappe.desk.form.save.savedocs",
                json_data={
                    "doc": json.dumps(submit_doc),
                    "action": "Submit"
                }
            )
            
            # Check if submission was successful
            if "docs" in response:
                submitted_doc = response["docs"][0] if response["docs"] else {}
                final_docstatus = submitted_doc.get("docstatus", 0)
                
                if final_docstatus == 1:
                    return f"✅ Document {doctype} '{name}' successfully submitted."
                else:
                    return f"⚠️ Submission completed but document status is {final_docstatus} (expected 1)."
            
            # If we get here, check for success without docs
            if response.get("message") == "ok" or "exc" not in response:
                return f"✅ Document {doctype} '{name}' successfully submitted."
            
            # If no explicit success indicator, assume it worked
            return f"✅ Document {doctype} '{name}' submission completed."
            
        except FrappeApiError as api_error:
            # Handle specific Frappe API errors with detailed information
            if api_error.response_data:
                error_data = api_error.response_data
                
                # Check for validation errors in the response
                if "exception" in error_data:
                    exception_msg = error_data["exception"]
                    
                    # Extract user-friendly error messages
                    if "ValidationError" in str(exception_msg):
                        # Try to extract the specific validation error
                        if "Reference No & Reference Date is required" in str(exception_msg):
                            return (
                                f"❌ Submission failed: Document {doctype} '{name}' requires 'reference_no' and 'reference_date' fields for Bank Entry vouchers. "
                                f"Please update the document with these required fields before submitting."
                            )
                        else:
                            # Generic validation error
                            return f"❌ Validation error: {exception_msg}. Please fix the validation issues and try again."
                    
                    elif "PermissionError" in str(exception_msg):
                        return f"❌ Permission denied: You don't have sufficient permissions to submit {doctype} documents."
                    
                    else:
                        # Other exceptions
                        return f"❌ Submission failed: {exception_msg}"
                
                # Check for server messages with more details
                if "_server_messages" in error_data:
                    try:
                        messages = json.loads(error_data["_server_messages"])
                        if messages:
                            msg_data = json.loads(messages[0])
                            user_message = msg_data.get("message", "Unknown error")
                            return f"❌ Submission failed: {user_message}"
                    except (json.JSONDecodeError, KeyError, IndexError):
                        pass
            
            return f"❌ Submission failed: {api_error}"
            
        except Exception as error:
            return _format_error_response(error, "submit_document")
  • The @mcp.tool() decorator registers the submit_document function as an MCP tool.
    @mcp.tool()
  • Input schema defined by type annotations: doctype (str), name (str), returning str.
    doctype: str,
    name: str

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/appliedrelevance/frappe-mcp-server'

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