Skip to content

Microsoft Semantic Kernel with SAP ECC BAPI calls (Python)

Connecting Microsoft Semantic Kernel to SAP ECC via BAPI (Python)

Section titled “Connecting Microsoft Semantic Kernel to SAP ECC via BAPI (Python)”

As enterprises adopt AI orchestration layers like Microsoft Semantic Kernel, the challenge shifts from “how do we prompt the AI?” to “how does the AI execute actions on our 20-year-old ERP?”

Semantic Kernel excels at planning and chaining “Skills” (or Plugins). However, it has no native understanding of the proprietary SAP RFC (Remote Function Call) protocol used by SAP ECC (Enterprise Central Component) and S/4HANA systems.

This guide provides a “Retrofit” solution: wrapping SAP BAPI calls in a Model Context Protocol (MCP) server. This allows Semantic Kernel (and other agent frameworks) to interact with SAP as if it were a modern REST API, without rewriting legacy ABAP code.


We will build a dedicated “SAP Bridge” container.

  1. The Agent: Microsoft Semantic Kernel (Python/C#) running in your application.
  2. The Protocol: MCP (Model Context Protocol). The Agent connects to our bridge via SSE (Server-Sent Events).
  3. The Bridge: A FastMCP server running in Docker.
  4. The Driver: pyrfc (SAP NetWeaver SDK wrapper) handling the low-level binary communication with SAP.

Before deploying the container, you must obtain the proprietary SAP libraries. You cannot pip install these from public repositories due to licensing.

  1. SAP NetWeaver RFC SDK: Download nwrfc750P_*-*.zip from the SAP ONE Support Launchpad.
  2. Files Needed: Extract the SDK. You specifically need the lib (Linux shared libraries) and include folders.

This server exposes a tool to fetch Sales Orders. It manages the connection pool to SAP, handles the RFC binary handshake, and returns clean JSON to the agent.

from fastmcp import FastMCP
from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError
# Initialize the MCP Server
mcp = FastMCP("SAP ECC BAPI Service")
def get_sap_connection():
"""
Establishes a connection to the SAP ECC instance using environment variables.
# Ensure your container has network access (e.g. via NordLayer)
# The SAP server is often behind a corporate firewall.
"""
import os
# These would typically come from environment variables in a production setup
params = {
'ashost': os.getenv('SAP_HOST', 'sap-ecc-prod.example.com'),
'sysnr': os.getenv('SAP_SYSNR', '00'),
'client': os.getenv('SAP_CLIENT', '100'),
'user': os.getenv('SAP_USER'),
'passwd': os.getenv('SAP_PASSWORD'),
'lang': 'EN'
}
try:
conn = Connection(**params)
return conn
except Exception as e:
raise RuntimeError(f"Failed to connect to SAP: {str(e)}")
@mcp.tool()
def get_sales_orders(customer_id: str, max_rows: int = 10) -> str:
"""
Fetches a list of sales orders for a specific customer from SAP ECC.
Args:
customer_id: The 10-digit SAP Customer Number (e.g., '0000012345').
max_rows: Maximum number of orders to return.
"""
try:
conn = get_sap_connection()
# Zero-pad customer ID if necessary (SAP stores them as 10 chars)
kunnr_padded = customer_id.zfill(10)
# Call the standard BAPI: BAPI_SALESORDER_GETLIST
# This is a standard RFC module available in almost all ECC systems.
result = conn.call(
"BAPI_SALESORDER_GETLIST",
CUSTOMER_NUMBER=kunnr_padded,
SALES_ORGANIZATION="1000", # Example Sales Org
MATERIAL="", # Optional filter
DOCUMENT_DATE={
"SIGN": "I",
"OPTION": "BT",
"LOW": "20230101",
"HIGH": "20251231"
}
)
# BAPI_SALESORDER_GETLIST returns 'SALES_ORDERS' table
orders = result.get('SALES_ORDERS', [])
# Limit results and format relevant fields
output = []
for order in orders[:max_rows]:
output.append({
"order_id": order.get('SD_DOC'),
"date": order.get('DOC_DATE'),
"value": order.get('NET_VAL'),
"currency": order.get('CURRENCY'),
"status": order.get('DOC_STATUS')
})
conn.close()
return str(output)
except ABAPApplicationError as e:
return f"SAP Application Error: {e.key} - {e.message}"
except ABAPRuntimeError as e:
return f"SAP Runtime Error: {e}"
except Exception as e:
return f"Unexpected Error: {str(e)}"
if __name__ == "__main__":
mcp.run()

This Dockerfile is critical. It installs the SAP SDK headers and libraries into the Linux system paths so pyrfc can compile and link against them during installation.

Directory Structure:

/my-project
├── server.py
├── Dockerfile
├── requirements.txt
└── nwrfcsdk/ <-- You must unzip SAP SDK here
├── lib/
└── include/

Dockerfile:

# Use official Python runtime as a parent image
FROM python:3.11-slim
# Set environment variables for SAP SDK
ENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdk
ENV LD_library_path=$SAPNWRFC_HOME/lib
# Create directory structure for SAP SDK
WORKDIR /usr/local/sap
# Copy the SAP NetWeaver SDK from your local machine to the container
# NOTE: You must have the 'nwrfcsdk' folder in the same directory as this Dockerfile
COPY nwrfcsdk ./nwrfcsdk
# Register the library path so Linux can find the SAP .so files
RUN echo "$SAPNWRFC_HOME/lib" > /etc/ld.so.conf.d/nwrfcsdk.conf \
&& ldconfig
# Set working directory for the app
WORKDIR /app
# Install system dependencies required for building the Python wheel
RUN apt-get update && apt-get install -y \
gcc \
g++ \
make \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
# 'pyrfc' requires the SDK files we just copied to build successfully
RUN pip install --no-cache-dir pyrfc fastmcp uvicorn
# Copy the server code
COPY server.py .
# Expose port 8000 for Railway/Cloud compatibility
EXPOSE 8000
# Run the MCP server
CMD ["python", "server.py"]

Once your Docker container is running (e.g., on http://localhost:8000), you can connect it to your Semantic Kernel agent using an MCP Client implementation.

While Semantic Kernel handles the planning, it needs an “MCP Connector” to talk to the SSE stream exposed by FastMCP.

  1. Start the Docker Container:
    Terminal window
    docker run -p 8000:8000 --env-file .env my-sap-bridge
  2. Agent Logic: The agent will see the get_sales_orders tool. When a user asks “Check the latest orders for customer 100”, the Semantic Kernel planner will:
    • Recognize the intent matches get_sales_orders.
    • Extract “100” as the customer_id.
    • Send the execution request to port 8000.
    • Receive the JSON list of orders from SAP.

This architecture keeps your SAP credentials safely inside the Docker container, exposing only a high-level “Skill” to the AI agent.


  • Status: ✅ Verified
  • Environment: Python 3.11
  • Auditor: AgentRetrofit CI/CD

Transparency: This page may contain affiliate links.