【Go类库分享】mcp-go Go搭建MCP服务

06-01 1406阅读

【Go类库分享】mcp-go Go搭建MCP服务

介绍

目前Go 生态圈有两个知名的开发 MCP 的库,一个是mark3labs/mcp-go,另一个是metoro-io/mcp-golang。

在介绍常用库之前,先来简单介绍一下mcp协议:

MCP全称Model Context Protocol 模型上下文协议,MCP 是一个开放协议,它为应用程序向 LLM 提供上下文的方式进行了标准化。你可以将 MCP 想象成 AI 应用程序的 USB-C 接口。就像 USB-C 为设备连接各种外设和配件提供了标准化的方式一样,MCP 为 AI 模型连接各种数据源和工具提供了标准化的接口。

相比之前各大AI厂商各自为战,接口以及协议之间不通用,导致开发者针对同一个功能为了适配多个AI模型,需要开发多套。现在有了MCP,各大模型厂商和开发者只需遵循MCP协议,即可实现一次编写,多模型适用。

MCP与大模型调用之间原理图:

【Go类库分享】mcp-go Go搭建MCP服务

MCP架构主要包含一下几个模块:

  • MCP Hosts: 如 Claude Desktop、IDE 、DeepChat或 AI 工具,希望通过 MCP 访问数据的程序
  • MCP Clients: 维护与服务器一对一连接的协议客户端
  • MCP Servers: 轻量级程序,通过标准的 Model Context Protocol 提供特定能力
  • 本地数据源: MCP 服务器可安全访问的计算机文件、数据库和服务
  • 远程服务: MCP 服务器可连接的互联网上的外部系统(如通过 APIs)

    安装

    go get "github.com/mark3labs/mcp-go"
    

    API介绍

    1. server.NewMCPServer:新建一个mcp server

    目前MCP 支持 SSE 和Stdio两种类型。

    1. stdio:standard input output,标准输入输出,适用于mcp client和mcp server部署在同一个机器上,不涉及跨机器。
    2. sse:Server-Sent Events,服务器发送事件,是一个基于HTTP的协议。适用于mcp client与mcp server不在同一个机器中的场景,涉及网络传输。

    这里我们以新建一个基于Stdio协议的mcp server为例:

    //新建mcp 服务
    mcpServer := server.NewMCPServer("ziyi Mcp Server", "1.0.0")
    //对外提供 stdio mcp server服务
    if err := server.ServeStdio(mcpServer); err != nil {
    	panic(err)
    }
    

    2. mcp.NewResource:对外提供资源

    资源是你向 LLMs 暴露数据的方式。它们可以是任何东西:文件、API 响应、数据库查询、系统信息等。资源可以是:

    • 静态资源(固定 URI)
    • 动态资源(使用 URI 模板)
      //新增一个mcp server对外暴露的静态资源(固定URI),比如:对外暴露项目的操作手册以及部署方式等,就可以通过静态资源README文件的方式来告诉大模型
      resource := mcp.NewResource(
      	"docs://readme",
      	"项目的README文件",
      	mcp.WithResourceDescription("这是一个项目的README文件"),
      	mcp.WithMIMEType("text/markdown"),
      )
      // 添加对静态资源的处理器
      mcpServer.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
      })
      

      3. mcp.NewTool:对外提供工具

      工具让 LLM 通过你的服务器执行操作。与资源不同,工具预期会进行计算并产生副作用。它们类似于 REST API 中的 POST 端点。 下面是一个算术运算的工具示例:

      工具可以用于任何种类的计算:

      1. Database queries 数据库查询
      2. File operations 文件操作
      3. External API calls 外部 API 调用
      4. Calculations 计算
      5. System operations 系统操作

      每个工具应该:

      1. 有清晰的描述
      2. 验证输入
      3. 优雅处理错误
      4. 返回结构化的响应
      5. 使用适当的结果类型
      //给该mcp server添加计算能力(Tools)
      // 1. 描述该工具,以及调用该工具调用的参数机器含义
      calculatorTool := mcp.NewTool("calculate",
      	mcp.WithDescription("进行基础的数学运算"),
      	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"),
      	),
      )
      // 2. 实现工具的具体处理逻辑,类比大模型function_calling中的func部分
      mcpServer.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
      })
      

      4. s.AddPrompt:添加提示词

      下面是一个简单的提示词示例,它需要一个名称参数,然后返回一个问候提示词:

      // 给mcpServer添加提示词模版
      mcpServer.AddPrompt(mcp.NewPrompt("打招呼",
      	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
      })
      

      实战使用

      1. 编写mcp server

      这里我们演示一个查询IP的mcp server。大模型传入ip,mcp server返回地址信息。

      ip mcp server全部代码:

      package main
      import (
      	"context"
      	"errors"
      	"fmt"
      	"github.com/mark3labs/mcp-go/mcp"
      	"github.com/mark3labs/mcp-go/server"
      	"io"
      	"net"
      	"net/http"
      )
      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)
      	}
      }
      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 {
      		return nil, errors.New("invalid IP address")
      	}
      	resp, err := http.Get("https://ip.rpcx.io/api/ip?ip=" + ip)
      	if err != nil {
      		return nil, fmt.Errorf("Error fetching IP information: %v", err)
      	}
      	defer resp.Body.Close()
      	data, err := io.ReadAll(resp.Body)
      	if err != nil {
      		return nil, fmt.Errorf("Error reading response body: %v", err)
      	}
      	fmt.Printf("call ip: %s  Response body: %s\n", ip, string(data))
      	return mcp.NewToolResultText(string(data)), nil
      }
      

      然后我们编译代码:

      # 执行命令编译mcp server
      go build -o mcp-ip main.go
      

      【Go类库分享】mcp-go Go搭建MCP服务

      2. 桌面版调用mcp server插件

      这里使用桌面版的deepchat来演示大模型调用mcp server。

      deepchat下载地址:https://deepchat.thinkinai.xyz/#/download

      1. 下载后配置本地大模型(通过ollama方式搭建等)或者直接配置远程模型地址

      远程模型这里我使用openrouter的免费deepseek-r1版本:https://openrouter.ai/deepseek/deepseek-r1:free

      1. 选择模型,配置URL以及Token后,点击校验

        【Go类库分享】mcp-go Go搭建MCP服务

      2. 点击下一步,然后就可以与大模型对话了

        【Go类库分享】mcp-go Go搭建MCP服务

      tips:

      1. 可修改页面文字为中文

        【Go类库分享】mcp-go Go搭建MCP服务

      2. 可修改对话模型

        【Go类库分享】mcp-go Go搭建MCP服务

      1. 下面我们配置mcp server

        【Go类库分享】mcp-go Go搭建MCP服务

      2. 跳过json方式配置,转为手动配置

        【Go类库分享】mcp-go Go搭建MCP服务

      3. 填写mcp server配置参数,然后点击提交

        【Go类库分享】mcp-go Go搭建MCP服务

      4. 启用mcp server

        【Go类库分享】mcp-go Go搭建MCP服务

      5. 输入问题,查看效果

      如:帮我查询39.156.66.10 IP信息

      【Go类库分享】mcp-go Go搭建MCP服务

      参考文章:

      https://mcp-docs.cn/introduction

      https://mp.weixin.qq.com/s/UgdXztu3SKYMs56DqiX3Sg

      https://www.junki.cn/archives/Zqgi7fzK

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码