我写过 MCP Server,却一直以为 MCP 只有 Tool

我很早就写过一个 GitLab MCP Server。

当时我找到官方 SDK,创建 Server,再用 TypeScript 和 Zod 注册了几个工具:

  • 获取 GitLab 项目列表
  • 按分支名搜索项目
  • 按项目名搜索项目

它后来也确实被 Agent 使用过。平时我还经常使用 Notion、Figma 等 MCP,所以我一直觉得自己"用过 MCP"。

但今天重新学习 MCP 的原理时,我才发现:我过去的实践虽然是真的,认知却不完整。

我一直把 Tool 当成了 MCP 的全部。

MCP 不只是 Tool

MCP 的全称是 Model Context Protocol,即模型上下文协议。

它解决的核心问题是:让支持 MCP 的应用能够按照统一协议发现和使用外部能力,而不需要为每个 Agent 单独设计一套工具接入方式。

MCP Server 可以暴露三类核心能力:

类型 作用 我的理解
Tool 执行操作 查询 GitLab 项目、创建 Issue、修改数据
Resource 提供可读取的数据 项目说明、仓库内容、当前用户可访问的资料
Prompt 提供可复用的提示模板 代码评审模板、项目分析模板、固定任务入口

我过去写的 GitLab MCP 只注册了 Tool,日常使用 MCP 时,我关注的也一直是 Agent 能调用哪些工具。因此在我的实际认知里,MCP 几乎等同于"为 Agent 统一接入工具的协议"。

直到今天我才知道,MCP Server 除了可以提供 Tool,还可以提供 Resource 和 Prompt。我并不是研究后认定 MCP 只有 Tool,而是过去的实践范围一直停留在 Tool,没有意识到协议还定义了另外两类能力。

目前我对 Resource 和 Prompt 还停留在概念理解,真正的使用场景与实现方式,留到后面的 MCP 实践中验证。

Host、Client 和 Server 到底分别是谁

学习过程中,另一个让我迷惑的词是 MCP Client。

我最初会把它理解成平时说的"客户端应用",于是产生了这样的认知:

MCP Server 运行在 MCP Client 里面。

这句话在某些本地运行场景下看起来很像事实,但它混淆了角色和进程的关系。

以 Codex 调用 GitLab MCP 为例,完整链路是:

text 复制代码
我
  → Codex(Host)
  → Codex 内部的 MCP Client
  → Transport
  → GitLab MCP Server
  → GitLab API

Host 是 MCP 官方架构中的角色。这里可以直接把它理解成承载并协调 Agent、MCP Client 和用户交互的应用,例如 Codex。

MCP Client 则是 Host 内负责连接某一个 MCP Server 的协议组件。它负责初始化连接、发现能力、发送 tools/call 请求和接收结果。

真正执行 GitLab 查询逻辑的是 GitLab MCP Server。Server 内部的 Tool 处理器再去请求 GitLab API。

因此,LLM 负责理解用户意图和选择能力,MCP Client 负责协议通信,MCP Server 负责执行对应处理器。它们不是同一层。

stdio 和 Streamable HTTP 改变的是连接方式

我原来认为"Server 运行在 Client 上",主要来自 stdio 的使用体验。

在 stdio 模式下,通常是 MCP Client 所在的应用启动本地 MCP Server 子进程,然后通过标准输入输出通信:

text 复制代码
Codex
  → MCP Client
  → 启动本地 GitLab MCP Server
  → stdin/stdout 通信

因此从进程生命周期看,本地 Server 的确可能由 Client 一侧启动和管理。

但在 Streamable HTTP 模式下,结构就不同了:

text 复制代码
Codex MCP Client
  → 连接 https://mcp.company.com
  → 已经独立部署的 GitLab MCP Server

远程 Server 由公司的部署系统负责启动和维护。Codex 内的 MCP Client 只负责连接它,不负责启动它。

两种方式改变的是 Transport 和部署拓扑,并没有改变 Client 与 Server 的职责。

Token 不应该进入 LLM 上下文

MCP 的信任边界不只是"能不能连接成功",还包括凭证到底经过哪些组件。

调用 GitLab API 时需要 Token,但 LLM 并不需要知道这个 Token。

理想链路应该是:

text 复制代码
LLM 看到:
- 用户问题
- Tool 描述
- Tool 参数结构
- 本次调用参数

LLM 看不到:
- GitLab Token
- Authorization 请求头
- 服务端环境变量

在 stdio 场景下,凭证可以通过 Server 的运行环境注入。

在远程 HTTP 场景下,访问凭证应通过标准的 Authorization: Bearer <token> 请求头传递,不能放进 URL 查询参数。

原因不只是"看起来不安全"。URL 可能进入浏览器历史、反向代理日志、访问日志或监控系统。即使使用 HTTPS,查询参数在到达代理或服务端并被解密后,仍可能被这些系统记录。

因此 Demo 中专门加入了一个错误场景:

js 复制代码
if (url.searchParams.has("token")) {
  throw new Error("access token 不得进入 URI query string");
}

而且这个校验必须发生在真正调用 GitLab API 之前。否则即使 MCP Server 最后报告失败,下游副作用也可能已经发生。

我用三个场景验证了这条边界

今天的 Demo 没有连接真实 GitLab,也没有读取真实凭证,而是用本地模拟验证三种情况。

运行方式:

bash 复制代码
node demo.mjs stdio
node demo.mjs http-safe
node demo.mjs http-unsafe

三个场景的结果分别是:

  1. stdio

    MCP Client 的 stdio transport 启动本地 Server,GitLab API 被调用一次。

  2. http-safe

    Server 已由公司部署系统启动,Client 使用 Authorization 请求头连接,GitLab API 被调用一次。

  3. http-unsafe

    Token 被故意放入 URL 查询参数,Server 在下游 API 调用前拒绝请求,GitLab API 调用次数为零。

三个场景还会共同检查:Token 没有进入模拟的 LLM 上下文。

完整 Demo:

2026-08-04 MCP 原理与信任边界实验

这个 Demo 是一个确定性的本地模型,不是生产级 MCP SDK 示例。它的目的不是教我复制框架代码,而是把 Client、Server、Transport、API 与凭证边界真正跑清楚。

MCP、API、Tool、Skill 和 Plugin 不是一回事

以 GitLab 场景为例,这几个概念可以这样区分:

概念 GitLab 场景中的职责
API GitLab 对外提供的 HTTP 接口
Tool Agent 可以调用的"按项目名查询"等具体能力
MCP Client 发现和调用 Server 能力的统一协议
Skill 告诉 Agent 什么时候调用、按什么流程处理的说明
Plugin 把 Skill、MCP Server 等能力进行安装、分发和版本管理的载体

Skill 可以定义流程,但它本身不会自动产生 GitLab 数据修改。

真正的副作用通常由 MCP Server 中的 Tool 处理器调用 GitLab API 产生。Plugin 则可以把 Skill 和 MCP Server 一起交付,但它也不等于 MCP。

我今天真正修正的认知

我并不是第一次使用 MCP,而是第一次把自己过去的 MCP 实践放回完整架构中理解。

过去我的实现只有 Tool,所以我以为 Tool 就是 MCP;过去 stdio 会启动本地进程,所以我以为 Server 运行在 Client 中;过去我知道 Token 应该放在环境变量里,但没有真正把 LLM、Client、Server 和 API 之间的凭证边界解释清楚。

今天我确认了:

  • MCP Server 不只可以暴露 Tool,还可以暴露 Resource 和 Prompt。
  • Host、MCP Client、MCP Server 是不同角色。
  • stdio 与 Streamable HTTP 改变的是连接和部署方式,不改变角色职责。
  • LLM 负责理解和选择,不应该接触登录凭证。
  • 凭证校验必须发生在产生下游副作用之前。
  • MCP、API、Tool、Skill 和 Plugin 各自解决不同问题。

下一步不是继续背概念,而是实现并真实接入一次 MCP Server:完成能力发现与调用,区分只读和写入权限,并观察调用失败时各层如何返回结果。

官方参考:

相关推荐
天国梦2 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能
阿里云云原生2 小时前
可用性从 99.9% 跃升至 99.995%:畅捷通如何用 AI 重塑运维底座?
运维·网络·人工智能
ZhengEnCi2 小时前
MoE(Mixture of Experts,混合专家模型)深度解析:从路由机制到专家专业化的迷思
人工智能
shxjnpl2 小时前
Qwen3-ASR 从 PyTorch 迁移到 vLLM:一次信创环境下的推理路径改造实录
人工智能·pytorch·vllm
阿童木写作3 小时前
Python实现Temu图片批量翻译自动化教程
运维·人工智能·python·自动化
冬奇Lab4 小时前
代码库知识库系列(06):把调用图编码进 Embedding——结构增强有效,但不够
人工智能
冬奇Lab4 小时前
开源项目第175期:Buzz — Jack Dorsey 的 Block 用 Nostr 重新定义团队协作,AI Agent 拥有自己的加密身份
人工智能·开源·资讯
AI分享猿4 小时前
游戏原画与建筑灵感:AI图像生成如何服务前期设计
人工智能·游戏
字节跳动视频云技术团队4 小时前
为什么 AI 视频,需要“懂生成”的画质增强
人工智能