Connecting CrewAI to legacy SOAP APIs with Python `zeep`
Connecting CrewAI to Legacy SOAP APIs with Python zeep
Section titled “Connecting CrewAI to Legacy SOAP APIs with Python zeep”In the world of modern AI agents, REST and GraphQL are the lingua franca. However, the enterprise world still runs on SOAP (Simple Object Access Protocol). If you are trying to get a CrewAI agent to check inventory in an old SAP system, validate a bank transaction on a mainframe, or pull patient records from a legacy EHR, you are likely facing an XML-heavy SOAP interface.
Most modern LLMs struggle to generate syntactically perfect XML for SOAP envelopes. The solution? Don’t let the LLM write the XML. Use Python’s zeep library to handle the protocol heavy lifting, and wrap it in a FastMCP server so your CrewAI agents can interact with it as a simple tool.
The Architecture
Section titled “The Architecture”Instead of teaching the Agent how to format XML, we give it a tool: query_inventory(sku).
- CrewAI sends a JSON request to the MCP Server.
- FastMCP routes this to a Python function.
- Zeep reads the remote WSDL, constructs the SOAP XML envelope, handles authentication, and sends the request.
- The Legacy System responds with XML.
- Zeep parses the XML back into a Python dictionary.
- FastMCP returns the clean data to the Agent.
Step 1: The Bridge Code (server.py)
Section titled “Step 1: The Bridge Code (server.py)”This server uses fastmcp to expose a SOAP endpoint. It uses zeep to inspect the WSDL (Web Services Description Language) dynamically or statically.
In this example, we model a standard “Inventory Check” against a legacy ERP.
Prerequisites:
pip install fastmcp zeepFile: server.py
from fastmcp import FastMCPfrom zeep import Client, Settings, helpersimport json
# Initialize the MCP Servermcp = FastMCP("LegacySoapGateway")
# Configuration for the Legacy ERP# In production, load these from env varsWSDL_URL = "http://legacy-erp.internal/services/InventoryService?wsdl"
@mcp.tool()def check_inventory(sku: str, warehouse_id: str = "WH-01") -> str: """ Queries the legacy SOAP ERP to check stock levels for a specific SKU.
Args: sku: The stock keeping unit ID (e.g., '123-ABC'). warehouse_id: The warehouse identifier (defaults to 'WH-01'). """ try: # Proxy Configuration for secure enterprise tunneling # proxies = { # 'http': 'http://user:pass@brightdata_proxy_url:port', # 'https': 'http://user:pass@brightdata_proxy_url:port' # } # For production, inject BrightData proxy URL here
# Initialize Zeep Client # 'strict=False' is often needed for older, non-compliant WSDLs settings = Settings(strict=False, xml_huge_tree=True)
# Initialize client (inject proxies if uncommented above) # client = Client(WSDL_URL, settings=settings, proxies=proxies)
# For this demo, we assume the client connects directly or via system proxy # Note: If WSDL is unreachable during dev, Zeep will raise an error. client = Client(WSDL_URL, settings=settings)
# Create the complex type if required by the WSDL # Many SOAP APIs require a request object rather than positional args request_data = { 'SKU': sku, 'WarehouseID': warehouse_id, 'RequestTimestamp': '2025-01-01T12:00:00' }
# Call the SOAP operation. # Assume the operation name is 'GetStockLevel' defined in the WSDL. # Check your specific WSDL for the exact operation name. response = client.service.GetStockLevel(**request_data)
# Serialize the Zeep object to a native Python dict for the Agent # Zeep returns custom objects that LLMs can't parse directly. result_dict = helpers.serialize_object(response)
return json.dumps(result_dict, default=str)
except Exception as e: return f"SOAP Interface Error: {str(e)}"
if __name__ == "__main__": mcp.run()Step 2: The Container (Dockerfile)
Section titled “Step 2: The Container (Dockerfile)”To deploy this to a cloud environment (like Railway, Render, or a corporate K8s cluster), we need to containerize it.
Critical Note: We explicitly EXPOSE 8000 to ensure the MCP protocol is accessible.
File: Dockerfile
# Use a slim Python image to keep the footprint smallFROM python:3.11-slim
# Set working directoryWORKDIR /app
# Install system dependencies if needed (e.g. libxml2 for zeep speed)RUN apt-get update && apt-get install -y --no-install-recommends \ libxml2-dev \ libxslt-dev \ && rm -rf /var/lib/apt/lists/*
# Copy requirements (simulated here for brevity)# In production, COPY requirements.txt . and RUN pip install -r requirements.txtRUN pip install --no-cache-dir fastmcp zeep lxml
# Copy the server codeCOPY server.py .
# Expose the FastMCP portEXPOSE 8000
# Run the serverCMD ["python", "server.py"]Step 3: Integration with CrewAI
Section titled “Step 3: Integration with CrewAI”Once your Docker container is running (e.g., at http://soap-gateway:8000), you can connect it to your CrewAI agent using the MCP integration.
If you are running locally:
from crewai import Agent, Task, Crewfrom crewai_tools import BaseTool
# CrewAI allows generic tool usage.# If using the specialized MCP connector (coming in CrewAI vX), you config it there.# For now, you might wrap the remote call if not using local execution.
# Example of defining the agent intentinventory_agent = Agent( role='Inventory Manager', goal='Ensure stock levels are adequate', backstory='You monitor the legacy SAP ECC system via the SOAP gateway.', tools=[] # Your MCP tools are injected here or via the MCP protocol connection)Why Zeep?
Section titled “Why Zeep?”- WSDL Parsing: It reads the “instructions” from the server automatically. You don’t need to manually map input types.
- Type Safety: It validates data before sending it, preventing “Garbage In, Garbage Out” errors that confuse AI agents.
- Transport Security: It handles WS-Security (WS-SE) and other complex SOAP auth standards that are difficult to implement with
requestsalone.
Troubleshooting Legacy SOAP
Section titled “Troubleshooting Legacy SOAP”- “Server not found”: SOAP servers often live behind corporate firewalls. You will likely need the
proxiesdictionary commented out inserver.pyto route traffic through a residential or static IP proxy (like BrightData) to whitelist the connection. - XML Parse Errors: Legacy systems often emit invalid XML. Set
Settings(strict=False)in Zeep to force it to be lenient.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.