Safely expose legacy SOAP/WSDL systems to AI agents as typed, schema-validated, audit-logged MCP servers
3
stars
8
commits
Python
primary language
Sep 8, 2026
updated
Turn a legacy SOAP/WSDL system into a safe, typed MCP server in minutes — so an AI agent can call it without a hand-written adapter.
Point legacy2mcp at a WSDL URL. It introspects every operation, generates a real
JSON Schema for each one from the WSDL's own XSD types, and exposes them as MCP
tools that any MCP client (Claude Desktop, an agent framework, your own code) can
call — with every call schema-validated before it reaches your SOAP endpoint,
write-like operations excluded by default, and every call audit-logged.
No hand-written adapter code. No hand-maintained tool schemas that drift from the WSDL. No arbitrary calls the WSDL itself doesn't define.

Regenerate this clip with vhs demo/demo.tape — see demo/.
Organizations run 10–20 year old SOAP services that aren't going away — systems of record, middleware, back-office and line-of-business platforms. More and more teams now want to point an AI agent at these systems.
Today that means, per WSDL:
DeleteRecord.legacy2mcp generates the adapter from the WSDL itself, so the tool schema
can never drift from what the service actually accepts, and ships a
safe-by-default posture (no writes without an explicit opt-in, no unvalidated
arguments, every call logged) instead of leaving that to whoever wrote the last
adapter.
<adapter_id>_<Operation>.jsonschema.validate
(with additionalProperties: false) before any network call.Create*, Update*, Delete*, Cancel*, Submit*, Pay*, …) are
not exposed unless you set allow_write_operations: true.include_operations / exclude_operations on
top of the heuristic.legacy2mcp inspect lists the generated tools and
exits, so a broken WSDL fails your pipeline instead of your production agent.See docs/security.md for the full, honest security model — what's covered today and what isn't yet.
pip install legacy2mcp # or: uv tool install legacy2mcp / pipx install legacy2mcp
Also on the MCP Registry
as io.github.bvenkata/legacy2mcp, so MCP-aware clients that read the registry
can discover it directly.
git clone https://github.com/bvenkata/legacy2mcp.git
cd legacy2mcp
pip install -e ".[dev]"
# 1. Start the bundled demo SOAP service (no external network needed)
python examples/soap/run_mock_calculator.py &
# 2. See the MCP tools generated from its WSDL
legacy2mcp inspect --config examples/soap/config.calculator.yaml
Or with Docker:
docker compose up demo-soap-service -d
docker compose run --rm legacy2mcp legacy2mcp inspect \
--config examples/soap/config.calculator.docker.yaml
# config.yaml
server:
name: my-legacy-mcp
adapters:
- id: legacy
type: soap
config:
wsdl_url: "https://service.example.com/LegacyService?wsdl"
auth:
type: basic
username: "svc-account"
password_env: "SERVICE_PASSWORD"
# Safe by default: Create*/Update*/Delete*/Cancel*/Submit*/... are
# excluded unless you opt in explicitly.
allow_write_operations: false
# Recommended for production: enumerate exactly what the agent may call.
include_operations: ["GetRecord", "GetRecordDetails", "SearchRecords"]
security:
audit:
enabled: true
path: "./legacy-mcp-audit.log"
export SERVICE_PASSWORD=...
legacy2mcp inspect --config config.yaml # review the generated tools
legacy2mcp run --config config.yaml # start the MCP server (stdio)
A full production-shaped template lives at
examples/soap/config.template.yaml.
{
"mcpServers": {
"legacy": {
"command": "legacy2mcp",
"args": ["run", "--config", "/absolute/path/to/config.yaml"]
}
}
}
legacy2mcp inspect loads the config, contacts the WSDL, builds every tool
schema, and exits non-zero if anything fails. Run it as a pipeline gate:
# .github/workflows/contract-check.yml
- name: Check the WSDL still generates valid MCP tools
env:
SERVICE_PASSWORD: ${{ secrets.SERVICE_PASSWORD }}
run: |
pip install legacy2mcp
legacy2mcp inspect --config config/legacy.yaml > tools.json
# optionally: diff tools.json against a committed snapshot to catch
# a backend team changing an operation's contract out from under you
git diff --exit-code --no-index tools/legacy.snapshot.json tools.json
legacy2mcp run speaks MCP over stdio — the transport Claude Desktop and most
agent frameworks spawn servers over. Package it with your config in the provided
Dockerfile and let your MCP client launch it.
Use the same generated, validated tools from your own Python (via any MCP client library) to pull records from the legacy system on a schedule, with the audit log giving you a record of exactly what was fetched.
zeep, a mature, widely
used Python SOAP client.src/legacy2mcp/schema/xsd_to_jsonschema.py) —
simple types, nested complex types, enums, and arrays, recursively.<adapter_id>_<OperationName>.zeep, serializes the response back to plain
JSON, and writes an audit log entry.allow_write_operations: true — see docs/security.md for
exactly what this heuristic does and doesn't catch.v0.1 — the SOAP/WSDL adapter is implemented and tested (pytest tests/ runs
against an in-process mock SOAP service, no network needed). A database adapter
(safe, parameterized-query-only, table/operation allowlists) and a queue adapter
(Kafka/RabbitMQ/SQS) are on the roadmap but not implemented
yet — the BaseAdapter interface
(src/legacy2mcp/adapters/base.py) is the
extension point if you want to build one.
pip install -e ".[dev]"
pytest tests/ -v
CI runs the suite on Python 3.10–3.12 (.github/workflows/ci.yml).
Releases to PyPI and the MCP Registry are tag-triggered — see
docs/releasing.md.
Adapters for new legacy systems are the highest-value contribution — implement
BaseAdapter (discover_tools() + invoke()) and the MCP server core handles
validation, dispatch, and audit logging for you automatically. Issues and PRs
welcome.
Apache 2.0 — see LICENSE.
8 commits
Python
98.9%
Dockerfile
1.1%
Safely expose legacy SOAP/WSDL systems to AI agents as typed, schema-validated, audit-logged MCP servers
3
stars
8
commits
Python
primary language
Sep 8, 2026
updated
Turn a legacy SOAP/WSDL system into a safe, typed MCP server in minutes — so an AI agent can call it without a hand-written adapter.
Point legacy2mcp at a WSDL URL. It introspects every operation, generates a real
JSON Schema for each one from the WSDL's own XSD types, and exposes them as MCP
tools that any MCP client (Claude Desktop, an agent framework, your own code) can
call — with every call schema-validated before it reaches your SOAP endpoint,
write-like operations excluded by default, and every call audit-logged.
No hand-written adapter code. No hand-maintained tool schemas that drift from the WSDL. No arbitrary calls the WSDL itself doesn't define.

Regenerate this clip with vhs demo/demo.tape — see demo/.
Organizations run 10–20 year old SOAP services that aren't going away — systems of record, middleware, back-office and line-of-business platforms. More and more teams now want to point an AI agent at these systems.
Today that means, per WSDL:
DeleteRecord.legacy2mcp generates the adapter from the WSDL itself, so the tool schema
can never drift from what the service actually accepts, and ships a
safe-by-default posture (no writes without an explicit opt-in, no unvalidated
arguments, every call logged) instead of leaving that to whoever wrote the last
adapter.
<adapter_id>_<Operation>.jsonschema.validate
(with additionalProperties: false) before any network call.Create*, Update*, Delete*, Cancel*, Submit*, Pay*, …) are
not exposed unless you set allow_write_operations: true.include_operations / exclude_operations on
top of the heuristic.legacy2mcp inspect lists the generated tools and
exits, so a broken WSDL fails your pipeline instead of your production agent.See docs/security.md for the full, honest security model — what's covered today and what isn't yet.
pip install legacy2mcp # or: uv tool install legacy2mcp / pipx install legacy2mcp
Also on the MCP Registry
as io.github.bvenkata/legacy2mcp, so MCP-aware clients that read the registry
can discover it directly.
git clone https://github.com/bvenkata/legacy2mcp.git
cd legacy2mcp
pip install -e ".[dev]"
# 1. Start the bundled demo SOAP service (no external network needed)
python examples/soap/run_mock_calculator.py &
# 2. See the MCP tools generated from its WSDL
legacy2mcp inspect --config examples/soap/config.calculator.yaml
Or with Docker:
docker compose up demo-soap-service -d
docker compose run --rm legacy2mcp legacy2mcp inspect \
--config examples/soap/config.calculator.docker.yaml
# config.yaml
server:
name: my-legacy-mcp
adapters:
- id: legacy
type: soap
config:
wsdl_url: "https://service.example.com/LegacyService?wsdl"
auth:
type: basic
username: "svc-account"
password_env: "SERVICE_PASSWORD"
# Safe by default: Create*/Update*/Delete*/Cancel*/Submit*/... are
# excluded unless you opt in explicitly.
allow_write_operations: false
# Recommended for production: enumerate exactly what the agent may call.
include_operations: ["GetRecord", "GetRecordDetails", "SearchRecords"]
security:
audit:
enabled: true
path: "./legacy-mcp-audit.log"
export SERVICE_PASSWORD=...
legacy2mcp inspect --config config.yaml # review the generated tools
legacy2mcp run --config config.yaml # start the MCP server (stdio)
A full production-shaped template lives at
examples/soap/config.template.yaml.
{
"mcpServers": {
"legacy": {
"command": "legacy2mcp",
"args": ["run", "--config", "/absolute/path/to/config.yaml"]
}
}
}
legacy2mcp inspect loads the config, contacts the WSDL, builds every tool
schema, and exits non-zero if anything fails. Run it as a pipeline gate:
# .github/workflows/contract-check.yml
- name: Check the WSDL still generates valid MCP tools
env:
SERVICE_PASSWORD: ${{ secrets.SERVICE_PASSWORD }}
run: |
pip install legacy2mcp
legacy2mcp inspect --config config/legacy.yaml > tools.json
# optionally: diff tools.json against a committed snapshot to catch
# a backend team changing an operation's contract out from under you
git diff --exit-code --no-index tools/legacy.snapshot.json tools.json
legacy2mcp run speaks MCP over stdio — the transport Claude Desktop and most
agent frameworks spawn servers over. Package it with your config in the provided
Dockerfile and let your MCP client launch it.
Use the same generated, validated tools from your own Python (via any MCP client library) to pull records from the legacy system on a schedule, with the audit log giving you a record of exactly what was fetched.
zeep, a mature, widely
used Python SOAP client.src/legacy2mcp/schema/xsd_to_jsonschema.py) —
simple types, nested complex types, enums, and arrays, recursively.<adapter_id>_<OperationName>.zeep, serializes the response back to plain
JSON, and writes an audit log entry.allow_write_operations: true — see docs/security.md for
exactly what this heuristic does and doesn't catch.v0.1 — the SOAP/WSDL adapter is implemented and tested (pytest tests/ runs
against an in-process mock SOAP service, no network needed). A database adapter
(safe, parameterized-query-only, table/operation allowlists) and a queue adapter
(Kafka/RabbitMQ/SQS) are on the roadmap but not implemented
yet — the BaseAdapter interface
(src/legacy2mcp/adapters/base.py) is the
extension point if you want to build one.
pip install -e ".[dev]"
pytest tests/ -v
CI runs the suite on Python 3.10–3.12 (.github/workflows/ci.yml).
Releases to PyPI and the MCP Registry are tag-triggered — see
docs/releasing.md.
Adapters for new legacy systems are the highest-value contribution — implement
BaseAdapter (discover_tools() + invoke()) and the MCP server core handles
validation, dispatch, and audit logging for you automatically. Issues and PRs
welcome.
Apache 2.0 — see LICENSE.
8 commits
Python
98.9%
Dockerfile
1.1%