Expose S/4HANA Cloud OData API as an MCP Server via CAP Node.js

Estimated read time 10 min read
Overview

 

This tutorial walks you through building a CAP Node.js project that wraps the SAP S/4HANA Cloud Outbound Delivery OData v2 API and exposes it as an MCP (Model Context Protocol) server. This allows AI tools (such as Claude) to query and create outbound deliveries directly through natural language.

 

By the end, you will have:

A CAP service that proxies the S/4HANA `API_OUTBOUND_DELIVERY_SRV` OData v2 APIAn MCP endpoint consumable by any MCP-compatible AI clientA deployed application on SAP BTP Cloud Foundry

 

Prerequisites

SAP BTP account with Cloud Foundry environmentS/4HANA Cloud system with access to the Outbound Delivery APISAP CAP (`@sap/cds`) installed globally. Refer to the CAP initial setup guideNode.js 20+Cloud Foundry CLI (`cf`)

 

Procedure

 

Step 1 — Generate a Sample CAP Project
Scaffold a new CAP Node.js project and open it in VS Code:

cds init capmcps4 –nodejs
cd capmcps4
code .

 

 

Step 2 — Download the OData API Metadata
Go to the SAP API Business Hub — Outbound Delivery API and download the EDMX metadata file.
 

 

 

 

Step 3 — Import the EDMX Metadata into CAP
Use the `cds import` command to generate a CDS definition from the downloaded EDMX file:

cds import <path-to-edmx-file> –as cds –out srv/external/API_OUTBOUND_DELIVERY_SRV_0002.cds

 

 

Step 4 — Configure `package.json`
Update `package.json` to add MCP support and configure the S/4HANA connection credentials.

 

Before:

“cds”: {
“requires”: {
“API_OUTBOUND_DELIVERY_SRV_0002”: {
“kind”: “odata-v2”,
“model”: “srv/external/API_OUTBOUND_DELIVERY_SRV_0002”
}
}
}

 
After:

“cds”: {
“mcp”: {
“per_action_tool”: true
},
“requires”: {
“API_OUTBOUND_DELIVERY_SRV_0002”: {
“kind”: “odata-v2”,
“model”: “srv/external/API_OUTBOUND_DELIVERY_SRV_0002”,
“[hybrid]”: {
“csrf”: true,
“csrfInBatch”: true,
“credentials”: {
“url”: “https://<S4-instance>-api.s4hana.ondemand.com/sap/opu/odata/sap/API_OUTBOUND_DELIVERY_SRV;v=0002”,
“authentication”: “BasicAuthentication”,
“username”: “<S4-communication-user>”,
“password”: “<S4-communication-password>”
}
},
“[production]”: {
“credentials”: {
“destination”: “<S4-destination-name>”,
“path”: “/sap/opu/odata/sap/API_OUTBOUND_DELIVERY_SRV;v=0002”
}
}
}
}
}

 
> Replace `<S4-instance>`, `<S4-communication-user>`, `<S4-communication-password>`, and `<S4-destination-name>` with your actual values.

 

Step 5 — Define the CAP Service (`srv/dnsrv.cds`)
Create `srv/dnsrv.cds` to expose the delivery entities and a `createDelivery` action, annotated with both OData v4 and MCP protocols:

using {API_OUTBOUND_DELIVERY_SRV_0002 as s4h} from ‘./external/API_OUTBOUND_DELIVERY_SRV_0002’;

@title : ‘Outbound Delivery Service’
@description: ‘Manages outbound delivery headers and items from SAP S/4HANA.’
service dnsservices {

@title : ‘Delivery Document’
@description: ‘Outbound delivery header from S/4HANA. Contains shipping details, partner data, dates, and overall status.’
entity DeliveryDocument as projection on s4h.A_OutbDeliveryHeader;

@title : ‘Delivery Document Item’
@description: ‘Line items of an outbound delivery. Each item holds material, quantity, plant, and storage details.’
entity DeliveryDocumentItem as projection on s4h.A_OutbDeliveryItem;

type DeliveryItemInput {
ReferenceSDDocument : String;
ReferenceSDDocumentItem: String;
}

action createDelivery(
ShippingPoint : String;
items : many DeliveryItemInput
) returns DeliveryDocument;
}

annotate dnsservices with @protocol: [
‘odata-v4’,
‘mcp’
];

 

 

 

 

Step 6 — Implement the Service Handler (`srv/dnsrv.js`)
Create `srv/dnsrv.js` to delegate CRUD operations to S/4HANA and handle the `createDelivery` action:

const cds = require(“@sap/cds”);

class Dnsrv extends cds.ApplicationService {
async init() {
const s4h = await cds.connect.to(“API_OUTBOUND_DELIVERY_SRV_0002”);

this.on(“createDelivery”, async (req) => {
const { ShippingPoint, items = [] } = req.data;
if (!ShippingPoint) return req.error(400, “ShippingPoint is required”);

return s4h.send({
method: “POST”,
path: “/A_OutbDeliveryHeader”,
data: {
ShippingPoint,
to_DeliveryDocumentItem: {
results: items.map((item) => ({
ReferenceSDDocument: item.ReferenceSDDocument,
ReferenceSDDocumentItem: item.ReferenceSDDocumentItem,
})),
},
},
});
});

this.on(“READ”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));
this.on(“CREATE”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));
this.on(“UPDATE”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));
this.on(“DELETE”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));

return super.init();
}
}

module.exports = { dnsservices: Dnsrv };

 

 

 

 

Step 7 — Add MCP, XSUAA, and MTA Support
Install the MCP plugin and add the required BTP service configurations:

npm add @cap-js/mcp
cds add xsuaa
cds add mta

 

 

 

 

Step 8 — Run the Application Locally (Hybrid Mode)
Start the CAP server using the hybrid profile to connect to the real S/4HANA system:

npm i
cds watch –profile hybrid

 

 

 

 

Step 9 — Test the MCP Endpoint
Create `test/http/dnsservices.http` and use the REST Client extension in VS Code to send MCP requests:

@server=http://localhost:4004
@username=alice
@password=

# ─── List available MCP tools ────────────────────────────────────────────────

### MCP – list tools
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 1,
“method”: “tools/list”
}

# ─── Describe service schema ─────────────────────────────────────────────────

### MCP – describe service
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 2,
“method”: “tools/call”,
“params”: {
“name”: “describe”,
“arguments”: {}
}
}

# ─── Query delivery documents ─────────────────────────────────────────────────

### MCP – query DeliveryDocument
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 3,
“method”: “tools/call”,
“params”: {
“name”: “query”,
“arguments”: {
“entity”: “DeliveryDocument”,
“limit”: 5
}
}
}

### MCP – query DeliveryDocumentItem
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 4,
“method”: “tools/call”,
“params”: {
“name”: “query”,
“arguments”: {
“entity”: “DeliveryDocumentItem”,
“limit”: 5
}
}
}

# ─── Create a delivery ────────────────────────────────────────────────────────

### MCP – action createDelivery
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 5,
“method”: “tools/call”,
“params”: {
“name”: “createDelivery”,
“arguments”: {
“ShippingPoint”: “1710”,
“items”: [
{
“ReferenceSDDocument”: “533916”,
“ReferenceSDDocumentItem”: “000010”
},
{
“ReferenceSDDocument”: “533917”,
“ReferenceSDDocumentItem”: “000010”
}
]
}
}
}

 

 

 

 

 

 

 

Step 10 — Deploy to SAP BTP Cloud Foundry
Log in to Cloud Foundry and deploy the application using `cds up`:

cf login -a <cloud-foundry-api-url> –sso
npm i
cds up

 

 

 

 

Step 11 — Verify the Deployed MCP Server
Confirm the MCP server is running and accessible in the BTP environment.
 

 

 
The End!
 
Thank you for your time! Jacky Liu

 

​ Overview This tutorial walks you through building a CAP Node.js project that wraps the SAP S/4HANA Cloud Outbound Delivery OData v2 API and exposes it as an MCP (Model Context Protocol) server. This allows AI tools (such as Claude) to query and create outbound deliveries directly through natural language. By the end, you will have:A CAP service that proxies the S/4HANA `API_OUTBOUND_DELIVERY_SRV` OData v2 APIAn MCP endpoint consumable by any MCP-compatible AI clientA deployed application on SAP BTP Cloud Foundry PrerequisitesSAP BTP account with Cloud Foundry environmentS/4HANA Cloud system with access to the Outbound Delivery APISAP CAP (`@sap/cds`) installed globally. Refer to the CAP initial setup guideNode.js 20+Cloud Foundry CLI (`cf`) Procedure Step 1 — Generate a Sample CAP ProjectScaffold a new CAP Node.js project and open it in VS Code:cds init capmcps4 –nodejs
cd capmcps4
code .  Step 2 — Download the OData API MetadataGo to the SAP API Business Hub — Outbound Delivery API and download the EDMX metadata file.    Step 3 — Import the EDMX Metadata into CAPUse the `cds import` command to generate a CDS definition from the downloaded EDMX file:cds import <path-to-edmx-file> –as cds –out srv/external/API_OUTBOUND_DELIVERY_SRV_0002.cds  Step 4 — Configure `package.json`Update `package.json` to add MCP support and configure the S/4HANA connection credentials. Before:”cds”: {
“requires”: {
“API_OUTBOUND_DELIVERY_SRV_0002”: {
“kind”: “odata-v2”,
“model”: “srv/external/API_OUTBOUND_DELIVERY_SRV_0002”
}
}
} After:”cds”: {
“mcp”: {
“per_action_tool”: true
},
“requires”: {
“API_OUTBOUND_DELIVERY_SRV_0002”: {
“kind”: “odata-v2”,
“model”: “srv/external/API_OUTBOUND_DELIVERY_SRV_0002”,
“[hybrid]”: {
“csrf”: true,
“csrfInBatch”: true,
“credentials”: {
“url”: “https://<S4-instance>-api.s4hana.ondemand.com/sap/opu/odata/sap/API_OUTBOUND_DELIVERY_SRV;v=0002”,
“authentication”: “BasicAuthentication”,
“username”: “<S4-communication-user>”,
“password”: “<S4-communication-password>”
}
},
“[production]”: {
“credentials”: {
“destination”: “<S4-destination-name>”,
“path”: “/sap/opu/odata/sap/API_OUTBOUND_DELIVERY_SRV;v=0002”
}
}
}
}
} > Replace `<S4-instance>`, `<S4-communication-user>`, `<S4-communication-password>`, and `<S4-destination-name>` with your actual values. Step 5 — Define the CAP Service (`srv/dnsrv.cds`)Create `srv/dnsrv.cds` to expose the delivery entities and a `createDelivery` action, annotated with both OData v4 and MCP protocols:using {API_OUTBOUND_DELIVERY_SRV_0002 as s4h} from ‘./external/API_OUTBOUND_DELIVERY_SRV_0002’;

@title : ‘Outbound Delivery Service’
@description: ‘Manages outbound delivery headers and items from SAP S/4HANA.’
service dnsservices {

@title : ‘Delivery Document’
@description: ‘Outbound delivery header from S/4HANA. Contains shipping details, partner data, dates, and overall status.’
entity DeliveryDocument as projection on s4h.A_OutbDeliveryHeader;

@title : ‘Delivery Document Item’
@description: ‘Line items of an outbound delivery. Each item holds material, quantity, plant, and storage details.’
entity DeliveryDocumentItem as projection on s4h.A_OutbDeliveryItem;

type DeliveryItemInput {
ReferenceSDDocument : String;
ReferenceSDDocumentItem: String;
}

action createDelivery(
ShippingPoint : String;
items : many DeliveryItemInput
) returns DeliveryDocument;
}

annotate dnsservices with @protocol: [
‘odata-v4’,
‘mcp’
];    Step 6 — Implement the Service Handler (`srv/dnsrv.js`)Create `srv/dnsrv.js` to delegate CRUD operations to S/4HANA and handle the `createDelivery` action:const cds = require(“@sap/cds”);

class Dnsrv extends cds.ApplicationService {
async init() {
const s4h = await cds.connect.to(“API_OUTBOUND_DELIVERY_SRV_0002”);

this.on(“createDelivery”, async (req) => {
const { ShippingPoint, items = [] } = req.data;
if (!ShippingPoint) return req.error(400, “ShippingPoint is required”);

return s4h.send({
method: “POST”,
path: “/A_OutbDeliveryHeader”,
data: {
ShippingPoint,
to_DeliveryDocumentItem: {
results: items.map((item) => ({
ReferenceSDDocument: item.ReferenceSDDocument,
ReferenceSDDocumentItem: item.ReferenceSDDocumentItem,
})),
},
},
});
});

this.on(“READ”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));
this.on(“CREATE”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));
this.on(“UPDATE”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));
this.on(“DELETE”, [“DeliveryDocument”, “DeliveryDocumentItem”], (req) => s4h.run(req.query));

return super.init();
}
}

module.exports = { dnsservices: Dnsrv };    Step 7 — Add MCP, XSUAA, and MTA SupportInstall the MCP plugin and add the required BTP service configurations:npm add @cap-js/mcp
cds add xsuaa
cds add mta    Step 8 — Run the Application Locally (Hybrid Mode)Start the CAP server using the hybrid profile to connect to the real S/4HANA system:npm i
cds watch –profile hybrid    Step 9 — Test the MCP EndpointCreate `test/http/dnsservices.http` and use the REST Client extension in VS Code to send MCP requests:@server=http://localhost:4004
@username=alice
@password=

# ─── List available MCP tools ────────────────────────────────────────────────

### MCP – list tools
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 1,
“method”: “tools/list”
}

# ─── Describe service schema ─────────────────────────────────────────────────

### MCP – describe service
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 2,
“method”: “tools/call”,
“params”: {
“name”: “describe”,
“arguments”: {}
}
}

# ─── Query delivery documents ─────────────────────────────────────────────────

### MCP – query DeliveryDocument
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 3,
“method”: “tools/call”,
“params”: {
“name”: “query”,
“arguments”: {
“entity”: “DeliveryDocument”,
“limit”: 5
}
}
}

### MCP – query DeliveryDocumentItem
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 4,
“method”: “tools/call”,
“params”: {
“name”: “query”,
“arguments”: {
“entity”: “DeliveryDocumentItem”,
“limit”: 5
}
}
}

# ─── Create a delivery ────────────────────────────────────────────────────────

### MCP – action createDelivery
POST {{server}}/mcp/dnsservices
Content-Type: application/json
Accept: application/json, text/event-stream

{
“jsonrpc”: “2.0”,
“id”: 5,
“method”: “tools/call”,
“params”: {
“name”: “createDelivery”,
“arguments”: {
“ShippingPoint”: “1710”,
“items”: [
{
“ReferenceSDDocument”: “533916”,
“ReferenceSDDocumentItem”: “000010”
},
{
“ReferenceSDDocument”: “533917”,
“ReferenceSDDocumentItem”: “000010”
}
]
}
}
}       Step 10 — Deploy to SAP BTP Cloud FoundryLog in to Cloud Foundry and deploy the application using `cds up`:cf login -a <cloud-foundry-api-url> –sso
npm i
cds up    Step 11 — Verify the Deployed MCP ServerConfirm the MCP server is running and accessible in the BTP environment.   The End! Thank you for your time! Jacky Liu   Read More Technology Blog Posts by SAP articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author