写点什么

一文弄懂用 Go 实现 MCP 服务

作者:王中阳Go
  • 2025-04-10
    北京
  • 本文字数:3715 字

    阅读完需:约 12 分钟

一文弄懂用Go实现MCP服务


最近这段时间,AI 领域里有一个非常热门的概念——MCP(模型上下文协议)。Anthropic 推出的这一开放标准旨在为大型语言模型和 AI 助手提供统一的接口,使其能够轻松操作外部工具并完成更复杂的任务。


本文将带你速览 MCP 的核心概念,并以 Go 语言为例,介绍如何开发 MCP 服务端和客户端

为什么 MCP 如此重要?

在过去,如果想要让 AI 处理特定的数据,通常只能依赖于预训练数据或者手动上传数据,这既麻烦又低效。即便对于强大的 AI 模型而言,也存在数据隔离的问题,无法直接访问新的数据源,每次更新数据都需要重新训练或上传。现在,MCP 解决了这个问题,它使得 AI 不再局限于静态知识库,而是能够像人类一样调用搜索引擎、访问本地文件、连接 API 服务等,极大提升了 AI 的动态交互能力

MCP 总体架构

MCP 的核心是“客户端-服务器”架构,其中 MCP 客户端可以连接到多个服务器。客户端是指希望通过 MCP 访问数据的应用程序,如 CLI 工具、IDE 插件或 AI 应用。


使用 mcp-go 构建 MCP 服务端与客户端

要开始使用 Go 语言构建 MCP 项目,首先需要安装mcp-go库,这是 Go 语言实现的 Model Context Protocol 库,支持 LLM 应用与外部数据源和工具之间的无缝集成。


go get github.com/mark3labs/mcp-go
复制代码

构建 MCP 服务端

接下来,我们将演示如何使用mcp-go提供的 server 模块来构建一个通过 stdio 方式连接的 MCP 服务器。


  1. 创建 Server 对象


s := server.NewMCPServer("My Server", "1.0.0")
复制代码


  1. 添加工具(Tools)


例如,我们可以创建一个简单的计算器工具,这次我们实现乘法和除法功能:


calculatorTool := mcp.NewTool("calculate",    mcp.WithDescription("执行基本的算术运算"),    mcp.WithString("operation",        mcp.Required(),        mcp.Description("要执行的算术运算类型"),        mcp.Enum("multiply", "divide"), // 修改为仅支持乘法和除法    ),    mcp.WithNumber("x",        mcp.Required(),        mcp.Description("第一个数字"),    ),    mcp.WithNumber("y",        mcp.Required(),        mcp.Description("第二个数字"),    ),)
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 "multiply": result = x * y case "divide": if y == 0 { return nil, errors.New("不允许除以零") } result = x / y }
return mcp.FormatNumberResult(result), nil})
复制代码


  1. 添加资源(Resources)


同样地,我们也可以注册一些静态资源,比如 README.md 文件的内容:


resource := mcp.NewResource(    "docs://readme",    "项目说明文档",    mcp.WithResourceDescription("项目的 README 文件"),    mcp.WithMIMEType("text/markdown"),)
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})
复制代码


  1. 启动基于 stdio 传输类型的服务器


if err := server.ServeStdio(s); err != nil {    fmt.Printf("Server error: %v\n", err)}
复制代码


以上步骤完成后,我们就成功搭建了一个基础的 MCP 服务器。

构建 MCP 客户端

接着,我们将展示如何使用mcp-go提供的 client 模块构建一个连接至上述 MCP 服务器的客户端。


  1. 创建 MCP 客户端


mcpClient, err := client.NewStdioMCPClient("./client/server", []string{})if err != nil {    panic(err)}defer mcpClient.Close()
复制代码


  1. 初始化客户端连接


ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)defer cancel()
initRequest := mcp.InitializeRequest{}initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSIONinitRequest.Params.ClientInfo = mcp.Implementation{ Name: "Client Demo", Version: "1.0.0",}
initResult, err := mcpClient.Initialize(ctx, initRequest)if err != nil { panic(err)}fmt.Printf("初始化成功,服务器信息: %s %s\n", initResult.ServerInfo.Name, initResult.ServerInfo.Version)
复制代码


  1. 调用远程工具


最后,我们可以通过构造CallToolRequest来调用服务器上的工具,如下所示:


toolRequest := mcp.CallToolRequest{    Request: mcp.Request{        Method: "tools/call",    },}toolRequest.Params.Name = "calculate"toolRequest.Params.Arguments = map[string]any{    "operation": "multiply", // 调用乘法    "x":         2,    "y":         3,}
result, err := mcpClient.CallTool(ctx, toolRequest)if err != nil { panic(err)}fmt.Println("调用工具结果:", result.Content[0].(mcp.TextContent).Text)
复制代码

完整代码示例

以下是完整的代码示例,包括服务端和客户端的实现:


服务端代码:


package main
import ( "context" "errors" "fmt" "os"
"github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server")
func main() { s := server.NewMCPServer("Server Demo", "1.0.0")
// 添加工具 calculatorTool := mcp.NewTool("calculate", mcp.WithDescription("执行基本的算术运算"), mcp.WithString("operation", mcp.Required(), mcp.Description("要执行的算术运算类型"), mcp.Enum("multiply", "divide"), ), mcp.WithNumber("x", mcp.Required(), mcp.Description("第一个数字"), ), mcp.WithNumber("y", mcp.Required(), mcp.Description("第二个数字"), ), )
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 "multiply": result = x * y case "divide": if y == 0 { return nil, errors.New("不允许除以零") } result = x / y }
return mcp.FormatNumberResult(result), nil })
// 启动基于 stdio 的服务器 if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) }}
复制代码


客户端代码:


package main
import ( "context" "fmt" "time"
"github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/mcp")
func main() { mcpClient, err := client.NewStdioMCPClient("./client/server", []string{}) if err != nil { panic(err) } defer mcpClient.Close()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel()
initRequest := mcp.InitializeRequest{} initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION initRequest.Params.ClientInfo = mcp.Implementation{ Name: "Client Demo", Version: "1.0.0", }
initResult, err := mcpClient.Initialize(ctx, initRequest) if err != nil { panic(err) } fmt.Printf("初始化成功,服务器信息: %s %s\n", initResult.ServerInfo.Name, initResult.ServerInfo.Version)
// 调用工具 toolRequest := mcp.CallToolRequest{ Request: mcp.Request{ Method: "tools/call", }, } toolRequest.Params.Name = "calculate" toolRequest.Params.Arguments = map[string]any{ "operation": "multiply", "x": 2, "y": 3, }
result, err := mcpClient.CallTool(ctx, toolRequest) if err != nil { panic(err) } fmt.Println("调用工具结果:", result.Content[0].(mcp.TextContent).Text)}
复制代码


希望这篇文章能帮助你快速入门 Go 语言下的 MCP 开发!

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:面试群。

发布于: 刚刚阅读数: 3
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
一文弄懂用Go实现MCP服务_Go_王中阳Go_InfoQ写作社区