Skip to content

AutoGen agents consuming and publishing to SOAP APIs (Python)

AutoGen Agents Consuming and Publishing to SOAP APIs (Python)

Section titled “AutoGen Agents Consuming and Publishing to SOAP APIs (Python)”

As enterprises adopt Microsoft AutoGen to orchestrate multi-agent workflows, they inevitably hit the “SOAP Wall.” While modern agents speak JSON and REST, critical business logic in Supply Chain, Banking, and Insurance often lives behind WSDL (Web Services Description Language) and XML-based SOAP interfaces.

This blueprint provides a production-ready Model Context Protocol (MCP) server that bridges AutoGen agents to legacy SOAP APIs using Python’s zeep library. It handles the XML translation, authentication, and network proxying required to talk to “Big Iron” systems.

We use FastMCP to create a lightweight middleware. The AutoGen agent does not need to know how to parse XML; it simply calls a Python tool, and the MCP server handles the SOAP handshake.

graph LR
    A[AutoGen Agent] -->|JSON-RPC via SSE| B[FastMCP Server]
    B -->|XML/SOAP| C[Legacy ERP/Mainframe]
    C -->|XML Response| B
    B -->|Clean JSON| A

Create a requirements.txt file. We use zeep for robust SOAP handling.

fastmcp==0.4.1
zeep==4.2.1
uvicorn==0.27.1
httpx==0.27.0
pyautogen==0.2.19
mcp==1.0.0

This server exposes SOAP operations as executable tools for your agents. It includes the mandatory network configuration for Docker environments.

from fastmcp import FastMCP
from zeep import Client, Settings
from zeep.transports import Transport
import requests
# Initialize FastMCP
mcp = FastMCP("SoapBridge")
# Configuration for Legacy SOAP Service
WSDL_URL = "http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL"
def get_soap_client():
"""
Creates a configured Zeep client for SOAP interaction.
"""
# ------------------------------------------------------------------
# ENTERPRISE PROXY CONFIGURATION
# Legacy systems are often behind firewalls requiring specific egress IPs.
# ------------------------------------------------------------------
# proxies = {
# 'http': 'http://user:[email protected]:22225',
# 'https': 'http://user:[email protected]:22225'
# }
# For production, inject BrightData proxy URL here
session = requests.Session()
# session.proxies.update(proxies) # Uncomment to enable proxying
# Zeep settings to handle strict vs lax XML parsing
settings = Settings(strict=False, xml_huge_tree=True)
transport = Transport(session=session)
return Client(WSDL_URL, transport=transport, settings=settings)
@mcp.tool()
def get_country_currency(country_iso_code: str) -> str:
"""
Retrieves the currency used by a specific country via SOAP.
Args:
country_iso_code: The 2-letter ISO code (e.g., 'US', 'JP', 'DE').
"""
try:
client = get_soap_client()
result = client.service.CountryCurrency(sCountryISOCode=country_iso_code)
return f"Currency: {result.sISOCode} - {result.sName}"
except Exception as e:
return f"SOAP Error: {str(e)}"
@mcp.tool()
def list_continents() -> str:
"""
Lists all continents defined in the legacy system.
"""
try:
client = get_soap_client()
result = client.service.ListOfContinentsByName()
return ", ".join([f"{item.sCode}: {item.sName}" for item in result])
except Exception as e:
return f"SOAP Error: {str(e)}"
if __name__ == "__main__":
# HOST MUST BE 0.0.0.0 to work inside Docker/Railway
mcp.run(transport='sse', host='0.0.0.0', port=8000)

This configuration ensures the application listens on the correct port and installs the necessary system dependencies for XML processing.

FROM python:3.11-slim
WORKDIR /app
# Install system dependencies for lxml (required by Zeep)
RUN apt-get update && apt-get install -y \
libxml2-dev \
libxslt-dev \
gcc \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY server.py .
# EXPOSE 8000 for Railway compatibility
EXPOSE 8000
CMD ["python", "server.py"]

The following script (agent.py) demonstrates how to equip an AutoGen assistant with the tools from your SOAP bridge. We use the mcps configuration pattern to define our server endpoints.

import asyncio
import autogen
from mcp import ClientSession, StdioServerParameters
from mcp.client.sse import sse_client
# ------------------------------------------------------------------
# AGENT CONFIGURATION
# ------------------------------------------------------------------
# List of MCP Server endpoints (SSE)
mcps = [
"http://localhost:8000/sse"
]
config_list = [
{"model": "gpt-4-turbo", "api_key": "YOUR_OPENAI_API_KEY"}
]
gpt4_config = {
"cache_seed": 42,
"temperature": 0,
"config_list": config_list,
"timeout": 120,
}
# ------------------------------------------------------------------
# TOOL REGISTRATION LOGIC
# ------------------------------------------------------------------
async def register_mcp_tools(agent: autogen.AssistantAgent, user_proxy: autogen.UserProxyAgent, mcp_url: str):
"""
Connects to an MCP server, fetches tools, and registers them with the AutoGen agent.
"""
# Connect via SSE
async with sse_client(url=mcp_url) as streams:
async with ClientSession(streams[0], streams[1]) as session:
await session.initialize()
# Fetch tools
tools_result = await session.list_tools()
# Register each tool
for tool in tools_result.tools:
print(f"Registering tool: {tool.name}")
# Dynamic wrapper to bridge AutoGen's generic call to MCP
async def tool_wrapper(**kwargs):
# Re-connect for the actual call (stateless execution)
async with sse_client(url=mcp_url) as call_streams:
async with ClientSession(call_streams[0], call_streams[1]) as call_session:
await call_session.initialize()
result = await call_session.call_tool(tool.name, arguments=kwargs)
return result.content[0].text
# Register with AutoGen
autogen.agentchat.register_function(
tool_wrapper,
caller=agent,
executor=user_proxy,
name=tool.name,
description=tool.description,
)
# Keep the connection info or context if needed, but for this simple
# pattern, we register the wrapper which creates its own short-lived session
# or relies on a persistent one if managed externally.
return tools_result
async def main():
# 1. Initialize Agents
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
code_execution_config={"work_dir": "coding", "use_docker": False},
)
assistant = autogen.AssistantAgent(
name="Legacy_Integrator",
llm_config=gpt4_config,
system_message="You are a helpful assistant capable of querying legacy SOAP databases via MCP."
)
# 2. Register Tools from all MCP servers
for url in mcps:
try:
# We connect briefly to fetch definitions.
# Note: In production, you might want a persistent connection manager.
# The wrapper logic above handles re-connection for execution.
await register_mcp_tools(assistant, user_proxy, url)
except Exception as e:
print(f"Failed to connect to MCP at {url}: {e}")
# 3. Execute Workflow
print("Initiating Chat with Legacy SOAP System...")
await user_proxy.a_initiate_chat(
assistant,
message="Check the currency for Japan (JP) and then list all continents available in the system."
)
if __name__ == "__main__":
asyncio.run(main())
  1. Transport Choice: We use sse (Server-Sent Events) over HTTP for Docker compatibility, as passing Stdio pipes into containers is complex.
  2. Statelessness: The tool_wrapper logic demonstrates a robust pattern where each tool call establishes its own fresh session or uses a connection pool. This prevents timeouts on long-running agent conversations.
  3. Strict Mode: In server.py, strict=False is crucial. Legacy SOAP implementations (Oracle Fusion, SAP ECC) often emit XML that technically violates their own WSDL schemas. Zeep’s lax mode handles this gracefully.

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

Transparency: This page may contain affiliate links.