AutoGen agents for SAP ECC data updates via RFC (Python)
AutoGen Agents for SAP ECC Data Updates via RFC (Python)
Section titled “AutoGen Agents for SAP ECC Data Updates via RFC (Python)”Slug: autogen-sap-ecc-data-updates-rfc-python
This guide explains how to enable AutoGen agents to securely update data in SAP ECC systems. We use the Model Context Protocol (MCP) to wrap the complex, stateful SAP RFC protocol into a stateless, agent-friendly interface.
By dockerizing the SAP connectivity layer (which requires specific C++ libraries and SDKs), we allow the AutoGen client to remain lightweight and portable, communicating solely over standard HTTP/SSE.
🏗️ Architecture
Section titled “🏗️ Architecture”- MCP Server (Docker): Hosts the
pyrfclibrary and SAP NetWeaver SDK. It exposes the SAPBAPI_CUSTOMER_CHANGEFROMDATA(or similar) as a typed tool. - AutoGen Client (Python): Uses a custom bridge to connect to the MCP server. It injects the remote tools into the
UserProxyAgentandAssistantAgentso they can autonomously execute SAP updates.
🚀 Step 1: The MCP Server (server.py)
Section titled “🚀 Step 1: The MCP Server (server.py)”This server handles the heavy lifting of talking to SAP. It binds to 0.0.0.0 to ensure it is accessible from outside the container.
import osfrom fastmcp import FastMCPfrom pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError
# Initialize FastMCP servermcp = FastMCP("SAP-ECC-Update-Gateway")
# SAP Connection Configuration# In production, inject these via Environment VariablesSAP_CONFIG = { "ashost": os.getenv("SAP_ASHOST", "192.168.1.10"), "sysnr": os.getenv("SAP_SYSNR", "00"), "client": os.getenv("SAP_CLIENT", "100"), "user": os.getenv("SAP_USER", "BTC_AGENT"), "passwd": os.getenv("SAP_PASSWORD", "Secret123"), "lang": "EN"}
@mcp.tool()def update_customer_credit(customer_id: str, new_limit: float) -> str: """ Updates the credit limit for a specific customer in SAP ECC via RFC.
Args: customer_id: The 10-digit SAP customer number (e.g., '0000101000'). new_limit: The new credit limit amount. """ # Ensure your container has network access (e.g. via NordLayer) conn = None try: conn = Connection(**SAP_CONFIG)
# Simplified BAPI call structure for demonstration # BAPI_CUSTOMER_CHANGEFROMDATA typically requires complex structures. # Here we map the agent's simple input to the RFC's requirements.
pi_personaldata = {"CITY": "New York"} # Example payload pi_personaldatax = {"CITY": "X"} # Update flag
result = conn.call( "BAPI_CUSTOMER_CHANGEFROMDATA", CUSTOMERNO=customer_id, PI_PERSONALDATA=pi_personaldata, PI_PERSONALDATAX=pi_personaldatax )
# RFCs often require an explicit commit conn.call("BAPI_TRANSACTION_COMMIT", WAIT="X")
returns = result.get("RETURN", []) messages = [f"{m['TYPE']}: {m['MESSAGE']}" for m in returns]
return f"SAP Result: {'; '.join(messages)}"
except (ABAPApplicationError, ABAPRuntimeError) as e: return f"SAP RFC Error: {str(e)}" except Exception as e: return f"System Error: {str(e)}" finally: if conn: conn.close()
if __name__ == "__main__": # LISTEN on 0.0.0.0 to expose ports outside Docker mcp.run(transport='sse', host='0.0.0.0', port=8000)🐳 Step 2: Dockerfile
Section titled “🐳 Step 2: Dockerfile”You must provide the proprietary SAP NetWeaver SDK in the nwrfcsdk/ directory relative to this Dockerfile.
# Base Python imageFROM python:3.10-slim
# Install system dependencies for SAP SDKRUN apt-get update && apt-get install -y \ gcc \ g++ \ make \ && rm -rf /var/lib/apt/lists/*
# Setup SAP NetWeaver SDK# You must download 'nwrfcsdk' from SAP Support Portal and place it in the build contextCOPY nwrfcsdk /usr/local/sap/nwrfcsdk
# Configure library pathsENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdkENV LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib
# Install Python dependenciesCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
# Copy server codeCOPY server.py .
# Expose port 8000 for the MCP SSE transportEXPOSE 8000
# Ensure your container has network access (e.g. via NordLayer)CMD ["python", "server.py"]requirements.txt:
fastmcp==0.2.1pyrfc==3.3.0uvicorn🤖 Step 3: AutoGen Client (agent.py)
Section titled “🤖 Step 3: AutoGen Client (agent.py)”Since AutoGen does not yet natively support the mcps parameter like CrewAI, we implement a lightweight MCPBridge class. This allows us to pass mcps configuration cleanly and handles the tool registration for both the User Proxy and the Assistant.
import asyncioimport osfrom contextlib import AsyncExitStackfrom typing import List, Dict, Any
from autogen import AssistantAgent, UserProxyAgentfrom mcp import ClientSession, StdioServerParametersfrom mcp.client.sse import sse_clientfrom mcp.types import CallToolResult
# 1. Helper Class to Bridge MCP Tools to AutoGenclass MCPAutoGenBridge: def __init__(self, mcps: List[str]): """ Args: mcps: List of MCP SSE endpoints (e.g. ["http://localhost:8000/sse"]) """ self.mcps = mcps self.stack = AsyncExitStack() self.sessions = []
async def initialize(self): """Connects to all MCP servers and fetches tools.""" tools_map = {}
for url in self.mcps: # Connect via SSE transport = await self.stack.enter_async_context(sse_client(url=url)) session = await self.stack.enter_async_context( ClientSession(transport[0], transport[1]) ) await session.initialize() self.sessions.append(session)
# Fetch tools mcp_tools = await session.list_tools() for tool in mcp_tools.tools: # Create a closure to capture the specific session and tool name async def tool_wrapper(customer_id: str, new_limit: float, _session=session, _tool_name=tool.name) -> str: result = await _session.call_tool( _tool_name, arguments={"customer_id": customer_id, "new_limit": new_limit} ) return "\n".join([c.text for c in result.content if c.type == 'text'])
# Store wrapper with metadata for registration tools_map[tool.name] = { "func": tool_wrapper, "description": tool.description or "MCP Tool" } return tools_map
async def close(self): await self.stack.aclose()
# 2. Main Agent Workflowasync def run_agents(): # Define Configuration with mcps argument bridge = MCPAutoGenBridge(mcps=["http://localhost:8000/sse"])
try: # Initialize bridge and get tools tools = await bridge.initialize() print(f"Loaded MCP Tools: {list(tools.keys())}")
# Configure AutoGen Agents config_list = [{"model": "gpt-4", "api_key": os.getenv("OPENAI_API_KEY")}]
assistant = AssistantAgent( name="SAP_Agent", llm_config={"config_list": config_list}, system_message="You are an SAP administrator. Use the available tools to update customer records." )
user_proxy = UserProxyAgent( name="User_Proxy", human_input_mode="NEVER", code_execution_config=False, max_consecutive_auto_reply=1 )
# Register MCP tools with AutoGen for name, data in tools.items(): func = data["func"] desc = data["description"]
# Register for execution (UserProxy runs the tool) user_proxy.register_for_execution(name=name)(func)
# Register for LLM (Assistant knows about the tool) assistant.register_for_llm(name=name, description=desc)(func)
# Start the conversation await user_proxy.a_initiate_chat( assistant, message="Please update the credit limit for customer 0000101000 to 75000." )
finally: await bridge.close()
if __name__ == "__main__": asyncio.run(run_agents())Key Components
Section titled “Key Components”mcpsArgument: TheMCPAutoGenBridgeaccepts a list of SSE endpoints, allowing you to easily scale to multiple MCP servers (e.g., one for SAP, one for Oracle) just by adding URLs to the list.- Tool Registration: The bridge dynamically wraps the remote MCP functions into Python async functions that AutoGen can natively understand and execute.
- Security: Credentials remain safely inside the Docker container; the Agent only sees the function signature
update_customer_credit(customer_id, new_limit).
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.