Skip to content

Semantic Kernel for SAP ECC RFC integration (.NET)

Integrating Semantic Kernel (.NET) with SAP ECC via RFC (MCP Bridge)

Section titled “Integrating Semantic Kernel (.NET) with SAP ECC via RFC (MCP Bridge)”

While Microsoft’s Semantic Kernel operates natively in .NET (C#), integrating with legacy SAP ECC systems via RFC presents a unique “Big Iron” challenge. The traditional SAP .NET Connector (NCo 3.1) is powerful but notoriously difficult to containerize and deploy in modern, serverless, or microservices-based AI architectures due to its Windows-centric DLL dependencies.

For the AgentRetrofit architecture, we recommend a Sidecar Pattern: using a lightweight Python MCP Server to handle the raw SAP RFC connectivity (via the stable pyrfc library) and exposing these capabilities as tools to your Semantic Kernel .NET application.

This guide provides the complete “Bridge” infrastructure: a Python-based Model Context Protocol (MCP) server that connects to SAP ECC, which your C# agents can consume as a remote toolset.

🏗️ Architecture: The .NET-to-Python Bridge

Section titled “🏗️ Architecture: The .NET-to-Python Bridge”

Instead of embedding SAP DLLs directly into your AI agent, we decouple the connection:

  1. SAP ECC: The legacy ERP system (RFC Protocol).
  2. MCP Server (Python): Running fastmcp and pyrfc. This handles authentication, data mapping, and connection pooling.
  3. Semantic Kernel (.NET): The AI Agent running in C#, which connects to the MCP Server to execute tools like “GetCustomer” or “CheckStock”.

This approach ensures your C# agent remains lightweight while leveraging Python’s superior ecosystem for SAP Linux support.


🚀 Step 1: The SAP Bridge Server (server.py)

Section titled “🚀 Step 1: The SAP Bridge Server (server.py)”

This server uses fastmcp to expose SAP BAPIs (Business Application Programming Interfaces) as AI-ready tools.

Prerequisites:

  • SAP NetWeaver RFC SDK (download from SAP Marketplace).
  • Python 3.10+.
import os
import sys
from fastmcp import FastMCP
from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError
# Initialize the MCP Server
# We name it "sap-ecc-bridge" to identify it within the Semantic Kernel
mcp = FastMCP("sap-ecc-bridge")
# Configuration via Environment Variables
SAP_HOST = os.getenv("SAP_HOST")
SAP_SYSNR = os.getenv("SAP_SYSNR", "00")
SAP_CLIENT = os.getenv("SAP_CLIENT", "100")
SAP_USER = os.getenv("SAP_USER")
SAP_PASSWORD = os.getenv("SAP_PASSWORD")
def get_sap_connection():
"""Establishes a connection to SAP ECC using PyRFC."""
try:
conn = Connection(
ashost=SAP_HOST,
sysnr=SAP_SYSNR,
client=SAP_CLIENT,
user=SAP_USER,
passwd=SAP_PASSWORD
)
return conn
except Exception as e:
print(f"SAP Connection Failed: {e}", file=sys.stderr)
raise RuntimeError("Could not connect to SAP ECC backend.")
@mcp.tool()
def get_customer_details(customer_id: str) -> str:
"""
Retrieves detailed customer information from SAP ECC.
Args:
customer_id: The 10-digit SAP Customer Number (KUNNR).
"""
conn = None
try:
conn = get_sap_connection()
# BAPI_CUSTOMER_GETDETAIL2 is a standard remote-enabled function module
# Using uppercase for parameter names as per SAP standard
result = conn.call(
"BAPI_CUSTOMER_GETDETAIL2",
CUSTOMERNO=customer_id.zfill(10) # Ensure zero-padding
)
# Extract relevant fields from the return structure
address = result.get("CUSTOMERADDRESS", {})
return (
f"Customer: {customer_id}\n"
f"Name: {address.get('NAME', 'Unknown')}\n"
f"City: {address.get('CITY', 'Unknown')}\n"
f"Country: {address.get('COUNTRY', 'Unknown')}\n"
f"Full Response: {str(result)}"
)
except (ABAPApplicationError, ABAPRuntimeError) as e:
return f"SAP ABAP Error: {e}"
except Exception as e:
return f"System Error: {e}"
finally:
if conn:
conn.close()
@mcp.tool()
def check_material_availability(material_id: str, plant: str) -> str:
"""
Checks stock availability for a material in a specific plant using BAPI_MATERIAL_AVAILABILITY.
Args:
material_id: The SAP Material Number (MATNR).
plant: The 4-character Plant Code (WERKS).
"""
conn = None
try:
conn = get_sap_connection()
result = conn.call(
"BAPI_MATERIAL_AVAILABILITY",
PLANT=plant,
MATERIAL=material_id.zfill(18), # Standard SAP material length
UNIT="EA"
)
# The 'AV_QTY_PLT' field typically holds the available quantity
qty = result.get("AV_QTY_PLT", 0)
return f"Material {material_id} at Plant {plant}: {qty} units available."
except Exception as e:
return f"Error checking stock: {str(e)}"
finally:
if conn:
conn.close()
if __name__ == "__main__":
# fastmcp runs on port 8000 by default when executed directly
mcp.run()

Containerizing SAP applications is strict because you must include the proprietary SAP NetWeaver RFC SDK. You cannot download this SDK via apt-get; you must download it from the SAP Support Portal and place it in your build context.

File Structure Requirement:

/project
├── server.py
├── Dockerfile
└── nwrfcsdk/ <-- Unzipped SAP SDK (linuxx86_64)
├── lib/
└── include/

The Dockerfile:

# Use a lightweight Python base
FROM python:3.11-slim
# Set environment variables for SAP SDK
# These tell the OS where to find the SAP C++ libraries
ENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdk
ENV LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib
WORKDIR /app
# Install system dependencies required by SAP SDK
RUN apt-get update && apt-get install -y \
gcc \
g++ \
make \
uuid-dev \
&& rm -rf /var/lib/apt/lists/*
# ---------------------------------------------------------------------
# CRITICAL: Copy the SAP NetWeaver SDK into the container
# You must download 'nwrfcsdk' from SAP and place it in your local dir
# ---------------------------------------------------------------------
COPY nwrfcsdk /usr/local/sap/nwrfcsdk
# Create a config file for ldconfig so the system finds the libs
RUN echo "/usr/local/sap/nwrfcsdk/lib" > /etc/ld.so.conf.d/nwrfcsdk.conf \
&& ldconfig
# Install Python dependencies
# pyrfc requires the SDK to be present during installation for compilation
RUN pip install --no-cache-dir fastmcp pyrfc
# Copy the application code
COPY server.py .
# Ensure your container has network access (e.g. via NordLayer)
# SAP ECC usually sits behind a corporate firewall/VPN.
# This container needs a route to port 3300 (standard SAP RFC port).
# Expose the MCP Server port
EXPOSE 8000
# Run the MCP Bridge
CMD ["python", "server.py"]

🔌 Step 3: Connecting Semantic Kernel (.NET)

Section titled “🔌 Step 3: Connecting Semantic Kernel (.NET)”

Once your Docker container is running (e.g., on localhost:8000), your C# application can treat it as an OpenAI Plugin or an MCP endpoint.

Terminal window
# Build the image (assuming nwrfcsdk folder is present)
docker build -t sap-mcp-bridge .
# Run the container
docker run -p 8000:8000 \
-e SAP_HOST=192.168.1.50 \
-e SAP_USER=ALICE \
-e SAP_PASSWORD=Secret123 \
sap-mcp-bridge

In your .NET console application:

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Plugins.OpenApi;
// 1. Initialize the Kernel
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion("gpt-4", "your-api-key");
var kernel = builder.Build();
// 2. Import the SAP Bridge as a Plugin
// FastMCP provides an SSE endpoint, but can also serve OpenAPI specs if configured.
// For direct MCP support, use the experimental MCP connectors.
// Alternatively, if exposing via HTTP, import via OpenAPI:
await kernel.ImportPluginFromOpenApiAsync(
pluginName: "SAP_ECC",
uri: new Uri("http://localhost:8000/openapi.json") // FastMCP auto-gen
);
// 3. Invoke the Agent
var result = await kernel.InvokePromptAsync(
"Check stock for material 'MAT-4040' in plant '1000' and verify customer '0000102030'."
);
Console.WriteLine(result);

By using this Bridge Pattern, you solve the “Knowledge Gap” between modern .NET AI agents and legacy SAP infrastructure without battling Windows DLL compatibility issues.


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

Transparency: This page may contain affiliate links.