Microsoft Semantic Kernel with SAP ECC BAPI calls (Python)
Microsoft Semantic Kernel with SAP ECC BAPI (Python)
Section titled โMicrosoft Semantic Kernel with SAP ECC BAPI (Python)โConnecting Microsoft Semantic Kernel to legacy SAP systems allows you to orchestrate complex ERP workflows using modern AI planners. By treating SAP BAPIs as Model Context Protocol (MCP) tools, you decouple the rigid legacy protocol from the flexible AI reasoning layer.
๐๏ธ Architecture
Section titled โ๐๏ธ ArchitectureโWe use FastMCP to create an SSE server that acts as the โGlueโ between the SAP RFC protocol and the Semantic Kernel.
- Server: A Python container running
pyrfcto talk to SAP. - Protocol: MCP (Model Context Protocol) over SSE (Server-Sent Events).
- Client: Semantic Kernel (Python) configured to consume the MCP stream.
๐ Server Implementation (server.py)
Section titled โ๐ Server Implementation (server.py)โThis server exposes SAP BAPI execution capabilities.
import osimport jsonfrom mcp.server.fastmcp import FastMCPfrom pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError
# Initialize FastMCP servermcp = FastMCP("SAP-ECC-Gateway")
# SAP Connection Config (Load from ENV for security)SAP_CONFIG = { 'ashost': os.getenv('SAP_ASHOST'), 'sysnr': os.getenv('SAP_SYSNR'), 'client': os.getenv('SAP_CLIENT'), 'user': os.getenv('SAP_USER'), 'passwd': os.getenv('SAP_PASSWORD'), 'lang': 'EN'}
def get_sap_connection(): # Ensure your container has network access (e.g. via NordLayer) try: return Connection(**SAP_CONFIG) except Exception as e: raise RuntimeError(f"SAP Connection Failed: {str(e)}")
@mcp.tool()def execute_bapi(bapi_name: str, parameters: str) -> str: """ Executes an SAP BAPI (RFC).
Args: bapi_name: Name of the BAPI (e.g. 'BAPI_SALESORDER_CREATEFROMDAT2') parameters: JSON string of import parameters. """ conn = None try: params_dict = json.loads(parameters) conn = get_sap_connection()
# Execute BAPI result = conn.call(bapi_name, **params_dict)
return json.dumps(result, default=str)
except (ABAPApplicationError, ABAPRuntimeError) as e: return json.dumps({"error": "SAP_ABAP_ERROR", "details": str(e)}) except Exception as e: return json.dumps({"error": "SYSTEM_ERROR", "details": str(e)}) finally: if conn: conn.close()
if __name__ == "__main__": # MANDATORY: Bind to 0.0.0.0 for Docker/Railway support mcp.run(transport='sse', host='0.0.0.0', port=8000)๐ณ Dockerfile
Section titled โ๐ณ DockerfileโThis Dockerfile sets up the SAP NetWeaver SDK environment.
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1ENV PYTHONUNBUFFERED=1ENV LD_LIBRARY_PATH="/opt/nwrfcsdk/lib"
# Install dependencies for SAP SDKRUN apt-get update && apt-get install -y \ wget \ unzip \ && rm -rf /var/lib/apt/lists/*
# Copy SAP SDK (Manual download required)COPY nwrfcsdk /opt/nwrfcsdk
COPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
COPY server.py .
# EXPOSE 8000 for Railway/Docker networkingEXPOSE 8000
CMD ["python", "server.py"]requirements.txt:
mcppyrfc๐ Client Usage: Semantic Kernel (agent.py)
Section titled โ๐ Client Usage: Semantic Kernel (agent.py)โTo use the MCP server with Semantic Kernel, we define a standard connection pattern. We define our mcps endpoints and register them as native plugins within the Kernel.
import asyncioimport jsonfrom semantic_kernel import Kernelfrom semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletionfrom semantic_kernel.functions import KernelArgumentsfrom mcp import ClientSession, StdioServerParametersfrom mcp.client.sse import sse_client
# --- Configuration ---# Standard MCP connection patternmcps = ["http://localhost:8000/sse"]
async def main(): # 1. Initialize Kernel kernel = Kernel()
# Add AI Service kernel.add_service( OpenAIChatCompletion( service_id="default", ai_model_id="gpt-4", api_key="sk-..." # Replace with env var ) )
# 2. Connect to MCP Servers # We loop through the mcps list to register tools for mcp_url in mcps: print(f"๐ Connecting to MCP Server: {mcp_url}")
# Note: We keep the session context open for the duration of the script async with sse_client(mcp_url) as streams: async with ClientSession(streams[0], streams[1]) as session: await session.initialize()
# List available tools tools = await session.list_tools() print(f"๐ ๏ธ Found {len(tools.tools)} tools.")
# 3. Dynamic Tool Registration # Wrap the MCP tool in a closure to register with Semantic Kernel async def mcp_wrapper(bapi_name: str, parameters: str) -> str: result = await session.call_tool("execute_bapi", arguments={ "bapi_name": bapi_name, "parameters": parameters }) return result.content[0].text
# Register the wrapped function kernel.add_function( plugin_name="SAP_ECC", function_name="execute_bapi", function=mcp_wrapper, description="Executes an SAP BAPI (RFC). Requires bapi_name and parameters JSON." )
# 4. Execute Workflow print("๐ค Agent is ready. Asking to fetch material details...")
# Example: Fetch Material Details bapi_args = KernelArguments( bapi_name="BAPI_MATERIAL_GET_DETAIL", parameters=json.dumps({"MATERIAL": "MAT-101", "PLANT": "1000"}) )
# Invoke the function result = await kernel.invoke( plugin_name="SAP_ECC", function_name="execute_bapi", arguments=bapi_args )
print(f"โ
SAP Response:\n{result}")
if __name__ == "__main__": asyncio.run(main())๐ Troubleshooting
Section titled โ๐ Troubleshootingโ- โSAP Connection Failedโ: Ensure the
SAP_ASHOST(Application Server Host) is reachable from within the Docker container. You may need a VPN sidecar (like NordLayer or Tailscale) if SAP is on-premise. - Port Mapping: Ensure
docker run -p 8000:8000is used solocalhost:8000in the client script can reach the container. - Authentication: SAP passwords should never be hardcoded. Use Docker secrets or environment variables.
๐ก๏ธ Quality Assurance
Section titled โ๐ก๏ธ Quality Assuranceโ- Status: โ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.