OpenAI Operator handling SAP ECC RFC errors and retries
OpenAI Operator: Handling SAP ECC RFC Errors and Retries
Section titled “OpenAI Operator: Handling SAP ECC RFC Errors and Retries”Integrating OpenAI Agents (Operators) with legacy SAP ECC systems often results in brittle pipelines. SAP’s Remote Function Call (RFC) protocol is notoriously sensitive to network fluctuations and throws cryptic ABAP exceptions that confuse standard LLMs.
This guide provides a robust Model Context Protocol (MCP) server designed to wrap SAP RFC calls with intelligent error handling and exponential backoff strategies. It acts as a stability layer, allowing your OpenAI Operator to interact with SAP without crashing due to transient RFC_COMMUNICATION_FAILURE errors.
🏗️ Architecture
Section titled “🏗️ Architecture”We use FastMCP to create an SSE (Server-Sent Events) endpoint. This server:
- Authenticates with SAP ECC using
pyrfc. - Intercepts specific SAP exceptions (Logon vs. Network).
- Retries transient network errors automatically using
tenacity. - Exposes a clean tool definition that OpenAI models can understand.
Prerequisites
Section titled “Prerequisites”- Python 3.11+
- SAP NW RFC SDK 7.50+ (Required for
pyrfc. You must download this from the SAP Marketplace and place it in your build context). - Docker
🛠️ 1. The Server Code (server.py)
Section titled “🛠️ 1. The Server Code (server.py)”This server implements the “Smart Retry” pattern. It distinguishes between fatal errors (e.g., “Bad Password”) and retryable errors (e.g., “Network Glitch”), ensuring the Agent doesn’t waste tokens retrying impossible tasks.
import osimport jsonimport loggingfrom typing import Dict, Any
from fastmcp import FastMCPfrom tenacity import ( retry, stop_after_attempt, wait_exponential, retry_if_exception_type)
# Initialize FastMCPmcp = FastMCP("SAP-ECC-Gateway")
# Configure Logginglogging.basicConfig(level=logging.INFO)logger = logging.getLogger(__name__)
# Try to import pyrfc; handle missing SDK gracefully for linting/devtry: from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationErrorexcept ImportError: logger.error("pyrfc not found. Ensure SAP NW RFC SDK is installed.") # Mock exceptions for structure validity if SDK is missing during dev class CommunicationError(Exception): pass class LogonError(Exception): pass class ABAPApplicationError(Exception): pass class ABAPRuntimeError(Exception): pass Connection = None
# --- Configuration ---SAP_CONFIG = { "ashost": os.getenv("SAP_ASHOST"), "sysnr": os.getenv("SAP_SYSNR", "00"), "client": os.getenv("SAP_CLIENT", "100"), "user": os.getenv("SAP_USER"), "passwd": os.getenv("SAP_PASSWORD"), "lang": "EN"}
# --- Retry Logic ---def log_retry_attempt(retry_state): """Callback to log retry attempts for the Agent's visibility.""" logger.warning(f"SAP RFC connection failed. Retrying... (Attempt {retry_state.attempt_number})")
@retry( retry=retry_if_exception_type(CommunicationError), wait=wait_exponential(multiplier=1, min=2, max=10), stop=stop_after_attempt(3), before_sleep=log_retry_attempt)def _saprfc_execute_internal(func_name: str, params: Dict[str, Any]): """ Internal function to execute RFC with Tenacity retries. Only retries on CommunicationError (Network). Fails fast on LogonError (Auth) or ABAPRuntimeError (Logic). """ # Ensure your container has network access (e.g. via NordLayer) if not Connection: raise ImportError("SAP SDK missing.")
conn = Connection(**SAP_CONFIG) try: result = conn.call(func_name, **params) return result finally: conn.close()
# --- MCP Tools ---
@mcp.tool()def execute_sap_bapi(bapi_name: str, parameters: str) -> str: """ Executes a specific SAP BAPI/RFC with automatic error handling and retries.
Args: bapi_name: The name of the function module (e.g., 'BAPI_SALESORDER_GETLIST'). parameters: A JSON string containing the import parameters for the BAPI.
Returns: JSON string of the BAPI result or a structured error message. """ try: # Parse input JSON params_dict = json.loads(parameters)
logger.info(f"Agent requesting BAPI: {bapi_name}")
# Execute with retry logic result = _saprfc_execute_internal(bapi_name, params_dict)
return json.dumps(result, default=str)
except json.JSONDecodeError: return json.dumps({"status": "error", "message": "Invalid JSON format in parameters."}) except LogonError as e: # Fatal: Do not retry authentication errors return json.dumps({"status": "fatal_error", "code": "AUTH_FAILURE", "message": str(e)}) except ABAPApplicationError as e: # Fatal: Business logic error in SAP (e.g., Order not found) return json.dumps({"status": "abap_error", "key": e.key, "message": e.message}) except CommunicationError as e: # If we reach here, retries were exhausted return json.dumps({"status": "network_error", "message": "SAP Unreachable after 3 retries.", "details": str(e)}) except Exception as e: return json.dumps({"status": "system_error", "message": str(e)})
if __name__ == "__main__": # HOST must be 0.0.0.0 for Docker/Railway compatibility mcp.run(transport='sse', host='0.0.0.0', port=8000)🐳 2. The Dockerfile
Section titled “🐳 2. The Dockerfile”SAP requires the NetWeaver RFC SDK C++ libraries to be present in the OS. This Dockerfile assumes you have the SDK extracted in a folder named nwrfc750 in the same directory.
# Use a slim Python baseFROM python:3.11-slim
# Install system dependencies required for SAP SDKRUN apt-get update && apt-get install -y \ gcc \ g++ \ make \ uuid-dev \ && rm -rf /var/lib/apt/lists/*
# Set up SAP SDK environment variables# NOTE: You must provide the 'nwrfc750' folder in your build contextENV SAPNWRFC_HOME=/opt/nwrfc750ENV LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib
# Copy SAP SDK (User must provide this, it is proprietary)COPY nwrfc750 /opt/nwrfc750
# Workdir setupWORKDIR /app
# Install Python libsCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
# Copy application codeCOPY server.py .
# Expose the SSE port (Required for Railway/Cloud)EXPOSE 8000
# Run the MCP serverCMD ["python", "server.py"]requirements.txt
Section titled “requirements.txt”fastmcppyrfctenacitycrewai🤖 3. The Agent Code (agent.py)
Section titled “🤖 3. The Agent Code (agent.py)”This section provides a complete, runnable CrewAI agent script. It automatically connects to the Dockerized MCP server running on port 8000 and attempts to fetch user details from SAP.
Prerequisites:
- Ensure the Docker container is running:
docker run -p 8000:8000 -d sap-mcp-server - Set
OPENAI_API_KEYin your environment.
import osfrom crewai import Agent, Task, Crew
# Check for API Keyif not os.getenv("OPENAI_API_KEY"): raise ValueError("OPENAI_API_KEY is not set.")
print("🚀 Initializing SAP Operator Agent...")
# Define the Agent# We use the 'mcps' parameter to connect to our local SSE server.sap_operator = Agent( role='SAP ERP Operations Specialist', goal='Execute SAP transactions and retrieve data for business analysis.', backstory=( "You are a specialized AI agent with direct access to the corporate SAP ECC system. " "Your job is to query user data and order details using BAPIs. " "You represent the bridge between modern AI and legacy ERP." ), # KEY INTEGRATION POINT: Connect to the MCP Server via SSE mcps=["http://localhost:8000/sse"], verbose=True, allow_delegation=False, llm="gpt-4o" # Recommended for complex tool usage)
# Define the Taskuser_audit_task = Task( description=( "Retrieve detailed information for the SAP user 'DEMO_USER'. " "Use the 'execute_sap_bapi' tool. " "The BAPI to use is 'BAPI_USER_GET_DETAIL'. " "Pass the parameter 'USERNAME' as 'DEMO_USER'. " "If the user is found, summarize their address data." ), expected_output="A summary of the SAP user's address and account status.", agent=sap_operator)
# Create the Crewcrew = Crew( agents=[sap_operator], tasks=[user_audit_task], verbose=True)
# Executionif __name__ == "__main__": print("📋 Starting Task: SAP User Audit") try: result = crew.kickoff() print("\n\n########################") print("## TASK RESULT ##") print("########################\n") print(result) except Exception as e: print(f"❌ Execution failed: {e}")How to Run
Section titled “How to Run”-
Start the Server:
Terminal window docker build -t sap-rfc-mcp .docker run -p 8000:8000 --env-file .env sap-rfc-mcp -
Run the Agent:
Terminal window python agent.py
The agent will connect to http://localhost:8000/sse, discover the execute_sap_bapi tool, and autonomously format the JSON parameters to call SAP. If the SAP system is temporarily offline, the server’s built-in tenacity logic will retry the connection before returning a final response to the agent.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.