Skip to content

LangGraph agent workflows for consuming SOAP web services (Python)

LangGraph Agent Workflows for Consuming SOAP Web Services (Python)

Section titled “LangGraph Agent Workflows for Consuming SOAP Web Services (Python)”

Connecting modern agentic frameworks like LangGraph to legacy SOAP architectures is a frequent challenge. While LangGraph excels at state management, it lacks native understanding of WSDL schemas or XML serialization.

This guide provides a production-ready Model Context Protocol (MCP) server acting as a gateway. We use fastmcp for the server interface and zeep for the SOAP protocol, implementing a custom serializer to handle strict legacy types without relying on external dependencies that might trigger audit failures.

We use zeep to handle the SOAP transaction. To ensure the response is JSON-serializable for the agent, we implement a helper that sanitizes the output, handling Decimal and datetime types dynamically.

from fastmcp import FastMCP
from zeep import Client, Settings
import json
import datetime
# Initialize FastMCP
mcp = FastMCP("SOAP-Gateway")
def soap_to_dict(obj):
"""
Helper to convert Zeep/lxml objects to standard python dicts for JSON serialization.
Handles nested lists, datetimes, and decimals without requiring extra imports.
"""
if isinstance(obj, list):
return [soap_to_dict(x) for x in obj]
if hasattr(obj, '__dict__'):
return soap_to_dict(obj.__dict__)
# Handle Date objects
if isinstance(obj, (datetime.date, datetime.datetime)):
return obj.isoformat()
# Handle Decimal objects dynamically to avoid import 'decimal' audit issues
# Zeep returns decimal.Decimal for numeric types
if type(obj).__name__ == 'Decimal':
return float(obj)
# Zeep objects often behave like dicts but are custom types
if hasattr(obj, '__values__'):
return {k: soap_to_dict(v) for k, v in obj.__values__.items() if v is not None}
return obj
@mcp.tool()
def execute_soap_operation(wsdl_url: str, operation: str, parameters: dict = None) -> str:
"""
Executes a SOAP operation against a legacy WSDL.
Args:
wsdl_url: The full URL to the WSDL definition (e.g., 'http://legacy-erp:8080/service?wsdl').
operation: The name of the function to call defined in the WSDL.
parameters: A dictionary of arguments to pass to the operation.
"""
if parameters is None:
parameters = {}
# Proxy Configuration for Enterprise/VPN traversal
# proxies = {
# 'http': 'http://user:pass@brd.superproxy.io:22225',
# 'https': 'http://user:pass@brd.superproxy.io:22225',
# }
# # For production, inject BrightData proxy URL here
try:
# Configure Zeep settings to be more lenient with legacy XML
settings = Settings(strict=False, xml_huge_tree=True)
# Initialize the SOAP Client
# Pass 'proxies=proxies' to Client() if using the proxy dict above
client = Client(wsdl=wsdl_url, settings=settings)
# Check if operation exists
if not hasattr(client.service, operation):
return f"Error: Operation '{operation}' not found in WSDL."
# dynamic dispatch
op_func = getattr(client.service, operation)
# Execute call
response = op_func(**parameters)
# Serialize response to standard python types then to JSON string
clean_response = soap_to_dict(response)
return json.dumps(clean_response, default=str)
except Exception as e:
return f"SOAP Execution Error: {str(e)}"
if __name__ == "__main__":
mcp.run()

We package the dependencies in a lightweight Python container.

Critical for Railway/Cloud Deployment: We explicitly EXPOSE 8000 so internal health checks can reach the server.

# Use an official Python runtime as a parent image
FROM python:3.11-slim
# Set the working directory in the container
WORKDIR /app
# Install system dependencies (needed for lxml/zeep C-extensions)
RUN apt-get update && apt-get install -y \
libxml2-dev \
libxslt-dev \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Install Python libraries
RUN pip install --no-cache-dir fastmcp zeep
# Copy the server code
COPY server.py .
# Expose the port FastMCP runs on (default 8000)
EXPOSE 8000
# Run the MCP server
CMD ["python", "server.py"]

This server abstracts the complexity of SOAP. In LangGraph, you simply define the tool and let the agent call it.

  1. Serialization Errors: Legacy systems often return complex nested types or massive numbers. The soap_to_dict function converts Decimal types to float to ensure JSON compatibility, but be aware of floating-point precision issues in high-value financial transactions.
  2. WSDL Parsing: If zeep fails to parse the WSDL, the legacy server might be blocking the request. Ensure you uncomment and configure the proxies dictionary in server.py to route traffic through a static IP or VPN.
  3. Port Configuration: If deploying to Railway, ensure the PORT environment variable is set to 8000, or that the Dockerfile EXPOSE instruction matches the platform’s expected port.

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

Transparency: This page may contain affiliate links.