最近这段时间,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服务器。
创建server对象
s := server.newmcpserver("my server", "1.0.0")
添加工具(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 })
- 添加资源(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 })
- 启动基于stdio传输类型的服务器
if err := server.servestdio(s); err != nil { fmt.printf("server error: %v\n", err) }
以上步骤完成后,我们就成功搭建了一个基础的mcp服务器。
构建mcp客户端
接着,我们将展示如何使用mcp-go
提供的client模块构建一个连接至上述mcp服务器的客户端。
- 创建mcp客户端
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)
- 调用远程工具
最后,我们可以通过构造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开发!
到此这篇关于一文弄懂用go实现mcp服务的示例代码的文章就介绍到这了,更多相关go mcp服务内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论