Integration Blog Posts
cancel
Showing results for 
Search instead for 
Did you mean: 

Introduction/Scenario

This post continues from the previous article, MCP Server with Integration Suite, expose S/4HANA ... - SAP Community, and focuses on addressing the identified issues by using API Artifacts.
 
Important Update 2026-Oct-02: The workaround on handling the SSO Authentication no longer valid as SAP updates not allowing developer to remove the auto generated HTTP channel in API artifact anymore. Of course, there is other workaround which considered dirty tick that I would not keen to share this publicly. Let wait for the official released by SAP on supporting the principal propagation. 
However, the handling of CSRF token or etag approach still valid.

Background:

The previous post demonstrated how to set up an MCP server with SAP Integration Suite and connect it to S/4HANA Public Cloud using OAuth2SAMLBearerAssertion. This approach helps maintain governance by ensuring that S/4HANA APIs are consumed using a named user account, where access is restricted based on the authorizations and roles assigned to that user.

When the MCP server is used for read-only scenarios, such as HTTP GET operations, it works well with clients such as GitHub Copilot and Claude. However, several issues were encountered when attempting to perform write operations against S/4HANA Public Cloud APIs, such as HTTP POST (create) and PATCH (update) requests through the MCP server.

Therefore, the approach described in this post is optional and only relevant if your MCP server needs to support create or update operations on S/4HANA APIs. If your use case is limited to HTTP GET requests, you can continue to follow the implementation approach described in the previous blog without the additional steps covered here.

Note: SAP may enhance Integration Suite in future releases to support these scenarios out of the box. As a result, the workaround described in this post may eventually become obsolete. Before implementing this approach, always refer to the latest SAP documentation available on SAP Help Portal to verify whether a native solution is available.

 

Issue CountIssue Detail
1

Data type that interpreted as object as example below, where causing issue when calling the MCP server.

Thanks @MioYasutake, shared the workaround to remove the "anyOf" in the OpenAPI specification with a plain type, that shall resolve this issue if direct expose the S/4HANA API via the MCP server.

However, the approach shared in this blog does not need touch the OpenAPI specification.

ChingHong_0-1790346046105.png
2

 Getting error as it is trying to convert the content before perform API call

Current workaround: Remove all the SAP_Messages and SAP__Messages from the downloaded OpenAPI file and load into the integration suite MCP server again. But this is touching the OpenAPI file that downloaded from api.sap.com. Looks like there is no other option beside touching the specification file.

ChingHong_0-1790264941269.png

 

3

CSRF token issue when doing HTTP Post action, looks like there is no way to enhance the MCP to send access HTTP header and update the MCP server to handle this.

This blog is demonstrating the possible option to resolve this.

4

ETag handling when doing HTTP patch action

This blog is demonstrating the possible option to resolve this.

5

Other data type issues, for example "Time" don't seem working as expected in Postman, SAP return "HH:MM:SS", but "Time" data type is expecting "HH:MM:SS{Z}" instead if not mistaken. Will need to remove the "Time Format" in the API artifact or update the OpenAPI specification prior loaded into the API artifact. 

ChingHong_1-1790435112981.png

The response in the Postman console

ChingHong_2-1790435270784.png

 The MCP artifact/policies only allows limited API policies application (refer - Configure an MCP Server Created from an API Artifact | SAP Help Portal), and no message transformation or additional HTTP called is allowed. Hence, this writing is demonstrating how to use the API Centric Artifact on solving some of the mentioned issued below and still supporting user principal propagation connection to the S/4HANA Public Cloud API.

Note:

  1. As of the date of writing, the API-centric artifacts and policies in SAP Integration Suite do not support principal propagation. During Devtoberfest 2026 From APIs to Agent Tools: How MCP Gateway changes what Integration means - YouTube, SAP indicated that this capability is on the roadmap for a future release. Therefore, this blog demonstrates a possible workaround to achieve principal propagation until native support becomes available.
  2. In addition, the final section of this blog shows how principal propagation can be implemented when connecting to SAP S/4HANA Private Cloud or SAP S/4HANA On-Premise via SAP Cloud Connector.

Flow:

→ Agent (Claude/Github Copilot/any AI Agent) 
  → MCP server by Integration Suite (Authenticated via IAS)
    → API Artifact by Integration Suite (Authenticated via IAS)
        → BTP Destination Service (OAuth2SAMLBearerAssertion) 
          → S/4HANA Public Cloud (executed as the authenticated user)

ChingHong_0-1790437970160.png

  • Will leverage the BTP destination API to generate SAML bearer assertion token to access the S/4HANA public cloud to overcome the limitation that API artifact don't support OAuth2SAMLBearerAssertion. Reference 

Pre-requisite:

  • SAP BTP with Cloud Foundry Enabled
  • SAP Integration Suite with MCP server, Integration Cell runtime capability
  • S/4HANA Public Cloud 
  • SAP Cloud Identity Services (IAS)
  • AI Agent able to communicate with MCP server
  • The BTP destination to S/4HANA Public Cloud already setup - refer previous blog 

Destination Service Instance Setup

 Goto BTP create an destination service instance

  • Service: Destination Service
  • Plan: lite
  • Create a key and copy the Client ID, Client Secret and uri for later usage

ChingHong_1-1790266815469.png


Create API Artifact

Important: Remove all the SAP_Messages and SAP__Messages from the downloaded OpenAPI file. You may use AI assistant on helping this if not familiar on changing this. 

Create a new API Artifact - choose Integration Cell as the Runtime Profile

ChingHong_2-1790267313450.png

Select URL or  Specification

ChingHong_3-1790267471378.png

Enter the information as below

  • Filename: OpenAPI specification(downloaded from api.sap.com) and remove the SAP_Messages and SAP__Messages from the file
  • URL: URL to access the S/4HANA public cloud sales order api
  • Name: your prefer name
  • ID: your prefer ID
  • Service Type: REST
  • API Base Path: your prefer path

ChingHong_4-1790267651021.png

Update description if required

ChingHong_6-1790268210077.png

The URL here will be come irrelevant to the policies as will overwrite the auto generated endpoint

ChingHong_7-1790268285748.png

Resources are auto generated based on the uploaded API specification

ChingHong_8-1790268349992.png

Policies

Important here: delete the auto generated target HTTP channel, recreate a new HTTP channel to target or S/4HANA Public Cloud API, as the default generated target HTTP channel not allowing the "Authorization" header passing

ChingHong_9-1790270518170.png

ChingHong_10-1790270568726.png

More information can refer to the blog Secure APIs: External OIDC-Based Authentication fo... - SAP Community

  • The Well-known URL: https://<ias tenant>.accounts.ondemand.com/.well-known/openid-configuration
  • Audience: Can leave empty unless restrict to certain client ID or target system only
  • ClientID Key: standard using ${authn.oidc.jwt.azp}, where you can find out this when studying the JWT via any JWT decoder, for example: SuperTokens JWT Decoder
  • User Info Key: standard using ${authn.oidc.jwt.email}, where you can find out this when studying the JWT via any JWT decoder, for example: SuperTokens JWT Decoder

 

ChingHong_11-1790270632849.png
import com.sap.it.script.v2.api.Message;
import groovy.json.JsonOutput;
import groovy.json.JsonSlurper;

def Message storeInputInformation(Message message) {
    
    Map<String, Object> headers = message.getHeaders();
    
    // Convert to JSON string
    String headersJson = JsonOutput.prettyPrint(JsonOutput.toJson(headers))
    // Store in exchange property
    message.setProperty("OriHeaders", headersJson);
    
    message.setProperty("OriBody", message.getBody());
    
    // get token
    String authHeader = message.getHeader("Authorization", String)
    String token = authHeader?.replaceFirst(/^Bearer\s+/, "")
    message.setProperty("AccessToken", token)
    
    // set token for destination fetch
    message.setHeader("x-user-token", token)
    
    return message;
}

 

Request-Reply to Destination Service

ChingHong_12-1790270763074.png

 

 

Extract Token return from destination, where this Token can be used to call S/4HANA

ChingHong_13-1790270992022.png

def Message extractTokenFromDestination(Message message) {
    
    // set back original headers
    String headersJson = message.getProperty("OriHeaders")
    if (headersJson) {
        def headersMap = new JsonSlurper().parseText(headersJson)
        headersMap.each { key, value ->
            if (value != null) {
                message.setHeader(key.toString(), value.toString())
            }
        }
    }

    def json = new JsonSlurper().parseText(message.getBody(String))

    def bearerToken = json.authTokens?.find { it.type == "Bearer" }?.value
    message.setHeader("Authorization", "Bearer ${bearerToken}")
    message.setProperty("SAMLBearerAssertionToken", bearerToken);
    
    message.setBody(message.getProperty("OriBody"));

    return message;
}

 

Router to decide fetch CSRF token

ChingHong_14-1790271199991.png

 

Content Modifier: Set CSRF Token Fetch Header

ChingHong_15-1790271220133.png

 

Request Reply - Fetch CSRF Token

  • Address: <api URL>
  • Proxy Type: Internet
  • Method: GET
  • Authentication: none (token already set in previous step, will be pass at request header)
  • Request Headers: Authorization|x-csrf-token
  • Response Headers: *
ChingHong_1-1790437703923.png

 

Extract CSRF response cookie and set cookie

ChingHong_1-1790346956030.png
def Message extractCSRFToken(Message message) {
    
    def cookies = message.getHeader("set-cookie");
    message.setHeader("cookie", String.join("; ", cookies));
    
    return message;
}

 

Router - set Etag header, set to * always also force update

ChingHong_0-1790347099752.png

 

 Set the original input header and body before perform the HTTP call to the actual target API URL

ChingHong_1-1790347177769.png
def Message prepareInputPriorCall(Message message) {
    // keep a copy of the cookies as this is returned by the CSRF token fetch
    def cookies = message.getHeader("cookie");
    
    // set back original headers
    String headersJson = message.getProperty("OriHeaders")
    if (headersJson) {
        def headersMap = new JsonSlurper().parseText(headersJson)
        headersMap.each { key, value ->
            if (value != null) {
                message.setHeader(key.toString(), value.toString())
            }
        }
    }
    
    // pass the bearer token as authorization header
    def bearerToken = message.getProperty("SAMLBearerAssertionToken");
    message.setHeader("Authorization", "Bearer ${bearerToken}")
    
    message.setBody(message.getProperty("OriBody"));
    
    // set back the CSRF token fetch cookie
    message.setHeader("cookie", cookies);
    
    return message;
}

 

Actual Request-Reply to the API URL based on the input

  • Address: <api URL>${header.camelhttppath}
  • Query: ${header.camelhttpquery}
  • Proxy Type: Internet
  • Method: Dynamic
  • Expression: ${header.camelhttpmethod}
  • Send Body: checkbox ticked
  • Authentication: none (token already set in previous step, will be pass at request header)
  • Request Headers: *
  • Response Headers: *
ChingHong_0-1790437654024.png

Setup the MCP server in Integration Suite

Information: Configure an MCP Server Created from an API Artifact | SAP Help Portal

ChingHong_3-1790347630526.png

Create a new MCP server in Integration Suite

  • Source Type - API

ChingHong_0-1790393821565.png

  • Select the API, Enter name, ID, MCP Path, Version

ChingHong_1-1790393926441.png

  • Select the tools and click Add

ChingHong_2-1790393994855.png

  • Remain all auto generated item and deploy the MCP server

ChingHong_3-1790394072496.png

Include the MCP server into the Product. Refer to the previous blog on how to setup product

ChingHong_4-1790394229859.png

 


Test the new MCP server in Github Copilot

Note: Refer to previous blog on how to setup connection to MCP server in VS Code

Scenarios:

  1. Get order detail
  2. Create a new order
  3. Update order
1

Get order detail

ChingHong_5-1790394675047.pngChingHong_6-1790394706190.png
2

Create new order via MCP

ChingHong_7-1790394811842.pngChingHong_8-1790394828383.pngChingHong_9-1790395286555.png

The payload that used to call MCP server - there is no issue passing the quantity in integer format now.

ChingHong_10-1790395332055.png
3

Update the sales order reference

ChingHong_11-1790395466109.pngChingHong_12-1790395488353.png

Sample payload call MCP server

ChingHong_13-1790395529483.png

 


Similar concepts communicate with S/4HANA Private Cloud or Onpremise via Cloud Connector (Principal Propagation)

Note:

  • The trial account used throughout this blog is not connected to a SAP Cloud Connector and therefore cannot access an SAP S/4HANA Private Cloud or SAP S/4HANA On-Premise system. For the demonstration below, I use a separate SAP Integration Suite tenant that is connected to an SAP S/4HANA On-Premise system via SAP Cloud Connector. Since this tenant does not have Integration Cell or MCP capabilities, a standard iFlow is used to illustrate the configuration and principal propagation flow.
  • Refer to this blog(Principal Propagation for MCP Servers - SAP Integr... - SAP Community / Principal propagation setup with SAP S/4HANA on-pr... - SAP Community) to understand how to setup cloud connector - principal propagation
    • Useful transaction code: SECTRACE, CERTRULE 
  • Expecting the caller calls the iFlow with OAuth2 Authorization code method, that allow the call to S/4HANA Private Cloud or Onpremise via Cloud Connector with principal propagation 

ChingHong_0-1790396082897.png

Content Modifier to setup the required header for Principal Propagation.

ChingHong_1-1790396119582.png

HTTP channel

  • Request Headers: SAP-Connectivity-Authentication
  • Authentication: None

ChingHong_2-1790396350719.png

ChingHong_3-1790396378393.png

Create SAP Process Integration Runtime service instance key to allow testing from Postman

  • Grant-type: authorization_code, refresh_token

ChingHong_5-1790396801943.pngChingHong_4-1790396771715.png

Test via postman

  • The authentication Token URL, Auth URL, Client ID and Client secret can be retrieved from the generated service instance in previous step

ChingHong_7-1790396889268.pngChingHong_0-1790433658248.png


I hope you found this blog helpful.

Reference

Labels in this area