Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

ERP Adapter

БесплатноНе проверен

ERP-agnostic MCP adapter with drop-in connectors for ERPNext and Dolibarr, supporting multi-tenant deployments with per-request connection credentials.

GitHubEmbed

Описание

ERP-agnostic MCP adapter with drop-in connectors for ERPNext and Dolibarr, supporting multi-tenant deployments with per-request connection credentials.

README

ERP-agnostic MCP adapter layer.

Drop-in adapters for ERPNext, Dolibarr, and more — designed to be embedded inside a multi-tenant MCP server. Every adapter takes an explicit ErpConnection (no env vars, no globals) so the same process can serve N tenants connected to N different ERPs.

Status — v0.1.0. Adapter contract, static tool catalog, @casys/mcp-server stdio/http projection, ERPNext Customer/Item/Sales Invoice/Sales Order/Quotation tools, and Dolibarr Thirdparty/Product/Invoice/Order/Proposal tools.

Usage

import {
  buildAdapter,
  type ErpConnection,
  ErpToolsClient,
} from "@casys/mcp-erp";

const connection: ErpConnection = {
  erpType: "erpnext",
  apiUrl: "https://erp.example.com",
  apiKey: "<frappe api_key>",
  apiSecret: "<frappe api_secret>",
  sandbox: false,
};

const adapter = await buildAdapter(connection);

const tools = adapter.tools(); // ErpToolDefinition[]
const result = await adapter.callTool("erpnext.customer_list", {
  limit: 20,
  limitStart: 0,
}, {
  tenantId: "acme",
  actorSubject: null,
});

await adapter.dispose();

Registering with @casys/mcp-server

ErpToolsClient is the MCP projection layer, mirroring EInvoiceToolsClient in mcp-einvoice. Adapters stay agnostic; MCP servers register the projected tools and handlers at the boundary.

import { McpApp } from "@casys/mcp-server";
import {
  buildAdapter,
  erpToolErrorMapper,
  ErpToolsClient,
} from "@casys/mcp-erp";

const adapter = await buildAdapter(connection);
const toolsClient = new ErpToolsClient({
  tenantId: "acme",
  actorSubject: null,
});

const app = new McpApp({
  name: "mcp-erp-acme",
  version: "0.1.0",
  validateSchema: true,
  backpressureStrategy: "queue",
  toolErrorMapper: erpToolErrorMapper,
});

toolsClient.registerTools(app, adapter);

await app.start(); // stdio — works on Deno AND Node (npm build)

// HTTP with port ownership (Deno AND Node — npm build uses node:http instead of Deno.serve):
// await app.startHttp({ port: 3020, hostname: "localhost" });

// HTTP embedded in an existing framework (Deno AND Node — npm build supported):
// const handler = await app.getFetchHandler();
// // handler is a Web-standard fetch function; mount it in Hono, Express, etc.

Node.js / npm — both startHttp() and getFetchHandler() work on Node. The npm build replaces Deno.serve with a node:http adapter so startHttp() binds a real TCP port. Use getFetchHandler() when you want to mount the handler inside an existing Node HTTP framework (Hono, Express, etc.) instead.

For a local HTTP smoke test against a hosted or local ERP instance:

deno task serve -- --config ./mcp-erp.config.json --port=3020

MCP Apps viewers

createErpMcpApp() registers four bundled MCP Apps viewers under ui://mcp-erp/*. The list, invoice, and detail viewers read provider-agnostic display data; provider-native payloads stay beside that display contract for callers that need them:

ui://mcp-erp/doclist-viewer
ui://mcp-erp/invoice-viewer
ui://mcp-erp/diagnostics-viewer
ui://mcp-erp/detail-viewer

erpnext.ping and dolibarr.ping point to diagnostics-viewer and return the ERP type, API URL, tenant context, and exposed tool surface. Provider-native list tools point to doclist-viewer. erpnext.sales_invoice_get and dolibarr.invoice_get point to invoice-viewer. ERPNext sales orders and quotations plus Dolibarr orders and proposals point to detail-viewer.

Detail/invoice viewers read structuredContent.data first and fall back to the root payload for legacy callers. The normalized data object uses shared fields such as name, status, currency, grand_total, net_total, total_taxes_and_charges, dates, parties, and items. Native records are kept as siblings, not interpreted by viewers:

// Dolibarr invoice detail
{
  data: mappedInvoice,
  invoice: nativeDolibarrInvoice,
  _native: nativeDolibarrInvoice,
}

// Dolibarr order/proposal detail
{
  data: mappedDocument,
  order: nativeDolibarrOrder,       // or proposal: nativeDolibarrProposal
  _native: nativeDolibarrDocument,
}

Compatibility note: detail-style consumers should prefer content.data. The root fallback remains for older viewer payloads, and Dolibarr invoice callers that previously consumed the native invoice can use content.invoice or content._native.

Current tool surface

Read-only provider-native tools shipped now:

erpnext.ping
erpnext.customer_list
erpnext.customer_get
erpnext.item_list
erpnext.item_get
erpnext.sales_invoice_list
erpnext.sales_invoice_get
erpnext.sales_order_list
erpnext.sales_order_get
erpnext.quotation_list
erpnext.quotation_get

dolibarr.ping
dolibarr.thirdparty_list
dolibarr.thirdparty_get
dolibarr.product_list
dolibarr.product_get
dolibarr.invoice_list
dolibarr.invoice_get
dolibarr.order_list
dolibarr.order_get
dolibarr.proposal_list
dolibarr.proposal_get

Public surface (v0.1.0)

// Connection
type ErpConnection
type ErpType
const ERP_TYPES
function isKnownErpType(value: string): value is ErpType

// Adapter contract
interface ErpAdapter
type ErpAdapterFactory
interface ErpToolDefinition
interface ErpToolCallContext
interface ErpToolCallResult
interface ErpToolAnnotations
interface ErpToolMeta
class UnknownToolError

// MCP projection, registry & factories
class ErpToolsClient
function erpToolErrorMapper(error, toolName): string | null
async function buildAdapter(connection: ErpConnection): Promise<ErpAdapter>
const REGISTERED_ERP_TYPES
function getErpToolDefinitions(erpType): ErpToolDefinition[]
function registerErpViewers(app): { registered: string[]; skipped: string[] }
function createErpnextAdapter(connection): ErpAdapter
function createDolibarrAdapter(connection): ErpAdapter
const ERP_VIEWERS
const ERP_DOCLIST_META
const ERP_INVOICE_META
const ERP_DIAGNOSTICS_META
const ERP_DETAIL_META
class FrappeApiError
class DolibarrApiError

Why this exists

This package is the OSS adapter layer. Authentication, multi-tenancy, audit, DCR proxy and dashboard live in the proprietary erp-platform SaaS that consumes this package. Splitting them keeps each side honest:

  • This package : agnostic protocol/adapters. No tenant model, no Zitadel, no DB. Receives ErpConnection per call.
  • erp-platform : multi-tenant Fresh+Prisma+Zitadel platform that resolves a tenant → credentials → ErpConnection and dispatches MCP calls through this adapter layer.

Design choices

  1. One package, not two. mcp-einvoice splits into core + mcp; we keep things in a single package until we have ≥2 consumers that would benefit from the split.
  2. Explicit ErpConnection, not env-based. Per-tenant safety in a single Deno process.
  3. Decoupled from @casys/mcp-server SDK shape. Adapters return ErpToolDefinition (JSON Schema + name + description). Consumers project this into the SDK format at boundary time. Same pattern as EInvoiceToolsClient in mcp-einvoice.
  4. Scope ruthless. v0.1 focuses on ERPNext and Dolibarr read-only tools first. Lifecycle mutations and normalized tools wait until the native API mapping is proven on both adapters. No Odoo, no SAP, until that foundation is boring.

Roadmap

See ROADMAP.md for the alpha-to-beta product roadmap.

Related projects

  • mcp-einvoice — sibling OSS package, same pattern, e-invoicing domain.
  • mcp-erpnext — mono-cible ERPNext MCP server (env-based singleton). Different scope: useful pattern reference, but not a runtime dependency of this package.
  • erp-platform (private) — the SaaS that consumes this package.

License

MIT — see LICENSE.

from github.com/casys-ai/mcp-erp

Установка ERP Adapter

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/casys-ai/mcp-erp

FAQ

ERP Adapter MCP бесплатный?

Да, ERP Adapter MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для ERP Adapter?

Нет, ERP Adapter работает без API-ключей и переменных окружения.

ERP Adapter — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить ERP Adapter в Claude Desktop, Claude Code или Cursor?

Открой ERP Adapter на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare ERP Adapter with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development