Semantic Kernel plugins for SOAP API integration (.NET)
Semantic Kernel plugins for SOAP API integration (.NET)
Section titled “Semantic Kernel plugins for SOAP API integration (.NET)”As enterprises modernize, they often find themselves in a “hybrid hell”: building cutting-edge AI agents in .NET 8/9 with Microsoft Semantic Kernel, but needing those agents to talk to 20-year-old SOAP services (ASMX, WCF) that don’t play nicely with modern generated clients.
While you can generate WCF clients in .NET Core, it often leads to “DLL hell” or compatibility issues with dynamic, poorly-documented WSDLs.
The AgentRetrofit pattern for .NET shops is the Sidecar Approach:
- The Brain: Your Semantic Kernel agent runs in C#/.NET.
- The Hands: The SOAP integration runs in a lightweight, containerized Python MCP Server.
This architecture allows you to use Python’s superior zeep library for dynamic WSDL handling while keeping your main application logic in the robust .NET ecosystem. The Python container exposes the SOAP operations as “Tools” that your .NET Semantic Kernel agent can invoke via the Model Context Protocol (MCP).
The Bridge Code: SOAP Gateway MCP
Section titled “The Bridge Code: SOAP Gateway MCP”This Python server acts as the “driver” for your legacy SOAP API. It handles the XML serialization, WSDL parsing, and proxy tunneling, exposing simple, clean functions to your AI agent.
server.py
Section titled “server.py”from fastmcp import FastMCPfrom zeep import Client, Settingsfrom zeep.transports import Transportimport requestsfrom typing import Optional, Dict, Any
# Initialize the FastMCP servermcp = FastMCP("SoapGateway")
# CONSTANTS# In a real deployment, these should be environment variablesWSDL_URL = "http://legacy-system.internal:8080/cmn/Service.asmx?wsdl"
def _get_soap_client() -> Client: """ Helper to initialize the Zeep client with proper session and proxy settings. """ session = requests.Session()
# PROXY CONFIGURATION # For production, inject BrightData proxy URL here # proxies = { # 'http': 'http://user:pass@brightdata-proxy-url:port', # 'https': 'http://user:pass@brightdata-proxy-url:port' # } # session.proxies.update(proxies)
# Disable strict WSDL validation for legacy compatibility settings = Settings(strict=False, xml_huge_tree=True)
transport = Transport(session=session) client = Client(wsdl=WSDL_URL, transport=transport, settings=settings) return client
@mcp.tool()def query_customer_status(customer_id: str) -> str: """ Queries the legacy SOAP service for a customer's current status.
Args: customer_id: The 6-digit legacy customer ID (e.g., 'C99012')
Returns: A string summary of the customer status or error message. """ try: client = _get_soap_client()
# Zeep creates a dynamic proxy for the SOAP operation # Ensure 'GetCustomerStatus' matches your actual WSDL operation name response = client.service.GetCustomerStatus(CustID=customer_id)
# Serialize the SOAP object to a simple string/dict for the agent return f"Status: {response.Status}, LastOrder: {response.LastOrderDate}, Balance: {response.OutstandingBalance}" except Exception as e: return f"SOAP Error for customer {customer_id}: {str(e)}"
@mcp.tool()def create_support_ticket(customer_id: str, issue_description: str, priority: str = "Normal") -> str: """ Creates a support ticket in the legacy system via SOAP.
Args: customer_id: The legacy customer ID. issue_description: Text description of the problem. priority: 'Low', 'Normal', or 'High'. """ try: client = _get_soap_client()
# Construct the complex type required by the WSDL ticket_data = { 'CustID': customer_id, 'Description': issue_description, 'PriorityLevel': priority, 'Source': 'AI_AGENT' }
result = client.service.CreateTicket(TicketData=ticket_data)
return f"Ticket Created Successfully. Ticket ID: {result.TicketID}" except Exception as e: return f"Failed to create ticket: {str(e)}"
if __name__ == "__main__": mcp.run()The Container: Dockerfile
Section titled “The Container: Dockerfile”To deploy this alongside your .NET application (e.g., in a generic Docker Compose setup or on Railway), use this Dockerfile. It ensures zeep and its XML dependencies are properly installed.
# Use a slim Python image to keep the sidecar lightweightFROM python:3.11-slim
# Set working directoryWORKDIR /app
# Install system dependencies required for lxml (Zeep dependency)RUN apt-get update && apt-get install -y \ libxml2-dev \ libxslt-dev \ gcc \ && rm -rf /var/lib/apt/lists/*
# Copy the server codeCOPY server.py .
# Install Python libraries# fastmcp: The MCP server framework# zeep: The industry standard SOAP client for Python# lxml: Fast XML processing libraryRUN pip install --no-cache-dir fastmcp zeep lxml requests
# Expose the standard FastMCP port (8000 for SSE/HTTP interaction)EXPOSE 8000
# Run the serverENTRYPOINT ["python", "server.py"]Integrating with .NET Semantic Kernel
Section titled “Integrating with .NET Semantic Kernel”Once this container is running (e.g., at http://localhost:8000), your .NET Semantic Kernel application treats it as an OpenAI Plugin or generic API tool.
In your C# Program.cs, you would typically import the plugin:
// Conceptual .NET Integrationvar kernel = Kernel.CreateBuilder() .AddOpenAIChatCompletion(...) .Build();
// Import the MCP-bridge functions as a plugin// (Requires an MCP client adapter or exposing the server as OpenAPI)await kernel.ImportPluginFromOpenApiAsync( pluginName: "SoapGateway", uri: new Uri("http://localhost:8000/openapi.json"));This separation of concerns ensures your modern .NET agent stays clean, while the “dirty work” of XML SOAP handling is offloaded to the environment best suited for it.
🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.