一文弄懂用Go实现MCP服务的示例代码

 更新时间:2025年04月21日 10:23:58   作者:王中阳讲编程  
本文主要介绍了一文弄懂用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服务器。

创建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服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang 实现 Redis系列(六)如何实现 pipeline 模式的 redis 客户端

    Golang 实现 Redis系列(六)如何实现 pipeline 模式的 redis 客户端

    pipeline 模式的 redis 客户端需要有两个后台协程负责 tcp 通信,调用方通过 channel 向后台协程发送指令,并阻塞等待直到收到响应,本文是使用 golang 实现 redis 系列的第六篇, 将介绍如何实现一个 Pipeline 模式的 Redis 客户端。
    2021-07-07
  • Go语言实现管理多个数据库连接

    Go语言实现管理多个数据库连接

    在软件开发过程中,使用 MySQL、PostgreSQL 或其他数据库是很常见的,由于配置和要求不同,管理这些连接可能具有挑战性,下面就来和大家聊聊如何在Go中管理多个数据库连接吧
    2023-10-10
  • golang gorm学习之如何指定数据表

    golang gorm学习之如何指定数据表

    在sql中首先要指定是从哪张表中查询,所以这篇文章小编就来带大家一起看一下gorm是如何根据model来自动解析表名的,感兴趣的小伙伴可以了解下
    2023-08-08
  • golang中slice扩容的具体实现

    golang中slice扩容的具体实现

    Go 语言中的切片扩容机制是 Go 运行时的一个关键部分,它确保切片在动态增加元素时能够高效地管理内存,本文主要介绍了golang中slice扩容的具体实现,感兴趣的可以了解一下
    2025-05-05
  • Go语言区别于其他语言的特性

    Go语言区别于其他语言的特性

    在本文中,今天这篇文章将给大家介绍一下 Go 与其他语言不同的 9 个特性,需要的朋友可以参考下面文章的具体内容
    2021-10-10
  • 浅谈go-restful框架的使用和实现

    浅谈go-restful框架的使用和实现

    这篇文章主要介绍了浅谈go-restful框架的使用和实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Go使用Protocol Buffers在数据序列化的优势示例详解

    Go使用Protocol Buffers在数据序列化的优势示例详解

    这篇文章主要为大家介绍了Go使用Protocol Buffers在数据序列化的优势示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 深入解析Go语言的io.ioutil标准库使用

    深入解析Go语言的io.ioutil标准库使用

    这篇文章主要介绍了Go语言的io.ioutil标准库使用,是Golang入门学习中的基础知识,需要的朋友可以参考下
    2015-10-10
  • GO语言ini配置文件的读取的操作

    GO语言ini配置文件的读取的操作

    这篇文章主要介绍了GO语言ini配置文件的读取的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • Go实现凯撒密码加密解密

    Go实现凯撒密码加密解密

    这篇文章主要为大家介绍了Go实现凯撒密码加密解密示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08

最新评论