The ERP5 MCP Server: Your ERP in Plain Language

How ERP5 learned to speak the Model Context Protocol: the story of the ERP5 MCP server and its HATEOAS toolset, from the first experiments to AI agents creating purchase orders.
  • Last Update:2026-09-20
  • Version:001
  • Language:en

The ERP5 MCP Server: Your ERP in Plain Language

What if you could ask your ERP a question the way you ask a colleague?

  • “What are the sales of customer X in July?”
  • “Show me all products which are out of stock.”
  • “Create a purchase order for project Y with 1 quantity of this product <amazon url>.”

No navigation through menus, no report configuration, no export to a spreadsheet. Just a question, and an answer — or an action, carried out exactly the way a trained user would. That is what the ERP5 MCP Server makes possible: ERP5, the free software ERP of Nexedi, now speaks the Model Context Protocol (MCP), the open standard that lets AI assistants and agents connect to tools and data. Any MCP client — Claude, Open WebUI, Continue, or your own scripts — can connect to a running ERP5 instance and work with it: search, read, create, edit, validate documents, run reports, even develop the ERP itself.

This article tells the story of how the ERP5 MCP Server came to be, how it works inside, and why the result is more than a convenience feature.

1. From first experiments to a server made of documents

The MCP server is the result of several people building on each other’s work.

Yusei Tahara did the first experiments connecting ERP5 to the Model Context Protocol, exploring how an AI host could let a language model perform actual work in ERP5 — searching, creating, modifying documents — and what such a bridge would need to look like.

Then Cédric Le Ninivin had the brilliant idea that shaped everything that followed: instead of building a new API layer for AI agents, use the HATEOAS API that ERP5 already exposes — the very same API that the renderjs user interface uses. The UI talks to ERP5 through one generic JSON interface; an MCP client can talk to ERP5 through exactly the same one. Cédric implemented this as a standalone Python MCP server, erp5-mcp-hateoas (lab.nexedi.com/nexedi/erp5-mcp-hateoas), which proved the concept end to end with a growing set of tools.

Levin Zimmermann created the server implementation inside ERP5 itself, in the erp5_mcp business template (merge request “Teach ERP5 to be a MCP Server”). An MCP endpoint is no longer a separate process next to ERP5 — it is an MCP Web Service document that you install like any other ERP5 capability, speaking the protocol natively over HTTP. Tools are defined as MCP Tool documents in portal_callables, described by JSON Forms.

Finally, Klaus Wölfel ported the tools of Cédric’s erp5-mcp-hateoas server to Levin’s ERP5 implementation, and hardened the whole stack for production use. That is the form the server ships in today: the erp5_mcp business template for the server, and the erp5_mcp_hateoas* business templates for the tools.

2. The key idea: one API that already existed

The decisive insight deserves its own section, because it is what makes this server cheap to maintain and complete in coverage.

ERP5’s renderjs UI does not have hundreds of bespoke endpoints. It has essentially one: ERP5Document_getHateoas, a hypermedia (HATEOAS) API that serves forms, fields, listboxes, actions and dialogs as JSON, and accepts the same submissions the browser sends. Every listbox with its columns and its list method, every form with its editable fields, every workflow action and dialog the UI offers — all of it is already described there.

So the MCP tools do not wrap a hand-picked set of ERP5 methods. They replay what the UI itself does: traverse a form, read its fields, submit a search the way the listbox submits it, fill a dialog, trigger a transition. Two consequences follow immediately:

  • Whatever the UI can do, the agent can do. The toolset does not age: when a business template adds a module, a form or a report, the HATEOAS API serves it, and the agent reaches it through the same tools — because the tools read the structure from the server instead of hard-coding it.
  • Little extra surface to maintain. There is no second API to keep in sync with the first. The contract the tools rely on is the one the UI has been exercising in production for years.

Cédric’s standalone server talked to that API over HTTP like a browser would. In today’s in-ERP5 implementation the tools call it directly, with the MCP Service providing the proper HAL request context (the Hal skin, application/hal+json accept header) so that even restricted scripts in portal_callables can use it.

3. Inside erp5_mcp: a server made of documents

The erp5_mcp business template is the server itself. It is deliberately built out of ordinary ERP5 building blocks, so that everything an operator is used to — permissions, workflows, business templates, the UI — applies to the MCP server as well.

The MCP Service

An MCP Service is a Web Service document created in portal_web_services. Called with Content-Type: application/json, it speaks MCP’s Streamable HTTP transport: JSON-RPC 2.0 over POST, an initialize handshake, a MCP-Session-Id header on every subsequent request, and DELETE to end the session. Sessions live in portal_sessions, so with a distributed cache they work across several Zope nodes. Every message — incoming and outgoing — is validated against the official MCP JSON Schemas (protocol versions 2025-03-26, 2025-06-18 and 2025-11-25 ship as skin files), down to the correct error codes when a client misbehaves.

One service publishes exactly the tools listed in its tool list. Two ready-made services come with the tool business templates: erp5_hateoas_mcp_ro, a read-only service, and erp5_hateoas_mcp_rw with the write tools. This is the deployment dial for safety: give the marketing analyst’s assistant the read-only URL, and give the back-office agent the read-write one.

MCP Tools in portal_callables

Each tool is an MCP Tool document in portal_callables — in essence a Python Script with a formal contract. The contract is a JSON Form (a sibling <tool>_spec document, linked through the specification category) that holds the tool’s input and output JSON Schemas. An interaction workflow derives the Python parameter signature from the input schema whenever the schema changes, validates arguments on every call, and validates the result against the output schema before it is returned. The MCP client receives clean structuredContent it can rely on — not just prose.

Because tools are documents, they are customizable without touching core code: an integrator can add a tool for a customer’s specific report, restrict one, or write their own, and ship all of it in a business template. Tools also carry metadata that MCP clients use to behave sensibly: readOnly flags, hints about which tools are destructive or idempotent, and descriptions written for the model, not the human.

Governance built in

  • ERP5 security applies in full. The service runs every tool call under the connected user’s ERP5 permissions. An agent cannot do more than the account it connects with could do in the UI.
  • Personal data policy. A service can strip personal data from tool results (GDPR), with the redaction rules in a hot-editable skin script and a per-tool block list. A test component (testMCPPersonalData) pins the policy down.
  • Call logging. Optionally, every tool call and response is written to the event log with a correlation id, truncated to a configurable size.

4. The toolset: erp5_mcp_hateoas*

Klaus Wölfel ported and extended Cédric’s tool set in a family of business templates, split by what they allow so an operator can pick the risk profile. Together they cover the full life cycle: read, write, develop.

Tool Purpose
erp5_discover Start here: the global worklist (pending tasks with counts) and every module on the instance
erp5_inspect Schema of a module: listbox columns, searchable/sortable columns, forms
erp5_search Catalog search inside a module or across the whole portal, with paging and counts
erp5_read One document: fields, editable flags, actions, views, exports, printouts
erp5_read_deep A document tree (e.g. a Sale Order with all its lines) in one call
erp5_collect All rows of a listbox with automatic pagination — or a report’s table
erp5_download Files and printouts: PDF, ODT, ODS, spreadsheets
erp5_guide Step-by-step tutorials for common operations
erp5_create Create a document or sub-object (order, line, event…)
erp5_write Edit fields — relation fields, dates, lists included
erp5_action Trigger a workflow transition (validate, ship, deliver…)
erp5_dialog Submit a dialog-based action
erp5_clone / erp5_delete Clone a document, delete a sub-object

The first nine tools form the read-only service; all fifteen together form the read-write service.

For development instances there is more: erp5_mcp_hateoas_dev ships tools that let an agent work on ERP5 itself — read, write and call scripts, write components, patch callables, run live tests on the instance (erp5_live_test), tail the Zope event log (erp5_log_tail), and commit a business template to its git working copy (erp5_bt_commit). erp5_mcp_bt_filesystem adds the business-template-to-filesystem workflow: two-way status, install, update and export between the repository and the live instance. And erp5_mcp_hateoas_test contains the test components that keep all of this honest.

5. What the agent actually does with your question

Take the three questions from the introduction and watch them decompose into tool calls:

“What are the sales of customer X in July?”

The agent searches the sale order module for the customer with a date range on July, pages through the matching orders, reads the totals — and answers with numbers, a table, or a chart, whichever you asked for. It used erp5_search, maybe erp5_read_deep for the lines, nothing more — the same data the Sales Report shows, without the dialog.

“Show me all products which are out of stock.”

The agent inspects the product module, finds the inventory listbox (or the stock report), collects every row below zero, and returns the list. When a customer then asks “order more of the first one”, the read-only agent says no — the read-write agent picks up erp5_create.

“Create a purchase order for project Y with 1 quantity of this product <amazon url>.”

This is where it gets interesting: the agent reads the Amazon page, matches (or creates) the product in ERP5, creates the purchase order linked to project Y, adds the line with quantity 1, sets the supplier from the page — and hands you the document’s URL for review, with the validation left to you. Mundane data entry, gone.

Because every tool returns structured data and the tool descriptions are written to guide the model, agents compose these steps reliably — and when they hit a dead end, the responses tell them which tool to use instead (hint and warning keys, a small but decisive usability detail).

6. Eating our own dog food

The most convincing proof of an MCP server is to run the company on it. Two things worth knowing:

ERP5 is being developed through its own MCP server. On our development instance, the coding agent edits tools and components in portal_callables and portal_skins through the dev tools, runs the test components live on the instance with erp5_live_test, tails the event log to debug, and commits the business template to git with erp5_bt_commit. The article you are reading was written and published the same way: cloned from a template, written and edited through erp5_write, and shared alive as a Web Page through erp5_action — the ERP5 MCP server used to publish an article about the ERP5 MCP server.

The boundaries are yours to draw. A read-only service for information, a read-write service for operations, dev tools only on the development instance, personal-data stripping where it is required — the security model is ERP5’s, not an afterthought bolted onto the protocol.

7. Where to find it

If you run ERP5, install the business templates, create an MCP Service in portal_web_services, point your MCP client at it — and start asking your ERP questions. Thanks to Yusei for the first experiments, to Cédric for the idea that made it elegant, to Levin for the server inside ERP5, and to everyone who keeps pushing agents from curiosity to infrastructure.

Contact

  • Photo Klaus Wölfel
  • Logo Nexedi GmbH
  • Klaus Wölfel
  • klaus (dot) woelfel (at) nexedi (dot) com