# How to build an MCP server for ERPNext

> Source: https://netray.co/integrations/erpnext-mcp-server
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Integrations

## 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.

## System

ERPNext

## Capability

mcp-server

## Intro

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.

## Use Cases

### Item and availability lookup

**Description:** A tool takes an item code or description and returns UOM, valuation rate range and quantities per warehouse from Bin.

### Order and delivery status

**Description:** Given a Sales Order or customer PO number, return line status, delivered quantity and linked Delivery Notes.

### BOM explosion

**Description:** Return a multi-level BOM for an item with required quantities and current stock, so the assistant can reason about shortages.

### Open purchasing view

**Description:** List open Purchase Orders and Material Requests by supplier or item with schedule dates, to answer what is inbound.

### Report runner

**Description:** 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)

**Description:** After read-only proves out, add tools that insert Draft Material Requests or Purchase Orders and return the document name for review.

## System 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

### Choose an SDK and language

**Detail:** Use an official MCP SDK in Python or TypeScript. Python fits teams already in the Frappe ecosystem.

### Design the tool list

**Detail:** 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.

### Implement the Frappe client

**Detail:** One small client class holds the base URL and token, sets timeouts, retries idempotent reads and translates Frappe error payloads into readable messages.

### Pick the transport

**Detail:** Use stdio for a local assistant on one workstation. Use streamable HTTP for shared use, behind TLS and an authentication layer you control.

### Scope permissions

**Detail:** Run the server as an ERPNext user with only the needed roles. For multiple audiences, run separate server instances with different users.

### Add audit logging

**Detail:** Log timestamp, client identity, tool name, arguments and number of rows returned. Do not log full document bodies.

### Test with a client and a script

**Detail:** 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.

**Steps:**

- 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.

**Steps:**

- 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.

## 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

- 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.

## Options

### Adopt a community Frappe or ERPNext MCP server

**Fit:** Fast experimentation. Review the code, check which DocTypes it exposes and pin the version.

**Effort:** Hours to try; expect to fork for production.

### Write your own thin server

**Fit:** You want tight control of tools, permissions and logging.

**Effort:** One to three weeks for a solid read-only server with tests.

### Have Netray build and run it

**Fit:** You need an audited server, private models and ERP domain knowledge on bills of material and approvals.

**Effort:** Scoped engagement, usually alongside an agent or assistant pilot.

## 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.

## Faq

### What is an MCP server for ERPNext?

**Answer:** 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?

**Answer:** 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?

**Answer:** 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?

**Answer:** 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?

**Answer:** 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.

## Search terms

erpnext mcp server, mcp server for erpnext, frappe mcp server, erpnext model context protocol, erpnext mcp tools, build mcp server erp, erpnext claude mcp, erpnext api ai tools, erpnext mcp on-prem

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
