Skip to main content
Glama

amend_document

Create amended versions of cancelled documents in Frappe by generating new documents with updated naming and proper field linkage.

Instructions

Amend a document in Frappe (create a new amended version of a cancelled document). This tool handles document amendment by creating a new document with an amended name (e.g., DOC-001-1, DOC-001-2) and copying all relevant field values from the original cancelled document, establishing proper linkage via the 'amended_from' field. Args: doctype: DocType name name: Document name (case-sensitive) - must be a cancelled document Returns: Success message with new amended document name if successful, or detailed error information if amendment fails due to validation errors or constraints.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
doctypeYes
nameYes

Implementation Reference

  • The main handler function for the 'amend_document' tool. It checks if the document is cancelled (docstatus=2), generates a new amended document name (e.g., DOC-001-1), copies fields from the original excluding system fields, sets 'amended_from', clears child names, and creates the new draft document via Frappe API.
    @mcp.tool() async def amend_document( doctype: str, name: str ) -> str: """ Amend a document in Frappe (create a new amended version of a cancelled document). This tool handles document amendment by creating a new document with an amended name (e.g., DOC-001-1, DOC-001-2) and copying all relevant field values from the original cancelled document, establishing proper linkage via the 'amended_from' field. Args: doctype: DocType name name: Document name (case-sensitive) - must be a cancelled document Returns: Success message with new amended document name if successful, or detailed error information if amendment fails due to validation errors or constraints. """ 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 == 0: return f"Document {doctype} '{name}' is in Draft status. Only cancelled documents (docstatus=2) can be amended." if current_docstatus == 1: return f"Document {doctype} '{name}' is submitted. You must cancel it first before amending." if current_docstatus != 2: return f"Document {doctype} '{name}' has unexpected status (docstatus={current_docstatus}). Only cancelled documents (docstatus=2) can be amended." except Exception as get_error: return f"Error retrieving document for amendment: {get_error}" # Generate amended document name base_name = name amended_counter = 1 # Check if this document is already an amendment (contains dash and number) if '-' in name: parts = name.rsplit('-', 1) if len(parts) == 2 and parts[1].isdigit(): base_name = parts[0] amended_counter = int(parts[1]) + 1 # Find the next available amended name amended_name = f"{base_name}-{amended_counter}" while True: try: # Check if amended name already exists check_response = await client.get(f"api/resource/{doctype}/{amended_name}") if "data" in check_response: # Name exists, try next number amended_counter += 1 amended_name = f"{base_name}-{amended_counter}" else: # Name doesn't exist, we can use it break except FrappeApiError as e: # If we get 404, the name doesn't exist and we can use it if e.status_code == 404: break else: # Some other error, we should handle it raise e # Prepare amended document data amended_doc = doc_data.copy() # Clear system fields that should not be copied system_fields = [ 'name', 'creation', 'modified', 'modified_by', 'owner', 'docstatus', 'idx', '_user_tags', '_comments', '_assign', '_liked_by' ] for field in system_fields: amended_doc.pop(field, None) # Set amendment fields amended_doc['name'] = amended_name amended_doc['amended_from'] = name amended_doc['docstatus'] = 0 # New document starts as draft # Clear any child table names to let Frappe generate new ones for key, value in amended_doc.items(): if isinstance(value, list): for item in value: if isinstance(item, dict): item.pop('name', None) # Clear child table row names item['parent'] = amended_name # Update parent reference # Create the amended document response = await client.post( f"api/resource/{doctype}", json_data=amended_doc ) if "data" in response: created_doc = response["data"] created_name = created_doc.get('name', amended_name) return f"✅ Document successfully amended: {doctype} '{created_name}' created from cancelled document '{name}'. The amended document is in Draft status and ready for editing." else: return f"⚠️ Amendment may have succeeded but response format unexpected: {json.dumps(response, indent=2)}" 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): # Common amendment validation errors if "amended_from" in str(exception_msg).lower(): return ( f"❌ Amendment failed: {doctype} does not have an 'amended_from' field configured. " f"This DocType may not support amendments. Contact your system administrator to enable amendment functionality." ) elif "DuplicateEntryError" in str(exception_msg) or "duplicate" in str(exception_msg).lower(): return f"❌ Amendment failed: Document name conflict. The amended name may already exist. Please try again." else: # Generic validation error return f"❌ Validation error: {exception_msg}. Please fix the validation issues before amending." elif "PermissionError" in str(exception_msg): return f"❌ Permission denied: You don't have sufficient permissions to amend {doctype} documents." else: # Other exceptions return f"❌ Amendment 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"❌ Amendment failed: {user_message}" except (json.JSONDecodeError, KeyError, IndexError): pass return f"❌ Amendment failed: {api_error}" except Exception as error: return _format_error_response(error, "amend_document")
  • src/server.py:40-40 (registration)
    Invocation of documents.register_tools(mcp), which registers the amend_document tool (and other document tools) with the MCP server instance.
    documents.register_tools(mcp)

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