如何使用golang实现一个MCP-Client

之前的几篇文章中,主要跟大家分享了如何创建一个MCP-Server,以及如何调试MCP-Server。今天,我们就写一个简单MCP-Client来与之前写的pgsql-mcp-server的交互示例,来看看MCP-Client是如何和MCP-Server进行通信的。

1. 如何编写一个MCP-Client

在官方For Client Developers的快速开始中,提供了几种编程语言的示例代码,但是示例代码写死了mcp服务的提供要么是js文件要么是py文件,所以分享一个通用的可以连接任意代码编写的MCP-Client的是有点价值的,这里我仅示例客户端和mcp-server的通信,和LLM大模型的交互后面再做分享。

1.1 读取MCP-Server的配置文件

我们看到许多MCP Host(例如cline、Claude for Desktop等)都是提供一个配置文件,供使用者将其要用到的MCP-Server进行配置连接,所以,我们先来读取配置文件。

这里仿照cline的配置,给出示例代码:

go 复制代码
type MCPConfig struct {
	McpServers map[string]MCPServer `json:"mcpServers"`
}

type MCPServer struct {
	Command     string            `json:"command"`
	Args        []string          `json:"args"`
	Env         map[string]string `json:"env"`
	Disabled    bool              `json:"disabled"`
	AutoApprove []string          `json:"autoApprove"`
}

这里忽略掉读取文件的代码,直接给出要解析的配置文件:

go 复制代码
	configData := `{
		"mcpServers": {
		  "pgsql-mcp-server": {
			"command": "C:\\Users\\Administrator\\go\\bin\\sql-mcp-server.exe",
			"args": [],
			"env": {
			  "GOPATH": "C:\\Users\\Administrator\\go",
			  "GOMODCACHE": "C:\\Users\\Administrator\\go\\pkg\\mod",
			  // 省略其他环境变量
			  ...
			  "DB_SSLMODE": "disable"
			},
			"disabled": false,
			"autoApprove": []
		  }
		}
	  }`

	// 解析配置文件
	var config MCPConfig
	if err := json.Unmarshal([]byte(configData), &config); err != nil {
		fmt.Printf("Failed to parse config file: %v\n", err)
		return
	}

1.2 初始化MCP-Client

通过上面的步骤,我们以及知道了待连接的pgsql-mcp-server配置信息,我们现在可以初始化一个MCP-Client,将其配置传入到MCP-Client中。

go 复制代码
	c, err := client.NewStdioMCPClient(
		mcpServerConfig.Command,
		envSlice,
		mcpServerConfig.Args...,
	)
	if err != nil {
		fmt.Printf("Failed to createa new stdio-based MCP client: %v\n", err)
		return
	}
	defer c.Close()

1.3 连接MCP-Server

现在可以与pgsql-mcp-server 进行通信,这里我们使用MCP-Client的Initialize方法进行初始化,并打印出pgsql-mcp-server的版本信息。

go 复制代码
	initRequest := mcp.InitializeRequest{}
	initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
	initRequest.Params.ClientInfo = mcp.Implementation{
		Name:    "mcp-client",
		Version: "1.0.0",
	}

	initResult, err := c.Initialize(ctx, initRequest)
	if err != nil {
		log.Fatalf("Failed to initialize: %v", err)
	}
    	fmt.Printf(
		"Initialized with server: %s %s\n\n",
		initResult.ServerInfo.Name,
		initResult.ServerInfo.Version,
	)

如果没有问题的话,将会打印出如下内容:

vbscript 复制代码
Initializing client...
Initialized with server: sql-mcp-server 🚀 1.0.0

2. 交互

MCP-Client主要和MCP-Server交互Resources,Prompts Tools,Sampling以及Roots,这里由于我上次写的pgsql-mcp-server只提供了Tools,所以下面仅说明List Tools和Call Tools的两种场景。

2.1 List Tools

go 复制代码
toolsRequest := mcp.ListToolsRequest{}
	tools, err := c.ListTools(ctx, toolsRequest)
	if err != nil {
		log.Fatalf("Failed to list tools: %v", err)
	}
	for _, tool := range tools.Tools {
		fmt.Printf("- %s: %s\n", tool.Name, tool.Description)
	}
	fmt.Println()

上面代码成功运行后,将会打印出如下内容:

  • create_table: Create a new table in the postgres database
  • list_tables: List all user tables in the database
  • read_query: Execute a SELECT query on the postgres database
  • write_query: Execute an INSERT, UPDATE, or DELETE query on the postgres database

2.1 Call Tools

上面已经给出了四个tool,接下来就实现对应的交互代码即可

go 复制代码
// List tables
	fmt.Println("Listing tables...")
	listTableRequest := mcp.CallToolRequest{
		Request: mcp.Request{
			Method: "tools/call",
		},
	}
	listTableRequest.Params.Name = "list_tables"

	result, err := c.CallTool(ctx, listTableRequest)
	if err != nil {
		log.Fatalf("Failed to list allowed directories: %v", err)
	}
	printToolResult(result)

	// Read table
	fmt.Println("Reading table...")
	readTableRequest := mcp.CallToolRequest{}
	readTableRequest.Params.Name = "read_query"
	readTableRequest.Params.Arguments = map[string]interface{}{
		"query": "SELECT * FROM users LIMIT 10",
	}

	result, err = c.CallTool(ctx, readTableRequest)
	if err != nil {
		log.Fatalf("Failed to create directory: %v", err)
	}
	printToolResult(result)
go 复制代码
func printToolResult(result *mcp.CallToolResult) {
	for _, content := range result.Content {
		if textContent, ok := content.(mcp.TextContent); ok {
			fmt.Println(textContent.Text)
		} else {
			jsonBytes, _ := json.MarshalIndent(content, "", "  ")
			fmt.Println(string(jsonBytes))
		}
	}
}

上面代码成功运行后,将会打印出如下内容:

less 复制代码
Listing tables...
Tables: [students articles]

Creating table...
Table created successfully

Writing table...
Operation successful. Rows affected: 1

Reading table...
Query results: [map[created_at:2025-03-29 03:52:12.545937 +0000 +0000 email:[email protected] id:1 name:John Doe]]

3. 总结

ok,以上就是一个简单的MCP-Client的示例代码,通过这个示例,大家可以了解如何使用golang来编写一个MCP-Client,以及如何使用MCP-Client与MCP-Server进行通信,完整的示例代码我已经提交到github,请参考demo_for_AI

相关推荐
Captaincc8 小时前
🔥A16z最近报告原因深入探讨MCP及其在未来AI工具中的作用
mcp
墨风如雪10 小时前
MCP服务宝库:让AI从聊天到实干的「技能超市」全解析
aigc·mcp
FSGF3210 小时前
大模型MCP:模块化计算的革命性突破
人工智能·mcp
关二哥拉二胡10 小时前
向零基础前端介绍什么是 MCP
前端·面试·mcp
PetterHillWater10 小时前
基于Cline MCP实践FireCrawl
aigc·ai编程·mcp
Captaincc10 小时前
全站最全!BrowserTools MCP 服务快速入门与安装指南
ai编程·mcp
Captaincc10 小时前
🤖 如何让你的 AI 代理集成 MCP 服务
mcp
Captaincc10 小时前
Anthropic 的 MCP(多组件协议)架构解读
mcp
zeron110 小时前
MCP协议:从“钢铁侠贾维斯“”愿景到可能实现(含MCP Gitee实操)
aigc·mcp
Captaincc11 小时前
用 28 行代码实现 MCP 服务,兼容任意 MCP 客户端
mcp