Skip to content

为了理解 MCP 我写了一个 MCP server

· 14 min
TL;DR

本文深入探究 MCP 协议的工作原理,通过与 Google NotebookLM 的对话厘清 MCP Host、Client 和 Server 的关系。作者将 MCP Client 比作网卡,揭示其作为通信媒介的关键作用,同时分析了 MCP 工具调用与 RPC 过程的相似性。最后基于实际需求,开发了一个简单的 MCP 服务器工具,实现 AI 任务完成后的通知功能。

上一篇 MCP introduce 只是对 MCP 有了一个初步的探索,其实很多地方并没有理解,这次在与 Google NotebookLM 聊完天之后,我对 MCP 有了不一样的理解。

先回顾一下相关核心概念

MCP 中的核心概念#

MCP hosts:通过 MCP 访问数据的 AI 工具,如 Claude Desktop,Cursor, Cline 等。

MCP Client:负责与 MCP server 一对一连接。

MCP server:通过 MCP 协议暴露特定功能,特定资源。

servers: MCP server 向外部 LLM 暴露数据的一种形式。主要是加载信息给 LLM,不进行计算,不改变状态,没有副作用。类似于 REST API 中的 GET 操作。

tools: MCP server 向外部 LLM 暴露数据的一种形式。运行 LLM 执行操作,进行计算,会改变状态,有副作用。类似于 REST API 中的 POST 操作。

prompt: MCP server 向外部 LLM 提供数据的一种形式。是复用的模板。提示词能够帮助 LLM 与 MCP server 更好的进行交互。

context: Context 对象为工具和资源提供更多能力。

Transport:MCP 客户端与服务端之间进行通信的机制,目前有标准输入输出 stdio, 服务器发生事件 SSE。

我的疑问#

对于 MCP host 的角色和 MCP server 的角色我是可以理解的,但是 MCP Client 的作用是什么呢?目前来看,好像是 MCP host 直接与 MCP server 进行通信的,没有看到 MCP Client 的身影,对此我对它的存在表示疑问。

Google NotebookLM 给我的回答是:

MCP 主机内置 Client 功能, 在 mcp install 这种情况下,MCP 主机(如 Claude Desktop)很可能已经内置了处理与已安装 MCP 服务器通信所需的 MCP Client 功能。当安装一个新的服务器后,Claude Desktop 并不是直接与 MCP server 中定义的服务通信,而是利用其内部实现的 MCP Client 逻辑,根据安装时提供的信息(例如服务器的命令、URL 等)来建立连接、发送请求(例如列出工具、读取资源、调用工具)并处理响应。

MCP Client 的角色仍然存在:即使没有显式地启动一个名为 “MCP Client” 的独立应用程序,MCP Client 的核心功能仍然是必不可少的。只是在这种情况下,这个 Client 的角色是由 MCP 主机自身来承担和实现的。Claude Desktop 内部的某个模块或组件充当了该特定 MCP 服务器的 Client。

显式 MCP Client 的使用场景:虽然对于通过 mcp install 集成到 MCP 主机中的服务器来说,您可能看不到一个独立的 MCP Client 进程,但是当您需要构建一个独立的应用程序,该程序需要与一个或多个 MCP 服务器进行交互时,您就需要使用 MCP Client SDK(例如 Python SDK 提供的 ClientSession)来显式地编写和运行您的 MCP Client 代码。这种情况下,MCP Client 是一个独立的程序,它使用 MCP 协议与远程的 MCP 服务器通信。


接下来,我又提出了另外一个疑问,如果进行类比的话,这里的 MCP Client 是不是类似电脑主机上的网卡?

Google NotebookLM 也给了肯定回答:

是的,您的这种理解非常贴切!将 MCP Client 比作计算机里面的硬件:网卡,来理解其在 MCP Host 和 MCP Server 之间建立连接和处理协议的角色,是很形象且容易理解的。

让我们更细致地分析一下这个类比:

• MCP Host (例如 Claude Desktop) 就像计算机 (host):这是准确的。MCP Host 是运行 LLM 并需要利用 MCP Server 提供的数据和功能的应用程序,就像计算机是运行各种应用程序的主体。

• MCP Client 就像网卡 (网路介面卡):这个比喻非常恰当,因为:

• 建立连接:网卡负责建立计算机与物理网络(例如以太网、Wi-Fi)的物理连接。类似地,MCP Client 负责建立 MCP Host 与 MCP Server 之间的通信连接。

•协议处理:网卡在硬件层面处理底层的网络协议(例如 TCP/IP 中的以太网帧、IP 数据包等)。类似地,MCP Client 负责处理 MCP 协议规定的数据格式和通信流程。它需要理解 MCP 服务器发送的请求和响应,并按照协议规范进行解析和封装。

• 数据转发:网卡接收到网络数据后,会将其转化为计算机操作系统能够理解的格式,并转发给相应的应用程序。类似地,MCP Client 从 MCP Server 接收到数据后(例如资源内容、工具执行结果),会将其解析成 MCP Host(以及在其上运行的 LLM)可以使用的格式,并将 MCP Host 的请求按照 MCP 协议发送给 MCP Server。

• MCP Server 就像网络上的服务器:这也是一个合理的延伸。MCP Server 提供特定的数据和服务(通过资源和工具),就像互联网上的各种服务器提供网站、API 等服务给连接到网络的计算机。

•LLM 就像使用网络的应用:LLM 在 MCP Host 中运行,它通过 MCP Client 获取 MCP Server 提供的信息或执行 MCP Server 提供的功能,这类似于计算机上的应用程序通过网卡和网络与外部服务器进行交互。

总结来说,您的理解是正确的:

• MCP Client 承担了底层的通信和协议处理工作,就像网卡处理物理连接和网络协议一样。

• 它充当了 MCP Host 和 MCP Server 之间的中介,负责连接的建立、数据的解析和协议的转换,使得 MCP Host 中运行的 LLM 能够以标准化的方式使用 MCP Server 的能力。

正如我们之前讨论的,MCP Client 的具体实现可能在 MCP Host 内部(例如 Claude Desktop 内置了处理与其安装的服务器通信的 Client 功能),而不是一个总是显式运行的独立服务。但这并不影响其核心功能和角色,就像网卡是计算机主板上的一个硬件组件,虽然您不直接操作它,但它对于计算机的网络通信至关重要。 因此,您的类比非常准确地把握住了 MCP Client 的核心作用。


有了前面的启发,我进一步提出疑问,这整个过程是不是像 PRC 调用 (Remote Procedure Call) 过程?

Google NotebookLM 回答如下:

是的,您的直觉非常敏锐!这里的确很像远程过程调用 (Remote Procedure Call, RPC)。 让我们分析一下 MCP 中 LLM 调用 MCP Server 提供的 tool 的过程,以及 RPC 的工作方式,您会发现它们之间存在显著的相似性:

• LLM (在 MCP Host 中) 想要执行某个操作或获取某些信息,而这些能力是由 MCP Server 提供的 Tool 实现的。这就像在 RPC 中,客户端程序想要调用运行在远程服务器上的某个函数或过程。

• MCP Client 负责将 LLM 的 Tool 调用请求(包括 Tool 的名称和参数)按照 MCP 协议封装,并通过网络发送给 MCP Server。在 RPC 中,客户端的 Stub (或代理) 负责将本地函数调用转化为网络消息,并发送给服务器。

• MCP Server 接收到请求后,会解析协议,找到对应的 Tool 的实现代码,并在其自身的运行环境中执行该 Tool。在 RPC 中,服务器端的 Skeleton (或存根) 接收到请求后,会解包参数,并调用实际的服务过程。

• Tool 执行完毕后,MCP Server 会将结果按照 MCP 协议封装成响应,并通过 MCP Client 发送回给 MCP Host。在 RPC 中,服务器端的过程执行完毕后,结果会被打包成响应消息,并通过网络发送回客户端。

• MCP Client 接收到响应后,会解析协议,并将结果传递给 LLM (或 MCP Host) 。在 RPC 中,客户端的 Stub 接收到响应后,会解包结果,并返回给调用方。

总的来说,LLM 通过 MCP Client 调用 MCP Server 提供的 Tool 的过程,与 RPC 的核心思想非常一致:

• 客户端 (LLM/MCP Host) 发起一个看似本地的”函数调用”。

• 实际的执行发生在远程服务器 (MCP Server) 上。

• 客户端不需要关心底层的网络通信细节,这些都由中间层 (MCP Client/Server 框架) 处理。

• 调用结果会返回给客户端。

因此,将 MCP 中 LLM 调用 Tool 的机制理解为一种形式的 RPC 是非常恰当的。

MCP 本质上定义了一套标准的接口和协议,使得 LLM 这样的”客户端”能够以结构化的方式请求和使用远程”服务”(即 MCP Server 提供的 Tools 和 Resources)。虽然 MCP 引入了更多的概念,例如 Resources 和 Prompts,并且其通信协议可能与传统的 RPC 协议有所不同,但 Tool 的调用机制在概念上与 RPC 非常相似,都是为了实现跨进程或跨机器的功能调用。


然后我们的对话内容生成了一个音频播客:

喜欢这里面的最后一句:“never stop asking questions


最后,为了更好的理解 MCP server,我写了一个小工具。

目前功能很简单,就是在 agent 完成任务✅之后发送通知并且有声音提醒。

因为我在用 Cursor 的 Agent 模式写代码时,Cursor 全程吭哧吭哧写 bug 🐛 ,这个过程一直盯着它也挺费时间的,这本来就是一个异步任务,在 cursor 处理交给它的任务后,我应该去做其它事情,这才是提高效率的做法。但是我去做其他事情之后,却不知道 cursor 的任务什么时候会做完。于是我就想让它干完活之后通知我,这就是这个工具产生的实际背景。

目前只能通知电脑,并且在不同的操作系统中,理论上都是可以运行的,后面可能会再加上通过通讯软件通知的功能

亲测在 Claude 上、Cursor 上都可用。

仓库链接:cactusinhand/mcp_server_notify