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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

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
Behavior4/5

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

With no annotations provided, the description carries full burden and does well by disclosing key behavioral traits: it performs a state change (submission), includes validation and error handling, and provides clear feedback. It doesn't mention authentication requirements, rate limits, or side effects on related records, but covers the core mutation behavior adequately for a tool with no annotations.

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

Conciseness4/5

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

The description is well-structured with a clear purpose statement, behavioral context, and parameter/return sections. Every sentence adds value, though the Args/Returns formatting is slightly verbose. It's appropriately sized for a 2-parameter mutation tool with no annotations.

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 this is a mutation tool with no annotations, 2 parameters, and an output schema exists, the description provides good coverage: clear purpose, parameter semantics, and behavioral context about validation/error handling. The output schema handles return values, so the description appropriately focuses on what the tool does rather than return format. Minor gaps include lack of prerequisites and alternative tool guidance.

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

Parameters5/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 fully. It provides clear semantic meaning for both parameters: 'doctype: DocType name' and 'name: Document name (case-sensitive)', explaining what each represents and important details like case sensitivity. This adds significant value beyond the bare schema with no titles or descriptions.

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

Purpose5/5

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

The description clearly states the specific action ('Submit a document in Frappe') with precise technical detail ('change docstatus from 0 to 1'), distinguishing it from sibling tools like create_document, update_document, or cancel_document. It explicitly identifies the resource being acted upon (documents in Frappe) and the state transition involved.

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

Usage Guidelines3/5

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

The description implies usage context through 'change docstatus from 0 to 1' and mentions validation/error handling, suggesting this is for finalizing draft documents. However, it doesn't explicitly state when to use this versus alternatives like update_document or cancel_document, nor does it mention prerequisites (e.g., document must exist and be in draft status).

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

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