我们用Go在90分钟内构建了一个MCP服务器
我们花了 90 分钟,用 Go 构建了一个 MCP Server

每个教程都在讲 TypeScript。而我们想要的,是一个二进制文件,而不是 node_modules。
Model Context Protocol 已经成为将 AI 模型连接到真实系统的默认方式。到目前为止,几乎所有指南都假设你使用 TypeScript 来编写。
这个假设给团队带来的成本,比表面看起来更高。它意味着每台运行服务器的机器上都要有 Node 运行时;意味着你必须审计一整棵依赖树;也意味着部署方式与你后端其余部分不匹配。
我们的大部分基础设施都是用 Go 构建的。于是我们花了一个下午去搞清楚:用 Go 写 MCP Server,到底是一个真实可行的选项,还是一种新鲜玩物。结果我们花了九十分钟,就让一个能正常工作的服务器与客户端对上了话。以下就是我们的收获。
MCP Server 到底是什么
抛开术语,这个概念本身并不复杂。
MCP Server 是一个程序,它会公布一份清单,列出自己能做的事情。模型连接到它,读取这份清单,然后请求服务器执行其中一项。服务器执行后返回结果。
从概念层面看,这就是整个协议。
→ Tools 是模型可以调用的操作。查询数据库。调用内部 API。读取文件。
→ Resources 是模型可以拉取的上下文片段。文档、记录、日志。
→ Prompts 是服务器可以返回给模型的可复用指令模板。
模型永远不会直接接触你的系统。它发送一个结构化请求,由你的服务器决定如何处理。正是这个边界让 MCP 值得使用,也正是它,让编写服务器所用的语言变得重要。
为什么我们选择 Go
三个原因,都很实际。
→ 单一二进制文件。用 Go 编写的 MCP Server 编译成单一文件,没有任何运行时依赖。你把它复制到机器上就能运行。对于任何要交付到客户环境、或驻留在客户网络内部的东西来说,这直接消除了一整类支持工单。
→ 并发才是真正的工作负载。MCP Server 的一生都在处理重叠的请求,每个请求都在等待数据库、API 或文件系统。Goroutines 处理这种模式,不需要其他语言所要求的那一堆异步管道机制。
→ 它契合技术栈的其余部分。我们的后端服务本来就是用 Go 写的。共享同样的日志、同样的错误处理、同样的部署流水线,比任何按语言区分的基准测试都更有价值。
九十分钟,如实交代
整个构建分为四个阶段,各阶段的耗时并不均匀。
第一阶段,大约十五分钟。项目搭建和传输方式。MCP Server 在本机使用时通过标准输入输出通信,远程使用时通过 HTTP。我们从本机传输开始,因为这是通向可测试状态的最短路径。
第二阶段,大约二十分钟。定义第一个工具。大部分思考都发生在这里。一个工具就是一个名称、一段描述和一个描述其输入的 schema。描述不是文档。它是模型决定是否调用你的工具时唯一会读取的东西,所以它干的是实打实的活。
记住我,以便更快登录
工具定义在协议层面上看起来像这样:
{
"name": "get_contract_status",
"description": "Returns the current audit status for a
deployed contract address",
"inputSchema": {
"type": "object",
"properties": {
"address": { "type": "string" }
},
"required": ["address"]
}
}
第三阶段,大约三十分钟。编写 handler。这就是普通的 Go 代码。解析参数,干活,返回结果。其中没有任何 AI 特有的东西,而这正是关键。
第四阶段,大约二十五分钟。连接客户端,修复没跑通的地方。下面会详述。
各个部分如何拼在一起
+----------------+
| AI Model |
+--------+-------+
|
| 1. asks: what can you do?
| 2. calls: run this tool
v
+--------------------------------+
| MCP SERVER (Go) |
| |
| +------------------------+ |
| | Tool registry | | names, descriptions,
| +-----------+------------+ | schemas
| | |
| v |
| +------------------------+ |
| | Handler | | validates input,
| +-----------+------------+ | runs the work
| | |
+---------------+----------------+
|
v
+--------------------------------+
| Your real systems |
| DB / API / files / RPC |
+--------------------------------+
模型永远不会越过底部边界。进入你系统的每一条路径,都要经过你编写、且可以审计的 handler。这是值得保护的安全属性。
四件消耗我们时间的事
→ 模糊的工具描述会被忽略。我们的第一条描述写的是“获取合约数据”。模型从未调用过它。把它重写成准确说明输入什么、输出什么之后,问题立刻解决了。把描述当作指令,而不是标签。
→ 往 stdout 打日志会毁掉一切。当传输方式是标准输入输出时,每一行多余的 print 语句都会污染协议流。日志要写到 stderr 或文件。这是最常见的失败原因,而且它产生的错误非常令人困惑。
→ Schema 必须严格。宽松的 schema 会招致格式错误的参数。把必填字段标为必填。约束类型。模型会发送 schema 允许的任何内容。
→ 错误应该被返回,而不是被抛出。执行失败的工具应该返回一条清晰的错误消息,让模型可以读取并作出反应。服务器因为坏输入而崩溃,只会让会话直接结束。
什么时候 Go 是正确选择,什么时候不是
当服务器要交付到自有基础设施之外、要贴近现有 Go 服务部署、或者要针对内部系统处理高并发负载时,Go 是更好的选择。
对于原型开发、已经身处 Node 生态的团队,以及主要封装 Web API 的服务器来说,TypeScript 依然是更快的选择。它的生态更大,示例也更容易找到。
坦率的总结是:这是一个部署决策,而不是性能决策。选择让服务器在它需要运行的地方最容易运行的语言。
这改变了什么
MCP 有意思的地方不在于协议本身,而在于模型与生产系统之间的边界,如今已经变成你可以刻意设计的东西:一个 schema、一个 handler、一份清晰的允许操作清单。
这对任何构建过 API 的人来说,都是熟悉的样子。它也应该用同样的纪律来构建:经过验证的输入、最小权限、审计日志,以及没有任何一条进入系统的路径能绕过被审查过的代码。
九十分钟就能让你得到一个能工作的服务器。真正的工程,体现在此后的每一件事里。
正在构建必须对接生产系统的 Agent 基础设施?
Ancilar 构建并审查 AI Agent 与真实基础设施之间的集成层,包括 MCP Server、工具边界,以及保障它们安全的权限设计。如果你正在把 Agent 从演示推向生产环境,我们可以帮你第一次就把边界做对。
通过 ancilar.com 联系我们
- 原文链接: medium.com/@ancilartech/...
- 鸿途知科网 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
鸿途知科网
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。