MCP Go SDK

2026年1月12日 · 375 字 · 2 分钟

mcp简介以及mcp go adk的服务端以及客户端的使用

MCP Go SDK

MCP

什么是MCP

每个人都会开发各种工具,工具除了自己调用,可以让别人调用,假如我用eino写个工具,langchain怎么调用呢,所以产生了mcp,可以理解为协议,便于各种语言和框架调用

MCP的三种通讯方式

  • Stdio
  • SSE
  • Streamable Http

MCP Go SDK

25年7月,谷歌协助mcp组织进行了go sdk,由此MCP Go SDK孕育而生

MCP http 服务端

在这里通过http启动一个mcp服务

需要的包

"github.com/modelcontextprotocol/go-sdk/mcp"

获取时间

type TimeInput struct {
	TimeZone string `json:"time_zone" jsonschema:"时区"`
}

type TimeOutput struct {
	Time string `json:"time" jsonschema:"当前时间"`
}

func GetCurrentTime(ctx context.Context, req *mcp.CallToolRequest, intput *TimeInput) (*mcp.CallToolResult, *TimeOutput, error) {
	if len(intput.TimeZone) == 0 {
		intput.TimeZone = "Asia/Shanghai"
	}
	loc, err := time.LoadLocation(intput.TimeZone)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to load location: %w", err)
	}
	now := time.Now().In(loc)
	return nil, &TimeOutput{Time: now.Format("2006-01-02 15:04:05")}, nil
}

获取城市

const (
	ip        = "XX.XX.XX.XX"
	GAODE_KEY = "xxxx"
)

type LocationResponse struct {
	Status   string `json:"status"`
	Province string `json:"province"`
	City     string `json:"city"`
	Adcode   string `json:"adcode"`
}

func GetLocation(ctx context.Context, req *mcp.CallToolRequest, intput struct{}) (*mcp.CallToolResult, *LocationResponse, error) {
	url := fmt.Sprintf("https://restapi.amap.com/v3/ip?key=%s&ip=%s", GAODE_KEY, ip)
	data, err := HttpGet(url)//HttpGet为包装的http的get请求方法,返回值为请求体
	if err != nil {
		return nil, nil, fmt.Errorf("failed to get location: %w", err)
	}
	var location LocationResponse
	err = sonic.Unmarshal(data, &location)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to unmarshal location: %w", err)
	}
	if location.Status != "1" {
		return nil, nil, fmt.Errorf("failed to get location: %w", err)
	}
	return nil, &location, nil
}

启动服务

func main() {
	server := mcp.NewServer(&mcp.Implementation{
		Name:    "easy_mcp",
		Version: "1.0.0",
	}, nil)
	mcp.AddTool(server, &mcp.Tool{
		Name:        "time_tool",
		Description: "获取当前时间",
	}, GetCurrentTime)
	mcp.AddTool(server, &mcp.Tool{
		Name:        "location_tool",
		Description: "获取当前位置",
	}, GetLocation)

	//http的server
	handler := mcp.NewStreamableHTTPHandler(
		func(*http.Request) *mcp.Server {
			return server
		}, &mcp.StreamableHTTPOptions{},
	)
	http.HandleFunc("/mcp", handler.ServeHTTP)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

MCP http 客户端

func main() {
	ctx := context.Background()
	client := mcp.NewClient(&mcp.Implementation{
		Name:    "easy_mcp",
		Version: "1.0.0",
	}, nil)

	transport := &mcp.StreamableClientTransport{
		Endpoint: "http://127.0.0.1:8080/mcp",
		HTTPClient: &http.Client{
			Timeout: 10 * time.Second,
		},
	}
	session, err := client.Connect(ctx, transport, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer session.Close()

	resp, err := session.CallTool(ctx, &mcp.CallToolParams{
		Name: "time_tool",
		Arguments: map[string]any{
			"time_zone": "Asia/Shanghai",
		},
	})
	if err != nil {
		log.Fatal("time_tool call failed:", err)
	}
	if resp.IsError {
		log.Fatal("time_tool returned error, content:", resp.Content)
	}

	resp1, err := session.CallTool(ctx, &mcp.CallToolParams{
		Name:      "location_tool",
		Arguments: map[string]any{},
	})
	if err != nil {
		log.Fatal("location_tool call failed:", err)
	}
	if resp1.IsError {
		log.Fatal("location_tool returned error, content:", resp1.Content)
	}
	for _, c := range resp.Content {
		fmt.Println(c.(*mcp.TextContent).Text)
	}
	for _, c := range resp1.Content {
		fmt.Println(c.(*mcp.TextContent).Text)
	}
}

调用结果

{"time":"2026-01-12 15:29:07"}
{"adcode":"150000","city":"呼和浩特市","province":"内蒙古自治区","status":"1"}