Skip to content

AutoGen for SAP ECC reporting and analytics automation

AutoGen for SAP ECC Reporting and Analytics Automation

Section titled “AutoGen for SAP ECC Reporting and Analytics Automation”

This guide demonstrates how to build a reporting agent using Microsoft AutoGen that connects to SAP ECC via the Model Context Protocol (MCP).

Unlike modern SaaS APIS, legacy SAP systems often require complex OData or RFC connections. We use the “Retrofit” pattern: a FastMCP server handles the heavy lifting (SAP Gateway authentication, OData parsing) and exposes simple, typed tools to the AutoGen agents.

  1. Server (FastMCP): A Python container that acts as the “SAP Gateway Bridge”. It speaks OData to SAP and MCP to the Agent.
  2. Client (AutoGen): A generic Python script using ClientSession to consume the MCP tools and register them with an AssistantAgent.
  3. Network: The Docker container requires a route to your on-premise SAP instance (e.g., via a Site-to-Site VPN or NordLayer).

The server uses the mcp library to define tools. We bind to 0.0.0.0 to ensure the server is accessible by the AutoGen client running in a separate process or container.

import os
import requests
from mcp.server.fastmcp import FastMCP
# Initialize the FastMCP server
mcp = FastMCP("SAP-ECC-Reporting-Node")
# Configuration
# In production, inject these via environment variables
SAP_ODATA_BASE_URL = os.getenv("SAP_URL", "https://sap-gateway.internal.corp:44300/sap/opu/odata/sap/Z_ANALYTICS_SRV")
SAP_AUTH = (os.getenv("SAP_USER", "REPORT_BOT"), os.getenv("SAP_PASSWORD", "Secret123"))
# Ensure your container has network access (e.g. via NordLayer)
# This is required to reach the on-premise SAP Gateway from a cloud environment.
@mcp.tool()
def get_sales_revenue(fiscal_year: str, company_code: str) -> str:
"""
Retrieves total sales revenue for a specific fiscal year and company code from SAP ECC.
Args:
fiscal_year: The 4-digit year (e.g., '2024').
company_code: The 4-character SAP Company Code (e.g., '1000').
"""
try:
# Construct OData filter
filter_query = f"$filter=FiscalYear eq '{fiscal_year}' and CompanyCode eq '{company_code}'"
url = f"{SAP_ODATA_BASE_URL}/SalesSummarySet?{filter_query}&$format=json"
# Make the request to SAP Gateway
# verify=False is often needed for internal self-signed SAP certs; use proper certs in prod.
response = requests.get(url, auth=SAP_AUTH, verify=False, timeout=30)
response.raise_for_status()
data = response.json()
results = data.get('d', {}).get('results', [])
if not results:
return f"No sales data found for Company {company_code} in {fiscal_year}."
# Aggregation logic
total_revenue = sum(float(item.get('Revenue', 0)) for item in results)
currency = results[0].get('Currency', 'USD')
return f"Total Revenue for {company_code} in {fiscal_year}: {total_revenue:,.2f} {currency}"
except requests.exceptions.RequestException as e:
return f"SAP OData Connection Error: {str(e)}"
@mcp.tool()
def get_stock_levels(plant_id: str, material_id: str) -> str:
"""
Checks current stock levels for a material at a specific plant.
"""
try:
url = f"{SAP_ODATA_BASE_URL}/StockSet(Plant='{plant_id}',Material='{material_id}')?$format=json"
response = requests.get(url, auth=SAP_AUTH, verify=False, timeout=30)
if response.status_code == 404:
return f"Material {material_id} not found at Plant {plant_id}."
response.raise_for_status()
data = response.json().get('d', {})
qty = float(data.get('UnrestrictedQty', 0))
uom = data.get('BaseUnit', 'PC')
return f"Current Stock: {qty} {uom}"
except Exception as e:
return f"Error retrieving stock: {str(e)}"
if __name__ == "__main__":
mcp.run(transport='sse', host='0.0.0.0', port=8000)

The Dockerfile exposes port 8000, allowing the AutoGen client (running on host or another container) to connect via HTTP SSE.

# Use a lightweight Python base
FROM python:3.11-slim
# Prevent Python from buffering stdout/stderr
ENV PYTHONUNBUFFERED=1
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# Create app directory
WORKDIR /app
# Install Python dependencies
# mcp: The Model Context Protocol SDK
# requests: For OData calls
RUN pip install --no-cache-dir mcp requests
# Copy the server code
COPY server.py .
# EXPOSE port 8000 for Railway/Docker networking
EXPOSE 8000
# Run the MCP server
CMD ["python", "server.py"]

Since AutoGen does not yet have a native mcps parameter like CrewAI, we use the mcp library’s ClientSession to bridge the connection. We define our servers in an mcps list and dynamically register their tools with the AutoGen UserProxy.

import asyncio
from autogen import AssistantAgent, UserProxyAgent
from mcp import ClientSession
from mcp.client.sse import sse_client
# Configuration: List of MCP servers to connect to
mcps = ["http://localhost:8000/sse"]
async def run_session():
# We will connect to the first server in our list for this example
server_url = mcps[0]
print(f"Connecting to MCP Server at: {server_url}")
async with sse_client(server_url) as (read, write):
async with ClientSession(read, write) as session:
# 1. Initialize Protocol
await session.initialize()
# 2. List Available Tools
tools_result = await session.list_tools()
mcp_tools = tools_result.tools
# 3. Create Tool Wrappers for AutoGen
# AutoGen requires Python functions that it can call.
# We create a dynamic map of functions that proxy calls to the MCP server.
function_map = {}
llm_functions_config = []
for tool in mcp_tools:
tool_name = tool.name
tool_desc = tool.description
# Define the wrapper function
async def make_tool_call(**kwargs):
# Execute the tool remotely on the MCP server
result = await session.call_tool(tool_name, arguments=kwargs)
return result.content[0].text
# Register wrapper
function_map[tool_name] = make_tool_call
# Configure for LLM (OpenAI schema)
llm_functions_config.append({
"name": tool_name,
"description": tool_desc,
"parameters": tool.inputSchema
})
# 4. Configure Agents
config_list = [{"model": "gpt-4", "api_key": "YOUR_OPENAI_API_KEY"}]
assistant = AssistantAgent(
name="SAP_Analyst",
system_message="You are a helpful SAP assistant. Use the provided tools to query SAP ECC.",
llm_config={
"config_list": config_list,
"functions": llm_functions_config
}
)
user_proxy = UserProxyAgent(
name="user_proxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=5,
code_execution_config=False,
)
# 5. Register Functions with User Proxy
# This allows the UserProxy to execute the tool calls requested by the Assistant
user_proxy.register_function(function_map=function_map)
# 6. Start the Conversation
print("Starting AutoGen Chat...")
await user_proxy.a_initiate_chat(
assistant,
message="What is the total sales revenue for Company 1000 in fiscal year 2024?"
)
if __name__ == "__main__":
# Ensure you have 'pip install pyautogen mcp httpx'
asyncio.run(run_session())
  • mcps Configuration: We define mcps = ["http://localhost:8000/sse"] to clearly indicate where the agent connects. This makes it easy to add multiple MCP servers (e.g., one for SAP, one for Oracle) by simply appending to the list.
  • Dynamic Tool loading: The script dynamically fetches tools from the MCP server at runtime. This means if you update server.py with a new report, the Agent sees it immediately without code changes in agent.py.
  • Authentication: The server.py handles the legacy SAP authentication. The Agent simply speaks JSON, insulating the LLM from the complexities of RFC/OData login flows.

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

Transparency: This page may contain affiliate links.