一、背景与行业趋势

在现代 AI Agent 生态中,MCP(Model Context Protocol) 作为 LLM 与外部工具/服务的桥梁,承担着“把已有 API 变成可被模型调用的工具”(Tool)的职责。企业里大量 REST API 通常有 OpenAPI 文档,把 OpenAPI → MCP 做好能快速把现有服务变为可编排的工具链。

本文以 Java / Python / Go 三条实现线为例,深入讲解从 OpenAPI 生成调用代码、映射为 MCP ToolDefinition、以及在三种 MCP 模式(stdio / streamable / SSE)下的实现细节、运维和安全要点。


二、概览

  • 使用 openapi-generator 将 OpenAPI 描述自动生成各语言的客户端 SDK。
  • 基于生成的 SDK 实现 MCP 的 Handler(工具)适配:将每个 operationId 映射为一个 MCP 工具。
  • 三种运行/传输模式:stdio(stdin/stdout)HTTP streamable(chunked)SSE(Server-Sent Events),各自有不同实现难点。
  • 需要关注的关键问题:流式输出(partial/delta)、多路复用与上下文透传、鉴权/headers 透传、错误与重试策略、工具自省(introspect)与 schema 兼容性。

1. OpenAPI Generator 简介

openapi-generator(社区版)是最常用的自动代码生成工具,支持几十种语言与框架。要点:

  • 输入:OpenAPI 3.x api.yaml / api.json
  • 输出:客户端 SDK(ApiClient、models、api classes),或服务端 stub。
  • 优点:快速、减少样板代码、保持契约。
  • 注意:生成代码在实际工程中常需二次适配(如 baseURL 配置、超时/重试、header 透传、streaming 支持)。

安装与使用示例(本段为 CLI 命令示意):

# 安装(示例)
brew install openapi-generator
# 或下载 jar
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.8.0/openapi-generator-cli-7.8.0.jar

# 生成 python 客户端
openapi-generator-cli generate \
  -i api.yaml \
  -g python \
  -o ./gen/python

# 生成 java 客户端
openapi-generator-cli generate \
  -i api.yaml \
  -g java \
  -o ./gen/java

2. 从 OpenAPI 到 MCP 的映射规则

下面是生成 ToolDefinition 与 handler 的自动化映射规则,越细越能保证运行时正确性。

2.1 映射总体思路

  1. 每个 operation → 一个 MCP Tool:使用 operationId 作为 tool.name(若无,则用 method_path 摘要)。
  2. 参数(parameters / requestBody) → ToolDefinition.inputSchema:把 OpenAPI 的 schema 转为标准 JSON Schema(或直接用 OpenAPI schema)。
  3. 响应(responses)→ ToolDefinition.outputSchema:取 2xx 响应 schema 为主;若支持多种响应,优先选择 application/json,同时记录 isStream if response 是流式(例如 text/event-stream / application/stream+json)。
  4. 鉴权:识别 OpenAPI securitySchemes(bearer, apiKey, basic),在 ToolDefinition 中暴露 auth 字段并支持运行时注入。
  5. headers / baseURL 透传:ToolDefinition 标注哪些 header 是可透传(如 X-User-IdAuthorization),并允许 runtime 覆盖 baseURL(支持 operation-level override)。
  6. 示例 / enum / required:把 OpenAPI 的 example / enum / required 字段带入 ToolDefinition,便于 LLM 在选择调用参数时具备约束信息(自省阶段用)。

2.2 ToolDefinition 示例(JSON 形式,供 introspect 返回使用)

(注意:下面示例用缩进代码块样式展示)

{
  "name": "get_user_info",
  "description": "按 user_id 查询用户信息",
  "inputSchema": {
    "type": "object",
    "properties": {
      "user_id": { "type": "string", "description": "用户 ID" },
      "include_detail": { "type": "boolean", "default": false }
    },
    "required": ["user_id"]
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "id": { "type": "string" },
      "name": { "type": "string" },
      "email": { "type": "string" }
    }
  },
  "http": {
    "method": "GET",
    "path": "/api/v1/users/{user_id}",
    "headers_pass_through": ["Authorization","X-Trace-Id"]
  },
  "auth": {
    "type": "bearer",
    "in": "header",
    "name": "Authorization"
  },
  "examples": [{ "user_id": "12345" }]
}

2.3 自动生成/转换注意点

  • 参数位置:把 path / query / header / cookie 映射到 inputSchema 的不同层(path 参数在 ToolDefinition 描述中标注必须)。
  • requestBody:优先取 application/json schema;若支持 multipart/form-data,需要标注 contentType 并在 handler 中做特殊处理(文件流)。
  • 流式响应识别:如果 response content-type 是 text/event-stream / application/stream+json / application/x-ndjson,标注 isStream=true,并实现逐条转发(SSE/streamable 下)。
  • 多语言适配:生成的 SDK 可能不支持 stream out-of-box,需在生成后 patch:设置 responseType=streamreadTimeout 增大,转为异步流读取。
  • 边界行为:enum、format、pattern 等保持并暴露给 LLM 作为约束,避免传参错误。

3. MCP 的三种模式(深入原理与实现要点)

3.1 STDIO(stdin/stdout)—最简单但强大

原理:进程通过 stdin 读取 JSON-RPC 请求,通过 stdout 写出 JSON-RPC 响应。
优点:无网络,最小依赖,延迟低。
难点

  • 消息边界:必须定义明确的分隔(通常使用 line-delimited JSON 或“长度前置”)。
  • 并发:stdin/stdout 是串行的,若需要并发处理需在进程内做线程/协程调度并做 request-id 分流/合并。
    实现要点
  • 使用 \n 分行 JSON(line-delimited),或采用 Content-Length 前置协议(更稳健)。
  • 响应时带上原请求 id 保证关联。
  • 流式返回可把多条事件包装为 result.events 列表或在 stdout 上写多条 partial-response(每条含同 id 与序号),并以 done 标记结束。

JSON-RPC 请求样例(stdin):

{"id":"req-1","jsonrpc":"2.0","method":"call_tool","params":{"name":"get_user_info","arguments":{"user_id":"123"}}}

JSON-RPC 响应样例(stdout):

{"id":"req-1","jsonrpc":"2.0","result":{"name":"get_user_info","content":{"id":"123","name":"Alice"}}}

3.2 HTTP Streamable(chunked response)—真实流式

原理:基于 HTTP chunked transfer,用服务器分块写出响应体;客户端可以边读边消费(典型用于 LLM token streaming)。
优点:天然兼容现有 HTTP 客户端,延迟小,适合大型任务。
难点

  • 客户端需要能处理 chunked 响应(多数 HTTP 客户端支持)。
  • chunk 格式要约定(每 chunk 为 JSON 事件或纯文本 token)。
    实现要点
  • 把每个流事件以单独 JSON 行发送(ndjson 风格)或发送 token 字符串并通过小的 JSON 包裹。
  • 对于多路(同一连接上并行多个请求),要保证请求级别上下文(通常每个请求单独 HTTP 连接更简单)。
  • 需要明确 Content-Type(如 application/x-ndjson 或 text/event-stream).

chunked 片段示例(body):

{"event":"delta","content":"Hello"}
{"event":"delta","content":" world"}
{"event":"done"}

3.3 SSE(Server-Sent Events)—浏览器友好且可扩展为“逻辑双向”

原生原理:浏览器用 EventSource 建立到服务端的单向长连接(text/event-stream),服务端不断推送 data: ... 事件。
原生限制:物理上单向(server → client),不能把 client 的消息通过同一连接发送到 server。
MCP 的扩展与实践

  • 在 MCP 场景中,通常结合两条通道来实现“伪双向”:
  1. Control / request 通道:客户端通过普通 HTTP POST 向 server 发起调用(或使用 WebSocket)。
  2. Event / response 通道(SSE):服务端在该 SSE 连接上推送执行进度与结果。

  • 另一种常见做法是:约定通过某个 HTTP endpoint 把 client → server 的事件写入服务端队列(或 DB),server 把结果推送到 SSE。效果上实现双向交互,但底层仍是两个方向的 HTTP 请求。
  • 有些实现会在 SSE 的 data 字段中嵌入 event: call 类型的封装,并让代理(proxy)把该封装转发到后端 HTTP 接口,从而在逻辑上实现“一个长连接承载双向语义”,但这本质上仍是对协议的扩展与中间代理支持。

SSE 事件格式建议(MCP 扩展)

event: mcp
data: {"type":"response","id":"req-1","payload":{"event":"delta","content":"hello"}}

event: mcp
data: {"type":"done","id":"req-1"}

实现要点

  • 为每个 SSE 订阅分配唯一 client-id,POST 请求时把 client-id 带上以便 server 知道向哪个 SSE 连接推送。
  • SSE 需注意连接重试、心跳(: 注释行)以及保持连接的超时策略。
  • 对于浏览器端必须注意 CORS 与证书(TLS)。

4. MCP 协议消息格式(建议标准化:JSON-RPC + Events)

统一采用 JSON-RPC 2.0 作为请求/响应骨架,辅以流事件 envelope(便于在 chunked / SSE 中传输 partial):

请求(JSON-RPC)

{
  "id":"req-1",
  "jsonrpc":"2.0",
  "method":"call_tool",
  "params": {
     "name":"get_user_info",
     "arguments": {"user_id":"123"},
     "meta": {"traceId":"t-1","clientId":"c-1","userContext":{...}}
  }
}

普通响应(一次性)

{
  "id":"req-1",
  "jsonrpc":"2.0",
  "result": {
     "name":"get_user_info",
     "content": {"id":"123","name":"Alice"}
  }
}

流式事件(在 chunked 或 SSE 中的 event payload)

{"type":"delta","id":"req-1","seq":1,"content":"Hello"}
{"type":"delta","id":"req-1","seq":2,"content":" world"}
{"type":"done","id":"req-1"}

错误样例(JSON-RPC error)

{
  "id":"req-1",
  "jsonrpc":"2.0",
  "error": {"code":500,"message":"UpstreamTimeout","data":{"upstream":"user-service"}}
}

5. Java 实现细节

5.1 McpHandler 接口

public interface McpHandler {
    String getName();
    String handle(Map input) throws Exception;
    ToolDefinition getDefinition();
}

工程实现要点

  • handle 内要:
    • 做参数校验(基于 ToolDefinition.inputSchema,避免把无效/恶意参数透传到后端)。
    • 构建 HTTP 请求(method/path/baseURL/header),支持 baseURL override。
    • 支持超时/重试策略(建议使用可配置的 HttpClient,带断路器)。
    • 识别响应是否流式(根据 Content-Type),若流式则把 upstream stream 转为 MCP 的 partial events 推出(SSE 或 chunked)。

  • 并发模型:推荐使用线程池 + CompletableFuture 异步处理,保证处理多请求时不阻塞 I/O 主线程。
  • 工具自省:实现 /introspect 接口,返回注册的 ToolDefinition 列表,供 LLM 在选择工具前拉取。

5.2 流式与 SSE 在 Java 中的实现建议

  • 对于 Streamable(chunked)模式:使用 HttpServletResponse.getOutputStream() 或 Netty 的 chunked writer,逐 chunk 写入 JSON 行并 flush。
  • 对于 SSE:可以使用 SseEmitter(Spring)或 Netty 的 text/event-stream 支持,事件包裹 JSON,包含 type/id/seq 等字段。

6. Python 实现细节(fastmcp + openapi-generator)

6.1 关键点(异步、schema、stream)

  • 推荐使用 asyncio/FastAPI + uvicorn 做 HTTP 层,fastmcp 或自家 mcp 框架负责 JSON-RPC / tool 注册。
  • openapi-generator 的 Python 客户端生成通常是同步的,建议在生成后手动改造或封装为异步:使用 httpx.AsyncClient 调用后端,或把生成的 ApiClient 用线程池包裹成异步函数。
  • 流式响应(streamable)时,使用 httpx 的 .aiter_lines() 或 FastAPI 的 StreamingResponse 把上游 stream 向下游转发成 ndjson/SSE。

6.2 fastmcp 示例

下面是一个概念示例(逻辑展示,便于直接阅读):

from fastmcp import MCPServer
from gen.python.api import DefaultApi  # openapi-generator 生成的客户端 (可封装成 async)

api_client = DefaultApi()

server = MCPServer(name="qihoo-openapi")

@server.tool()
async def get_user_info(user_id: str):
    # 参数校验/转型
    resp = await api_client.get_user_async(user_id=user_id)  # 如果没有 async,需要封装
    return resp

if __name__ == "__main__":
    server.run(mode="sse", port=7330)  # 或 mode="stdio"/"streamable"

实现建议

  • 若生成的客户端是同步的,用 anyio.to_thread.run_sync 或 asyncio.to_thread 把它包装为异步以免阻塞事件循环。
  • SSE 模式:使用 FastAPI 的 EventSourceResponse(或者 sse-starlette)把 server.emit(event) 转为 text/event-stream
  • 支持 --mode stdio:程序启动时根据参数切换 I/O 层,stdio 模式用 line-delimited JSON 在 stdin/stdout 读写。

7. Go 实现

你已有的 Go 二进制支持三平台(Linux/Windows/mac),实现要点如下:

  • baseURL 与 header 透传:在 operation 级别支持 baseURL 覆盖(方便在不同环境掉到 mock/proxy)。
  • 跨平台打包:使用 go build 交叉编译多平台二进制,或使用 goreleaser 做 release 管理。
  • 协议支持:同一二进制内部根据启动参数切换 stdio / streamable / sse 模式(例如 --http 与 --http-transport=sse)。
  • 流式实现:在 HTTP 模式下用 net/http 的 Flush 支持 chunked;SSE 模式写 text/event-stream
  • 运维:内置健康检查 /healthz、元信息 /metrics(Prometheus),便于容器化部署。

启动示例(你已有):

# As stdio
qihoo-openapi-mcp

# As HTTP-streamable server
qihoo-openapi-mcp --http=:8080

# As SSE server
qihoo-openapi-mcp --http=:8080 --http-transport=sse

8. 常见问题(FAQ)

Q:SSE 能否单条连接回传客户端消息?
A:原生 SSE 是单向(server → client)。在 MCP 里常用的模式是:客户端用普通 HTTP POST 发起调用(或用一个额外的 control channel),服务端在 SSE 连接上推送执行进度与结果;也有实现通过中间代理把“事件”从 SSE 的 data 中送往后端,从逻辑上实现“单连接交互”,但这依赖于部署端的代理/网关实现与协议约定,不是浏览器标准行为。

Q:如何判断某个 OpenAPI operation 是否应启用流式(isStream)?
A:查看 responses 的 content-type:若存在 text/event-streamapplication/x-ndjsonapplication/stream+json 或服务端文档说明 streaming,则标注 isStream=true

Q:ToolDefinition schema 变化如何兼容?
A:使用 schema version 字段与兼容策略(backward-compatible additive changes OK,breaking change 则需要发布新 tool 名或 version),并在 introspect 响应中返回 schemaVersion


9. 结语与落地建议

  • 先做 POC:从一个较小的 API(例如 get_user_info)开始,走通 OpenAPI → 生成 SDK → 生成 Handler → 部署 MCP(stdio + SSE),验证模型调用链路。
  • 自动化生成:把映射规则脚本化(OpenAPI → ToolDefinition → handler stub),降低维护成本。
  • 逐步扩展:优先把高价值、低风险的 API 转换为工具,再覆盖更复杂的状态/长连接/文件上传场景。
  • 观察与灰度:在真实流量下监控 latency、stream stability、错误率,逐步调整超时与重试策略。

三、API协作云MCP生成服务多语言版本落地实践与操作流程

注:使用生成 MCP 功能前,请先在 API 协作云平台创建项目或加入项目成为成员,并确保项目已创建 API 文档。 查看操作流程

生成MCP服务源码功能介绍:

基于APICloud API生成可部署的MCP服务(可执行服务、Python、Java语言),供AI调用。通过APICloud,可生成 OPENAPI 3.0规范文档及MCP服务源码,进而上传至MCP市场生成可访问的MCP服务,也可部署在本地MCP服务器或第三方MCP服务平台供访问。

步骤1:MCP Generator主页,点击API文档项目生成MCP按钮。或项目列表操作列生成MCP

步骤2:选择API接口文档页面

步骤3:选择后的API接口文档列表,可编辑、删除;选择MCP服务可执行服务和MCP源码(Python、Java语言)

步骤4:生成MPC服务可执行下载,本地可直接运行;也可下载压缩MCP源码包,可修改API接口参数等

生成MCP源码后,压缩包可以上传到MCP市场中运行MCP执行服务。


三、关于API协作云

API协作云(APICloud) 是企业 API &文档资源空间、接口调试、API Mock一体化协作平台,定位 Postman + Swagger + Mock 集合体。通过一套系统、一份数据,解决多个系统间或不同企业组织间的业务和数据的同步问题。

我们诚挚地邀请各业务线同仁们使用API协作云产品,体验各个功能带来的便捷与高效。在使用过程中,如果您遇到任何问题或需要帮助,请随时与我们联系。我们拥有专业的客服团队和技术支持团队,将为您提供全方位的服务与支持。

产品地址:https://apicloud.360.cn/

Logo

更多推荐