S/4HANA MCP Server
Enables interaction with SAP S/4HANA systems, providing 38 tools to search and manage business partners, products, pricing, purchase orders, supplier invoices, service entry sheets, journal entries, and cost centers via OData V2/V4 and SOAP.
README
S/4HANA MCP Server
An MCP server exposing 38 tools for SAP S/4HANA (Cloud Public Edition and on-premise Private Edition) over OData V2, OData V4, and SOAP: business partners, products, sales pricing, warehouses, purchase orders, purchasing info records, supplier invoices (including posting and cancellation), service entry sheets, journal entries, cost centers, and finance org structure.
Write tools (create_*, cancel_supplier_invoice, check_invoice_posting_readiness) and get_finance_structure return their result inline as JSON. Every other (read) tool writes its result — CSV for collections, Markdown for single records — to an E2B sandbox and returns the file path(s), instead of inlining potentially large SAP result sets (hundreds of business partners, full journal-entry item detail, etc.) directly into the calling agent's context. This server only connects to an E2B sandbox your MCP client already owns — it never creates one. Your client needs its own E2B integration (the E2B SDK, or a Claude environment with matching code-execution access) to read the files back; see E2B sandbox setup.
Quick start
git clone https://github.com/ilia-inovaflow/s4hana-mcp-server.git
cd s4hana-mcp-server
npm install
npm run build
cp .env.example .env # fill in your E2B sandbox + SAP connection details
npm start # stdio transport (Claude Desktop, MCP Inspector, etc.)
For local development without building first: npm run dev.
E2B sandbox setup
Register for a free API key at e2b.dev, then start (or reuse) a sandbox your MCP client can read files from, and set:
E2B_API_KEY=<your E2B API key>
SANDBOX_ID=<an already-running sandbox ID> # stdio only — HTTP takes this per-session
Over the HTTP transport, SANDBOX_ID is supplied per session instead, via the sandbox-id request header — useful when one running server instance handles multiple callers, each with their own sandbox.
This is unrelated to SAP's own sandbox.api.sap.com trial host below — "sandbox" means two different things in this README.
Try it with no SAP tenant of your own
SAP publishes a free, public read-only API sandbox at sandbox.api.sap.com that this server talks to out of the box. Register for a free API key at api.sap.com, then set:
SAP_HOST=https://sandbox.api.sap.com
SAP_CLIENT_ID=<your sandbox API key>
No username, password, or OAuth setup needed — the sandbox authenticates with a single APIKey header. Business partner, product, and pricing tools work immediately against sandbox demo data (you still need the E2B sandbox above to receive read-tool results).
Connecting a real SAP tenant
Set SAP_HOST to your tenant URL and pick one of three auth modes via SAP_AUTH_MODE:
| Mode | Use case | Required variables |
|---|---|---|
basic |
Quick testing, on-prem systems without OAuth configured | SAP_USERNAME, SAP_PASSWORD |
cc |
S/4HANA Cloud Public Edition, service-to-service (OAuth 2.0 Client Credentials) | SAP_TOKEN_URL, SAP_CLIENT_ID, SAP_CLIENT_SECRET |
oauth |
User-delegated OAuth Authorization Code — HTTP transport only, caller supplies a fresh token per request via the sap-access-token header |
none (token comes from the MCP client) |
SAP_CLIENT (the SAP client/mandant number, e.g. 100) defaults to 100 if unset.
Two API families need basic or X.509 authentication by SAP design and reject OAuth: journal entry posting (create_journal_entry, SOAP SAP_COM_0002) and the accounting-document detail views (get_journal_entry, search_journal_entries with document_level=true). Everything else works under any of the three modes.
See .env.example for the full variable list, including the optional SAP_JE_SOAP_PATH override some on-premise SOAMANAGER configurations need.
Transports
stdio (default, npm start / npm run dev) — one SAP connection and one E2B sandbox per process, configured entirely from .env. This is what Claude Desktop and most local MCP clients expect:
{
"mcpServers": {
"s4hana": {
"command": "node",
"args": ["/absolute/path/to/s4hana-mcp-server/dist/index.js"],
"env": {
"E2B_API_KEY": "...", "SANDBOX_ID": "...",
"SAP_HOST": "...", "SAP_AUTH_MODE": "basic", "SAP_USERNAME": "...", "SAP_PASSWORD": "..."
}
}
}
}
Streamable HTTP (npm run start:http / npm run dev:http) — for remote or multi-tenant deployment. Each session's SAP connection is configured either from .env defaults or per-request headers (sap-host, sap-auth-mode, sap-username, sap-password, sap-token-url, sap-client-id, sap-client-secret, sap-client, sap-je-soap-path), and its E2B sandbox from the sandbox-id header (or SANDBOX_ID env as a fallback) — letting one running server field requests against different tenants and sandboxes. E2B_API_KEY is always read from the server's own environment. PORT (default 3000) and HOST (default localhost) configure the listener; the MCP endpoint is POST /mcp, with GET /health for liveness checks.
If you deploy the HTTP transport somewhere reachable over the network, put it behind your own authentication/network boundary — this server does not itself gate access to the /mcp endpoint, only to the downstream SAP connection.
Tools
<details> <summary><strong>Business Partners</strong> (3 tools)</summary>
search_business_partners— search customers, vendors, persons, organizationsget_business_partner— full detail for one Business Partnerquery_business_partner_odata— generic query against anyAPI_BUSINESS_PARTNERentity set
</details>
<details> <summary><strong>Products</strong> (3 tools)</summary>
search_products— search materials, finished goods, services, raw materialsget_product— full detail for one productquery_product_odata— generic query against anyAPI_PRODUCT_SRVentity set
</details>
<details> <summary><strong>Sales Pricing</strong> (4 tools)</summary>
get_product_pricing— combined price lookup for a material (start here for "what does X cost")search_pricing_conditions— browse condition records by type/rateget_pricing_condition— full detail for one condition recordquery_pricing_odata— generic query against any pricing entity set
</details>
<details> <summary><strong>Warehouses</strong> (2 tools)</summary>
list_warehousesget_warehouse
</details>
<details> <summary><strong>Purchase Orders</strong> (4 tools)</summary>
search_purchase_ordersget_purchase_orderquery_purchase_order_odata— generic query, including item/schedule-line levelget_purchase_order_confirmations— supplier order/shipping/GR confirmations, bulk lookup
</details>
<details> <summary><strong>Purchasing Info Records</strong> (3 tools)</summary>
search_purchasing_info_recordsget_purchasing_info_recordquery_purchasing_info_record_odata
</details>
<details> <summary><strong>Supplier Invoices</strong> (8 tools)</summary>
search_supplier_invoicesget_supplier_invoicequery_supplier_invoice_odatacreate_supplier_invoice_po⚠️ write — PO-referenced 3-way-match invoicecreate_supplier_invoice_gl⚠️ write — non-PO expense invoice, direct G/L linescreate_supplier_credit_memo⚠️ write — PO-referenced credit memocancel_supplier_invoice⚠️ write — reverses a posted invoice or credit memocheck_invoice_posting_readiness— read-only pre-flight guard check
</details>
<details> <summary><strong>Service Entry Sheets</strong> (3 tools)</summary>
search_service_entry_sheetsget_service_entry_sheetquery_service_entry_sheet_odata
</details>
<details> <summary><strong>Journal Entries & FI-CO</strong> (8 tools)</summary>
create_journal_entry⚠️ write — posts a G/L document (SOAP, basic/X.509 auth only)search_journal_entries— analytical (aggregated) or accounting-document (line-level) viewget_journal_entry— one accounting document by numbersearch_gl_accountssearch_open_po_items— a supplier's still-invoiceable PO lines, in one callsearch_cost_centersget_cost_center_hierarchy— the standard cost center hierarchy treeget_finance_structure— company codes, ledgers, charts of accounts, segments, business areas
</details>
Every write tool runs server-side guard checks (existence, blocking flags, duplicate detection, balance validation) before posting and reports a structured reason list — with nothing sent to SAP — if any guard fails. Deterministic SAP rejections (closed posting periods, missing tax jurisdiction, etc.) are translated into actionable messages rather than raw error codes.
Architecture
src/
├── server.ts # McpServer factory — tool registration, schemas, annotations
├── client.ts # SapClient — OData V2/V4 requests, CSRF-protected writes, SOAP posts
├── auth.ts # Auth strategies: Basic, OAuth Client Credentials, OAuth Authorization Code
├── config.ts # Connection config + SAP public sandbox detection
├── index.ts # stdio entry point
├── http.ts # Streamable HTTP entry point (Express, per-session auth)
└── tools/
├── shared.ts # OData/CSV/error-parsing + E2B sandbox file I/O, shared by every tool
└── *.ts # one file per tool (schema + handler)
Writes to OData V2 endpoints follow SAP's CSRF token protocol: fetch a token via GET with X-CSRF-Token: Fetch, resend it with the session cookie on the POST, retry once on a 403. Journal entry posting instead builds and sends a raw SOAP envelope, since that API has no OData equivalent.
Development
npm run dev # stdio, hot reload via tsx
npm run dev:http # HTTP, hot reload via tsx
npm run typecheck # tsc --noEmit
npm run build # compile to dist/
License
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.