"""Document CRUD tools — create, read, update, delete, list Frappe documents.""" import json from mcp.types import Tool from frappe_mcp.client.frappe_api import FrappeClient from frappe_mcp.config import get_settings def tools() -> list[Tool]: return [ Tool( name="frappe_list_documents", description="List documents of a given DocType with optional filters.", inputSchema={ "type": "object", "required": ["doctype"], "properties": { "doctype": {"type": "string"}, "fields": { "type": "array", "items": {"type": "string"}, "description": "Fields to return. Defaults to ['name', 'modified'].", }, "filters": { "type": "array", "description": "Filter list e.g. [[\"status\", \"=\", \"Open\"]]", }, "limit": {"type": "integer", "default": 20}, "order_by": {"type": "string", "default": "modified desc"}, }, }, ), Tool( name="frappe_get_document", description="Get a single Frappe document by DocType and name.", inputSchema={ "type": "object", "required": ["doctype", "name"], "properties": { "doctype": {"type": "string"}, "name": {"type": "string"}, }, }, ), Tool( name="frappe_create_document", description="Create a new document in any DocType.", inputSchema={ "type": "object", "required": ["doctype", "data"], "properties": { "doctype": {"type": "string"}, "data": {"type": "object", "description": "Field values for the new document"}, }, }, ), Tool( name="frappe_update_document", description="Update fields on an existing document.", inputSchema={ "type": "object", "required": ["doctype", "name", "data"], "properties": { "doctype": {"type": "string"}, "name": {"type": "string"}, "data": {"type": "object", "description": "Fields to update"}, }, }, ), Tool( name="frappe_delete_document", description="Delete a document. Blocked in read-only mode.", inputSchema={ "type": "object", "required": ["doctype", "name"], "properties": { "doctype": {"type": "string"}, "name": {"type": "string"}, }, }, ), Tool( name="frappe_submit_document", description="Submit a submittable document (changes status to Submitted).", inputSchema={ "type": "object", "required": ["doctype", "name"], "properties": { "doctype": {"type": "string"}, "name": {"type": "string"}, }, }, ), Tool( name="frappe_cancel_document", description="Cancel a submitted document.", inputSchema={ "type": "object", "required": ["doctype", "name"], "properties": { "doctype": {"type": "string"}, "name": {"type": "string"}, }, }, ), ] def handlers() -> dict: return { "frappe_list_documents": _list_documents, "frappe_get_document": _get_document, "frappe_create_document": _create_document, "frappe_update_document": _update_document, "frappe_delete_document": _delete_document, "frappe_submit_document": _submit_document, "frappe_cancel_document": _cancel_document, } async def _list_documents(args: dict) -> str: client = FrappeClient() result = await client.get_list( args["doctype"], fields=args.get("fields", ["name", "modified"]), filters=args.get("filters"), limit=args.get("limit", 20), order_by=args.get("order_by", "modified desc"), ) return json.dumps(result, indent=2) async def _get_document(args: dict) -> str: client = FrappeClient() result = await client.get_doc(args["doctype"], args["name"]) return json.dumps(result, indent=2) async def _create_document(args: dict) -> str: client = FrappeClient() data = {"doctype": args["doctype"], **args["data"]} result = await client.create_doc(args["doctype"], data) return json.dumps(result, indent=2) async def _update_document(args: dict) -> str: client = FrappeClient() result = await client.update_doc(args["doctype"], args["name"], args["data"]) return json.dumps(result, indent=2) async def _delete_document(args: dict) -> str: if get_settings().read_only_mode: return "Error: read_only_mode is enabled. Deletion blocked." client = FrappeClient() result = await client.delete_doc(args["doctype"], args["name"]) return json.dumps(result, indent=2) async def _submit_document(args: dict) -> str: client = FrappeClient() result = await client.update_doc(args["doctype"], args["name"], {"docstatus": 1}) return json.dumps(result, indent=2) async def _cancel_document(args: dict) -> str: client = FrappeClient() result = await client.update_doc(args["doctype"], args["name"], {"docstatus": 2}) return json.dumps(result, indent=2)