最近我在看 Istio 的代码,顺带了解了一下 MCP(Model Context Protocol)协议,发现虽然这个协议现在不再是主流(Istio 已逐步转向 xDS 协议),但作为服务配置下发的一种协议形式,还是挺有意思的,我这边结合学习过程,写一篇自己的实践记录。
🤔 什么是 MCP?
MCP,全称是 Model Context Protocol,是一种 用于配置分发的 gRPC 协议,最初被 Istio 引入,用于把配置从 control plane 推送到 data plane。
简单来说,它让你可以通过 gRPC 发送一大堆“配置资源”(例如服务发现、路由规则、安全策略等)给一个客户端。客户端接收之后就可以更新本地的服务网格配置。
虽然 MCP 后来被 xDS 替代,但了解它仍有价值,毕竟设计思想是类似的。
🔧 搭建一个最小可运行的 MCP Server
首先我们要定义的是:MCP 本质上是基于 protobuf 和 gRPC 的协议,所以我们要准备以下几个部分:
📦 Protobuf 定义(简化版)
下面是一个最精简的 .proto 定义,保留核心结构:
syntax = "proto3";
package mcp;
service AggregatedResourcesService {
rpc StreamAggregatedResources(stream AggregatedResourcesRequest) returns (stream AggregatedResourcesResponse);
}
message AggregatedResourcesRequest {
string node_id = 1;
string type_url = 2;
}
message AggregatedResourcesResponse {
string type_url = 1;
bytes resource = 2;
}
这个定义里我们关注的是:
- StreamAggregatedResources 是核心 RPC 方法,支持双向流。
- 客户端会发出请求(比如我想要某种类型的配置)
- 服务器响应对应的资源内容。
⚙️ 生成 Go 代码
你需要安装如下插件:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
然后生成代码:
protoc –go_out=. –go-grpc_out=. mcp.proto
生成之后,会得到一组 .pb.go 文件,可以直接 import 使用。
🚀 实现 MCP Server
package main
import (
"log"
"net"
"google.golang.org/grpc"
pb "your_project_path/mcp"
)
type server struct {
pb.UnimplementedAggregatedResourcesServiceServer
}
func (s *server) StreamAggregatedResources(stream pb.AggregatedResourcesService_StreamAggregatedResourcesServer) error {
for {
req, err := stream.Recv()
if err != nil {
log.Printf("Error receiving request: %v", err)
return err
}
log.Printf("Received request for type_url: %s from node: %s", req.TypeUrl, req.NodeId)
// 模拟返回一个响应
resp := &pb.AggregatedResourcesResponse{
TypeUrl: req.TypeUrl,
Resource: []byte(`{"config":"example"}`),
}
if err := stream.Send(resp); err != nil {
log.Printf("Error sending response: %v", err)
return err
}
}
}
🧪 启动 gRPC 服务
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
pb.RegisterAggregatedResourcesServiceServer(grpcServer, &server{})
log.Println("MCP server listening on port 50051…")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
运行:
go run main.go
🎯 客户端
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
client := pb.NewAggregatedResourcesServiceClient(conn)
stream, _ := client.StreamAggregatedResources(context.Background())
stream.Send(&pb.AggregatedResourcesRequest{
NodeId: "test-node",
TypeUrl: "type.googleapis.com/example.Config",
})
resp, _ := stream.Recv()
fmt.Println("Received:", string(resp.Resource))
📌 总结
通过上面这些步骤,我们就实现了一个最小可用的 MCP Server:
- 🧱 基于 Protobuf + gRPC 协议
- 📦 提供了资源类型的请求和响应
- 🚀 可以扩展为配置中心、服务网格控制组件等
虽然 MCP 现在不再是主流(Istio 改用 xDS 了),但这个练手项目依然适合用来学习 gRPC 流式传输、协议设计、配置推送等内容。
🔍 延伸思考
- 如果你熟悉 Envoy 或 Istio,可以对比一下 MCP 和 xDS 协议的设计差异。
- MCP 中也有资源版本、Nonce 等机制来支持一致性和确认机制,这里我们为了简洁省略了。
- 想进一步练习的朋友可以试试加个客户端 + 资源监听逻辑 + 资源更新推送。
📎 参考链接:
- https://github.com/istio/api/tree/master/mcp
🧑💻 本文由 @你的名字 撰写,更多 Go 网络协议实现和服务端框架开发内容,欢迎关注!
评论前必须登录!
注册