sap-cloud-erp-mcp
# SAP Cloud ERP MCP Server
[](LICENSE)
An MCP (Model Context Protocol) server for **SAP S/4HANA Cloud Public Edition**, built on
the SDK's released business OData APIs. It exposes `list` / `get` / `create` (`/update`)
tools for 14 business objects, plus a small number of object-specific actions (e.g.
releasing a production order), for a total of 57 tools.
| Object | Tools |
|---|---|
| Material (Product) | `s4_material_list`, `s4_material_get`, `s4_material_create`, `s4_material_update` |
| Material BOM | `s4_material_bom_list`, `s4_material_bom_get`, `s4_material_bom_create`, `s4_material_bom_update` |
| Purchase Requisition | `s4_purchase_requisition_list`, `s4_purchase_requisition_get`, `s4_purchase_requisition_create`, `s4_purchase_requisition_update` |
| Purchase Order | `s4_purchase_order_list`, `s4_purchase_order_get`, `s4_purchase_order_create`, `s4_purchase_order_update` |
| Purchase Contract | `s4_purchase_contract_list`, `s4_purchase_contract_get`, `s4_purchase_contract_create`, `s4_purchase_contract_update` |
| Sales Quotation | `s4_sales_quotation_list`, `s4_sales_quotation_get`, `s4_sales_quotation_create`, `s4_sales_quotation_update` |
| Sales Order | `s4_sales_order_list`, `s4_sales_order_get`, `s4_sales_order_create`, `s4_sales_order_update` |
| Sales Contract | `s4_sales_contract_list`, `s4_sales_contract_get`, `s4_sales_contract_create`, `s4_sales_contract_update` |
| Production Order | `s4_production_order_list`, `s4_production_order_get`, `s4_production_order_create`, `s4_production_order_update`, `s4_production_order_release` |
| Planned Order | `s4_planned_order_list`, `s4_planned_order_get`, `s4_planned_order_create`, `s4_planned_order_update` |
| Production Order Confirmation | `s4_production_order_confirmation_list`, `s4_production_order_confirmation_get`, `s4_production_order_confirmation_create` |
| Production Operation Confirmation | `s4_production_operation_confirmation_list`, `s4_production_operation_confirmation_get`, `s4_production_operation_confirmation_create` |
| Material Document (goods movement) | `s4_material_document_list`, `s4_material_document_get`, `s4_material_document_create` |
| Outbound Delivery | `s4_outbound_delivery_list`, `s4_outbound_delivery_get`, `s4_outbound_delivery_create`, `s4_outbound_delivery_update` |
| Inbound Delivery | `s4_inbound_delivery_list`, `s4_inbound_delivery_get`, `s4_inbound_delivery_create`, `s4_inbound_delivery_update` |
`s4_production_order_release` releases a production order via the OData V2 function
import `ReleaseOrder` — order status fields are read-only via `PATCH`, so this is the only
way to release an order through the API.
## Setup
```bash
npm install
npm run build
cp .env.example .env # fill in your SAP connection details
```
Required env vars (see `.env.example`):
- `S4_BASE_URL` — your SAP S/4HANA Cloud API base URL
- `S4_AUTH_TYPE` — `oauth2_client_credentials` or `basic`
- OAuth2: `S4_OAUTH_TOKEN_URL`, `S4_CLIENT_ID`, `S4_CLIENT_SECRET`
- Basic: `S4_USERNAME`, `S4_PASSWORD`
- `MCP_TRANSPORT` — `stdio` (default) or `http`; `PORT` when using `http`
The services must be exposed via a **Communication Arrangement** in your SAP tenant
(Communication User + the matching Communication Scenario for each API — see the table
below, and the comments at the top of each `src/tools/*.ts` file for the exact service path).
## Running
```bash
npm run start # stdio transport, for MCP clients like Claude Desktop
MCP_TRANSPORT=http npm run start # Streamable HTTP on $PORT
npm run inspector # MCP Inspector UI against the stdio server
```
### Registering with an MCP client
```json
{
"mcpServers": {
"sap-cloud-erp": {
"command": "node",
"args": ["/absolute/path/to/sap-cloud-erp/dist/index.js"],
"env": {
"S4_BASE_URL": "https://your-tenant-api.s4hana.cloud.sap",
"S4_AUTH_TYPE": "basic",
"S4_USERNAME": "...",
"S4_PASSWORD": "...",
"MCP_TRANSPORT": "stdio"
}
}
}
}
```
## Verified against a live tenant
`list` (and CSRF-token acquisition) for the following was confirmed working against a
real S/4HANA Cloud Public Edition tenant: Purchase Order, Purchase Requisition, Sales
Quotation, Sales Contract, Sales Order, Production Order, Planned Order, Material
Document, Outbound Delivery, Inbound Delivery, Production Order Confirmation (both
levels). `create` (including deep-insert with nested account assignment), `update`, and
the `release` action were verified end-to-end for Purchase Order, Production Order,
Sales Order, and Material Document (goods receipt against a PO) against a live tenant.
`create` was also verified for Sales Order against a mock server — see `evaluation/`.
**Not yet independently verified** — these returned SAP-side authorization errors on the
original test tenant, not code errors (the error was "no start authorization" / "no
authorization to access service group", which happens even when the matching
Communication Arrangement exists — it means either the arrangement's *Inbound
Communication* tab doesn't have that specific API checked, or the Communication User's
backend role/authorization profile is missing the corresponding authorization object):
- `s4_material_*` (Product, `CE_PRODUCT_0002`, comm. scenario `SAP_COM_0009`)
If you hit this, open the relevant Communication Arrangement in your tenant, check the
*Inbound Communication* → services list, and confirm the Communication User's
authorization profile includes that scenario.
## Communication Scenarios (confirmed on a live SAP_COM catalog)
| Object | Comm. Scenario |
|---|---|
| Material | `SAP_COM_0009` |
| Material BOM | `SAP_COM_0105` |
| Purchase Requisition | `SAP_COM_0102` |
| Purchase Order | `SAP_COM_0053` |
| Purchase Contract | `SAP_COM_0101` |
| Sales Quotation | `SAP_COM_0118` |
| Sales Order | `SAP_COM_0109` |
| Sales Contract | `SAP_COM_0119` |
| Planned Order | `SAP_COM_0104` (Production Planning Integration) |
| Production Order / Confirmation | `SAP_COM_0522` (Manufacturing Execution — Order and Confirmation Integration) |
| Material Document | `SAP_COM_0108` |
| Outbound / Inbound Delivery | `SAP_COM_0106` (shared) |
## Known limitations
- All `additionalFields` (create) / `fields` (update) parameters accept arbitrary extra
OData fields as a passthrough, since exact optional-field lists vary by tenant
configuration (e.g. account assignment, batch management, variant configuration).
- No delete/cancel tools are implemented by design — SAP has no hard-delete for these
objects, and cancellation flows were explicitly out of scope.
- `s4_material_document_*`, `s4_production_order_confirmation_*`,
`s4_production_operation_confirmation_*` have no update tool — these SAP objects are
immutable once posted (only cancellation exists, which is out of scope).
- Production order *component* fields (e.g. batch number) are read-only on the classic
OData entity set exposed by this server's `s4_production_order_get`; updating them
requires the RAP-BO-based component entity, which is not yet wrapped in a dedicated tool
(see `CLAUDE.md` §3 for the pattern if you need to add one).
## Architecture
- `src/sapClient.ts` — shared OAuth2/basic auth, token caching, CSRF token handling,
V2/V4 response normalization, OData error-message extraction, and
`sapCallFunctionImport()` for calling OData V2 function imports (actions like release).
- `src/tools/*.ts` — one file per business object, each registering its own
`list`/`get`/`create`(/`update`) tools with explicit Zod schemas. No shared "generic SAP
object" abstraction by design — each object's fields and quirks are handled explicitly.
- `src/index.ts` — server bootstrap; registers all tools and starts either the stdio or
stateless Streamable HTTP transport based on `MCP_TRANSPORT`.
See `CLAUDE.md` for implementation gotchas discovered while building and hardening this
server (OData V2 vs V4 decimal encoding, deep-insert requirements, ETag handling for
function imports, composite-key pitfalls, and more) — read it before modifying
`sapClient.ts` or adding a new create/update tool.
## License
[GNU General Public License v3.0](LICENSE).
TDQS
Scored across 27 tools
Every tool targets a distinct SAP document/resource and action, such as sales orders, purchase orders, sales contracts, or production orders. The get/list/create/update/release verbs are applied consistently, so there is little risk of selecting the wrong tool.
Tool names follow a strict s4_<resource>_<action> pattern with snake_case throughout. Actions are consistently list/get/create/update/release, making the API surface highly predictable.
27 tools is on the heavy side, but the server covers multiple ERP domains: sales, purchasing, manufacturing, and logistics. Each tool is distinct and purposeful, though the count is above the ideal range for a tightly scoped server.
Several document lifecycles are incomplete: there is no purchase order list, no sales quotation create, no production order create, and no outbound delivery list. These are significant gaps that would block common ERP workflows, even though core sales order and purchase order operations are covered.