Model Context Protocol (MCP) server for ERPNext/Frappe REST API, providing integration for authentication, document fetching, querying, creating, updating, and running reports
ERPNext MCP Server has 7 tools with basic structure but significant gaps in description quality, parameter documentation, and output schema specification. Tool names follow verb_noun convention (get_, create_, update_, run_) which is positive. However, descriptions are sparse (average ~40-70 chars, below the 194-char baseline), critical parameters lack type constraints, and output schemas are completely undocumented. Error handling exists at the HTTP layer but provides no actionable recovery guidance to LLMs. The server exposes write operations (create_document, update_document) with minimal input validation guidance. Parameters like 'document' and 'filters' are typed as generic objects with minimal constraint documentation, inviting malformed requests. No permission gates, no audit logging patterns, and no tool annotations (readOnlyHint/destructiveHint).
Create a new document in ERPNext
Get fields list for a specific DocType
Get a list of all available DocTypes
Get a specific document by DocType and name
Get a list of documents for a specific DocType with optional filters and field selection
Run a report in ERPNext
Update an existing document in ERPNext
Tool descriptions are too brief (40-70 chars vs. 194-char baseline). Descriptions lack WHEN-to-use context and expected output structure. E.g., 'Get a list of documents for a specific DocType with optional filters and field selection' does not explain that results are paginated, what fields are returned, or when to call this vs. get_document.
Output schemas are completely undocumented. Tools return 'any' with no guidance on structure, fields, or pagination. LLMs cannot plan downstream calls or extract required IDs (e.g., does get_document return a 'name' field for use in update_document?). This violates the 100% A+ baseline for documented return types.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 52 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 0 | - | v1 |
Parameters 'document' and 'filters' are typed as generic objects with no constraints or field documentation. LLMs must guess what fields are valid, leading to malformed API calls. No enum, pattern, or range constraints anywhere. Missing dependency hints (e.g., 'filters' should document expected field names and operator syntax).
Write operations (create_document, update_document) lack confirmation/dry-run support. No indication that these calls are irreversible. No tool annotations (destructiveHint) to signal to LLMs that these are high-risk operations. Agents could accidentally create/modify production data without safeguards.
Error handling is basic (try/catch with message concatenation). Errors do not guide recovery ('Failed to get Customer list: Unknown error' is not actionable). No classification (retryable vs. user-fixable vs. fatal). No context-aware suggestions (e.g., 'DocType not found. Did you mean: Customer, Supplier, Item?').
No permission gates or scope declarations. Tools do not declare what permissions they require (e.g., 'read:doctype', 'write:document'). Server does not verify caller authority before executing write operations. This violates pattern:permission-gate and pattern:scope-declaration.
No audit logging or call tracing. Tool implementations catch errors but do not log caller identity, timestamp, parameters, or outcome. This is required for compliance and incident response when agents modify production data.
get_documents and run_report lack result-size limits. No documented cap on result count (e.g., 'Returns max 50 results; use pagination for more'). A large DocType list or report could exceed context window. Missing pagination guidance in descriptions.
Tool naming is verb-first (good), but 'get_documents' and 'get_document' are confusingly similar. No parameter suffixing convention (e.g., doctype_name vs. doctype_id). Parameter 'name' in get_document is ambiguous, could be document name, ID, or alias. Missing descriptions like 'Document name/ID (human-readable identifier or internal ERPNext name)'.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). WRITE tools (create_document, update_document) should be marked destructiveHint: true, but this pattern is not used. LLMs cannot distinguish safe reads from risky writes without explicit hints.