乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • 运维

  • 监控

  • 开发

    • 基于Golang开发一个接口拨测系统
    • 使用Go开发MCP服务
      • MCP是什么
      • MCP服务开发
        • mcp-go介绍
        • (1)启动服务
        • (2)增加资源
        • (3)增加工具
        • (4)增加提示
        • 开发一个查询IP地理信息的MCP Tool
        • 测试MCP服务
  • 安全

  • 随笔

  • 博客
  • 开发
乔克
2025-07-18
目录

使用Go开发MCP服务

✍ 道路千万条,安全第一条。操作不规范,运维两行泪。

# MCP是什么

MCP,全名是Model Context Protocol,它是一个开放的、通用的、有共识的协议标准。

  • MCP是标准的协议,就像给AI大模型的一个万能接口,让AI模型能够与不同的数据源和工具进行无缝交互。
  • MCP 旨在替换碎片化的 Agent 代码集成,从而使 AI 系统更可靠,更有效。通过建立通用标准,服务商可以基于协议来推出它们自己服务的 AI 能力,从而支持开发者更快的构建更强大的 AI 应用。开发者也不需要重复造轮子,通过开源项目可以建立强大的 AI Agent 生态。
  • MCP 可以在不同的应用 / 服务之间保持上下文,从而增强整体自主执行任务的能力。

MCP遵循CS架构,包含以下几个核心部分:

  • MCP主机:发起请求的AI应用程序,比如聊天机器人,AI驱动的IDE等。
  • MCP客户端:在主机程序内部,与MCP服务器保持一对一的连接。
  • MCP服务器:为MCP客户端提供上下文、工具和提示信息。
  • 本地资源:本地计算机中可供MCP服务器安全访问的资源,如文件、数据库。
  • 远程资源:MCP服务器可以连接到的远程资源,如通过API提供的数据。

[[附件/images/2b8d59e46d889fee1b400851f04b8f09_MD5.jpeg|Open: Pasted image 20250410092142.png]] 2b8d59e46d889fee1b400851f04b8f09 MD5

MCP的工作流程可以简单的概括为以下几个步骤:

1、连接:MCP主机连接到一个或者多个服务器。 2、请求:主机发送请求以获取数据或者执行工具。 3、处理:服务器处理请求,访问相关数据源或外部服务。 4、返回:服务器将结果返回给主机。 5、响应:主机将信息提供给AI模型,用于生成用户响应。

下面,我们来开发一个简单的MCP服务。

# MCP服务开发

当前 Go 生态圈有两个比较知名的开发 MCP 的库,一个是mark3labs/mcp-go,另一个是metoro-io/mcp-golang,两个使用起来都很简单,这里我们将采用第一个库进行演示。

# mcp-go介绍

# (1)启动服务

MCP 支持 SSE 和标准输入输出两种类型,一般我们在自己的机器上常用标准输入输出传输方式:

// Create a basic server  
s := server.NewMCPServer(  
    "My Server",  // Server name  
    "1.0.0",     // Version  
)  
  
// Start the server using stdio  
if err := server.ServeStdio(s); err != nil {  
    log.Fatalf("Server error: %v", err)  
}
1
2
3
4
5
6
7
8
9
10

# (2)增加资源

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

  • 静态资源(固定 URI)

  • 动态资源(使用 URI 模板)

这是一个静态资源的简单示例:

// Static resource example - exposing a README file  
resource := mcp.NewResource(  
    "docs://readme",  
    "Project README",  
    mcp.WithResourceDescription("The project's README file"),  
    mcp.WithMIMEType("text/markdown"),  
)  
  
// Add resource with its handler  
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# (3)增加工具

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

calculatorTool := mcp.NewTool("calculate",  
    mcp.WithDescription("Perform basic arithmetic calculations"),  
    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"),  
    ),  
)  
  
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 "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  
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

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

  • Database queries   数据库查询
  • File operations   文件操作
  • External API calls   外部 API 调用
  • Calculations   计算
  • System operations   系统操作

每个工具应该:

  • 有清晰的描述
  • 验证输入
  • 优雅处理错误
  • 返回结构化的响应
  • 使用适当的结果类型

# (4)增加提示

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

// Simple greeting prompt  
s.AddPrompt(mcp.NewPrompt("greeting",  
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 开发一个查询IP地理信息的MCP Tool

首先我们先实现这个 MCP Tool main 函数的主逻辑:

package main  
  
import (  
 "context"  
 "errors"  
 "fmt"  
 "io"  
 "net"  
 "net/http"  
  
 "github.com/kataras/golog"  
 "github.com/mark3labs/mcp-go/mcp"  
 "github.com/mark3labs/mcp-go/server"  
)  
  
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)  
 }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

这里我们增加了一个ip_query查询 IP 信息的工具,描述清楚它的功能是查询 IP 地址的地理位置。 这个工具需要一个参数:待查询的 IP 地址。 然后这个工具具体的实现是ipQueryHandler函数。 这个 MCP Server 使用标准输入输出传输。

接下来就是ipQueryHandler函数实现了。先前我实现了一个 IP 地址查询的网站 https://ip.rpcx.io, 所以这里我调用它的 API 进行封装就很简单了。

我将请求的数据以文本的方式返回 MCP Client。 因为这个数据是 JSON 格式,所以 MCP Client 会得到一个 JSON 格式的文本。

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 {  
  golog.Errorf("invalid IP address: %s", ip)  
  return nil, errors.New("invalid IP address")  
 }  
  
 resp, err := http.Get("https://ip.rpcx.io/api/ip?ip=" + ip)  
 if err != nil {  
  golog.Errorf("Error fetching IP information: %v", err)  
  return nil, fmt.Errorf("Error fetching IP information: %v", err)  
 }  
 defer resp.Body.Close()  
  
 data, err := io.ReadAll(resp.Body)  
 if err != nil {  
  golog.Errorf("Error reading response body: %v", err)  
  return nil, fmt.Errorf("Error reading response body: %v", err)  
 }  
  
 return mcp.NewToolResultText(string(data)), nil  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

注意检查参数的合法性,处理程序中的 error。在 2025 年的今天,这些琐碎的事都可以由代码辅助工具如 github copilot 自动完成,我们一路回车即可。

# 测试MCP服务

我们使用deepchat[3]来测试我们开发的这个 IP 查询的 MCP 工具。 deepchat 已经支持 MCP 了,而且配置起来也非常简单。

在 MCP 配置界面,我们增加一个 MCP Server,配置如下(注意:ip-mcp 工具的实际路径):

[[附件/images/07ab5bdb860ec62c2d5c4ed9ce56be9c_MD5.jpeg|Open: Pasted image 20250410095608.png]] 07ab5bdb860ec62c2d5c4ed9ce56be9c MD5

然后启动它:

[[附件/images/fc1a4482f557d7d4b267d35368587127_MD5.jpeg|Open: Pasted image 20250410095637.png]] fc1a4482f557d7d4b267d35368587127 MD5

这个时候你应该在对话框窗口看到运行着的 MCP Tool,包括我们的 IP 查询工具:

对话框中测试一把:

[[附件/images/e2e6ec0acf034c5cbf69e7eb585ab1bd_MD5.jpeg|Open: Pasted image 20250410095657.png]] e2e6ec0acf034c5cbf69e7eb585ab1bd MD5

测试正常。看起来 deepchat 还会把工具的返回结果交给 deepseek 处理。

这样,我们就简单了实现了一个 MCP Server 并测试成功。可以看到我们可以对既有的 API 或者产品很快的进行封装成 MCP 工具,这也是 baidu 地图、高德地图能够很快推出 MCP Server 的原因。

#mcp server#golang
上次更新: 2025/07/18, 16:47:24
基于Golang开发一个接口拨测系统
服务器被黑了

← 基于Golang开发一个接口拨测系统 服务器被黑了→

最近更新
01
2025年,SRE在企业中可以做哪些事
07-18
02
SRE 如何提升自己在团队中的影响力
07-18
03
服务器被黑了
07-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式