Skip to content

OpenAI Operator for SAP ECC BAPI integration via `pyrfc`

OpenAI Operator for SAP ECC BAPI Integration via pyrfc

Section titled “OpenAI Operator for SAP ECC BAPI Integration via pyrfc”

This guide provides the complete architectural blueprint for connecting an OpenAI Operator (or autonomous agent) to a legacy SAP ECC system using the Model Context Protocol (MCP).

We use pyrfc, the standard Python wrapper for the SAP NetWeaver RFC SDK, to execute BAPIs (Business Application Programming Interfaces). This enables your agent to perform complex ERP tasks—like creating sales orders or checking inventory—without screen scraping.

We encapsulate the proprietary SAP connectivity inside a Dockerized FastMCP server. This server exposes SAP BAPIs as tools that the OpenAI Operator can invoke via the Model Context Protocol.

The Challenge: “Big Iron” Connectivity

Section titled “The Challenge: “Big Iron” Connectivity”

SAP ECC uses the RFC (Remote Function Call) protocol, which is binary and proprietary. It does not speak HTTP or JSON native.

  • Solution: A Python adapter using pyrfc.
  • Constraint: You cannot simply pip install the driver; you must include the SAP NWRFC SDK (C++ libraries) in your Docker container.

This FastMCP server exposes a generic execute_bapi tool. This allows the Agent to call any whitelisted BAPI dynamically.

import os
import sys
from fastmcp import FastMCP
from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationError
# Initialize FastMCP Server
mcp = FastMCP("sap-ecc-bapi-server")
# Configuration from Environment Variables
SAP_HOST = os.getenv("SAP_HOST")
SAP_SYSNR = os.getenv("SAP_SYSNR", "00")
SAP_CLIENT = os.getenv("SAP_CLIENT", "100")
SAP_USER = os.getenv("SAP_USER")
SAP_PASSWORD = os.getenv("SAP_PASSWORD")
def get_connection():
"""Establishes a connection to SAP ECC."""
try:
conn = Connection(
ashost=SAP_HOST,
sysnr=SAP_SYSNR,
client=SAP_CLIENT,
user=SAP_USER,
passwd=SAP_PASSWORD
)
return conn
except LogonError as e:
raise RuntimeError(f"SAP Login Failed: {e}")
except CommunicationError as e:
raise RuntimeError(f"SAP Network Error: {e}")
@mcp.tool()
def execute_bapi(bapi_name: str, parameters: dict = None) -> dict:
"""
Executes a standard SAP BAPI via RFC.
Args:
bapi_name: The exact name of the BAPI (e.g., 'BAPI_CUSTOMER_GETDETAIL2').
parameters: A dictionary of import parameters expected by the BAPI.
Returns:
A dictionary containing the export parameters and tables returned by SAP.
"""
if parameters is None:
parameters = {}
conn = None
try:
conn = get_connection()
# The invoke() method in pyrfc calls the remote function
result = conn.call(bapi_name, **parameters)
return result
except (ABAPApplicationError, ABAPRuntimeError) as e:
return {"error": "ABAP Error", "details": str(e), "code": 500}
except Exception as e:
return {"error": "System Error", "details": str(e), "code": 500}
finally:
if conn and conn.alive:
conn.close()
@mcp.tool()
def check_connection() -> str:
"""Ping the SAP server to verify connectivity."""
try:
conn = get_connection()
info = conn.get_connection_attributes()
conn.close()
return f"Connected to SAP Release: {info.get('rel')}"
except Exception as e:
return f"Connection Failed: {e}"
if __name__ == "__main__":
# Ensure your container has network access (e.g. via NordLayer)
mcp.run(transport='sse', host='0.0.0.0', port=8000)

This is the critical part. You must download the SAP NetWeaver RFC SDK 7.50 (Linux x86_64) from the SAP Support Portal. Extract it into a folder named nwrfc in your project directory.

Your project structure should look like this:

.
├── Dockerfile
├── server.py
└── nwrfc/ <-- Extracted SAP SDK (contains lib, include, bin)
# Base image
FROM python:3.10-slim
# Install system dependencies required for SAP SDK
# 'unzip' and 'gcc' might be needed depending on your specific setup
RUN apt-get update && apt-get install -y \
libaio1 \
unzip \
&& rm -rf /var/lib/apt/lists/*
# Set up environment variables for SAP NWRFC
ENV SAPNWRFC_HOME=/usr/local/sap/nwrfc
ENV PATH="${SAPNWRFC_HOME}/bin:${PATH}"
ENV LD_LIBRARY_PATH="${SAPNWRFC_HOME}/lib:${LD_LIBRARY_PATH}"
# Create directory and copy SAP SDK files
# ASSUMPTION: You have the SDK extracted in a local 'nwrfc' folder
WORKDIR /usr/local/sap
COPY nwrfc/ ./nwrfc/
# Verify the library path is picked up
RUN echo "/usr/local/sap/nwrfc/lib" > /etc/ld.so.conf.d/sap.conf && ldconfig
# Application setup
WORKDIR /app
COPY server.py .
# Install Python dependencies
# pyrfc requires the SDK to be present during installation if building from source,
# or use the wheel if you have generated one.
# For simplicity, we assume pip can build it because SDK is now in default paths.
RUN pip install --no-cache-dir fastmcp pyrfc
# Expose port 8000 for Railway/Docker networking
EXPOSE 8000
# Ensure your container has network access (e.g. via NordLayer)
# Run the FastMCP server
CMD ["python", "server.py"]

Once the server is running, you can connect your OpenAI Operator (or an Agent framework like CrewAI) to it.

This configures a CrewAI agent to use the running Docker container as a tool provider.

from crewai import Agent, Task, Crew
# Ensure you have the 'crewai[mcp]' extras installed if required,
# or use a generic MCP client wrapper.
# Note: Syntax varies by version; below is the standard pattern for MCP tool sources.
# Define the Agent
sap_agent = Agent(
role='SAP ERP Specialist',
goal='Retrieve customer data from SAP ECC',
backstory='You are an expert in SAP BAPIs and legacy data structures.',
# Connect to the FastMCP server running in Docker
mcps=["http://localhost:8000/sse"],
verbose=True
)
# Define the Task
# The agent will automatically discover the 'execute_bapi' tool
fetch_customer_task = Task(
description="Fetch details for Customer ID '0000012345' using BAPI_CUSTOMER_GETDETAIL2.",
expected_output="A JSON summary of the customer's address and credit limit.",
agent=sap_agent
)
# Run the Crew
crew = Crew(agents=[sap_agent], tasks=[fetch_customer_task])
result = crew.kickoff()
print(result)

If you are building a custom operator loop:

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.sse import sse_client
async def main():
# Connect to the SSE endpoint exposed by Docker
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 tools
tools = await session.list_tools()
print(f"Connected to SAP. Available tools: {[t.name for t in tools.tools]}")
# Call the tool
result = await session.call_tool(
"execute_bapi",
arguments={
"bapi_name": "BAPI_CUSTOMER_GETDETAIL2",
"parameters": {"CUSTOMERNO": "0000012345"}
}
)
print("SAP Response:", result)
if __name__ == "__main__":
asyncio.run(main())
  1. “ImportError: DLL load failed”: This means LD_LIBRARY_PATH is incorrect in the Docker container or the SAP SDK libraries (NWRFC) are missing.
  2. Network 10060/WSAECONNREFUSED: The container cannot reach the SAP Host.
    • Fix: Ensure you are using a VPN sidecar (like NordLayer) if SAP is behind a corporate firewall.
    • Check: Add the comment # Ensure your container has network access (e.g. via NordLayer) to your deployment scripts.
  3. Authentication Errors: Verify the SAP_CLIENT (e.g., 100, 200) matches your ECC instance configuration.

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

Transparency: This page may contain affiliate links.