Handling SAP ECC RFC Authentication for AI Agents (Python)
Handling SAP ECC RFC Authentication for AI Agents (Python)
Section titled “Handling SAP ECC RFC Authentication for AI Agents (Python)”Slug: sap-ecc-rfc-authentication-agents-python
The Legacy Bottleneck: SAP RFC Protocol
Section titled “The Legacy Bottleneck: SAP RFC Protocol”Connecting modern AI Agents (CrewAI, AutoGen, LangGraph) to SAP ECC (Enterprise Central Component) is one of the hardest challenges in enterprise automation. Unlike REST or GraphQL, SAP ECC primarily communicates via RFC (Remote Function Call), a proprietary binary protocol over TCP/IP (port 3300+).
Most agents fail here because:
- Authentication is Stateful: RFC connections are not stateless HTTP requests; they require a persistent session handle.
- Binary Dependency: You cannot just
pip installa driver; you need the C++ SAP NetWeaver SDK installed at the OS level. - Network Isolation: SAP ECC usually sits deep in an on-premise DMZ, inaccessible to cloud-hosted agent runners without VPN tunneling.
This guide provides a FastMCP wrapper that turns the complex SAP RFC protocol into a clean, agent-friendly tool interface.
🛠️ The Architecture
Section titled “🛠️ The Architecture”We will deploy a Model Context Protocol (MCP) server that acts as the “translator.”
- The Agent speaks JSON (MCP) to our server.
- The Server uses
pyrfcand the SAP NetWeaver SDK to speak binary RFC to SAP. - Docker encapsulates the messy C++ dependencies.
Prerequisites
Section titled “Prerequisites”- SAP NetWeaver RFC SDK 7.50: You must download this from the SAP Support Portal (requires an S-User ID). You need the Linux implementation.
- VPN Access: Your container must be able to reach the SAP Application Server IP.
1. The Bridge Code (server.py)
Section titled “1. The Bridge Code (server.py)”This server exposes a tool read_sap_table that allows an agent to query legacy data structures (like MARA for materials or VBAK for sales orders) without understanding RFC syntax.
import osimport sysfrom fastmcp import FastMCPfrom pydantic import Field
# Note: pyrfc requires the SAP NW RFC SDK libraries to be in the LD_LIBRARY_PATHtry: from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationErrorexcept ImportError: print("CRITICAL: pyrfc not found. Ensure SAP NW RFC SDK is installed.") sys.exit(1)
# Initialize FastMCP Servermcp = 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"), # Application Server Host sysnr=os.getenv("SAP_SYSNR"), # System Number (e.g., "00") client=os.getenv("SAP_CLIENT"), # Client (e.g., "100") user=os.getenv("SAP_USER"), # RFC User passwd=os.getenv("SAP_PASSWORD"), # RFC Password lang=os.getenv("SAP_LANG", "EN") # Language ) return conn except LogonError as e: raise ValueError(f"SAP Logon Failed: {e}") except CommunicationError as e: # Ensure your container has network access (e.g. via NordLayer) raise ConnectionError(f"Network Error connecting to SAP: {e}")
@mcp.tool()def read_sap_table( table_name: str = Field(..., description="The technical name of the SAP table (e.g., 'MARA', 'KNA1')"), row_count: int = Field(10, description="Max rows to retrieve"), fields: list[str] = Field(default=["*"], description="List of column names to retrieve")) -> str: """ Executes RFC_READ_TABLE to fetch raw data from SAP ECC. Useful for looking up customer details, material stock, or order status. """ conn = None try: conn = get_sap_connection()
# Prepare the fields format for RFC_READ_TABLE query_fields = [] if "*" in fields: # Empty list implies all fields in some versions of RFC_READ_TABLE, # but explicit selection is safer. We'll pass empty to let SAP decide or select specific keys. pass else: query_fields = [{"FIELDNAME": f} for f in fields]
options = [{"TEXT": f"ROWCOUNT = {row_count}"}] if row_count else []
# Call the standard BAPI for table reading result = conn.call( "RFC_READ_TABLE", QUERY_TABLE=table_name, DELIMITER=";", FIELDS=query_fields, ROWCOUNT=row_count )
# Parse the chaotic 'DATA' return format of RFC_READ_TABLE data_lines = result.get("DATA", []) headers = [f["FIELDNAME"] for f in result.get("FIELDS", [])]
output = [] for line in data_lines: # SAP returns data as a single delimited string in the WA column raw_row = line.get("WA", "").strip() row_values = raw_row.split(";") row_dict = dict(zip(headers, row_values)) output.append(row_dict)
return str(output)
except (ABAPApplicationError, ABAPRuntimeError) as e: return f"SAP ABAP Error: {e}" except Exception as e: return f"System Error: {e}" finally: if conn: conn.close()
if __name__ == "__main__": # Required for Docker compatibility mcp.run(transport='sse', host='0.0.0.0', port=8000)2. The Dockerfile
Section titled “2. The Dockerfile”This is the most critical part. You cannot run pyrfc on a standard Python image without the SAP C++ libraries (nwrfcsdk).
Structure Assumption:
You have downloaded the SAP NW RFC SDK for Linux (x86_64) and extracted it to a folder named nwrfcsdk in your project root.
FROM python:3.11-slim-bookworm
WORKDIR /app
# Install system dependencies# gcc and make are required if pyrfc needs to compile bindings (wheel vs source)RUN apt-get update && apt-get install -y \ gcc \ g++ \ make \ && rm -rf /var/lib/apt/lists/*
# -----------------------------------------------------------# SAP SDK SETUP# -----------------------------------------------------------# Copy the downloaded SAP NetWeaver SDK into the container# Ensure you have the 'nwrfcsdk' folder in your build contextCOPY nwrfcsdk /usr/local/sap/nwrfcsdk
# Setup Environment variables for SAP SDKENV SAPNWRFC_HOME=/usr/local/sap/nwrfcsdkENV PATH=$PATH:$SAPNWRFC_HOME/binENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SAPNWRFC_HOME/lib
# Create the configuration file for the dynamic linkerRUN echo "/usr/local/sap/nwrfcsdk/lib" > /etc/ld.so.conf.d/nwrfcsdk.conf \ && ldconfig# -----------------------------------------------------------
# Install Python Dependencies# We install cython first as it's often a build requirement for pyrfcRUN pip install --no-cache-dir cythonRUN pip install --no-cache-dir pyrfc fastmcp uvicorn
# Copy Server CodeCOPY server.py .
# Ensure your container has network access (e.g. via NordLayer)# This is crucial for reaching on-prem SAP instances.
# Expose the SSE portEXPOSE 8000
# Run the MCP ServerCMD ["python", "server.py"]3. Agent Connectivity
Section titled “3. Agent Connectivity”Once your Docker container is running, you can connect your agent framework to the SAP bridge.
Option A: CrewAI (Python)
Section titled “Option A: CrewAI (Python)”CrewAI supports MCP tools natively via the mcps parameter.
from crewai import Agent, Task, Crewfrom crewai.project import CrewBase
# Define the SAP Agentsap_analyst = Agent( role='SAP Data Analyst', goal='Retrieve material master data from the legacy ECC system', backstory='You are an expert in SAP T-Codes and database schema.', # Connect to the FastMCP server running in Docker mcps=["http://localhost:8000/sse"], verbose=True)
task = Task( description="Find the description for Material Number 'MAT-2024-X' from the MARA table.", agent=sap_analyst, expected_output="The material description.")
crew = Crew(agents=[sap_analyst], tasks=[task])result = crew.kickoff()print(result)Option B: LangChain / Generic Client
Section titled “Option B: LangChain / Generic Client”If you need a manual connection or are using a different framework, use the sseclient approach to verify the stream.
import httpxfrom mcp import ClientSessionfrom mcp.client.sse import sse_client
async def query_sap(): # Connect to the Docker container async with sse_client("http://localhost:8000/sse") as (read, write): async with ClientSession(read, write) as session:
# Initialize connection await session.initialize()
# List available SAP tools tools = await session.list_tools() print(f"Connected to SAP Bridge. Tools: {[t.name for t in tools.tools]}")
# Execute the SAP Query result = await session.call_tool( "read_sap_table", arguments={ "table_name": "MARA", "row_count": 1, "fields": ["MATNR", "MAKTX"] } ) print(f"SAP Data: {result.content}")
# Run in an async loop# import asyncio; asyncio.run(query_sap())Troubleshooting Common Errors
Section titled “Troubleshooting Common Errors”| Error Code | Meaning | Fix |
|---|---|---|
ImportError: libsapnwrfc.so | OS cannot find the SAP SDK. | Check LD_LIBRARY_PATH in Dockerfile and ensure ldconfig ran. |
RFC_ERROR_LOGON_FAILURE | Bad Credentials. | Verify SAP_USER and SAP_PASSWORD in env vars. Account might be locked. |
NI_ECONN_REFUSED | Network Isolation. | The container cannot reach port 3300 on the SAP host. Check VPN/NordLayer/Firewall. |
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.