一文弄懂用Go實(shí)現(xiàn)MCP服務(wù)的示例代碼
最近這段時間,AI領(lǐng)域里有一個非常熱門的概念——MCP(模型上下文協(xié)議)。Anthropic推出的這一開放標(biāo)準(zhǔn)旨在為大型語言模型和AI助手提供統(tǒng)一的接口,使其能夠輕松操作外部工具并完成更復(fù)雜的任務(wù)。
本文將帶你速覽MCP的核心概念,并以Go語言為例,介紹如何開發(fā)MCP服務(wù)端和客戶端。
為什么MCP如此重要?
在過去,如果想要讓AI處理特定的數(shù)據(jù),通常只能依賴于預(yù)訓(xùn)練數(shù)據(jù)或者手動上傳數(shù)據(jù),這既麻煩又低效。即便對于強(qiáng)大的AI模型而言,也存在數(shù)據(jù)隔離的問題,無法直接訪問新的數(shù)據(jù)源,每次更新數(shù)據(jù)都需要重新訓(xùn)練或上傳?,F(xiàn)在,MCP解決了這個問題,它使得AI不再局限于靜態(tài)知識庫,而是能夠像人類一樣調(diào)用搜索引擎、訪問本地文件、連接API服務(wù)等,極大提升了AI的動態(tài)交互能力。
MCP總體架構(gòu)
MCP的核心是“客戶端-服務(wù)器”架構(gòu),其中MCP客戶端可以連接到多個服務(wù)器。客戶端是指希望通過MCP訪問數(shù)據(jù)的應(yīng)用程序,如CLI工具、IDE插件或AI應(yīng)用。
使用mcp-go構(gòu)建MCP服務(wù)端與客戶端
要開始使用Go語言構(gòu)建MCP項(xiàng)目,首先需要安裝mcp-go
庫,這是Go語言實(shí)現(xiàn)的Model Context Protocol庫,支持LLM應(yīng)用與外部數(shù)據(jù)源和工具之間的無縫集成。
go get github.com/mark3labs/mcp-go
構(gòu)建MCP服務(wù)端
接下來,我們將演示如何使用mcp-go
提供的server模塊來構(gòu)建一個通過stdio方式連接的MCP服務(wù)器。
創(chuàng)建Server對象
s := server.NewMCPServer("My Server", "1.0.0")
添加工具(Tools)
例如,我們可以創(chuàng)建一個簡單的計算器工具,這次我們實(shí)現(xiàn)乘法和除法功能:
calculatorTool := mcp.NewTool("calculate", mcp.WithDescription("執(zhí)行基本的算術(shù)運(yùn)算"), mcp.WithString("operation", mcp.Required(), mcp.Description("要執(zhí)行的算術(shù)運(yùn)算類型"), mcp.Enum("multiply", "divide"), // 修改為僅支持乘法和除法 ), mcp.WithNumber("x", mcp.Required(), mcp.Description("第一個數(shù)字"), ), mcp.WithNumber("y", mcp.Required(), mcp.Description("第二個數(shù)字"), ), ) 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)
同樣地,我們也可以注冊一些靜態(tài)資源,比如README.md文件的內(nèi)容:
resource := mcp.NewResource( "docs://readme", "項(xiàng)目說明文檔", mcp.WithResourceDescription("項(xiàng)目的 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傳輸類型的服務(wù)器
if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) }
以上步驟完成后,我們就成功搭建了一個基礎(chǔ)的MCP服務(wù)器。
構(gòu)建MCP客戶端
接著,我們將展示如何使用mcp-go
提供的client模塊構(gòu)建一個連接至上述MCP服務(wù)器的客戶端。
- 創(chuàng)建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("初始化成功,服務(wù)器信息: %s %s\n", initResult.ServerInfo.Name, initResult.ServerInfo.Version)
- 調(diào)用遠(yuǎn)程工具
最后,我們可以通過構(gòu)造CallToolRequest
來調(diào)用服務(wù)器上的工具,如下所示:
toolRequest := mcp.CallToolRequest{ Request: mcp.Request{ Method: "tools/call", }, } toolRequest.Params.Name = "calculate" toolRequest.Params.Arguments = map[string]any{ "operation": "multiply", // 調(diào)用乘法 "x": 2, "y": 3, } result, err := mcpClient.CallTool(ctx, toolRequest) if err != nil { panic(err) } fmt.Println("調(diào)用工具結(jié)果:", result.Content[0].(mcp.TextContent).Text)
完整代碼示例
以下是完整的代碼示例,包括服務(wù)端和客戶端的實(shí)現(xiàn):
服務(wù)端代碼:
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("執(zhí)行基本的算術(shù)運(yùn)算"), mcp.WithString("operation", mcp.Required(), mcp.Description("要執(zhí)行的算術(shù)運(yùn)算類型"), mcp.Enum("multiply", "divide"), ), mcp.WithNumber("x", mcp.Required(), mcp.Description("第一個數(shù)字"), ), mcp.WithNumber("y", mcp.Required(), mcp.Description("第二個數(shù)字"), ), ) 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 的服務(wù)器 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("初始化成功,服務(wù)器信息: %s %s\n", initResult.ServerInfo.Name, initResult.ServerInfo.Version) // 調(diào)用工具 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("調(diào)用工具結(jié)果:", result.Content[0].(mcp.TextContent).Text) }
希望這篇文章能幫助你快速入門Go語言下的MCP開發(fā)!
到此這篇關(guān)于一文弄懂用Go實(shí)現(xiàn)MCP服務(wù)的示例代碼的文章就介紹到這了,更多相關(guān)Go MCP服務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang 實(shí)現(xiàn) Redis系列(六)如何實(shí)現(xiàn) pipeline 模式的 redis 客戶端
pipeline 模式的 redis 客戶端需要有兩個后臺協(xié)程負(fù)責(zé) tcp 通信,調(diào)用方通過 channel 向后臺協(xié)程發(fā)送指令,并阻塞等待直到收到響應(yīng),本文是使用 golang 實(shí)現(xiàn) redis 系列的第六篇, 將介紹如何實(shí)現(xiàn)一個 Pipeline 模式的 Redis 客戶端。2021-07-07Go語言實(shí)現(xiàn)管理多個數(shù)據(jù)庫連接
在軟件開發(fā)過程中,使用?MySQL、PostgreSQL?或其他數(shù)據(jù)庫是很常見的,由于配置和要求不同,管理這些連接可能具有挑戰(zhàn)性,下面就來和大家聊聊如何在Go中管理多個數(shù)據(jù)庫連接吧2023-10-10golang?gorm學(xué)習(xí)之如何指定數(shù)據(jù)表
在sql中首先要指定是從哪張表中查詢,所以這篇文章小編就來帶大家一起看一下gorm是如何根據(jù)model來自動解析表名的,感興趣的小伙伴可以了解下2023-08-08golang中slice擴(kuò)容的具體實(shí)現(xiàn)
Go 語言中的切片擴(kuò)容機(jī)制是 Go 運(yùn)行時的一個關(guān)鍵部分,它確保切片在動態(tài)增加元素時能夠高效地管理內(nèi)存,本文主要介紹了golang中slice擴(kuò)容的具體實(shí)現(xiàn),感興趣的可以了解一下2025-05-05淺談go-restful框架的使用和實(shí)現(xiàn)
這篇文章主要介紹了淺談go-restful框架的使用和實(shí)現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03Go使用Protocol?Buffers在數(shù)據(jù)序列化的優(yōu)勢示例詳解
這篇文章主要為大家介紹了Go使用Protocol?Buffers在數(shù)據(jù)序列化的優(yōu)勢示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11深入解析Go語言的io.ioutil標(biāo)準(zhǔn)庫使用
這篇文章主要介紹了Go語言的io.ioutil標(biāo)準(zhǔn)庫使用,是Golang入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-10-10