Skip to content

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

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:

  1. Token Bloat: A simple “Get Price” request can require 50 lines of XML boilerplate.
  2. 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 zeep library, handles the SOAP handshake, and returns clean JSON.

You will need a Python environment with the following installed:

Terminal window
pip install fastmcp zeep lxml requests

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 FastMCP
import zeep
import requests
from requests.auth import HTTPBasicAuth
# Initialize the FastMCP server
mcp = 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()

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 small
FROM python:3.11-slim
# Install system dependencies required for XML processing (lxml)
# libxml2-dev and libxslt-dev are often needed for SOAP libraries
RUN apt-get update && apt-get install -y \
gcc \
libxml2-dev \
libxslt-dev \
&& rm -rf /var/lib/apt/lists/*
# Set the working directory
WORKDIR /app
# Install Python dependencies
# fastmcp handles the server, zeep handles SOAP
RUN pip install --no-cache-dir fastmcp zeep requests
# Copy the server code
COPY server.py .
# EXPOSE 8000 for Railway compatibility
EXPOSE 8000
# Run the FastMCP server
CMD ["python", "server.py"]
  1. Initialization: When the Semantic Kernel agent connects to this MCP server, it sees a tool named get_invoice_details.
  2. Invocation: The agent calls the tool with a string like "INV-5599".
  3. Transformation: The server.py script initializes a zeep.Client. It downloads the WSDL definition from the legacy server to understand the required XML structure.
  4. Transport: The request is routed (optionally through a BrightData proxy) to the on-premise SOAP endpoint.
  5. Response: The complex XML response (<soap:Envelope>...<Status>PAID</Status>...) is parsed into a Python dictionary and returned as text to the agent.
  • WSDL Parsing Errors: If zeep complains about the WSDL, try using strict=False in the Settings object, or download the .wsdl file 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.

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

Transparency: This page may contain affiliate links.