LangGraph agent orchestration for SAP ECC BAPI calls (Python)
LangGraph Agent Orchestration for SAP ECC BAPI Calls
Section titled “LangGraph Agent Orchestration for SAP ECC BAPI Calls”This guide demonstrates how to orchestrate SAP ECC business processes using LangGraph agents. We use the Model Context Protocol (MCP) to expose SAP BAPIs (Business Application Programming Interfaces) as standardized tools that the agent can invoke during its reasoning loop.
Architectural Overview
Section titled “Architectural Overview”- Server: Python (FastMCP) exposing SAP RFCs via SSE (Server-Sent Events).
- Client: LangGraph (Python) connecting via the standard
mcpclient library. - Transport: HTTP/SSE over Docker.
- Network: Requires Line-of-Sight to SAP (VPN/Direct Connect).
1. The MCP Server (server.py)
Section titled “1. The MCP Server (server.py)”The server uses fastmcp to wrap the pyrfc library. This allows the agent to call any SAP BAPI dynamically by passing the function name and parameters.
Prerequisite: You must have the SAP NW RFC SDK installed.
import osimport sysfrom typing import Dict, Any, Optionalfrom fastmcp import FastMCP
# Initialize FastMCP servermcp = FastMCP("sap-ecc-bapi-server")
# Import SAP connector# Ensure pyrfc is installed and SAP NWRFC SDK is configured in the environmenttry: from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationErrorexcept ImportError: print("CRITICAL: pyrfc not found. Ensure SAP NW RFC SDK is installed.") sys.exit(1)
def get_connection(): """Establishes a connection to SAP ECC using environment variables.""" return Connection( ashost=os.getenv("SAP_HOST"), sysnr=os.getenv("SAP_SYSNR", "00"), client=os.getenv("SAP_CLIENT", "100"), user=os.getenv("SAP_USER"), passwd=os.getenv("SAP_PASSWORD"), lang=os.getenv("SAP_LANG", "EN") )
@mcp.tool()def execute_bapi(function_name: str, parameters: Optional[Dict[str, Any]] = None) -> str: """ Executes a BAPI or RFC function in SAP ECC.
Args: function_name: The name of the BAPI (e.g., 'BAPI_SALESORDER_CREATEFROMDAT2'). parameters: A dictionary of import parameters and tables for the BAPI.
Returns: A JSON string containing the export parameters and tables returned by SAP. """ if parameters is None: parameters = {}
try: conn = get_connection() result = conn.call(function_name, **parameters) conn.close() return str(result) except (ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationError) as e: return f"SAP Error: {str(e)}" except Exception as e: return f"System Error: {str(e)}"
if __name__ == "__main__": # Binds to 0.0.0.0 to ensure Docker compatibility mcp.run(transport='sse', host='0.0.0.0', port=8000)2. Docker Deployment (Dockerfile)
Section titled “2. Docker Deployment (Dockerfile)”This Dockerfile handles the complex installation of the proprietary SAP SDK.
# Use a slim Python base imageFROM python:3.11-slim
# Set environment variablesENV PYTHONDONTWRITEBYTECODE=1ENV PYTHONUNBUFFERED=1
# Install system dependenciesRUN apt-get update && apt-get install -y \ build-essential \ libaio1 \ unzip \ wget \ && rm -rf /var/lib/apt/lists/*
# --- SAP NW RFC SDK SETUP ---# NOTE: Place the 'nwrfcsdk' folder (downloaded from SAP Service Marketplace)# in the same directory as this Dockerfile before building.COPY nwrfcsdk /usr/local/sap/nwrfcsdk
# Configure dynamic linkerRUN echo "/usr/local/sap/nwrfcsdk/lib" > /etc/ld.so.conf.d/nwrfcsdk.conf \ && ldconfig
# Set SAP env varsENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdk# ----------------------------
WORKDIR /app
# Install Python dependencies# pyrfc requires the SDK to be presentRUN pip install fastmcp pyrfc
# Copy application codeCOPY server.py .
# Ensure your container has network access (e.g. via NordLayer)# This is required to reach the SAP Application Server IP.
# Expose port 8000 for Railway compatibilityEXPOSE 8000
# Run the MCP serverCMD ["python", "server.py"]3. Client Agent (agent.py)
Section titled “3. Client Agent (agent.py)”This LangGraph client connects to the Dockerized MCP server defined in mcps. It creates a tool node that allows the LLM to execute BAPIs during its workflow.
import asynciofrom typing import Annotated, Literal
# LangGraph & LangChain importsfrom langgraph.graph import StateGraph, START, ENDfrom langgraph.prebuilt import ToolNodefrom langgraph.graph.message import add_messagesfrom langchain_core.messages import HumanMessagefrom langchain_openai import ChatOpenAIfrom langchain_core.tools import tool
# MCP Client importsfrom mcp import ClientSession, StdioServerParametersfrom mcp.client.sse import sse_client
# --- CONFIGURATION ---# Define the list of MCP servers this agent connects tomcps = ["http://localhost:8000/sse"]# ---------------------
# Define Agent Stateclass AgentState(dict): messages: Annotated[list, add_messages]
async def run_agent(): # Connect to the SAP MCP Server defined in configuration sap_server_url = mcps[0]
print(f"Connecting to MCP server at: {sap_server_url}")
async with sse_client(url=sap_server_url) as streams: async with ClientSession(streams[0], streams[1]) as session:
# Initialize connection await session.initialize()
# Create a wrapper tool for LangGraph @tool async def call_sap_bapi(function_name: str, parameters: dict = {}) -> str: """ Interacts with SAP ECC. Use this tool to read/write data to SAP. Args: function_name: The RFC/BAPI name (e.g., 'BAPI_USER_GET_DETAIL'). parameters: Dictionary of parameters. """ # Delegate to the remote MCP tool result = await session.call_tool("execute_bapi", arguments={ "function_name": function_name, "parameters": parameters }) return str(result.content)
tools = [call_sap_bapi]
# Define the LLM and Graph llm = ChatOpenAI(model="gpt-4-turbo", temperature=0).bind_tools(tools)
def chatbot_node(state: AgentState): return {"messages": [llm.invoke(state["messages"])]}
graph_builder = StateGraph(AgentState) graph_builder.add_node("chatbot", chatbot_node) graph_builder.add_node("tools", ToolNode(tools=tools))
graph_builder.add_edge(START, "chatbot") graph_builder.add_conditional_edges( "chatbot", lambda state: "tools" if state["messages"][-1].tool_calls else END, ) graph_builder.add_edge("tools", "chatbot")
graph = graph_builder.compile()
# Execute Workflow # Example: Retrieve SAP User Details print("--- Starting Agent Workflow ---") query = "Check the details for SAP user 'DEVELOPER01'." inputs = {"messages": [HumanMessage(content=query)]}
async for event in graph.astream(inputs): for key, value in event.items(): print(f"\nNode: {key}") if "messages" in value: msg = value["messages"][-1] print(f"Content: {msg.content}") if hasattr(msg, 'tool_calls') and msg.tool_calls: print(f"Tool Call: {msg.tool_calls}")
if __name__ == "__main__": asyncio.run(run_agent())Deployment Instructions
Section titled “Deployment Instructions”- Download SDK: Obtain the SAP NW RFC SDK (Linux x64) from the SAP Support Portal.
- Build:
docker build -t sap-mcp-server . - Run:
Terminal window docker run -p 8000:8000 \-e SAP_HOST=192.168.1.100 \-e SAP_USER=mcp_agent \-e SAP_PASSWORD=secret \sap-mcp-server - Connect: Run
python agent.py. The LangGraph agent will connect tolocalhost:8000, authenticate via the MCP session, and execute the requested BAPIs.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.