当我们使用 Codex 时,可以直接告诉它:"帮我查看 GitHub 上 openai/codex 仓库的 README.md,总结这个项目是做什么的。"
Codex 本身是一个 AI 编程助手,但它为什么能够访问 GitHub?它是否直接调用 GitHub API?MCP Client 和 MCP Server 分别在哪里?JSON-RPC 2.0 又起什么作用?
本文从几个概念入手,最后用 Codex 调用 GitHub MCP Server 的 get_file_contents 工具串起完整流程。
Codex 作为 MCP Host 管理 MCP Client;Client 按 MCP 协议与 Server 通信;Server 提供工具并连接 GitHub 等外部系统;MCP 的消息建立在 JSON-RPC 2.0 之上。
1. 什么是 JSON-RPC 2.0?
JSON-RPC 2.0 是一种基于 JSON 的远程过程调用协议(Remote Procedure Call)。简单来说,调用方不需要知道另一端函数的内部实现,只需要按照约定发送一条 JSON 请求,就能让对方执行某个方法,并拿到结果。
例如,一次抽象的加法远程调用:
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "add",
"params": {"a": 10, "b": 20}
}
对方执行完成后返回:
json
{
"jsonrpc": "2.0",
"id": 1,
"result": 30
}
其中,jsonrpc 声明协议版本;method 表示调用什么方法;params 携带参数;id 将一次请求与它的响应关联起来;成功响应中使用 result,失败时则使用 error。id 只是本次 JSON-RPC 请求的关联标识,不是 GitHub Issue ID,也不是业务用户 ID。
另外,如果消息没有 id,它在 JSON-RPC 中通常属于通知(Notification),接收方不需要返回响应。MCP 也利用通知进行协议生命周期管理。
特别注意:JSON-RPC 定义的是消息格式与调用约定,并不规定只能通过 HTTP 发送。 它可以搭配不同传输方式。
2. 什么是 MCP?它和 JSON-RPC 2.0 有什么关系?
MCP(Model Context Protocol,模型上下文协议) 是让 AI 应用与外部工具、数据及上下文能力交互的一套开放协议。
可以把它理解成在 JSON-RPC 之上规定了一套适用于 AI 应用的标准操作,例如:
initialize:建立会话,协商协议版本和能力。tools/list:获取 Server 暴露的工具列表。tools/call:调用指定工具。resources/list、resources/read:发现、读取服务端提供的资源(如果支持)。prompts/list、prompts/get:发现、获取服务端提供的提示词模板(如果支持)。
两者的区别是:JSON-RPC 2.0 解决"消息怎么表达";MCP 进一步解决"AI 应用和工具服务器具体按什么规则交互"。
例如 tools/call 不是 JSON-RPC 2.0 标准自带的方法,而是 MCP 定义的方法;它用 JSON-RPC 2.0 消息格式传输。
目前主要有两种传输方式:stdio 和 Streamable HTTP。
第九节会介绍
3. MCP Server 是不是一个工具的统一入口?
可以这样理解,但它的能力不止 Tools。
一个 MCP Server 可以提供多个 Tool ,也可以按需提供 Resources 和 Prompts。以 GitHub MCP Server 为例,它可能提供读取文件、搜索仓库、查看 PR、管理 Issue 等不同工具。并不需要每一个 GitHub API 功能都单独运行一个 MCP Server。
需要区分两个层次:
- MCP Server:负责暴露一组符合 MCP 规范的能力,处理协议消息。
- 具体 Tool :MCP Server 内的某一个可被调用的功能,例如
get_file_contents。
因此,一个 GitHub MCP Server 可以同时拥有 get_file_contents、list_pull_requests、issue_write 等工具。但某个连接实际能看到哪些工具,还取决于 Server 的版本、启用的 toolsets、访问权限和只读模式等配置。
4. Codex Host、MCP Client、MCP Server 到底是什么关系?
这是理解 MCP 架构最关键的一步。
Codex Host 指的是承载 Agent 工作流程的 Codex 主应用或运行环境,而不是大模型本身。它负责与用户交互、组织模型请求、管理工具、处理安全与权限,并创建 MCP Client 连接外部 Server。
MCP Client 是 Host 内用于与某个 Server 建立连接、交换协议消息的客户端组件。它负责初始化、列出工具、发起工具调用、接收结果等协议工作。
MCP Server 则在另一端实现工具、资源等能力。以 GitHub 为例,它接收 Client 的 tools/call,在具备权限时调用 GitHub API,再把结果返回给 Client。

第一,一个 Host 可以管理多个 MCP Client。 Codex 可以同时接入 GitHub、Filesystem 等多个 MCP Server。
第二,一个 MCP Client 实例通常与一个特定 MCP Server 建立一对一连接。 并不是Codex 整个程序只注册一个 Client,然后由它连接所有 Server。
text
Codex Host
├── MCP Client ① ── GitHub MCP Server
│ ├── get_file_contents
│ ├── list_pull_requests
│ └── issue_write
│
└── MCP Client ② ── Filesystem MCP Server
├── read_file
└── list_directory
这里的一对一说的是MCP Client 实例到特定 Server 的逻辑连接/会话关系,不是说一个 MCP Server 只能服务一个用户,也不是说 Codex 只能连接一个 Server。
5. Codex 为什么称为 Host,而不是 MCP Client?
因为 Codex 做的事情比协议通信多得多。
用户发起任务以后,Codex 要协调 LLM 的推理与工具使用、决定是否允许某个操作、维护对话上下文、处理结果,再形成最终回答。这些都是 Host 的职责。
而 MCP Client 只负责其中一段:通过 MCP 协议与外部 Server 通信。
因此,说Codex 是 MCP Client只能粗略表达Codex 支持连接 MCP,技术上更准确的说法是:
Codex 是 MCP Host,它在内部创建或管理 MCP Client,通过这些 Client 连接不同 MCP Server。
6. 实例:让 Codex 读取 GitHub 仓库的 README
接下来假设用户对 Codex 说:
帮我读取 GitHub 上
openai/codex仓库的README.md,然后总结项目主要功能。
这里我们选择 GitHub MCP Server 实际提供的 get_file_contents 工具。它接受 owner、repo、path 等参数。以下是解释调用原理的示意流程,不代表本文真的执行了这次 GitHub 读取。

6.1 首先,Codex 需要连接并初始化 MCP Server
Codex Host 根据配置创建 GitHub MCP Client。客户端与服务端首先协商版本和能力,典型会话包括 initialize 请求及响应,之后客户端发送 notifications/initialized 通知。
简化流程:
text
Codex Host 创建 GitHub MCP Client
↓
连接 GitHub MCP Server
↓
initialize
↓
协商协议版本、能力
↓
notifications/initialized
所以,并不是一启动就直接调用 GitHub 的 get_file_contents;一般要先建立可用的 MCP 会话。
6.2 然后,通过 tools/list 发现工具
GitHub MCP Client 发送:
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Server 会返回当前允许使用的工具清单。下面只是一个删减后的示例:
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "get_file_contents",
"description": "Get file or directory contents",
"inputSchema": {
"type": "object",
"properties": {
"owner": {"type": "string"},
"repo": {"type": "string"},
"path": {"type": "string"}
},
"required": ["owner", "repo"]
}
}
]
}
}
这里的 inputSchema 通常使用 JSON Schema 描述参数。Codex 就能知道:这个工具叫 get_file_contents,调用它需要什么参数,以及它大概能做什么。
6.3 LLM 判断应该调用哪个工具
模型看到用户要求"读取 GitHub 仓库的 README",再结合工具描述,就可能决定使用 get_file_contents。
这里有一个非常容易混淆的点:不是大模型亲自向 GitHub MCP Server 发送 JSON-RPC。 模型在 Codex 的工具调用机制中表达"想使用哪个工具和参数",真正构造并发送 MCP 请求的是 Codex 的工具执行层和对应的 MCP Client。
6.4 MCP Client 通过 tools/call 发出请求
示例请求:
json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_file_contents",
"arguments": {
"owner": "openai",
"repo": "codex",
"path": "README.md"
}
}
}
最重要的是分清楚 method 和 name:
method: "tools/call"表示正在执行 MCP 的"调用工具"操作。params.name: "get_file_contents"表示具体调用哪个 GitHub 工具。arguments是这个工具需要的业务参数。id: 2用于把该次请求与后面的 JSON-RPC 响应匹配。
所以 MCP 中的 tools/call 和 GitHub 工具名不是同一层的概念。
6.5 GitHub MCP Server 真正执行工具
GitHub MCP Server 收到请求后,会定位到 get_file_contents 对应的处理逻辑,检查参数与权限,在后台访问 GitHub API 获取仓库文件内容。
也就是说:
text
Codex MCP Client
↓ MCP / JSON-RPC
GitHub MCP Server
↓ GitHub API
GitHub 平台
Codex 与 GitHub MCP Server 之间使用 MCP;GitHub MCP Server 与 GitHub 平台之间使用 GitHub 的 API。 这两段不是同一个协议层次。
6.6 结果返回 Codex,再由模型组织答案
成功响应可能像这样(text 内容只作示意):
json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "README.md 的文件内容......"
}
],
"isError": false
}
}
MCP Client 接收响应,把工具结果交给 Codex Host。Host 再把必要的文件内容放入模型可使用的上下文中,让模型根据实际 README 内容生成中文总结。
至此才完成一个完整的:用户提问 → 模型选工具 → MCP 工具调用 → GitHub API → 工具结果 → 模型回答 的闭环。
7. MCP Client 为什么不是只有一个?
假设 Codex 还需要执行另一项任务:"读取本地项目配置,然后结合 GitHub 仓库代码给出修改建议。"
它可能同时需要:
- GitHub MCP Client:连接 GitHub MCP Server,读取 GitHub 仓库。
- Filesystem MCP Client:连接 Filesystem MCP Server,读取本地文件。
一个 Host 可以维护这些不同的 Client 连接,并把不同来源的结果汇总到同一个 Agent 任务中。但每个 Server 不会因为连进 Codex,就自动获得完整对话或其他 Server 的私有数据;Host 仍然需要负责权限与上下文隔离。
因此,应该记成 一个 Host → 多个 Client → 各自连接 Server,而不是 一个 Codex → 一个全局 Client → 所有 Server。
8. JSON-RPC、MCP、Function Calling 到底有什么区别?
这几个概念经常一起出现,但分工不同。
| 概念 | 主要解决什么问题 | 在这次例子中的作用 |
|---|---|---|
JSON-RPC 2.0 |
请求、响应、通知怎么表示 | 定义 jsonrpc/id/method/params/result |
MCP |
AI 应用如何发现和调用外部能力 | 定义 initialize、tools/list、tools/call 等 |
MCP Client |
与 Server 建立会话、收发协议消息 | GitHub 专用连接组件 |
MCP Server |
暴露工具,并完成实际工具处理 | 提供 get_file_contents 等工具 |
Codex Host |
协调用户、模型、工具与权限 | 调度整个任务 |
Function/Tool Calling |
模型向 Host 表达需要调用工具的意图 | 选择 get_file_contents 和参数 |
这里尤其要注意:模型产生的 Tool Calling 请求,和 MCP Client 发出的 JSON-RPC 请求,不一定是同一个 JSON 结构,也不是同一层协议。 Host 需要负责把模型层的工具调用意图转换成实际可执行的 MCP 调用。
9. JSON-RPC 等于 HTTP 吗?stdio 又是什么?
不等于。JSON-RPC 规定消息结构,MCP 则规定应用层交互与支持的传输方式。
MCP 常见传输方式包括:
stdio: Host 启动本地 MCP Server 子进程,通过标准输入/输出交换协议消息。适合本地开发工具、文件系统工具等。
Streamable HTTP: Client 通过 HTTP 与 MCP Server 通信,适合远程服务。例如 GitHub 托管的 MCP Server 可使用这种方式。
在这两种方式下,MCP 的 tools/list、tools/call 依然采用 JSON-RPC 消息结构,只是消息在底层怎样传输不同。
10. 如果不用 MCP,Codex 能不能直接调用 GitHub API?
技术上可以。只要 Host 自己集成了 GitHub API 客户端、身份认证和工具逻辑,就不一定非得通过 MCP。
MCP 的价值主要在于:把"外部服务提供什么工具、参数如何描述、调用结果怎么返回"等能力标准化。 这样,支持 MCP 的 Host 不必为每一个服务都重新设计一套工具接入协议。
但这不表示 MCP Server 是万能代理,更不意味着所有工具都会被自动开放给模型。权限控制、工具描述、错误处理和安全边界仍然非常重要。
11. 最容易混淆的六个问题
① Codex Host 是不是大模型? 不是。Host 是运行和协调 Agent 的应用层;LLM 是其中用于理解和决策的模型。
② Codex 里是不是只有一个 MCP Client? 不是。一个 Host 可以管理多个 Client 实例,通常每个 Client 对应一个 Server 连接。
③ 一个 MCP Server 是不是只能提供一个工具? 不是。一个 Server 可以同时提供多个 Tools,还可以提供 Resources、Prompts。
④ tools/call 是不是某个 GitHub 工具? 不是。tools/call 是 MCP 定义的通用调用方法;get_file_contents 才是这次调用的具体工具名。
⑤ 是不是大模型直接发送 JSON-RPC? 通常不是。模型提出工具调用意图,由 Host 和 MCP Client 负责执行协议通信。
⑥ MCP 是不是 JSON-RPC 的另一个名字? 不是。JSON-RPC 定义消息格式,MCP 在它之上提供 AI 工具发现、调用、资源访问和生命周期等规范。
总结
text
用户:帮我读取 GitHub README
↓
Codex Host
(管理任务、LLM 与工具)
↓
GitHub MCP Client
↓
MCP / JSON-RPC 2.0
↓
GitHub MCP Server
↓
get_file_contents
↓
GitHub API
↓
GitHub README 文件
↓
结果沿原路返回 → LLM 总结
一个 Codex Host 可以管理多个 MCP Client;一个 MCP Client 通常对应一个 MCP Server 连接;一个 MCP Server 可以提供多个 Tools。JSON-RPC 2.0 是它们之间收发 MCP 消息时使用的基础格式,而 Codex 作为 Host 则负责把用户任务、LLM 决策与外部工具连接起来。