Skip to content

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.

  • Server: Python (FastMCP) exposing SAP RFCs via SSE (Server-Sent Events).
  • Client: LangGraph (Python) connecting via the standard mcp client library.
  • Transport: HTTP/SSE over Docker.
  • Network: Requires Line-of-Sight to SAP (VPN/Direct Connect).

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 os
import sys
from typing import Dict, Any, Optional
from fastmcp import FastMCP
# Initialize FastMCP server
mcp = FastMCP("sap-ecc-bapi-server")
# Import SAP connector
# Ensure pyrfc is installed and SAP NWRFC SDK is configured in the environment
try:
from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationError
except 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)

This Dockerfile handles the complex installation of the proprietary SAP SDK.

# Use a slim Python base image
FROM python:3.11-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Install system dependencies
RUN 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 linker
RUN echo "/usr/local/sap/nwrfcsdk/lib" > /etc/ld.so.conf.d/nwrfcsdk.conf \
&& ldconfig
# Set SAP env vars
ENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdk
# ----------------------------
WORKDIR /app
# Install Python dependencies
# pyrfc requires the SDK to be present
RUN pip install fastmcp pyrfc
# Copy application code
COPY 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 compatibility
EXPOSE 8000
# Run the MCP server
CMD ["python", "server.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 asyncio
from typing import Annotated, Literal
# LangGraph & LangChain imports
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode
from langgraph.graph.message import add_messages
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
# MCP Client imports
from mcp import ClientSession, StdioServerParameters
from mcp.client.sse import sse_client
# --- CONFIGURATION ---
# Define the list of MCP servers this agent connects to
mcps = ["http://localhost:8000/sse"]
# ---------------------
# Define Agent State
class 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())
  1. Download SDK: Obtain the SAP NW RFC SDK (Linux x64) from the SAP Support Portal.
  2. Build: docker build -t sap-mcp-server .
  3. 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
  4. Connect: Run python agent.py. The LangGraph agent will connect to localhost:8000, authenticate via the MCP session, and execute the requested BAPIs.

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

Transparency: This page may contain affiliate links.