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:
- SAP ECC: The legacy ERP system (RFC Protocol).
- MCP Server (Python): Running
fastmcpandpyrfc. This handles authentication, data mapping, and connection pooling. - 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 osimport sysfrom fastmcp import FastMCPfrom pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError
# Initialize the MCP Server# We name it "sap-ecc-bridge" to identify it within the Semantic Kernelmcp = FastMCP("sap-ecc-bridge")
# Configuration via Environment VariablesSAP_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()🐳 Step 2: The Container (Dockerfile)
Section titled “🐳 Step 2: The Container (Dockerfile)”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 baseFROM python:3.11-slim
# Set environment variables for SAP SDK# These tell the OS where to find the SAP C++ librariesENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdkENV LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib
WORKDIR /app
# Install system dependencies required by SAP SDKRUN 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 libsRUN 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 compilationRUN pip install --no-cache-dir fastmcp pyrfc
# Copy the application codeCOPY 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 portEXPOSE 8000
# Run the MCP BridgeCMD ["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.
1. Build and Run the Bridge
Section titled “1. Build and Run the Bridge”# Build the image (assuming nwrfcsdk folder is present)docker build -t sap-mcp-bridge .
# Run the containerdocker run -p 8000:8000 \ -e SAP_HOST=192.168.1.50 \ -e SAP_USER=ALICE \ -e SAP_PASSWORD=Secret123 \ sap-mcp-bridge2. Consuming in C# (Semantic Kernel)
Section titled “2. Consuming in C# (Semantic Kernel)”In your .NET console application:
using Microsoft.SemanticKernel;using Microsoft.SemanticKernel.Plugins.OpenApi;
// 1. Initialize the Kernelvar 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 Agentvar 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.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.