LangGraph for SAP ECC data extraction and reporting (Python)
LangGraph for SAP ECC Data Extraction and Reporting (Python)
Section titled “LangGraph for SAP ECC Data Extraction and Reporting (Python)”Slug: langgraph-sap-ecc-data-extraction-python
Legacy SAP ECC systems often operate as “black boxes,” locking critical operational data behind proprietary protocols like RFC (Remote Function Call). Modern AI agents running on LangGraph struggle to access this data directly.
This guide provides a production-ready Model Context Protocol (MCP) server that acts as a bridge. It uses the pyrfc library to communicate natively with SAP ECC, exposing safe, read-only tools that an autonomous LangGraph agent can use to extract data (e.g., T-Codes, Table reads) and generate financial or inventory reports.
🏗️ Architecture
Section titled “🏗️ Architecture”We use a decoupled architecture to keep the “Big Iron” connectivity separate from your AI logic:
- SAP ECC: The legacy ERP system (on-premise or private cloud).
- MCP Server (Dockerized): Runs
pyrfcandFastMCP. It handles the complex RFC handshakes and data type conversion. - LangGraph Agent: Connects to the MCP server via SSE (Server-Sent Events). It uses a streamlined tool loader to access SAP functions.
🚀 Step 1: The MCP Server (server.py)
Section titled “🚀 Step 1: The MCP Server (server.py)”This server exposes a specific tool sap_read_table which wraps the standard SAP RFC function RFC_READ_TABLE. This allows the agent to query raw SAP tables (like KNA1 for customers or VBAK for sales orders) using natural language logic.
Prerequisites:
- You must provide SAP NetWeaver RFC SDK libraries (nwrfcsdk) in your environment.
pip install fastmcp pyrfc
import osfrom fastmcp import FastMCPfrom pyrfc import Connection
# Initialize FastMCPmcp = FastMCP("SAP-ECC-Gateway")
def get_sap_connection(): """Establishes a connection to SAP ECC using environment variables.""" try: conn = 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") ) return conn except Exception as e: raise RuntimeError(f"Failed to connect to SAP: {str(e)}")
@mcp.tool()def sap_read_table(table_name: str, row_count: int = 10, fields: list = None) -> str: """ Reads data from a standard SAP table using RFC_READ_TABLE.
Args: table_name: The SAP table to read (e.g., 'KNA1', 'MARA', 'VBAK'). row_count: Number of rows to retrieve (default 10). fields: List of specific field names to retrieve (optional). """ conn = None try: conn = get_sap_connection()
options = []
# Prepare fields structure for RFC_READ_TABLE fields_table = [] if fields: for f in fields: fields_table.append({"FIELDNAME": f})
# Call the standard RFC result = conn.call( "RFC_READ_TABLE", QUERY_TABLE=table_name, ROWCOUNT=row_count, FIELDS=fields_table, OPTIONS=options )
# Process data: SAP returns data in a delimited 'WA' field data = result.get("DATA", []) structure = result.get("FIELDS", [])
# Basic parsing (Production would require offset mapping) parsed_output = [] for entry in data: parsed_output.append(entry["WA"].strip())
return f"Successfully retrieved {len(data)} rows from {table_name}. \nStructure: {str(structure)}\nRaw Data Sample: {str(parsed_output[:5])}"
except Exception as e: return f"SAP RFC Error: {str(e)}" finally: if conn and conn.alive: conn.close()
if __name__ == "__main__": # Binds to 0.0.0.0 to allow Docker networking mcp.run(transport='sse', host='0.0.0.0', port=8000)🐳 Step 2: Dockerfile
Section titled “🐳 Step 2: Dockerfile”SAP connectivity requires system-level C++ libraries (nwrfcsdk). You cannot just pip install everything; you must mount or copy the SDK into the container.
# Use a slim Python baseFROM python:3.11-slim
# Install system dependenciesRUN apt-get update && apt-get install -y \ build-essential \ curl \ && rm -rf /var/lib/apt/lists/*
# SAP NWRFC SDK SETUP# Ensure the SDK files are present in the build context under ./nwrfcsdkCOPY ./nwrfcsdk /usr/local/sap/nwrfcsdk
# Update library paths so Python can find the SAP C++ libsENV LD_LIBRARY_PATH="/usr/local/sap/nwrfcsdk/lib:${LD_LIBRARY_PATH}"ENV SAPNWRFC_HOME="/usr/local/sap/nwrfcsdk"
WORKDIR /app
# Install Python dependenciesRUN pip install --no-cache-dir fastmcp pyrfc
# Copy application codeCOPY server.py .
# Ensure your container has network access (e.g. via NordLayer)# SAP servers are usually behind corporate firewalls.
# Required for Railway/Cloud deploymentEXPOSE 8000
CMD ["python", "server.py"]🤖 Step 3: LangGraph Agent Integration
Section titled “🤖 Step 3: LangGraph Agent Integration”To keep the agent code clean and decoupled from low-level networking, we use a utility wrapper to load tools from the MCP server URL. This matches the configuration pattern used in other agent frameworks like CrewAI.
agent.py
import asynciofrom typing import Listfrom langgraph.prebuilt import create_react_agentfrom langchain_openai import ChatOpenAIfrom mcp import ClientSession, StdioServerParametersfrom mcp.client.sse import sse_clientfrom langchain_core.tools import tool
# --- MCP Connection Helper ---async def load_mcp_tools(mcps: List[str]): """ Connects to the list of MCP SSE endpoints and returns LangChain-compatible tools. In a real implementation, this would handle lifecycle management (enter/exit). For this script, we initialize and return the wrapped tools. """ tools = [] for url in mcps: # Note: In production, you need to manage the session context properly (async with). # This is a simplified connector for demonstration. client = sse_client(url) streams = await client.__aenter__() session = ClientSession(streams[0], streams[1]) await session.__aenter__() await session.initialize()
# Fetch tools from server mcp_tools = await session.list_tools()
# Wrap tool for LangChain for t in mcp_tools.tools: @tool(t.name) async def dynamic_tool(**kwargs): """Dynamic MCP Tool Wrapper""" result = await session.call_tool(t.name, arguments=kwargs) return result.content[0].text
# Update metadata to match the MCP tool definition dynamic_tool.description = t.description or "MCP Tool" tools.append(dynamic_tool)
return tools
# --- Main Agent Workflow ---
async def run_agent(): # Configuration Parameter mcps = ["http://localhost:8000/sse"]
# 1. Load Tools from MCP Servers print(f"Connecting to MCP Servers: {mcps}...") tools = await load_mcp_tools(mcps=mcps) print(f"Loaded {len(tools)} tools: {[t.name for t in tools]}")
# 2. Define the Agent llm = ChatOpenAI(model="gpt-4-turbo") agent_executor = create_react_agent(llm, tools)
# 3. Execute the Workflow print("--- Starting SAP Extraction ---") response = await agent_executor.ainvoke({ "messages": [ ("user", "Query the SAP table 'VBAK' (Sales Documents). Get the last 3 orders and show me the sales document number and date.") ] })
# Output the final result print(f"\nAgent Response:\n{response['messages'][-1].content}")
if __name__ == "__main__": asyncio.run(run_agent())💡 Implementation Notes
Section titled “💡 Implementation Notes”mcpsConfiguration: We define the server endpoints as a list (mcps), making it easy to add multiple SAP gateways (e.g., one for HR, one for Logistics) without changing the core agent logic.- Tool Abstraction: The
load_mcp_toolshelper handles the SSE handshake and wraps the remote function into a format LangGraph expects, keeping thecreate_react_agentcall clean. - Network Access: Ensure your Docker container exposes port 8000 and the agent script can reach
localhost:8000.
Troubleshooting
Section titled “Troubleshooting”- Connection Refused: Verify the server is running with
host='0.0.0.0'inside Docker. - RFC Errors: If you see
RFC_COMMUNICATION_FAILURE, check that the container has VPN access to the SAP host. - Missing SDK: The Docker build will fail if
nwrfcsdkis not in the directory. You must download this from the SAP Support Portal.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.