模型上下文协议(MCP),以及在Go语言中实现MCP服务器的注意事项
关于在 GO 中实现 MCP 规范的长文解读
这里我们对**模型上下文协议(MCP)**进行了描述,简要说明了如何用Go语言实现一个MCP服务器,包括消息结构和协议规范。
模型上下文协议(MCP)概述
**模型上下文协议(MCP)**是一个开放、标准化的框架 (由Anthropic于2024年底引入) 用于将AI语言模型连接到外部数据源、工具和系统。其目标是通过提供一个通用接口来解决“N×M集成”问题,例如在不同应用程序中读取文件、执行函数(工具)和使用上下文提示。MCP不是专有或内部协议;它是一个开放标准,具有官方规范和开源参考实现。事实上,主要的AI提供商(包括OpenAI和Google DeepMind)在MCP推出后宣布支持MCP,这表明它旨在成为一个广泛采用的标准,而不是特定供应商的解决方案。
MCP的目的和架构
MCP旨在标准化应用程序如何向LLMs提供上下文——常用的类比是“AI应用的USB-C端口”。通过定义一个通用协议,MCP使AI助手和工具能够无缝地与数据库、文件系统、API和其他资源进行交互,而无需定制的一次性集成。这有助于语言模型通过安全访问所需数据,生成更相关、更及时的响应。
架构: MCP遵循客户端-服务器模型,具有明确的角色划分:
- MCP主机: 管理连接的父应用程序(例如聊天客户端或IDE),其中包含一个或多个MCP客户端(连接器)。
- MCP客户端: 在主机内部的一个连接器实例,它与MCP服务器建立一对一的会话。客户端处理会话生命周期、路由消息并执行任何用户权限或安全策略。
- MCP服务器: 一个轻量级服务,通过MCP协议公开特定功能(访问某些数据或函数)。每个服务器可能封装一个数据源(文件、数据库、API等)或工具。多个服务器可以并行运行,每个服务器提供不同的集成。
- 数据源/服务: 服务器实际交互的资源——这可以包括本地文件和数据库或远程服务(Web API、SaaS应用等)。MCP服务器充当这些资源的适配器,确保LLM仅通过标准化协议访问数据。
这种设计灵感来源于IDE世界中的语言服务器协议(LSP)。就像LSP允许任何编辑器通过通用协议支持任何编程语言一样,MCP允许任何AI应用程序连接到任何使用MCP的数据/工具集成。这种解耦意味着AI工具开发人员只需编写一次MCP服务器,就可以与许多AI客户端配合使用,而AI应用程序开发人员只需插入一个MCP服务器即可添加新的集成,避免了定制的集成代码。
协议和消息结构
通信: MCP通信基于使用JSON-RPC 2.0消息的持久、有状态会话。所有请求和响应都符合JSON-RPC的格式(包含"jsonrpc": "2.0"
字段、方法名、参数和相关ID)。客户端或服务器任一方都可以发送请求或通知,实现双向交互。一个MCP会话通常以握手开始:
- 客户端以一个**
initialize
**请求开始,提出协议版本并宣传其能力(支持的功能)。例如,客户端可能表明它可以处理服务器驱动的“采样”请求或提供某些文件访问的根目录。服务器以它支持的协议版本和能力进行响应,最终确定此会话中启用的功能(MCP使用与LSP中可选功能类似的特性协商系统)。如果关键功能或版本不兼容,连接将优雅地中止。 - 在达成一致后,客户端发送一个**
initialized
**通知以标记准备就绪。之后,正常操作可以继续。会话保持打开状态,用于持续交换JSON-RPC消息,直到一方发出关闭指令。
传输: MCP不强制使用单一传输方式——它可以在任何能承载JSON文本的通道上运行。通常,MCP服务器作为子进程运行,并通过STDIO(stdin/stdout管道)进行通信,用于本地集成。这类似于语言服务器的操作,对于本地工具来说非常方便(主机可以启动服务器进程并传输消息)。另外,MCP服务器也可以作为独立服务运行,通过HTTP访问。MCP规范定义了一个流式HTTP传输方式,其中服务器暴露一个HTTP端点用于JSON-RPC调用(客户端发送POST请求,服务器可以通过Server-Sent Events(SSE)对长期运行的操作进行响应或流式传输结果)。无论哪种方式,消息都是UTF-8 JSON行,协议支持流式响应和服务器发起的消息(HTTP+SSE方式允许服务器异步推送通知或部分结果)。安全指南建议本地服务器绑定到localhost并验证Origin
头以防止不必要的远程访问,远程服务器应使用适当的认证(如令牌或OAuth流程)。
消息格式: MCP利用JSON-RPC的三种消息类型:请求、响应和通知。请求包含一个id
、一个method
字符串和(可选的)params
(通常是参数的JSON对象)。接收方必须用相应的响应(包含匹配的id
)进行回复,响应中包含result
或error
对象。通知是单向消息,包含method
和params
但没有id
(因此不会得到响应)。MCP在基础JSON-RPC之上施加了一些规则(例如,id
必须非空且在会话中不能重复)以保持清晰。
会话和状态: 连接被认为是状态化的——客户端和服务器维护彼此能力的上下文,可能还维护一些会话状态(如对更改的订阅、正在进行的操作等)。还有定义良好的优雅关闭程序(例如,客户端可以发送关闭请求或直接关闭传输;服务器应处理清理,双方都实现超时处理以应对挂起的操作)。错误处理遵循JSON-RPC惯例(错误响应包含代码和消息),规范定义了某些条件的标准错误代码(例如,权限被拒绝、工具未找到等)。MCP还提供了工具来处理跨切面的问题:例如,内置了进度更新通知、长运行请求的取消(CancelledNotification
)、日志/调试消息和配置更改通知。这些有助于管理长时间或复杂的交互(客户端可以取消正在进行的工具调用,或服务器可以向客户端发送警告日志等)。
MCP的功能和操作
初始化后,MCP会话使上下文和命令的交换以结构化的方式进行。MCP的核心服务器端功能包括提示、资源和工具(服务器在初始化时声明是否支持这些功能):
-
提示: 服务器可以提供给客户端的预定义提示模板或指令。这些通常是用户触发的助手(用户明确选择一个提示插入到对话中,例如通过UI中的斜杠命令)。MCP提供了列出可用提示和获取提示内容的方法。例如,客户端可以调用
prompts/list
来获取提示模板列表(每个模板都有名称、描述和可选参数)。要获取提示,客户端使用prompts/get
并提供提示名称和任何参数值;服务器随后返回提示内容(通常是一组消息,客户端将这些消息注入到LLM的上下文中)。提示允许用户按需重用复杂的指令或工作流程(例如,“代码审查模板”)。服务器会声明一个prompts
能力(可选子功能如listChanged
,用于通知客户端提示集是否动态变化)。 -
资源: 提供模型上下文的结构化数据或内容。资源通常是文件、文档、数据库条目等——AI助手可能读取或引用的信息。MCP标准化了资源的识别和传输方式:每个资源都有一个URI标识符(例如
file:///path/to/file.txt
或数据库的自定义方案)。客户端可以通过resources/list
查询可用资源(服务器可能暴露目录树、最近文档列表等)。服务器的响应包括每个资源的元数据(URI、名称、类型、描述等)。然后客户端可以通过resources/read
请求特定资源的内容,传递URI。服务器回复资源内容,可能是文本(对于文件)或结构化数据(MCP支持不同的内容类型,如文本、JSON、二进制等,使用MIME类型)。还支持资源模板(通过模板URI标识的参数化资源,客户端可以填充,例如数据库查询中用户提供的参数)。如果启用,服务器可以在资源更改时发送通知(例如notifications/resources/updated
)或允许客户端订阅资源更改(resources/subscribe
)。在MCP的设计中,资源是由应用程序控制的上下文:通常由主机应用程序(客户端)决定将哪些资源内容实际注入到模型的提示中(通常在用户确认后或基于UI上下文)。 -
工具: 服务器暴露的可执行函数或操作,供模型调用。工具代表AI可以执行的操作——例如调用外部API、运行数据库查询、发送电子邮件或修改文件。每个工具都有名称和输入(和可选输出)参数的JSON模式,因此AI(或客户端)知道预期的参数。工具通常是由模型控制的:想法是语言模型(代理)决定何时以及是否在对话中使用工具以满足用户请求。然而,出于安全考虑,人类用户或主机应用程序可能会调解工具使用(例如,要求确认点击)。在MCP中使用工具涉及两个主要操作:列出和调用。客户端可以调用
tools/list
以获取可用工具及其模式。例如,服务器可能会列出一个工具get_weather
,并提供描述和需要“location”字符串的输入模式。然后,当模型决定使用工具(或用户调用它)时,客户端发送一个tools/call
请求,包含工具名称和参数的JSON对象。服务器执行该函数并返回结果,通常作为result.content
字段,其中可以包含文本或结构化数据(MCP支持返回多个内容部分,例如文本加图片等,尽管文本较为常见)。一个简单的例子:调用get_weather
工具可能会返回一个文本负载,如“纽约当前天气:72°F,部分多云”,作为助手展示的内容。工具也可以指示错误(响应中包含isError
标志或错误对象,如果发生错误)。与提示和资源一样,tools
能力可以有一个可选的listChanged
标志,用于在运行时通知可用工具发生变化(例如,动态加载/卸载插件)。
除了上述服务器提供的功能外,MCP还定义了客户端提供的功能(如果客户端支持,服务器可以利用这些功能)。这些包括采样、根目录和引导:
-
采样允许服务器请求客户端(及其LLM)在会话中执行模型推理。例如,服务器可以通过发送一个
sampling/request
请求来启动一个LLM调用(可能是为了继续一个推理链或总结某些内容)——客户端随后会提示模型并返回结果。这使得代理行为成为可能,服务器可以驱动AI协助其自身的子任务。(所有此类操作都需用户批准和策略——例如,用户可能需要同意让服务器触发模型以进行额外查询。) -
根目录允许服务器询问或操作某些允许的文件系统或URI根目录。客户端可以通过
roots/list
提供服务器被允许访问的“根”目录/URI列表。这是一个安全功能,确保服务器知道边界(例如,它可以读取哪些文件夹树)。 -
引导允许服务器在需要时请求客户端从用户那里获取更多信息。例如,如果一个工具需要一个未提供的信息片段,服务器可以发送一个引导请求,客户端(UI)会将其转换为用户提示(“X集成需要您的API密钥,请输入它”)。这样,服务器可以通过客户端交互式地收集输入。
这些功能都是可选的,并在初始化时进行协商。MCP的一个关键设计方面是能力协商在初始化期间发生——客户端和服务器会宣传它们支持的上述功能,因此双方都知道会话中可用的操作。例如,如果服务器没有声明tools
能力,客户端将不会尝试与它进行任何tools/list
或tools/call
操作。这种可扩展性意味着MCP可以随着新功能的引入而不断发展,同时保持向后兼容性(不支持的方法在未协商时将不会被使用)。
实现、SDK和构建MCP服务器(尤其是Go语言)
官方规范与文档: 权威的MCP规范是公开可用的,包括所有消息类型的正式模式。它由Model Context Protocol网站和GitHub维护。规范以TypeScript模式文件(以及对应的JSON Schema)定义,精确记录了所有请求、响应和结构。文档网站(modelcontextprotocol.io)提供了指南、常见问题解答和每个功能和消息类型的详细分解,以及一个“MCP Inspector”工具用于交互式调试。虽然MCP目前还不是IETF或ISO标准,但它作为开放标准开发,有社区输入,并使用熟悉的RFC 2119术语来定义要求。它是一个不断演进的协议(版本以日期标记;例如,2025-06-18是最近一次修订),并有版本管理政策来管理变更。
参考实现: 在引入MCP时,Anthropic开源了多个MCP服务器连接器和SDK。有一个GitHub组织**modelcontextprotocol
托管规范和多个仓库。值得注意的是,一个“servers”仓库包含一组为常见服务和数据源构建的预装MCP服务器实现。这些作为参考集成,通常可以直接使用或作为自定义服务器的模板。例如,官方仓库包括Google Drive**(Google Drive中的文件访问和搜索)、Slack(工作区消息和频道内容)、GitHub/Git(代码仓库上下文)、PostgreSQL(带模式信息的只读数据库查询)、Google Maps(位置和路线API)、Puppeteer(网页浏览和抓取)等服务器。通过安装或运行这些服务器,像Claude或Cursor这样的AI应用可以立即获得这些集成。还有一个由社区驱动的MCP注册服务(用Go语言开源),用于索引可用服务器,许多第三方贡献将MCP扩展到各种领域(从CRM到区块链数据)。
SDK和库: 为了便于构建自己的MCP服务器/客户端,有多个语言的官方SDK。截至2025年,该项目提供了TypeScript/Node、Python、Java(和Kotlin)、C#(与微软合作开发)、Ruby(与Shopify合作)、Swift等语言的SDK。这些库处理协议的底层实现——例如管理JSON-RPC传输、实现规范模式并提供注册工具或提供资源的辅助API。例如,TypeScript SDK可用于快速编写Node.js服务器,Python SDK允许在Python应用中集成MCP。SDK方法意味着开发者不需要手动构建JSON-RPC消息或实现完整的状态机;相反,他们只需调用高级方法发送请求或发布能力。
Go语言实现: Go由于其性能和并发优势(适合处理多个同时请求),已成为MCP服务器的热门选择。现在有一个官方Go SDK,由Google的Go团队合作维护。(该SDK于2025年4月左右宣布,第一个稳定版本计划于2025年8月发布。)Go SDK提供了一个mcp
包用于构建客户端/服务器,以及一个jsonschema
辅助工具用于工具模式。使用Go SDK,开发者只需几次调用即可创建一个MCP服务器。例如,可以使用名称和版本实例化一个新服务器,然后通过AddTool
添加工具,提供工具定义(名称、描述、输入模式)以及一个Go处理函数,当该工具被调用时执行。SDK负责在协议中暴露该工具(在tools/list
中宣传并处理tools/call
请求)。类似地,可以使用类似的API公开资源或提示。最后,运行服务器——例如,server.Run(ctx, mcp.NewStdioTransport())
将开始通过stdio处理JSON-RPC消息,直到客户端断开连接。在客户端方面,Go SDK可以启动一个子进程并通过mcp.NewCommandTransport(exec.Command("myserver"))
连接,然后客户端可以调用session.CallTool(ctx, params)
以调用工具并在Go代码中轻松获取结果。
示例: 官方Go SDK文档展示了一个简单的“问候”服务器。服务器注册了一个名为
greet
的工具,该工具接受一个名称并返回问候字符串。客户端随后通过名称调用该工具并打印结果。这说明了基本模式:定义工具 -> 客户端调用工具 -> 获取结果。在底层,这对应于JSON-RPC消息("method": "tools/call", params: {"name": "greet", ...}
和包含result.content
文本的响应),如MCP规范所定义。
在官方Go SDK发布之前,社区创建了自己的Go库。特别值得一提的是,Ed Zynda的**mcp-go
项目(mark3labs/mcp-go)被广泛使用,并影响了官方SDK的设计。另一个库,mcp-golang
**由Metoro提供,实现了Go语言的实现和API(Elton Minetto在2025年初的Dev社区博客文章使用了这个库)。这些社区SDK让Go开发者可以早期尝试MCP——例如,一个教程展示了如何使用Metoro的mcp-golang
库构建一个MCP服务器,该服务器通过暴露一个“zipcode”工具来查找巴西邮政编码(CEP)。在该示例中,Go服务器注册了一个函数,该函数调用一个外部API以从ZIP码查找地址,并返回文本结果——允许AI助手通过MCP按需获取地址信息。另一个指南演示了如何使用mark3labs的mcp-go
SDK将自定义的内存数据库(DiceDB)封装为MCP服务器:它定义了一个ping
工具以检查数据库连接性,以及其他用于数据操作的工具。这些示例突显了创建MCP集成的简便性:大部分代码只是业务逻辑(API调用、数据库查询等),而SDK处理JSON-RPC的连接。
使用 Go 构建 MCP 服务器(教程亮点)
为了概述这个过程,这里是一个使用 Go SDK 或类似库的典型流程:
-
设置服务器: 使用基本信息(名称、版本和声明支持的功能)初始化一个新的服务器实例。例如,在 Go 中:
server := mcp.NewServer("MyServer", "1.0.0", nil)
将创建一个默认支持核心协议功能的服务器。你可以通过选项启用特定功能(如提示语/资源/工具),或者通过注册这些功能(添加工具或资源意味着启用该功能)来实现。 -
注册功能: 添加你希望暴露的功能:
- 如果要暴露 工具,定义每个工具的模式和处理程序。例如,使用 Go SDK 的
AddTool
:提供一个mcp.Tool{Name: "...", Description: "..."}
和一个处理函数,该函数接收调用请求并返回结果(可能包括文本或其他内容)。SDK 会根据处理函数的参数类型自动生成 JSON Schema(或者你可以手动指定)。 - 如果要暴露 资源,你可能会使用 API 注册资源列表或提供一个读取内容的回调。例如,在 Python SDK 中,你可以继承 ResourceProvider;在 Go 中,SDK 正在不断发展,但你可能会提供用于列出和读取资源的函数。每个资源应具有稳定的 URI。
- 如果要暴露 提示语,定义提示语模板(可以是静态文件或字符串),并使用名称和可选参数进行注册。服务器会将其广告出去,以便客户端可以获取并显示给用户。
- 如果要暴露 工具,定义每个工具的模式和处理程序。例如,使用 Go SDK 的
-
实现传输: 决定服务器如何运行。对于本地使用,最简单的是 stdio – 例如,在 Go 中,
server.Run(ctx, mcp.NewStdioTransport())
将开始从 stdin 读取 JSON-RPC。如果服务器需要联网,你可以实现一个 HTTP 处理程序,使用 Go SDK 接收通过 HTTP 的 JSON-RPC(官方 Go SDK 可能很快会提供 HTTP/SSE 传输的辅助工具)。 -
客户端测试: 你可以使用兼容 MCP 的客户端测试服务器。例如,Anthropic 的 Claude 2(桌面版 Claude)支持加载本地 MCP 服务器;你可以配置 Claude 启动或连接到你的服务器二进制文件。还有一个名为
mcp-cli
的 CLI 工具和一个名为 MCP Inspector 的 GUI 工具,用于在没有完整 AI 客户端的情况下测试服务器 – 这些工具会向你的服务器发送 MCP 请求并显示结果,有助于调试。 -
安全与权限: 在构建服务器时,考虑认证和权限范围。对于本地服务器,主机可能以特定的 OS 权限运行它,或通过环境变量提供 API 密钥。对于远程服务器,使用认证头或 OAuth 流程。MCP 包含针对 HTTP 传输的授权规范(服务器可以要求令牌,客户端可以发送它)。始终确保服务器仅访问用户允许的数据(例如,尊重客户端提供的根目录,不要在其他地方泄露数据) – MCP 指南强调用户同意、数据隐私和工具安全性是基本原则。
总而言之,MCP 是一种正式但灵活的协议,用于连接大型语言模型(LLM)与外部世界。它 不是 与某家公司绑定的内部 API,而是一个正在被广泛采用的开放标准,并拥有丰富的集成生态系统。该协议定义了清晰的消息结构(基于 JSON-RPC)和一组操作(如提示语、工具、资源等的方法),任何符合规范的客户端/服务器都可以实现。官方文档和规范已发布,众多 SDK、库和示例服务器(包括 Go)使得实现更加容易。通过使用 MCP,开发者可以构建 AI 功能的应用程序,安全地利用现有数据和服务,而无需为每个新模型或数据集重新发明集成逻辑。
有用的链接
- https://www.anthropic.com/news/model-context-protocol
- https://modelcontextprotocol.io/introduction
- https://github.com/modelcontextprotocol/go-sdk - Model Context Protocol 服务器和客户端的官方 Go SDK。与 Google 联合维护。