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)”The “Big Iron” Problem
Section titled “The “Big Iron” Problem”Enterprises running on Microsoft stacks often face a dilemma: their core business logic lives in legacy SOAP services (WCF, ASMX) behind corporate firewalls, but their new AI initiatives use modern Semantic Kernel (.NET) agents that expect RESTful, JSON-based tools.
Parsing XML schemas (WSDL) and handling SOAP envelopes in modern AI pipelines is brittle and error-prone. The AgentRetrofit pattern solves this by offloading the heavy SOAP lifting to a specialized Python bridge (using zeep), exposed as a Model Context Protocol (MCP) server.
While the primary consumer is often .NET, this guide includes a Python agent.py using CrewAI patterns to verify the bridge connectivity before integrating it into your C# Semantic Kernel application.
1. The Bridge Server (server.py)
Section titled “1. The Bridge Server (server.py)”This Python script runs inside Docker. It uses zeep to dynamically parse the WSDL and FastMCP to serve the functions over SSE.
from fastmcp import FastMCPfrom zeep import Client, Settingsimport json
# Initialize the MCP Servermcp = FastMCP("SoapBridge")
# Configuration for the Legacy SOAP ServiceWSDL_URL = "http://legacy-system:8080/Service.asmx?WSDL"
# PRODUCTION: Inject proxies here to bypass corporate firewalls or handle IP rotation# For production, inject BrightData proxy URL herePROXIES = { # 'http': 'http://user:[email protected]:22225', # 'https': 'http://user:[email protected]:22225'}
@mcp.tool()def query_soap_service(operation: str, parameters: str) -> str: """ Executes a SOAP operation against the legacy WSDL.
Args: operation: The name of the SOAP method to call (e.g., 'GetCustomerById'). parameters: A JSON string of arguments matching the WSDL schema. """ try: # Strict XML handling for legacy systems settings = Settings(strict=False, xml_huge_tree=True)
# Initialize Zeep Client with proxies if defined client = Client(wsdl=WSDL_URL, settings=settings) # client.transport.session.proxies = PROXIES # Uncomment to enable proxies
# Dynamically get the method from the service service_method = getattr(client.service, operation, None)
if not service_method: return f"Error: SOAP Operation '{operation}' not found in WSDL."
# Parse JSON parameters into a dictionary params_dict = json.loads(parameters)
# Execute the call # Zeep handles the XML packaging and SOAP Envelope automatically result = service_method(**params_dict)
# Serialize the Zeep object (which is often lxml based) back to standard JSON return str(result)
except Exception as e: return f"SOAP Fault or Connection Error: {str(e)}"
if __name__ == "__main__": # Binds to 0.0.0.0 to allow access from the Docker host network mcp.run(transport='sse', host='0.0.0.0', port=8000)2. Docker Deployment (Dockerfile)
Section titled “2. Docker Deployment (Dockerfile)”This Dockerfile ensures the Python environment handles the heavy XML processing requirements (lxml) that often break in lightweight containers.
# Use a slim Python base imageFROM python:3.11-slim
# 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/*
# Set working directoryWORKDIR /app
# Install Python dependenciesRUN pip install --no-cache-dir fastmcp zeep lxml
# Copy the server codeCOPY server.py .
# Expose the SSE port for Railway/Docker compatibilityEXPOSE 8000
# Run the serverCMD ["python", "server.py"]3. The Agent Client (agent.py)
Section titled “3. The Agent Client (agent.py)”To verify the MCP server is functioning correctly before connecting your C# Semantic Kernel, we use a Python agent (CrewAI compatible) to test the connection. This demonstrates how the mcps configuration automatically loads the SOAP tools.
import osfrom crewai import Agent, Task, Crew
# 1. Define the Agent with MCP Connectivity# The 'mcps' argument connects to our running Docker containersoap_specialist = Agent( role="Legacy Systems Integrator", goal="Retrieve data from SOAP APIs using the MCP bridge", backstory="You are an expert in legacy protocols. You use the SoapBridge tools to fetch data.", llm="gpt-4-turbo", mcps=["http://localhost:8000/sse"], # Connects to the server.py running in Docker verbose=True)
# 2. Define the Taskintegration_task = Task( description=( "Query the legacy SOAP service using the 'query_soap_service' tool. " "Operation: 'GetInventoryStatus'. " "Parameters: { \"sku\": \"WIDGET-99\" }. " "Return the raw XML response as a simplified string." ), expected_output="Inventory status string from the legacy system.", agent=soap_specialist)
# 3. Run the Crewif __name__ == "__main__": crew = Crew( agents=[soap_specialist], tasks=[integration_task] )
result = crew.kickoff() print("### SOAP Integration Result ###") print(result)4. Semantic Kernel (.NET) Implementation
Section titled “4. Semantic Kernel (.NET) Implementation”Once the agent.py verifies the bridge is working, you can consume the same MCP endpoint in your C# application using the Semantic Kernel MCP connector.
// C# Example: Consuming the Python Bridgeusing Microsoft.SemanticKernel;using Microsoft.SemanticKernel.ChatCompletion;using System;
// Note: Requires experimental MCP support or a custom SSE connector implementation// This pattern matches the architecture verified by the Python agent above.
var builder = Kernel.CreateBuilder();builder.AddOpenAIChatCompletion("gpt-4", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));var kernel = builder.Build();
// Connect to the same Docker container used in agent.py// await kernel.ImportMcpPluginFromSseAsync("SoapBridge", new Uri("http://localhost:8000/sse"));
// The agent can now be invoked to call 'query_soap_service' natively.🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.