CodeGym /课程 /ChatGPT Apps /什么是 MCP,以及它为何对你的 ChatGPT App 必不可少

什么是 MCP,以及它为何对你的 ChatGPT App 必不可少

ChatGPT Apps
第 6 级 , 课程 0
可用

1. 为什么需要一个单独的协议

在本模块中,我们终于会弄清楚什么是 MCPModel Context Protocol),以及它如何融入 ChatGPT App 的技术栈。我们先确定 MCP 在架构中的位置,把它与“典型的 REST”作个对比,并梳理协议的核心实体:toolsresourcesprompts

设想你在编写一个常规的 Web 服务。按老办法你会起一个 REST API:你有 /api/gifts/api/users/api/orders, 每个端点都有自己的入参、出参格式、错误码和鉴权。这很常见,但有个细节:你必须向每个客户端解释你是如何实现的。文档、OpenAPI、示例、SDK——这些都要有,因为 API 的格式是你自定义的。

在 ChatGPT App 中情况更复杂。你的客户端不只是前端,还是模型本身。模型需要:

  • 知道有哪些操作可用;
  • 搞清每个操作需要哪些参数;
  • 在对话过程中调用这些操作,有时调用多次,有时用不同参数;
  • 解析结构化响应,决定哪些展示给用户,哪些仅作为下一轮对话的上下文。

如果每个开发者都自定一套 API 格式,模型会陷入集成地狱:每个 App 都要写自定义客户端、堆一堆“胶水代码”,逻辑还很脆弱。协议的思想可以解决这个问题。

MCP(Model Context Protocol)是一份开放规范,定义了 LLM 客户端(ChatGPT、IDE 插件、智能体等)与您的工具/数据服务器进行通信的标准方式。它提供一门通用语言:服务器在其中声明自己的工具、资源和提示词,而客户端按此调用并获取结果。

直观地说,MCP 就是 AI 世界的 USB‑C 接口:如果你做了一只“U 盘”(服务、数据库、CRM、搜索引擎),只需实现一个标准插口。这样任何“笔记本”(ChatGPT、其他智能体、IDE)都能无缝连接,无需定制线缆。

2. 俯瞰全局:MCP 在 ChatGPT App 架构中的位置

为了固定这张图景,我们回忆一下熟悉的架构,这次显式引入 MCP 层。

你已经见过当前的心智模型:用户与 ChatGPT 交互,对话内部渲染小部件(Apps SDK),你的后端运行在某个外部位置。现在加上 MCP,把一切按层展开。

下面是简化示意:

用户
   ↓(自然语言)
ChatGPT(模型 + UI)
   ↓(通过 MCP 的工具调用)
ChatGPT 内部的 MCP 客户端
   ↓(JSON-RPC,MCP)
你的 MCP 服务器(backend)
   ↓
你的数据库 / 外部 API / 队列

这里的“ChatGPT 内部的 MCP 客户端”指的是平台的内部组件,它按协议与你的 MCP 服务器对话:做能力发现(discovery)、调用工具、读取资源。

从 Apps SDK 的视角,一个最小的 ChatGPT App 由三个组件构成。其一是 MCP 服务器,它声明工具并返回结构化数据。其二是 UI 包(小部件),它在 ChatGPT 内渲染,并通过 window.openai 读取这些数据。其三是模型本身,它决定何时调用哪个工具,以及如何回复用户。

这里有个关键点。在之前的模块里,你主要在 Apps SDK 和小部件这层(图的上半部分)工作。现在我们下潜到 MCP 服务器层——这是你与 ChatGPT 及任何其他客户端交流的官方“通用语言”,凡是想接入你的 App 的客户端都能使用它。

3. MCP 与“典型的 REST”有何不同

上面的示意图确定了 MCP 在 ChatGPT App 架构中的位置。现在我们仔细对比“自建 REST”与 MCP 这两种方式,从而理解为什么在 ChatGPT Apps 的语境下,后者几乎总是更优。

REST 模式下,你按自己的习惯设计端点、请求和响应格式。为了让客户端能用,需要知道 URL、方法、模式和错误码。有时 OpenAPI 能帮点忙,有时你只是在 README 里扔个请求示例。模型本身对这些一无所知:它需要一层代码把“帮我给 50 岁的妈妈挑个礼物”转成具体的 HTTP 请求,再把 JSON 响应变成可用于对话的数据。

而在 MCP 中不一样。协议本身规定了:

  • 客户端如何获知你有哪些工具;
  • 如何通过 JSON Schema 描述参数与结果;
  • 如何描述资源与提示词;
  • 工具调用与其响应的标准形态。

因此,ChatGPT 和其他 MCP 客户端可以自动:

  • 执行 discovery——了解你有哪些 tools/resources/prompts
  • 为每个工具构建内部的参数模式;
  • 无需客户端的定制硬编码逻辑即可调用;
  • 缓存元数据,并在应用的搜索与排序中使用它们。

可以把差异归纳为一张小表:

问题 自建 REST / gRPC MCP
客户端如何知道你的能力? 查文档、README、OpenAPI 通过标准的发现方法(列出 tools/resources
谁来描述参数? 你随意定义(JSON、FormData 等) 在工具的字段中用 JSON Schema 描述
模型如何调用函数? 通过你自定义的客户端代码 直接通过 MCP 原语
客户端需要多少“胶水”? 很多,并且每个服务都不同 对所有 MCP 服务器统一的协议
多客户端支持 需要为每个客户端编写 SDK MCP 服务器自文档化,客户端可复用通用逻辑

如果用感性一点的话说:REST 是“各自为政”,MCP 是“整个生态就如何与模型和数据交互达成共识”。

4. MCP 的核心实体:toolsresourcesprompts

现在我们来点名 MCP 的三位主角:工具、资源和提示词。

Tools:你早已熟悉的动作

你在第 4 模块已经接触过 tools:我们为工具定义了名称、描述和参数的 JSON Schema,然后模型通过 callTool 来调用它。从 MCP 的角度看,工具是一个有清晰契约的服务端操作:

  • 名称与描述(既服务于模型,也服务于 UX/发现);
  • 参数的 JSON Schema;
  • 结果结构的 JSON Schema 或描述;
  • 额外的元信息(例如与 Apps SDK 中特定 UI 组件的绑定)。

MCP 服务器至少必须能响应“列出工具”的请求,并能处理“调用工具”,返回结构化结果。

在我们的 Gift 助手教学应用里,已经有一个工具 suggest_gifts,它接受年龄、关系、预算和一些偏好,返回推荐的礼物列表。

MCP 服务器代码里的一个 TypeScript 草图可能长这样(伪代码/占位):

// 伪代码,非最终的 SDK API
const suggestGiftsTool = defineTool({
  name: "suggest_gifts",
  description: "根据收礼人的参数挑选礼物创意",
  inputSchema: z.object({
    age: z.number(),
    relation: z.enum(["friend", "partner", "parent"]),
    budgetUsd: z.number(),
  }),
  handler: async (input) => {
    // TODO: 你的业务逻辑
    return { items: [] };
  },
});

具体的签名我们会在后续讲解,这里只强调一个理念:工具不仅仅是一个 REST 端点,它是带有已声明模式的协议元素。

资源(resources):可按 ID/URI 访问的数据

MCP 中,资源(resources)用于描述可用的数据:文件、目录、数据库记录、Wiki 页面,甚至搜索索引结果。客户端可以:

  • 获取资源列表;
  • 按 ID/URI 读取具体资源;
  • 有时——在它们之上执行搜索。

与“做事”的 tools 不同,resources 通常是“存放东西”。例如,在 Gift App 中,你可以把商品目录建模为资源 gift_catalog,模型可以访问它以了解可用类别、筛选条件、价格区间等。

在代码里,概念上可能是这样:

const giftCatalogResource = defineResource({
  uri: "catalog://gifts",
  description: "可用于推荐的礼物目录",
  read: async () => {
    // 返回目录结构
    return { categories: [], priceRanges: [] };
  },
});

我们暂不深入 MCP 消息格式,但请记住:资源是可寻址的实体,MCP 服务器可以引用它们,客户端可以读取并把它们作为上下文的一部分。

Prompts:预制的提示词

MCP 语境下,Prompts 是服务器可提供给客户端的请求或指令模板。例如,你可以声明一个提示词 gift_followup,指示模型在调用工具之前,如何向用户追问关于收礼人的细节。

典型做法是:服务器给出提示词的名称、用途,有时还有参数。客户端可以请求提示词列表,选择需要的那个,并把它填入对模型的请求中。

这对 ChatGPT App 有什么价值?首先,它为不同客户端复用复杂提示词提供统一方式。其次,MCP 让这些提示词变得显式、受契约约束,而不是散落在代码角落的“隐形配置”。

Capabilities:声明你所支持的能力

最后是第四个元素——capabilities。它是一份声明:服务器说明自己支持哪些实体(tools、resources、prompts、通知等)以及具体实现了哪些方法。客户端据此不必猜测“能做什么、不能做什么”,而是能将自身行为与服务器能力对齐。

在实践中,ChatGPT 连接到你的 MCP 服务器时,会先完成“握手”,拿到 capabilities 列表,然后再说:“好的,把你的工具和资源列表给我看看。”

5. MCP 如何嵌入到你当前的 App

这些听起来有点抽象,但事实上你已经通过 Apps SDK 接触过 MCP 了。我们不妨先理清,它如何与您已在 Apps SDK 中写下的内容对齐?把刚刚介绍的实体,映射到你当前的 App 模板上。

回忆一下你在模板里已经实现的链路:

  1. 小部件通过 window.openai 或现成的 hooks,调用 callTool,传入工具名与参数。
  2. Apps SDK 在 ChatGPT 内部把这个请求转给 App 的服务端部分。
  3. 服务器执行工具并返回 ToolOutput,其中包含 structuredContentcontent_meta
  4. 小部件拿到 ToolOutput 并渲染 UI。

秘密在于,第 2–3 步是通过 MCP 对话完成的。你的 Next.js 模板包含一个端点(通常是 app/mcp/route.ts 或类似路径),它正是 MCP 服务器。它会:

  • 注册你的工具;
  • 通过 JSON Schema 描述它们;
  • 实现处理器;
  • 响应 ChatGPT 的 MCP 请求:list toolscall tool

也就是说,即便现在只是使用模板,你已经在“自动”使用 MCP 了:大部分协议魔法都被封装在 SDK 中。

第 6 模块的目标,是让你不再把 MCP 当作“神秘黑盒”,而是有意识地去设计它:

  • 新增并做工具的版本化;
  • 不仅用 tools,还要用 resources 与 prompts;
  • 阅读并理解 MCP 日志;
  • 在需要时,把 MCP 服务器从 Next.js 模板中拆出来独立运行(例如为某个 ML 模型提供的 Python 服务,或访问企业数据库的独立服务)。

6. 从不同角色看 MCP:产品 vs 开发

分别说说 MCP 对产品经理与工程师的价值。

MCP 面向产品

从产品视角看,MCP 让你的服务成为面向众多客户端的“可插拔模块”:ChatGPT、其他 LLM 客户端、IDE 插件、自研智能体。你只需把服务器的能力用 tools/resources/prompts 这套方式描述清楚,任何客户端都可以:

  • 自动发现你的服务;
  • 理解它能解决哪些问题;
  • 安全地调用所需操作。

在 ChatGPT App 的场景下,这也提升了你的应用被选中的概率:模型会利用你工具的元数据,来判断何时向用户推荐你的 App,以及如何正确展示它。

一句话概括:MCP 让你的服务成为生态中的标准“积木”,而不是为一两个客户端做的定制集成。

MCP 面向开发者

从工程视角看,MCP 是契约与协议。它回答了这些问题:

  • 我应该以什么格式声明一个工具?
  • 如何描述参数并返回结果?
  • 客户端如何知道我支持资源与提示词?
  • 网络上传输的 JSON 到底长什么样?

有了这样的协议,会更容易:

  • 用不同语言编写服务器(已有 TypeScript 与 Python 的官方 SDK);
  • 通过 MCP Inspector 或类似工具调试应用;
  • 在团队之间划分职责:一队做带数据与工具的 MCP 服务器,另一队做基于 Apps SDK 的小部件,第三队甚至可以在同一个 MCP 服务器之上构建他们的智能体。

7. 一个小实操视角:我们的第一个 MCP 服务器

本讲不深入消息格式和服务器实现的细节——那是后续内容。但为了让你提前知道要去往何处,看看一个最小化的 TypeScript MCP 服务器的整体结构是有帮助的。

在真实场景中,官方的 TypeScript MCP 库会提供用于创建服务器、注册 tools/resources/prompts 以及启动传输层(通常是 HTTP 或 SSE)的原语。

一个概念性伪示例可能是这样:

// 这是一个概念性示例,我们稍后再讲 SDK API
import { createServer } from "@modelcontextprotocol/sdk";

const server = createServer({
  name: "gift-genius",
  version: "1.0.0",
});

// 注册工具
server.tool("suggest_gifts", {
  description: "根据收礼人的偏好挑选礼物",
  inputSchema: {/* ... */},
  handler: async (input) => {
    // 你的逻辑
    return { items: [] };
  },
});

// 启动传输层(例如 HTTP)
server.listen(3001);

重要的是:这里没有任何关于 ChatGPT、Apps SDK 或你的具体前端的描述。MCP 服务器是自足的。它只是会响应 MCP 请求。ChatGPT App 只是能使用该服务器的一类客户端。

在本课程中,我们会继续沿用 Next.js 模板,其中 MCP 服务器作为项目的一部分存在,但这并非唯一选择。

8. 生态中的 MCP:Apps SDK、Agents SDK 与 ACP

为了不把 MCP 当成“只服务于 Apps SDK 的功能”,我们把它放进更大的图景里看。

首先,Apps SDK 直接基于 MCP,把它作为 ChatGPT 与外部服务之间的标准桥梁。官方文档强调:Apps SDK 可与任何 MCP 服务器协同工作。协议本身支持描述工具、返回结构化数据,并指定 UI 中的渲染组件。

其次,你会在单独模块中学习的 Agents SDK 也能连接到 MCP 服务器。这意味着同一个包含业务逻辑的 MCP 服务器可以被如下方式复用:

  • 作为你的 App 的一部分,在 ChatGPT 内部使用;
  • 作为独立智能体的后端,在你的产品后台或批处理模式中运行。

第三,用于购物与即时结账的 ACP(Agentic Commerce Protocol)在逻辑上也建构在 MCP 思路之上:模型与智能体会调用 commerce 工具,而这些工具同样按标准契约来描述。

因此,MCP 成为地基,其上才有 UI(Apps SDK)、智能体场景(Agents SDK)与商业闭环(ACP)。只要你对 MCP 足够熟悉,其他部分都会更清晰、更可预期。

注:从规范上讲,ACP 并不依赖MCP;但在实际实现中,ACP 的工具很可能会由模型通过 MCP 接口来调用。这两种思路高度契合,所以你大可拭目以待。

9. 实操前的几个小练习

在下一讲深入 MCP 消息格式之前,做两三个“脑内练习”会很有帮助,它能把你的思维从“典型的 REST”切换到“协议 + 契约”。

设想你的 Gift App 不只想被 ChatGPT 使用,还想被 VS Code 的 IDE 插件和公司内部的 Slack 助手使用。请用一句话描述他们都需要了解你的服务哪些内容。多半答案会是:“我们有一个名为 suggest_gifts 的工具,参数是……;还有一个礼物目录,通过某个资源可访问。”这正是 MCP 要形式化表达的内容。

也请尝试用两句话概括:

  • MCP 对你的 App 的产品而言是什么(提示:把功能“打包”给不同客户端的标准方式);
  • MCP 对开发者而言是什么(提示:带有清晰 tools/resources/prompts 原语的 JSON‑RPC 协议)。

如果你能顺畅地说出来——你已经走在熟练掌握 MCP 的半路上了。

把以上内容归结为一句话:MCP 不是又一个加在上层的 API,而是你的业务逻辑与 LLM 客户端之间的基础契约。接下来我们会走进协议内部:拆解 MCP 消息格式、握手/capabilities,并学会通过各类检查器观察流量,让这些原则不再停留在概念层,而成为可用的工作利器。

10. 关于 MCP 的常见错误与误区

错误 1:把 MCP 当成“我的 REST 之上的又一层 API”。
有时会有这种想法:“我已经有 REST 了,不如加个薄适配器,把 MCP 调用转成 REST 再转回来,然后就不管了。”形式上可行,但你往往会把旧 API 的怪异之处“拖”进 MCP:奇怪的类型、非结构化响应、没有明确的模式。随着时间推移,适配器会臃肿,MCP 的收益被稀释。更好的做法是把 MCP 当作主契约,而把旧的 REST 当内部实现细节(如果仍需要的话)。

错误 2:认为 MCP “只适用于 ChatGPT Apps”。
MCP 是面向任何 LLM 客户端的通用开放协议:ChatGPT、IDE 插件、自治智能体等。如果你只面向一个 App 来设计 MCP 服务器,就限制了未来的空间。更划算的思路是:从一开始就假设“其他客户端也能用这个服务器”,再把工具与资源设计得更通用些。

错误 3:忽视 JSON Schema,只“口头”描述参数。
即使 SDK 某些地方允许你传“任意 JSON”,也别偷懒——请写清楚参数与结果的模式。模型能否正确调用你的工具、自动补全与发现的质量、以及通过检查器调试的便利性,都直接取决于此。未描述或描述不佳的参数,直接通向神秘的 tool‑call 错误。

错误 4:把 MCP 当成“魔法传输层”,从不看日志。
一切顺利时,MCP 像是个“看不见的东西”,无需操心。问题是,一旦出故障,如果不了解 MCP 的结构,你就会一直猜:“是 Apps SDK 出问题?是模型?还是我的后端?”尽早养成查看 MCP 消息与日志的习惯,可以避免长时间的无效排障。

错误 5:在复杂流程中只用 REST,忽视 MCP 原语。
当你出现多步骤场景(找礼物 → 追问偏好 → 选择 → 下单)时,很容易想做“一个大 REST 端点”。在 ChatGPT Apps 语境中,这常会降低可控性:模型更难理解中间步骤,MCP 客户端也失去复用资源与提示词的机会。更好的方式是把功能拆解为若干个描述清晰的 tools/resources,用系统提示词与恰当的描述把它们编排起来。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION