Skip to content

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)”

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.


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 FastMCP
from zeep import Client, Settings
import json
# Initialize the MCP Server
mcp = FastMCP("SoapBridge")
# Configuration for the Legacy SOAP Service
WSDL_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 here
PROXIES = {
# '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)

This Dockerfile ensures the Python environment handles the heavy XML processing requirements (lxml) that often break in lightweight containers.

# Use a slim Python base image
FROM 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 directory
WORKDIR /app
# Install Python dependencies
RUN pip install --no-cache-dir fastmcp zeep lxml
# Copy the server code
COPY server.py .
# Expose the SSE port for Railway/Docker compatibility
EXPOSE 8000
# Run the server
CMD ["python", "server.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 os
from crewai import Agent, Task, Crew
# 1. Define the Agent with MCP Connectivity
# The 'mcps' argument connects to our running Docker container
soap_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 Task
integration_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 Crew
if __name__ == "__main__":
crew = Crew(
agents=[soap_specialist],
tasks=[integration_task]
)
result = crew.kickoff()
print("### SOAP Integration Result ###")
print(result)

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 Bridge
using 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.

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

Transparency: This page may contain affiliate links.