来源:互联网 更新时间:2026-06-23 13:56
快速掌握Go语言开发MCP Server,从入门到实践。
核心内容:

好,不绕弯子,假设你对MCP(Model Context Protocol)的背景已经心里有数。目前Go生态里有两款比较知名的MCP开发库:一个是mark3labs/mcp-go[1],另一个是metoro-io/mcp-golang[2]。两个用起来都很顺手,这次咱们按star数量选第一个来做演示。
mark3labs/mcp-go这个库提供了丰富的示例代码,而且README里已经把每种MCP Tool类型的写法都列出来了,算是很贴心的入门指南。
MCP支持SSE和标准输入输出两种通信方式。平时在自己机器上开发测试,标准输入输出(stdio)是最常见的用法:
// Create a basic server
s := server.NewMCPServer(
"My Server", // Server name
"1.0.0", // Version
)
// Start the server using stdio
if err := server.ServeStdio(s); err != nil {
log.Fatalf("Server error: %v", err)
}
几行代码就能跑起一个MCP服务,没什么复杂的。
资源是你向LLM暴露数据的方式。它们可以来自任何地方:文件、API响应、数据库查询、系统信息等等。资源分两种:
下面是一个静态资源的例子——暴露一个README文件:
// Static resource example - exposing a README file
resource := mcp.NewResource(
"docs://readme",
"Project README",
mcp.WithResourceDescription("The project's README file"),
mcp.WithMIMEType("text/markdown"),
)
// Add resource with its handler
s.AddResource(resource, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
content, err := os.ReadFile("README.md")
if err != nil {
return nil, err
}
return []mcp.ResourceContents{
mcp.TextResourceContents{
URI: "docs://readme",
MIMEType: "text/markdown",
Text: string(content),
},
}, nil
})
看到没?定义资源的时候指定一个URI和MIME类型,再写一个handler读取真实数据,一个数据暴露通道就打通了。
工具让LLM通过你的服务器执行操作。和资源不同,工具预期会进行实际的运算并产生副作用——你可以把它想象成REST API里的POST端点。下面是一个简单的算术工具:
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("Perform basic arithmetic calculations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Description("The arithmetic operation to perform"),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x",
mcp.Required(),
mcp.Description("First number"),
),
mcp.WithNumber("y",
mcp.Required(),
mcp.Description("Second number"),
),
)
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
op := request.Params.Arguments["operation"].(string)
x := request.Params.Arguments["x"].(float64)
y := request.Params.Arguments["y"].(float64)
var result float64
switch op {
case "add":
result = x + y
case "subtract":
result = x - y
case "multiply":
result = x * y
case "divide":
if y == 0 {
return nil, errors.New("Division by zero is not allowed")
}
result = x / y
}
return mcp.FormatNumberResult(result), nil
})
工具的用途远不止计算,它可以做很多事情:
每个工具设计时都应该注意:
提示(Prompt)是预定义的模板,LLM会按模板和用户进行交互。下面是一个问候提示的例子,它需要一个名字参数,然后返回一段问候语:
// Simple greeting prompt
s.AddPrompt(mcp.NewPrompt("greeting",
mcp.WithPromptDescription("A friendly greeting prompt"),
mcp.WithArgument("name",
mcp.ArgumentDescription("Name of the person to greet"),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
name := request.Params.Arguments["name"]
if name == "" {
name = "friend"
}
return mcp.NewGetPromptResult(
"A friendly greeting",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewTextContent(fmt.Sprintf("Hello, %s! How can I help you today?", name)),
),
},
), nil
})
理论知识够用了,来一个真正能用的东西——查询IP地址地理位置的MCP工具。
先写出main函数的主逻辑:
package main
import (
"context"
"errors"
"fmt"
"io"
"net"
"net/http"
"github.com/kataras/golog"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
// Create MCP server
s := server.NewMCPServer(
"ip-mcp",
"1.0.0",
)
// Add tool
tool := mcp.NewTool("ip_query",
mcp.WithDescription("query geo location of an IP address"),
mcp.WithString("ip",
mcp.Required(),
mcp.Description("IP address to query"),
),
)
// Add tool handler
s.AddTool(tool, ipQueryHandler)
// Start the stdio server
if err := server.ServeStdio(s); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}
这里我们创建了一个名为ip_query的工具,描述很清楚:查询IP地址的地理位置。它需要一个参数:待查询的IP地址。具体逻辑交给ipQueryHandler函数去实现。通信方式选的是标准输入输出,本地测试最方便。
接下来是ipQueryHandler的实现。之前我搭过一个IP地址查询网站 https://ip.rpcx.io,直接调用它的API,封装起来非常简单。
请求到的数据(JSON格式)直接以文本方式返回给MCP Client。Client拿到的是JSON字符串,自己解析就好。
func ipQueryHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
ip, ok := request.Params.Arguments["ip"].(string)
if !ok {
return nil, errors.New("ip must be a string")
}
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
golog.Errorf("invalid IP address: %s", ip)
return nil, errors.New("invalid IP address")
}
resp, err := http.Get("https://ip.rpcx.io/api/ip?ip=" + ip)
if err != nil {
golog.Errorf("Error fetching IP information: %v", err)
return nil, fmt.Errorf("Error fetching IP information: %v", err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
golog.Errorf("Error reading response body: %v", err)
return nil, fmt.Errorf("Error reading response body: %v", err)
}
return mcp.NewToolResultText(string(data)), nil
}
注意参数合法性检查和错误处理这些常规操作。2025年了,这类琐事交给GitHub Copilot这类工具自动补全,一路回车就行。
编译成可执行二进制文件:
go build -o ip-mcp
你可以把它放在系统目录里方便调用,也可以不放在系统目录——后面配置MCP Server时需要指定它的路径。
测试工具我们选用deepchat[3],它已经原生支持MCP,配置起来极其简单。
在MCP配置界面,新增一个MCP Server,配置如下(注意把ip-mcp工具的路径换成你本地的实际路径):
然后启动它:
此时在对话框窗口应该能看到运行着的MCP Tool列表,我们刚写的IP查询工具就在其中:
直接打一句“查询一下8.8.8.8的地理位置”试试——
测试正常。而且看起来deepchat还会把工具的返回结果自动交给deepseek进一步处理,体验很流畅。
就这样,一个简单的MCP Server实现了,并且跑通了全流程。可以看到,我们可以非常快速地把已有的API或产品封装成MCP工具——这也是百度地图、高德地图能迅速推出MCP Server的原因。
《Off Campus》第二季官宣:这对CP还在,但不再是主角
币安Binance虚拟货币交易平台 币安官方APP安卓苹果下载入口
客单价碾压宝马奥迪!极氪5月交付新车34377辆:连续4个月双增长
HBO 奇幻剧《龙之家族》第三季定档 6 月 22 日,最终预告片曝光喉道海战
帅气继父网名女生可爱英文(精选100个)
折后价近千元 澳洲一店主将真老鼠缝到内裤上当时尚单品卖
帅到极致的网名女生霸气(精选100个)
如何在夸克浏览器中开启网页视频的倍速播放功能?
作家助手如何上传自制封面 作家助手如何设置小说的封面
蒙古上单是什么梗
DOTA2 TI时隔七年重返上海!门票6月10日开抢,国服享受优先购买!
archiveofourown 实战指南:常见用法整理
韦一敏是什么梗
韩漫小少爷网名大全女生(精选100个)
网络热词聊污是什么意思
抖音最火沙雕男生网名(精选100个)
有寓意的易经网名男生(精选100个)
欧易OKX官方网站直达入口 2026欧易官方App安卓版v7.1.0下载安装
阿里发布Qwen3.7-Max大模型,全球第五、国产第一
小众游戏抖音网名男生(精选100个)
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc