关于 legacy2mcp
legacy2mcp 可根据 SOAP/WSDL、数据库结构及 REST API 描述或发现结果生成带类型的 MCP 服务。它按生成的 JSON Schema 校验工具参数,默认隐藏写操作,并记录每次调用以供审计。
主要功能
- 01从旧系统接口生成带类型的工具
- 02检查 WSDL、数据库和 REST 定义
- 03依据 JSON Schema 校验参数
- 04默认隐藏写操作
- 05记录每次工具调用
- 06通过 init 生成起始配置
适用场景
- 01向 MCP 客户端开放 SOAP 服务
- 02向 Agent 提供允许列表中的数据库操作
- 03让 MCP 客户端连接 REST API
- 04启动服务前检查发现的工具
MCP 相关
可从 SOAP 操作、允许列表中的数据库表和查询,或已配置的 REST 端点生成 MCP 工具。服务通过 stdio 运行,并在请求到达后端前校验调用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
legacy2mcp
快速开始
无需 API 密钥,也无需克隆仓库——选择适合你现有环境的方式, 连接到实时公开演示目标:
pip install legacy2mcp
# REST API -- tries OpenAPI/Swagger discovery
legacy2mcp init --rest-url "https://petstore3.swagger.io/api/v3"
# WSDL / SOAP service -- zeep introspects it live, no scan needed
legacy2mcp init --wsdl-url "http://www.dneonline.com/calculator.asmx?WSDL"
# A website with no API docs at all -- crawls it for forms/content
legacy2mcp init --webpage-url "https://legacy2mcp.com/"
在真实终端中运行其中任意一条命令,整个流程就完成了:它会写入 config.yaml,打开本地测试聊天页面,并在每个发现的工具下方显示一个可点击的示例问题——点击后即可看到实时数据源返回的真实响应,无需 AI 密钥,只通过本地关键词匹配来检查服务是否正常工作——同时还会输出一段可直接粘贴到 Claude Desktop、Cursor、VS Code 和 Claude Code 中的连接配置。将它接入真实 AI 客户端只需复制粘贴,无需单独执行其他步骤。
(更喜欢原始工具列表?运行 legacy2mcp inspect --config config.yaml。)
legacy2mcp discover
适用于需要先经过审核的来源(Postman 集合、HAR 捕获文件等),执行相同的流程:编写契约、打开同一个测试聊天页面、输出同一段连接配置——两种方式都只需一条命令。
你有自己的 WSDL、REST API、网站或代码库吗?legacy2mcp init(不带标志)会引导你完成配置——请参阅
自动生成配置。更多演示(本地 SOAP 服务、Docker、通过原始 URL 提供的 WSDL)列在
examples/ 中。
说明
legacy2mcp会实时检查你的旧系统——所有 WSDL 操作、所有数据库表,以及它能找到的所有 REST 规范——并据此为每个工具构建真实的 JSON Schema。每次 MCP 工具调用在到达后端前都会经过架构验证,默认排除写入操作,并且每次调用都会记录审计日志。无需手写适配器代码,无需手动维护架构,也不会让大模型执行任意 SQL。
目录
- 安装
- 快速开始
- 工作原理
- 为什么不直接手写适配器?
- 连接到你自己的 WSDL
- 连接到你自己的数据库
- 连接到你自己的 REST API
- 自动生成配置
- 生成服务前发现旧版接口
- 让你的 AI 编码 Agent 了解 legacy2mcp
- 常用命令
- 客户端支持
- 支持的功能
- 安全模型
- 数据流与隐私
- 使用场景
- 实际使用
- 配置参考
- 文档
- 路线图
- 开发 · 贡献 · 许可证
安装
# Full install (recommended)
pip install "legacy2mcp[ai]"
# Or the identical, scan-only-ready core -- AI-assisted `legacy2mcp init`
# needs no extra package either way, just an API key at runtime; `[ai]`
# above installs nothing extra today, it's just a stable, familiar name
pip install legacy2mcp
# or: uv tool install legacy2mcp · pipx install legacy2mcp
该项目也已发布到 MCP Registry,名称为 io.github.bvenkata/legacy2mcp,因此支持注册表的 MCP 客户端可以直接发现它。
工作原理
flowchart LR
WSDL["WSDL / XSD"] --> GEN["legacy2mcp<br/>schema generation"]
DB["DB schema<br/>(allowlisted tables)"] --> GEN
GEN --> TOOLS["Typed MCP tools<br/>one per operation / table / query"]
AGENT["AI agent /<br/>MCP client"] -->|tool call| VAL{"schema<br/>validation"}
TOOLS -. defines .-> VAL
VAL -->|invalid args| REJ["rejected, never<br/>reaches SOAP/DB"]
VAL -->|valid and allowed| BACKEND["SOAP endpoint<br/>or database"]
BACKEND --> RESP["plain JSON<br/>back to the agent"]
VAL --> LOG[("audit log")]
SOAP:
- 使用成熟且广泛采用的 Python SOAP 客户端
zeep加载 WSDL。 - 针对每个端口/绑定上的每个操作,将 XSD 输入类型转换为 JSON Schema(
schema/xsd_to_jsonschema.py)——递归处理简单类型、嵌套复杂类型、枚举和数组,并限制深度以应对异常复杂的 WSDL。 - 为每个操作注册一个 MCP 工具,命名为
<adapter_id>_<OperationName>。 - 调用工具时:使用
jsonschema验证参数(架构使用additionalProperties: false),通过zeep调用操作,将响应序列化为纯 JSON,并写入一条审计记录。
DB:
- 使用对应方言的驱动连接(
psycopg/pyodbc/oracledb,按需导入),并内省每个允许列表中表的实时列类型(adapters/db_dialects.py),将其转换为 JSON Schema(schema/sql_to_jsonschema.py)。 - 为每个允许列表中的表和操作注册
select_<table>/insert_<table>,并为配置中的每个命名查询注册query_<name>。 - 调用工具时:验证参数,根据允许列表中的表/列构建 SQL(或运行配置提供的命名查询),使用统一且不依赖方言的
:param占位符约定,执行查询,并写入一条审计记录。大模型看不到也不会编写 SQL 文本。 - 除非设置
allow_write_operations: true,否则会排除名称看起来像写入操作的操作。
REST:
- 普通 REST API 没有可供内省的实时架构,不像 WSDL 或 DB 目录那样;因此,端点列表(方法、路径、类型化参数)来自配置,可以手动编写,也可以由
legacy2mcp init的 OpenAPI/Swagger 发现功能或源代码扫描生成。 - 为每个允许列表中的端点注册一个 MCP 工具,命名为
<adapter_id>_<name>。 - 调用工具时:验证参数,根据每个参数声明的
location将其拆分为路径/查询/正文参数,将{param}占位符替换到 URL 中,并使用requests发起调用——身份验证根据适配器的auth配置应用(basic/bearer/none)。 - 除非设置
allow_write_operations: true,否则会排除标记为write: true的端点(默认是非GET端点)。
为什么不手动编写适配器?
因为手动编写的适配器会成为系统架构的第二份副本,而没人会记得更新它。WSDL 操作签名或列第一次发生变化时,工具的 JSON Schema 就会悄然偏离实际情况——而调用它的大模型只能通过传入错误参数才会发现问题,但这种错误可能无法被捕获,也可能导致 SOAP/DB 客户端深处抛出令人困惑的运行时错误。legacy2mcp 每次启动时都会根据实时系统构建架构,因此,架构偏离后,调用会在验证阶段失败,不会等到请求抵达后端才失败。
| 手动编写的适配器(FastMCP/原始 SDK) | 通用 OpenAPI-to-MCP 代理 | legacy2mcp | |
|---|---|---|---|
| 架构来源 | 手动为每个工具编写 | OpenAPI 规范(如果存在) | 实时 WSDL/DB 架构,或发现的 OpenAPI 规范 |
| 是否可能偏离实际系统 | 是——没有任何机制重新检查 | 仅当规范本身过时时 | 否——启动时会根据实时来源重新构建 |
| 是否支持 SOAP/数据库 | 需要自行编写客户端代码 | 否——仅支持 REST/OpenAPI | 是,还支持 REST 和普通网站 |
| 默认隐藏写入操作 | 否——需要记得逐个设置门控 | 否——通常会公开规范定义的所有内容 | 是——需显式启用 allow_write_operations |
| 记录每次调用的审计日志 | 需要自行实现 | 通常没有 | 内置 |
| 搭建可用服务所需时间 | 每个系统需数小时到数天 | 对于带规范的 REST API,只需几分钟 | 几分钟——legacy2mcp init |
将其指向你自己的 WSDL
# 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" # value read from the environment, never the file
allow_write_operations: false # Create*/Update*/Delete*/… stay hidden
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)
包含注释的生产级模板位于 examples/soap/config.template.yaml。
连接到你自己的数据库
pip install "legacy2mcp[db-postgres]" # or db-mssql / db-oracle
# config.yaml
adapters:
- id: orders
type: db
config:
dialect: postgres # postgres | mssql | oracle
dsn_env: "ORDERS_DB_DSN" # connection string, read from the environment
allow_write_operations: false # insert_<table> / write: true queries stay hidden
tables:
- name: orders
operations: [select]
columns: [id, status, total, created_at] # column allowlist
filterable_columns: [status] # equality filters on select_orders
max_rows: 200
queries:
- name: orders_by_status_since
sql: "SELECT id, status, total FROM orders WHERE status = :status AND created_at >= :since"
params:
- { name: status, type: string, required: true }
- { name: since, type: string, required: true }
export ORDERS_DB_DSN=...
legacy2mcp inspect --config config.yaml # review the generated tools
启动时会从实时架构中内省列,方式与从 WSDL 中获取 SOAP 操作架构相同——无需手动维护。LLM 绝无途径执行任意 SQL:它只能调用 tables: 下列出的表对应的 select_<table> / insert_<table>,或调用 queries: 下由你编写 SQL 的 query_<name> 工具——LLM 只能提供查询的 params 声明的占位符值,不能提供 SQL 文本。生产环境风格的模板位于
examples/db/config.template.yaml。
连接到你自己的 REST API
普通的 REST/JSON API 没有 WSDL 或实时数据库架构可供内省,因此 rest 适配器的端点列表需要在配置中显式指定——手动编写,或使用 legacy2mcp init 生成初始配置(见下一节)。
# config.yaml
adapters:
- id: orders
type: rest
config:
base_url: "https://api.example.com"
auth:
type: bearer
token_env: "ORDERS_API_TOKEN"
allow_write_operations: false
endpoints:
- name: get_order
method: GET
path: "/orders/{order_id}"
params:
- { name: order_id, location: path, type: integer, required: true }
- name: create_order
method: POST
path: "/orders"
write: true # stays hidden unless allow_write_operations: true
params:
- { name: total, location: body, type: number, required: true }
生产环境风格的模板位于
examples/rest/config.template.yaml。
说明
非
GET方法和 LLM 辅助分类都只是启发式判断,不能保证端点在无人监督的情况下调用是安全的——在连接真实后端运行之前,请检查write:标志和allow_write_operations。SOAP 适配器下文所述的写入动词启发式判断也有同样的注意事项。
自动生成配置
legacy2mcp init 会询问你要将它指向哪里,然后为你编写一份起始
config.yaml:
legacy2mcp init
What do you want to point legacy2mcp at?
1) WSDL URL (SOAP service)
2) REST API URL (tries OpenAPI/Swagger discovery)
3) A website with no API docs at all (crawls it for forms/content)
4) GitHub repo URL or a local path to its source code
Choice [1-4]:
| 选项 | 执行内容 | 需要 LLM 密钥吗? |
|---|---|---|
| WSDL URL | 直接将 soap 适配器指向该 URL——zeep 无论如何都会在 inspect/run 时检查实时 WSDL,因此无需预先扫描。 | 否 |
| REST API URL | 尝试该 URL 下常见的 OpenAPI/Swagger 规范位置(/openapi.json、/swagger.json 等),如果找到规范,就根据真实规范构建 rest 适配器的端点列表;否则生成一个空框架。 | 否 |
| 网站 | 从该网站开始抓取同站页面(由 --max-pages/--max-depth 限制,默认值为 25/2),方式与 legacy2mcp discover --webpage-url 相同,然后直接生成配置,而不是停在 contract.yaml;生成的 TODO 中,每项操作仍会标记为 confidence: low / needs_review: true。使用 init 只是跳过一个文件,并不代表跳过审查。 | 否 |
| GitHub 仓库 / 本地路径 | 克隆(或读取)仓库,并对其 Python 源代码进行静态扫描(仅分析 AST,从不执行代码),查找 zeep.Client(...) 调用、SQLAlchemy/Flask-SQLAlchemy 模型或 Flask/FastAPI 路由,并据此选择 soap/db/rest。 | 可选 |
每种方式也都可以通过标志以非交互方式使用——--wsdl-url、--rest-url、
--webpage-url、--github-url 或 --local-path——适用于脚本或 CI。
只有 GitHub/源代码路径可以使用 LLM,而且仅用于完善静态分析已发现的内容(例如含糊不清的参数类型、读写分类)——绝不会转储你的仓库。它无需额外依赖,只需通过 --llm-api-key-env 提供一个兼容 OpenAI 的 API 密钥;如果省略该参数,则会以交互方式提示输入(不会写入磁盘)。传入 --scan-only 可直接跳过这一步,仅运行静态分析,效果与不输入密钥相同。
legacy2mcp init --github-url https://github.com/you/your-api --scan-only --out config.yaml
无论选择哪种方式,运行前都要检查生成的文件——无法有把握地推断的内容会用 # TODO 注释标出(例如未解析的 base_url、未经验证的参数类型、哪些端点被分类为 write: true);在你进行验证前,其中的任何内容都尚未根据真实后端验证:
legacy2mcp inspect --config config.yaml # review the generated tools
legacy2mcp run --config config.yaml # start the MCP server
legacy2mcp init 还会在配置文件旁生成一份通俗易懂的 HTML 报告(例如,config.yaml -> config.html)。在浏览器中打开它,即可用文字而非 YAML 查看服务将公开哪些工具(发现的每个 REST 端点 / DB 表 / SOAP 目标、哪些工具可以更改数据并受 allow_write_operations 限制,以及上述审查事项)。传入 --html-out 可更改报告保存位置,传入 --no-html-report 可跳过生成。
在真实终端中,针对已经可用的配置运行 init
(实时 --wsdl-url/--rest-url,或扫描发现了具体内容),
它还会在浏览器中打开一个本地测试聊天页面,每个发现的工具下方都有一个可点击的示例问题(根据该工具自身的名称和架构生成,例如 getPetById -> “按 ID 获取宠物 4”),这样你就不必猜该输入什么。点击示例,或输入自己的问题,页面会将其匹配到已发现的工具,调用真实适配器,并显示真实响应。此功能无需 AI/API 密钥——它通过工具名称/描述进行本地关键词匹配,不使用 LLM,只是足以在接入真正的 MCP 客户端前检查服务是否确实可用。当配置中仍有待填写的 TODO(尚无可连接的内容)时,会自动跳过;在非交互式/脚本运行中则完全不会打开。传入 --no-chat 可选择退出此功能。
在将其指向任何真实目标之前,请参阅 docs/security.md,了解这种启发式方法具体能保证什么、不能保证什么。
生成服务前先发现旧版接口
init 支持在线 WSDL、在线 REST URL、网站(--webpage-url)以及可供扫描的代码仓库——这些来源都会直接生成配置,无需单独步骤。其他来源则需要先执行明确的步骤,例如已有的 Postman 集合、代码仓库中尚未启动服务器的 OpenAPI 规范文件、数据库的存储过程目录、真实流量的 HAR 捕获文件,或你已知的队列:
legacy2mcp discover --postman-file my-collection.json --out contract.yaml
legacy2mcp discover --openapi-file spec.yaml --out contract.yaml
legacy2mcp discover --har-file traffic.har --out contract.yaml
legacy2mcp discover --stored-procs --db-dialect postgres --db-dsn-env LEGACY_DB_DSN --out contract.yaml
legacy2mcp discover --queue-config queues.yaml --out contract.yaml
如果想在生成任何内容之前先检查契约,网站也可以通过 discover --webpage-url 处理(见下文);init --webpage-url 会执行相同的爬取,只是不会在此处暂停。
每个命令都会生成一份 Legacy Interface Contract(contract.yaml):其中包含每个操作的输入、输出、枚举、错误代码、读写属性,以及置信度——在线架构或目录为 high,Postman 集合等经过整理的工件为 medium,根据采样流量推断的内容为 low——还会标注 needs_review 标记,并对不确定的内容附上说明。请像检查 config.yaml 中的 # TODO 一样检查它。
不过,如果在真实终端中运行同一条命令,discover 不会止步于生成契约:只要契约中包含可调用的内容(目前并非每种来源都支持,见下文),它还会生成可运行的 config.yaml,打开与 init 可自动启动的相同免 API 密钥测试聊天页面,并打印可直接粘贴的 MCP 客户端 JSON——只需运行一条命令,就能完成发现、试用并获取连接代码片段。传入 --no-chat 可跳过这些操作,只生成契约(非交互式运行或 CI 运行时默认如此);传入 --no-write-config 则只跳过写入 config.yaml。
想先检查契约,再生成或运行任何内容?可以自行直接跳到以下任一阶段:
legacy2mcp init --from-contract contract.yaml --out config.yaml
legacy2mcp demo --from-contract contract.yaml
demo 与 discover 可自动启动的“试用”步骤相同,只是可以单独调用(也支持使用现有的 --config config.yaml,不局限于契约)。它会生成一个独立的 chat.html,指向刚启动的服务(除非传入 --no-open,否则会自动打开),并在配置就绪后打印客户端 JSON,以便指向该配置。要让页面正常工作,命令必须持续运行(按 Ctrl+C 停止);这是一个没有自带后端的轻量客户端页面,因此真实的 HTTP 调用仍须由某个程序发起。这与浏览器无法直接打开配置文件并调用 REST API 的原因相同。
以下几点值得了解:
- 绝不会将原始密钥写入契约。 Postman 集合中保存的 bearer 令牌、HAR 捕获中的
Authorization/Cookie标头值——这些内容都不会被持久化;只会记录存在身份验证的说明,供你自行配置。唯一受控的例外是少量看起来不敏感的枚举(例如,status字段在足够多的样本中只出现过少数几个值,因此有参考意义)——详见 docs/security.md。 - 对于
--har-file,legacy2mcp 不会自行驱动捕获代理——你可以指定由任何工具生成的 HAR:浏览器开发者工具中的“Export HAR”、Postman 自带的流量捕获功能,或 mitmproxy 内置的导出器(mitmdump --set hardump=out.har,或在 GUI 中选择“Export as HAR”)。这是置信度最低的来源(从采样到的内容推断,而非来自明确定义的契约)——每项操作都会被标记为需要审核。 --webpage-url适用于完全没有 API 文档的旧版 Web 应用或内容网站——你只需提供 URL。它会从该地址开始抓取同一网站的页面(范围受--max-pages/--max-depth限制,默认 25 个页面/深度 2,且绝不会离开起始主机),将每个<form>转换为一项操作(<select>的选项或同名单选/复选框组会成为enum),并将每个包含实际内容且没有表单的页面转换为只读的“获取此页面”工具。不会执行任何 JavaScript,也不会提交任何内容;对于非 GET 表单,会添加说明,提示确认后端是否接受 JSON 请求体(REST 适配器始终会发送 JSON 请求体,即使真实浏览器会以application/x-www-form-urlencoded发送 POST 请求)。其置信度与--har-file一样低——但与其他所有discover来源不同,base_url会自动填充(即刚刚抓取的主机),因此测试聊天页面可以立即打开。完整的抓取机制请参阅:docs/security.md。- 存储过程和队列描述目前只会记录在文档中,尚不可运行。
--stored-procs和--queue-config仍会生成真实的契约条目——目前还没有适配器可以实际调用它们(参见 docs/roadmap.md),因此init --from-contract会跳过这些条目并明确标注 TODO,而不会假装它们可以运行。出于相同原因,如果契约仅由这些条目组成,discover的自动演示(见上文)也没有可启动的内容;它会说明原因,然后直接退出,并保留已写入的契约,而不会让整个命令失败。 - 每个生成的服务还会免费提供一个
describe_capabilities工具——已连接的 Agent 可以调用它,询问“这个系统能做什么?”(获取每个工具的描述、副作用、置信度、必填字段和已知错误代码),然后再实际调用任何工具。 --out contract.html会生成易于阅读的报告,而不是普通 YAML——在浏览器中以表格展示相同的操作。它仍然是有效的--from-contract/demo --from-contract输入:完整契约会嵌入页面中的<script type="application/json">标签,而不只是生成供阅读的摘要。
让你的 AI 编码 Agent 了解 legacy2mcp
上面的章节介绍的是 legacy2mcp 生成的 MCP 服务。本节有所不同:它面向这样的场景——AI 编码 Agent(Claude Code、Cursor、Codex CLI、Gemini CLI、GitHub Copilot 等)正在帮助你构建集成,而你希望它一开始就知道该怎么做。
legacy2mcp install-skill
这会将简短、以命令为先的 legacy2mcp 指引直接写入当前仓库自己的 Agent 上下文文件——Claude Code 斜杠命令(.claude/commands/legacy2mcp.md)、Cursor 规则(.cursor/rules/legacy2mcp.mdc),以及追加(或原地更新)在 AGENTS.md、GEMINI.md 和 .github/copilot-instructions.md 中的 ## legacy2mcp 章节。这样,Agent 就会掌握核心工作流——哪种 init 标志适用于哪种来源、在信任生成的配置前检查 # TODO、在实际运行任何内容前先检查 inspect——你无需在每次会话中重新解释。这项操作具有幂等性:再次运行时会替换自身章节,而不是重复添加,因此升级后可以放心再次运行。检查它写入的内容并提交,这样整个团队就能获得相同的指引(本仓库正是这么做的——参见 AGENTS.md)。
本仓库中还有一份独立的 SKILL.md,遵循开放的 Agent Skills 标准编写——它以相同的形式提供这些知识,方便 Agensi 等市场独立于任何特定仓库列出此技能,供以这种方式发现技能的 Agent 使用。
常用命令
# Print the installed legacy2mcp version
legacy2mcp --version
# Generate a config from a live REST API (tries OpenAPI/Swagger discovery)
legacy2mcp init --rest-url "https://api.example.com" --out config.yaml
# Generate a config from a WSDL URL directly -- no scan needed
legacy2mcp init --wsdl-url "https://service.example.com/Legacy?wsdl" --out config.yaml
# Generate a config from a website with no API docs at all -- crawls it
legacy2mcp init --webpage-url "https://your-legacy-app.example.com" --out config.yaml
# Generate a config by statically scanning a GitHub repo (no AI, no API key)
legacy2mcp init --github-url https://github.com/you/your-api --scan-only --out config.yaml
# Same, with AI-assisted refinement of ambiguous parameter types / read-vs-write
legacy2mcp init --github-url https://github.com/you/your-api --llm-api-key-env OPENAI_API_KEY --out config.yaml
# Review a source before generating anything -- a Postman collection, OpenAPI
# file, HAR capture, stored-procedure catalog, or queue description
legacy2mcp discover --postman-file my-collection.json --out contract.yaml
# Try a config or contract in a chat page right now, no separate init step
legacy2mcp demo --from-contract contract.yaml
legacy2mcp demo --config config.yaml
# Review the tools a config generates -- no server started
legacy2mcp inspect --config config.yaml
# Print the tool list as JSON, for scripting or a CI diff check
legacy2mcp inspect --config config.yaml > tools.json
# Show only one exact tool name
legacy2mcp inspect --config config.yaml --tool legacy_get_order
# Start the MCP server (stdio)
legacy2mcp run --config config.yaml
# Teach the AI coding agent working in *this* repo how to drive legacy2mcp
# (see "Teach your AI coding agent about legacy2mcp" above)
legacy2mcp install-skill
客户端支持
这里的“已验证”有一个具体且有限的含义:下文展示的确切命令和配置格式已实际启动,并通过 stdio 完成了真实的 MCP initialize 握手——而不只是“理论上应该兼容 MCP”。对于 MCP Inspector,测试还进一步执行了真实的 tools/list、真实的 tools/call,并检查了由此生成的审计日志条目;整个过程均通过 Inspector 自带的 --cli 模式无界面运行。最后一个徽章确保这一声明能持续经受检验,而非仅仅反映某个时间点的快照:CI 任务(mcp-compatibility.yml)会在每次推送时重新运行相同的 tools/list / tools/call / 审计日志流程;如果服务无法启动或暴露了错误的工具,构建就会失败。下方所有客户端都仅通过 stdio 与 legacy2mcp 通信——目前还没有 HTTP/SSE 传输(这项功能在路线图中,尚未发布),因此 http://localhost:... 形式的 MCP URL 在这里无法使用。
| 客户端 | 状态 | 验证方式 |
|---|---|---|
| Claude Desktop | 已验证 | 启动 claude_desktop_config.json 中的确切命令,完成真实的 initialize 握手,并确认已列出工具 |
| Cursor | 已验证 | 同上,通过 .cursor/mcp.json 中的确切命令验证 |
| VS Code | 已验证 | 同上,通过 .vscode/mcp.json 中的确切命令验证 |
| Claude Code | 已说明 | 通过 claude mcp add 使用与上述已验证内容相同的启动命令;但该命令本身并未在此环境中单独重新运行 |
| MCP Inspector | 已测试 | 完整的 CLI 流程——tools/list、tools/call,以及由此生成的审计日志条目 |
| 此仓库还附带已纳入版本控制的配置文件—— | ||
.mcp.json、.cursor/mcp.json 和 | ||
.vscode/mcp.json——它们指向打包的 Petstore | ||
演示,因此在这些工具中打开此仓库,无需设置即可获得可运行的服务。将与你的工具对应的配置文件复制到自己的项目中,并将 --config 指向你自己的 config.yaml。 |
Claude Desktop — claude_desktop_config.json
macOS:~/Library/Application Support/Claude/claude_desktop_config.json
Windows:%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"legacy2mcp": {
"command": "uvx",
"args": ["legacy2mcp", "run", "--config", "/absolute/path/to/config.yaml"]
}
}
}
如果你使用 pip/pipx 而非 uv 安装,请使用 "command": "legacy2mcp",并删除 args 的第一个元素。
Cursor — .cursor/mcp.json
项目本地配置(.cursor/mcp.json)或全局配置(~/.cursor/mcp.json):
{
"mcpServers": {
"legacy2mcp": {
"command": "uvx",
"args": ["legacy2mcp", "run", "--config", "/absolute/path/to/config.yaml"]
}
}
}
VS Code — .vscode/mcp.json
{
"servers": {
"legacy2mcp": {
"type": "stdio",
"command": "uvx",
"args": ["legacy2mcp", "run", "--config", "/absolute/path/to/config.yaml"]
}
}
}
Claude Code — CLI
claude mcp add legacy2mcp -- uvx legacy2mcp run --config /absolute/path/to/config.yaml
添加 --scope project,即可为团队写入共享的 .mcp.json(请勿在其中存放密钥);使用 claude mcp list 检查。
MCP Inspector — 验证工具,而非 AI 客户端
npx @modelcontextprotocol/inspector uvx legacy2mcp run --config /absolute/path/to/config.yaml
打开本地 Web 界面:连接到服务,确认工具已列出,运行一个只读工具,并检查 legacy2mcp-audit.log 中对应的条目。上方“Tested with MCP Inspector”徽章所依据的,正是这一完整流程——发现工具、实际调用一次,以及查看生成的审计日志;该流程通过 Inspector 自带的 --cli 模式在无界面环境中运行,而非仅在浏览器中打开。
传递密钥和故障排查:docs/clients.md。
已处理的内容
| 领域 | 覆盖内容 |
|---|---|
| 类型映射 | string / int / long / decimal / boolean / date / dateTime / base64Binary / … → JSON Schema 类型 + 格式 |
| 结构 | 嵌套复杂类型、重复元素 → 数组,xsd:enumeration → enum,递归深度受限 |
| 发现 | 每个服务 → 端口 → 绑定 → 操作;启动时拒绝重复的工具名称 |
| 调用 | 参数验证、zeep 调用、将响应序列化为纯 JSON、将单字段响应重新包装为具名结果 |
| 错误 | 捕获 SOAP 错误和传输错误,并以清晰的消息返回——不会向调用方返回堆栈跟踪 |
| 身份验证 | HTTP 基本身份验证(用户名 + *_env 密码);承载令牌(*_env);匿名 |
| 传输 | stdio(Claude Desktop 和大多数 Agent 框架会启动的传输方式) |
| 数据库方言 | Postgres、SQL Server、Oracle——表允许列表(select/insert),支持实时架构内省,以及具名参数化查询 |
| REST | 从配置或 legacy2mcp init 设置显式端点允许列表(方法 + 路径 + 类型化参数)——没有可供内省的实时架构,因此运行前无法验证此处的任何内容 |
| 发现数据源 | Postman 集合、本地 OpenAPI/Swagger 文件、实时数据库的存储过程目录、HAR 流量捕获、声明式队列描述,以及网站(--webpage-url,可抓取表单/内容)→ 可供审核的 contract.yaml(置信度、枚举、错误代码)→ legacy2mcp init --from-contract 或直接使用 init --webpage-url/demo |
describe_capabilities | 每个生成的服务都免费提供此元工具——Agent 可在调用任何内容之前询问服务能做什么 |
| 试用 + 连接 | init/discover/demo 都会自动打开一个无需 API 密钥的测试聊天页面,并打印可直接粘贴的连接代码片段,适用于 Claude Desktop、Cursor、VS Code 和 Claude Code |
完整且如实的安全模型(包括目前已覆盖和尚未覆盖的内容),请参阅 docs/security.md。
安全模型
| 层 | 作用 |
|---|---|
| 架构验证 | 所有参数都会先根据该工具生成的架构通过 jsonschema.validate 验证,之后才会到达 SOAP/DB 层。 |
| 默认只读 | SOAP:操作名称会与写入动词前缀(Create、Update、Delete、Cancel、Void、Submit、Pay 等)进行匹配。DB:表/查询必须显式选择加入,此外,insert/标记为写入的查询也需要选择加入。除非设置 allow_write_operations: true,否则不会公开这些操作。 |
| 显式允许/拒绝 | SOAP:include_operations / exclude_operations。DB:表/列允许列表——没有等同于“所有表”或任意 SQL 的选项。 |
| 审计日志 | 每次调用记录一行 JSON——工具、参数、时间戳、结果、耗时。 |
| 密钥管理 | 凭据和 DB 连接字符串来自指定名称的环境变量;YAML 文件可安全提交。 |
警告
SOAP 写入操作过滤器是基于名称的启发式规则,而非语义分析——名为
ProcessRecord、但会删除数据的操作无法被识别。对于错误调用会造成实际后果的系统,请显式设置include_operations,不要依赖该启发式规则。DB 适配器的允许列表在设计上是显式的,但没有列级数据屏蔽——允许列表中的列,其值始终会原样返回。此外,MCP 服务本身尚未实现身份验证/授权——请勿将服务暴露给不受信任的调用方。详情请参阅 docs/security.md。
数据流和隐私
- 不收集遥测数据。 legacy2mcp 不收集使用数据,也不会向外发送任何信息。它发起的每个网络调用都是你配置的调用——在写下这句话之前,我们通过检查源代码中的每个出站 HTTP 调用位置进行了验证。
- 适配器调用只会前往你指定的位置,不会前往其他地方。 SOAP 调用会发送到你的
wsdl_url,DB 调用会使用dsn_env连接,REST 调用会发送到你的base_url。 legacy2mcp init的发现调用仅限于你提供的内容。 WSDL 和 REST(OpenAPI)路径只会联系你传入的 URL。GitHub/源代码路径会克隆你指定的仓库,并使用ast在本地解析——不会执行其中的任何内容。- 可选的 LLM 辅助步骤只会发送已检测到的模糊片段,不会发送你的仓库。 该步骤仅在
legacy2mcp init的 GitHub/源代码路径中运行,且只有在你提供 API 密钥时才会运行;它只会发送静态扫描已标记为模糊的具体路由名称/路径/参数,不会发送源代码转储。使用--scan-only可完全跳过此步骤。 legacy2mcp discover会读取本地文件,但--stored-procs除外。 Postman/OpenAPI/HAR/队列来源不会访问网络——它们只会读取你提供的文件。--stored-procs会像db适配器一样,连接到你指定的环境变量中的 DSN,但只用于读取过程/函数目录。生成的contract.yaml中绝不会写入原始密钥或采样值——请参阅 docs/security.md。- 密钥绝不会存储在
config.yaml中。 密码、DSN 和 API 令牌都会通过环境变量名称(password_env、dsn_env、token_env)进行引用,并在运行时读取——YAML 文件可安全提交。 - 审计日志保存在本地,且静态存储时未加密。 每次工具调用都会作为一行 JSON 追加到
security.audit.path。参数会原样记录——不会对个人身份信息(PII)进行脱敏;审计日志的完整功能说明请参阅 docs/security.md。
用例
| 领域 | 形式 |
|---|---|
| 记录系统 | Agent 以只读方式从旧版后台平台读取状态和详情记录,每次查询都会记录日志。 |
| 金融服务 | 提供账户和交易的读取功能,但不开放转账或调整操作。 |
| 供应链 / ERP | 从旧版 SOAP 中间件层获取订单状态、库存和货运跟踪信息。 |
| 内部支持工具 | 支持助手可安全地以类型化方式访问记录系统,而不是使用抓取的 UI。 |
| 迁移与现代化 | 现在在旧版服务前部署 MCP 层;以后更换后端,无需改动 Agent。 |
实际应用
在 CI/CD 中——在 WSDL 变更进入生产环境前发现问题
legacy2mcp inspect 会加载配置、连接 WSDL、构建所有架构;如果任何步骤失败,则以非零状态码退出:
- 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
git diff --exit-code --no-index tools/legacy.snapshot.json tools.json # optional: pin the contract
退出码:
| 代码 | 含义 |
|---|---|
0 | 成功 |
1 | 配置、源或运行时错误——WSDL/DB/REST 配置错误、无法克隆仓库、缺少必需的环境变量等 |
2 | 命令行参数无效(argparse 自带的默认值) |
作为 sidecar / 长时间运行的 MCP 服务
legacy2mcp run 通过 stdio 使用 MCP。使用提供的 Dockerfile 将其与配置一起打包,然后让 MCP 客户端启动它。
在数据管道中
通过任意 MCP 客户端库,在自己的代码中调用同一批已生成并经过验证的工具,按计划拉取记录——审计日志会准确记录获取了哪些数据。
配置参考
| 键 | 默认值 | 含义 |
|---|---|---|
server.name | legacy2mcp | 向客户端报告的 MCP 服务名称 |
server.transport | stdio | 目前仅实现了 stdio |
adapters[].id | — | 此适配器工具名称的前缀 |
adapters[].type | — | soap、db 或 rest(已实现);queue 已列入路线图 |
SOAP 适配器配置:
| 键 | 默认值 | 含义 |
|---|---|---|
adapters[].config.wsdl_url | — | WSDL 位置(http(s)://…?wsdl 或文件路径) |
adapters[].config.auth | {type: none} | none 或 {type: basic, username, password_env} |
adapters[].config.allow_write_operations | false | 暴露类似写入的操作 |
adapters[].config.include_operations | all | 操作名称的允许列表 |
adapters[].config.exclude_operations | [] | 操作名称的拒绝列表 |
adapters[].config.timeout_seconds | 15 | 每次 SOAP 调用的超时时间 |
DB 适配器配置:
| 键 | 默认值 | 含义 |
|---|---|---|
adapters[].config.dialect | — | postgres、mssql 或 oracle |
adapters[].config.dsn_env | — | 保存连接字符串/DSN 的环境变量 |
adapters[].config.allow_write_operations | false | 暴露 insert_<table> 和 write: true 查询 |
adapters[].config.timeout_seconds | 15 | 连接超时时间 |
adapters[].config.tables[].name / .schema | — | 允许列表中的表(以及可选的架构/所有者) |
adapters[].config.tables[].operations | [select] | select 和/或 insert |
adapters[].config.tables[].columns | all introspected | 列允许列表 |
adapters[].config.tables[].filterable_columns | [] | 可在 select_<table> 中用作等值筛选条件的列 |
adapters[].config.tables[].max_rows | 200 | 行数上限,在查询运行后强制执行 |
adapters[].config.queries[].name / .sql / .params | — | 命名查询;sql 使用 :param_name 占位符 |
adapters[].config.queries[].write | false | 此查询是否受 allow_write_operations 控制 |
REST 适配器配置:
| 键 | 默认值 | 含义 |
|---|---|---|
adapters[].config.base_url | — | 已配置端点所基于的 URL |
adapters[].config.auth | {type: none} | none、{type: basic, username, password_env} 或 {type: bearer, token_env} |
adapters[].config.allow_write_operations | false | 暴露标记为 write: true 的端点 |
adapters[].config.timeout_seconds | 15 | 每次 HTTP 调用的超时时间 |
adapters[].config.endpoints[].name / .method / .path / .description | — | 允许列表中的一个端点;path 使用 {param} 占位符表示路径参数 |
adapters[].config.endpoints[].params[].name / .location / .type / .required | — | location 可以是 path、query 或 body |
adapters[].config.endpoints[].params[].enum | unset | 允许值的封闭集合,通过架构验证强制执行,而非仅作描述 |
adapters[].config.endpoints[].write | false | 此端点是否受 allow_write_operations 控制 |
adapters[].config.endpoints[].confidence / .error_codes / .needs_review | unset / [] / false | 仅由 legacy2mcp discover + init --from-contract 填充——表示对发现结果的信任程度、已知错误响应,以及是否需要人工审查 |
安全配置:
| 键 | 默认值 | 含义 |
|---|---|---|
security.audit.enabled | true | 写入审计日志 |
security.audit.path | ./legacy2mcp-audit.log | 审计日志位置 |
文档
| 文档 | 内容 |
|---|---|
| docs/security.md | 完整、坦诚的安全模型——当前已验证和审计的内容,以及尚未完成的部分 |
| docs/roadmap.md | 按版本列出的已发布与计划内容 |
| docs/clients.md | 连接所有受支持的 MCP 客户端、密钥和故障排查 |
| docs/releasing.md | PyPI / MCP Registry 发布流程 |
| docs/registry-submissions.md | Registry / awesome-list 提交状态和可复用文案 |
| examples/README.md | 所有可运行的演示配置(SOAP、REST、Docker) |
| llms.txt | 面向大模型和 Agent 的机器可读项目摘要 |
| skill/legacy2mcp/ | 面向编码 Agent(Claude Code、Cursor、Copilot 等)的 SKILL.md——教 Agent 何时以及如何使用 legacy2mcp 本身 |
| CHANGELOG.md | 按版本列出的重要变更 |
| CONTRIBUTING.md | 开发环境设置、添加适配器的方法和 PR 要求 |
路线图
| 版本 | 范围 | 状态 |
|---|---|---|
| v0.1 | SOAP/WSDL 适配器、架构生成、验证、默认只读、审计日志、run + inspect CLI、基本身份验证、stdio | ✅ 已发布 |
| v0.2 | 数据库适配器(Postgres / SQL Server / Oracle;表/操作允许列表 + 命名参数化查询,绝不执行任意 SQL) | ✅ 已发布 |
| v0.2.x | REST 适配器(显式端点允许列表);legacy2mcp init -- 扫描代码库(SOAP 客户端 / ORM 模型 / Flask/FastAPI 路由)并生成初始配置,可选用兼容 OpenAI 的 LLM 辅助处理含糊内容 | ✅ 已发布 |
| v0.3.x | legacy2mcp discover(Postman / OpenAPI 文件 / HAR / 存储过程 / 队列 / --webpage-url)→ 可供审核的 contract.yaml;--webpage-url 会抓取整个网站,而不只是单个页面;describe_capabilities 元工具 | ✅ 已发布 |
| v0.4.x | legacy2mcp demo -- 无需单独执行 init,即可在聊天页面中试用合约/配置;discover --out contract.html | ✅ 已发布 |
| v0.5.x | discover/init/demo 都会自动打开测试聊天,并打印可直接粘贴的 MCP 客户端连接代码片段;init --webpage-url 可直接生成配置 | ✅ 已发布 |
| 计划中 | HTTP/SSE 传输、角色→工具授权、SOAP 的 OAuth2 | 计划中 |
| 想法 | 队列适配器(Kafka/RabbitMQ/SQS)、带审批关卡的工作流编排、OpenTelemetry 导出 | 想法 |
详见 docs/roadmap.md。BaseAdapter 接口(discover_tools() + invoke())是扩展点——服务器核心负责处理任意适配器的验证、分发和审计。
开发
pip install -e ".[dev]"
pytest tests/ -v
测试使用进程内模拟 SOAP 服务,以及基于 SQLite 的进程内模拟数据库适配器——无需网络,也无需真实的 Postgres/SQL Server/Oracle。数据库适配器的 Postgres/SQL Server/Oracle 方言(db_dialects.py)通过不依赖驱动程序的单元测试覆盖其 SQL 转换逻辑;默认测试套件不包含连接到各类真实实例的测试。
CI 在 Python 3.10–3.12 上运行测试套件 (ci.yml)。PyPI 和 MCP Registry 的发布由标签触发——详见 docs/releasing.md。演示 GIF 使用 vhs demo/demo.tape 重新生成(demo/)。
贡献
为新的旧系统开发适配器是最有价值的贡献——实现 BaseAdapter,其余工作由核心处理。有关开发环境设置、适配器结构和 PR 要求,请参阅 CONTRIBUTING.md。本项目遵循行为准则。欢迎提交 Issue 和 PR。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。