Microsoft Semantic Kernel consuming legacy SOAP web services (Python)
Microsoft Semantic Kernel consuming legacy SOAP web services (Python)
Section titled “Microsoft Semantic Kernel consuming legacy SOAP web services (Python)”Slug: semantic-kernel-soap-web-services-python
The “Knowledge Gap”
Section titled “The “Knowledge Gap””Microsoft Semantic Kernel (SK) is designed to orchestrate AI “skills” and “plugins,” but it struggles significantly with the rigid, verbose nature of legacy SOAP (Simple Object Access Protocol) web services.
Most enterprise billing, inventory, and HR systems from the early 2000s communicate strictly via XML-based SOAP interfaces. A raw LLM trying to construct a valid SOAP envelope often fails due to:
- Token Bloat: A simple “Get Price” request can require 50 lines of XML boilerplate.
- Strict Schemas: SOAP services crash if a single namespace or type definition is slightly off—nuances LLMs often hallucinate.
The Solution: The “SoapGateway” MCP Server
Section titled “The Solution: The “SoapGateway” MCP Server”Instead of forcing Semantic Kernel to write XML, we use the Model Context Protocol (MCP) to create a SoapGateway.
- The Agent (SK) sends a clean function call:
check_invoice(id="INV-992"). - The MCP Server translates this into the heavy XML envelope using Python’s
zeeplibrary, handles the SOAP handshake, and returns clean JSON.
1. Prerequisites
Section titled “1. Prerequisites”You will need a Python environment with the following installed:
pip install fastmcp zeep lxml requests2. The Bridge Code (server.py)
Section titled “2. The Bridge Code (server.py)”This MCP server exposes a tool that connects to a legacy Billing Service. It uses zeep to parse the WSDL (Web Services Description Language) file automatically, removing the need for manual XML string manipulation.
from fastmcp import FastMCPimport zeepimport requestsfrom requests.auth import HTTPBasicAuth
# Initialize the FastMCP servermcp = FastMCP("SoapGateway")
@mcp.tool()def get_invoice_details(invoice_id: str) -> str: """ Retrieves detailed invoice status and amount from the legacy Billing SOAP Service.
Args: invoice_id: The unique invoice identifier (e.g., 'INV-2024-001'). """ # Configuration for the Legacy System # In a real deployment, these would come from environment variables wsdl_url = "http://billing-legacy.internal:8080/ws/InvoiceService?wsdl"
# PROXY CONFIGURATION # Legacy systems are often behind strict corporate firewalls that require # static IP origins. We use a proxy to route traffic correctly. # proxies = { # "http": "http://user:pass@proxy-server:port", # "https": "http://user:pass@proxy-server:port", # } # For production, inject BrightData proxy URL here
try: # Create a session to handle auth and proxies session = requests.Session()
# If using proxies, uncomment the line below: # session.proxies.update(proxies)
# Example: Legacy SOAP often uses Basic Auth # session.auth = HTTPBasicAuth('legacy_user', 'password123')
# Initialize the Zeep Client # strict=False helps with older, non-compliant WSDLs client = zeep.Client(wsdl=wsdl_url, transport=zeep.Transports(session=session))
# Call the SOAP operation. # Note: 'GetInvoiceStatus' is the specific method defined in the WSDL. # Zeep handles the XML envelope construction automatically. response = client.service.GetInvoiceStatus( InvoiceNumber=invoice_id, IncludeTaxData=True )
# Convert the complex Zeep object to a string/dict for the agent return str(response)
except zeep.exceptions.Fault as fault: return f"SOAP Fault (Server Error): {fault.message}" except requests.exceptions.ConnectionError: return "Network Error: Could not reach the legacy billing server. Check VPN/Proxy settings." except Exception as e: return f"Unknown Error: {str(e)}"
if __name__ == "__main__": mcp.run()3. Containerization (Dockerfile)
Section titled “3. Containerization (Dockerfile)”This Dockerfile ensures the environment handles the underlying C dependencies required by lxml (used by zeep for XML parsing) and exposes the correct port for Railway or local deployment.
# Use a slim Python image to keep the footprint smallFROM python:3.11-slim
# Install system dependencies required for XML processing (lxml)# libxml2-dev and libxslt-dev are often needed for SOAP librariesRUN apt-get update && apt-get install -y \ gcc \ libxml2-dev \ libxslt-dev \ && rm -rf /var/lib/apt/lists/*
# Set the working directoryWORKDIR /app
# Install Python dependencies# fastmcp handles the server, zeep handles SOAPRUN pip install --no-cache-dir fastmcp zeep requests
# Copy the server codeCOPY server.py .
# EXPOSE 8000 for Railway compatibilityEXPOSE 8000
# Run the FastMCP serverCMD ["python", "server.py"]4. How It Works
Section titled “4. How It Works”- Initialization: When the Semantic Kernel agent connects to this MCP server, it sees a tool named
get_invoice_details. - Invocation: The agent calls the tool with a string like
"INV-5599". - Transformation: The
server.pyscript initializes azeep.Client. It downloads the WSDL definition from the legacy server to understand the required XML structure. - Transport: The request is routed (optionally through a BrightData proxy) to the on-premise SOAP endpoint.
- Response: The complex XML response (
<soap:Envelope>...<Status>PAID</Status>...) is parsed into a Python dictionary and returned as text to the agent.
Troubleshooting Legacy SOAP
Section titled “Troubleshooting Legacy SOAP”- WSDL Parsing Errors: If
zeepcomplains about the WSDL, try usingstrict=Falsein theSettingsobject, or download the.wsdlfile locally and modify broken definitions manually. - Timeouts: Legacy SOAP servers are notoriously slow. Ensure your agent’s timeout settings allow for 30-60 second waits.
- “Transport Error 401”: This usually means Basic Auth credentials are missing or the IP isn’t allowlisted. Verify the proxy configuration.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.