MCP
MCP (Model Context Protocol) 是一种标准化协议,允许语言模型与外部工具和服务进行交互。通过 MCP,模型可以:
- 访问文件系统
- 执行命令行操作
- 调用外部 API
- 与其他服务进行交互
1. MCP Tool
在https://github.com/cloudwego/eino-ext项目中的components/tool/mcp中实现了一个MCP Tool,能够与Eino框架的工具系统轻松集成,支持获取和调用MCP工具
1.1 安装
go get github.com/cloudwego/eino-ext/components/tool/mcp@latest
go get github.com/mark3labs/mcp-go
1
2
2
1.2 创建MCP服务器
这里我们先自己创建一个MCP服务器,来提供一个天气查询的MCP服务。
package main
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
mcpServer := server.NewMCPServer("weather", mcp.LATEST_PROTOCOL_VERSION)
tool := WeatherTool()
mcpServer.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
//解析输入参数
params := request.GetArguments()
city, ok := params["city"].(string)
if !ok || city == "" {
return nil, fmt.Errorf("city is required")
}
//构建API请求URL
baseURL := "https://restapi.amap.com/v3/weather/weatherInfo"
queryParams := url.Values{}
queryParams.Set("city", city)
queryParams.Set("key", "you api key")
//设置可选参数
if extensions, ok := params["extensions"].(string); ok {
queryParams.Set("extensions", extensions)
} else {
// 默认查询实况天气
queryParams.Set("extensions", "base")
}
//设置返回格式为JSON
queryParams.Set("output", "JSON")
fullURL := fmt.Sprintf("%s?%s", baseURL, queryParams.Encode())
//发送HTTP请求
req, err := http.NewRequestWithContext(ctx, "GET", fullURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
//读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
//检查HTTP状态码
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
return mcp.NewToolResultText(string(body)), nil
})
err := server.NewSSEServer(mcpServer).Start("localhost:12345")
if err != nil {
panic(err)
}
}
func WeatherTool() mcp.Tool {
tool := mcp.NewTool("get_weather",
mcp.WithDescription("Get weather information for a given city"),
mcp.WithString("city", mcp.Required(), mcp.Description("城市名称")),
mcp.WithString("extensions",
mcp.Required(),
mcp.Enum("base", "all"),
mcp.Description("返回数据类型,base为实况天气,all为预报天气"),
mcp.DefaultString("base"),
),
)
return tool
}
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
1.3 MCP客户端
package main
import (
"context"
"github.com/cloudwego/eino-ext/components/model/ollama"
mcpTool "github.com/cloudwego/eino-ext/components/tool/mcp"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/flow/agent/react"
"github.com/cloudwego/eino/schema"
"github.com/mark3labs/mcp-go/client"
"github.com/mark3labs/mcp-go/mcp"
)
func main() {
ctx := context.Background()
chatModel, err := ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
BaseURL: "http://127.0.0.1:11434",
Model: "modelscope.cn/Qwen/Qwen3-32B-GGUF:latest",
})
if err != nil {
panic(err)
}
mcpTools, err := getMcpTools()
if err != nil {
panic(err)
}
agent, err := react.NewAgent(ctx, &react.AgentConfig{
ToolCallingModel: chatModel,
ToolsConfig: compose.ToolsNodeConfig{
Tools: mcpTools,
},
})
if err != nil {
panic(err)
}
msg := []*schema.Message{
schema.SystemMessage("请根据提供的天气查询工具,查询天气情况"),
schema.UserMessage("查询北京今天的天气"),
}
result, err := agent.Generate(ctx, msg)
if err != nil {
panic(err)
}
println(result.Content)
}
func getMcpTools() ([]tool.BaseTool, error) {
ctx := context.Background()
// 创建SSE客户端连接到MCP服务器
cli, err := client.NewSSEMCPClient("http://localhost:12345/sse")
if err != nil {
panic(err)
}
// 启动客户端
err = cli.Start(ctx)
if err != nil {
panic(err)
}
initializeRequest := mcp.InitializeRequest{}
initializeRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
initializeRequest.Params.ClientInfo = mcp.Implementation{
Name: "weather-tool",
Version: "0.0.1",
}
_, err = cli.Initialize(ctx, initializeRequest)
if err != nil {
return nil, err
}
tools, err := mcpTool.GetTools(ctx, &mcpTool.Config{
Cli: cli,
})
return tools, 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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
