How to build an MCP server for ERPNext
Short answer
An ERPNext MCP server is a small service that translates tool calls from Claude, ChatGPT or any MCP client into Frappe REST API requests. Start with read-only tools for items, stock, orders and BOMs, authenticate with a dedicated API user, and log every call.
The Model Context Protocol gives AI clients a standard way to call tools and read resources. For ERPNext, that means you write the integration once and let different assistants use it, instead of rebuilding glue for each. It also gives you one place to enforce permissions and keep an audit trail.
ERPNext is friendly to this because the Frappe API is uniform. A generic wrapper is tempting, but it is the wrong design: a tool that accepts any DocType and any filter lets a model wander through payroll and bank records. A better server exposes a short list of business questions.
Below is a practical tool list, an authentication approach that respects Frappe permissions, and notes on transport, testing and what changes when ERPNext is on-prem.
What teams use it for
Item and availability lookup
A tool takes an item code or description and returns UOM, valuation rate range and quantities per warehouse from Bin.
Order and delivery status
Given a Sales Order or customer PO number, return line status, delivered quantity and linked Delivery Notes.
BOM explosion
Return a multi-level BOM for an item with required quantities and current stock, so the assistant can reason about shortages.
Open purchasing view
List open Purchase Orders and Material Requests by supplier or item with schedule dates, to answer what is inbound.
Report runner
Run a short allow-list of saved Query Reports with parameters and return capped rows, reusing logic your finance team already trusts.
Draft creation (later phase)
After read-only proves out, add tools that insert Draft Material Requests or Purchase Orders and return the document name for review.
ERPNext integration surface
- GET /api/resource/<DocType> with fields, filters, order_by and limit_page_length, used for list tools; GET /api/resource/<DocType>/<name> for single documents.
- POST /api/method/frappe.client.get_list and related frappe.client methods, which some teams prefer because the filters travel in a JSON body.
- Reports through the frappe.desk.query_report.run method, with filters passed as JSON; check the exact parameters for your version.
- Authorization header with token key:secret generated for a User, or OAuth 2 bearer tokens when per-user identity matters.
- Custom whitelisted methods in your own app for joined views that would take several REST calls to assemble.
- Permission checks via roles, User Permissions and field level permission levels, all enforced server side for the calling user.
How it works
- 1
Choose an SDK and language
Use an official MCP SDK in Python or TypeScript. Python fits teams already in the Frappe ecosystem.
- 2
Design the tool list
Write each tool with a clear name, a description of when to use it, typed arguments and a capped response. Aim for under fifteen tools.
- 3
Implement the Frappe client
One small client class holds the base URL and token, sets timeouts, retries idempotent reads and translates Frappe error payloads into readable messages.
- 4
Pick the transport
Use stdio for a local assistant on one workstation. Use streamable HTTP for shared use, behind TLS and an authentication layer you control.
- 5
Scope permissions
Run the server as an ERPNext user with only the needed roles. For multiple audiences, run separate server instances with different users.
- 6
Add audit logging
Log timestamp, client identity, tool name, arguments and number of rows returned. Do not log full document bodies.
- 7
Test with a client and a script
Use an MCP inspector tool and a regression script of known questions with expected document names.
Example flows
Availability question
Trigger: A buyer asks an MCP client: do we have enough of item CB-2201 for next week's builds.
- The client calls get_item_availability with the item code.
- The server reads Bin for each warehouse and open Work Order Item requirements.
- It returns on-hand, reserved and required quantities in a compact JSON object.
- The client explains the gap and suggests checking inbound Purchase Orders.
Result: A sourced answer built from live data, with no manual report run.
Draft PO creation with approval
Trigger: A planner approves the assistant's suggestion to order a short item.
- The client calls create_draft_purchase_order with item, quantity, supplier and date.
- The server validates the supplier against the Item Supplier list and quantity against limits.
- It inserts the document and confirms docstatus is 0.
- It returns the name and a desk link for the buyer to review and submit.
Result: The order exists as a Draft with a clear human gate before posting.
Keeping data on-prem
An MCP server is just a process that talks to your site, so it fits an on-prem bench well. Deploy it on the same network, use the internal site URL and keep the secret in your vault. For remote clients, put the HTTP transport behind your reverse proxy with TLS and an identity layer, or connect only from inside the VPN. Pair it with a locally served open-weight model if prompts must not leave the plant. Multi-company benches deserve extra care: filter by company in every tool and test that one company's user cannot see another's documents.
Security checklist
- Use a dedicated ERPNext user per server instance, never an administrator, and rotate its secret on a schedule.
- Allow-list DocTypes and fields inside the server code; do not accept arbitrary DocType names from the model.
- Cap rows and response size, and reject unbounded filters such as an empty list request on a large table.
- Authenticate every HTTP request to the server itself; an unauthenticated MCP endpoint is an open door to your ERP.
- Treat all text returned from ERPNext as untrusted when it is passed back into a model context.
Ways to get it done
Adopt a community Frappe or ERPNext MCP server
Effort: Hours to try; expect to fork for production.
Fast experimentation. Review the code, check which DocTypes it exposes and pin the version.
Write your own thin server
Effort: One to three weeks for a solid read-only server with tests.
You want tight control of tools, permissions and logging.
Have Netray build and run it
Effort: Scoped engagement, usually alongside an agent or assistant pilot.
You need an audited server, private models and ERP domain knowledge on bills of material and approvals.
Pitfalls
- !Building a single query_anything tool. It is hard to secure and models use it badly.
- !Returning entire documents with child tables, which wastes context and leaks fields.
- !Skipping timeouts, so a slow report stalls the client.
- !Mixing read and write tools in the first release. Ship read-only, then add Drafts.
- !Hard-coding version-specific field names without a test that fails after upgrades.
Frequently asked questions
What is an MCP server for ERPNext?
It is a service that exposes ERPNext actions as named tools that MCP clients can call, such as get_item_availability. Internally it calls the Frappe REST API with a limited user. The client sees clean tools, and you keep control of permissions and logging in one place.
Which clients can use it?
Any client that supports the Model Context Protocol, including Claude and a growing set of other assistants and developer tools. Support for remote servers and authentication varies by client and plan, so test your intended client before you design around it.
Stdio or HTTP transport?
Use stdio when the server runs locally next to a single client, for example during development. Use HTTP for shared access across a team, with TLS, authentication and rate limits. Never expose an HTTP server without its own authentication.
How do we keep ERPNext permissions in force?
Call the API as a user whose roles and User Permissions match the audience, since Frappe enforces them server side. For different audiences, run separate server instances or use OAuth so each person acts as themselves. Avoid one shared administrator key.
Can the same server serve a private model?
Yes. The server does not care which model is calling. Pair it with a local open-weight model that supports tool calling, and verify tool-use accuracy on your own questions, since smaller models make more argument mistakes.
Want MCP server working on your ERPNext?
A free 30 minute assessment: we map the integration path for your version and setup, and where it should run.
Get a free assessment