gRPC MCP Gateway
gRPC MCP Gateway
grpc-mcp-gateway is a Go code generator that maps gRPC service methods to MCP tools using protobuf annotations, similar in spirit to grpc-gateway but targeting MCP instead of REST.
What is MCP?
MCP (Model Context Protocol) is a lightweight protocol that lets AI clients discover tools and call them over a simple JSON-RPC interface. It provides a standard way to expose capabilities (tools) so models can interact with your systems safely and consistently.
Status
- Generates MCP tool registrations from annotated gRPC methods.
- Bridges MCP tool calls to gRPC methods.
- Supports MCP tool metadata (name, title, description, annotations).
- Generates strongly-typed JSON Schema for tool inputs derived from protobuf message definitions.
- Provides a lightweight MCP HTTP handler (
runtime.MCPServeMux) with pluggable request logging. - Keeps MCP tooling stateless (no sessions).
MCP spec compatibility
| grpc-mcp-gateway version | MCP spec version | | --- | --- | | v0.6.0+ | 2025-11-25 (JSON-RPC 2.0) |
MCP annotations
Define MCP annotations in your proto file alongside any REST annotations:
syntax = "proto3";
package demo.v1;
import "google/api/annotations.proto";
import "mcp/gateway/v1/annotations.proto";
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/hello"
body: "*"
};
option (mcp.gateway.v1.mcp) = {
tool: {
name: "greeter.say_hello"
title: "Say Hello"
description: "Greets a caller."
read_only: true
}
};
}
}
Annotation schema lives at proto/mcp/gateway/v1/annotations.proto.
Generator usage
protoc \
-I . \
-I ./proto \
--go_out=. --go-grpc_out=. \
--mcp-gateway_out=. \
path/to/your.proto
Buf usage
If you generate protos with Buf, install the plugin and add it to your buf.gen.yaml.
Install Buf:
brew install buf
Install the plugin (puts protoc-gen-mcp-gateway on your PATH):
go install github.com/linkbreakers-com/grpc-mcp-gateway/cmd/protoc-gen-mcp-gateway@latest
Example buf.gen.yaml:
version: v1
plugins:
- name: go
out: generated/go
- name: go-grpc
out: generated/go
- name: mcp-gateway
out: generated/go
Then run:
buf generate
Generated API
For each service with annotated methods, the generator emits:
func Register<YourService>MCPHandler(mux *runtime.MCPServeMux, client <YourService>Client)
This registers MCP tools for annotated methods and routes MCP tool calls to the gRPC client.
Minimal server startup
lis, _ := net.Listen("tcp", ":50051")
grpcServer := grpc.NewServer()
demov1.RegisterGreeterServer(grpcServer, greeterSvc)
go grpcServer.Serve(lis)
conn, _ := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
client := demov1.NewGreeterClient(conn)
handler := runtime.NewMCPServeMux(
runtime.ServerMetadata{Name: "greeter-mcp", Version: "v0.1.0"},
runtime.WithRequestLogger(func(ctx context.Context, req *runtime.MCPRequest) {
// Optional: log MCP requests here
}),
)
demov1.RegisterGreeterMCPHandler(handler, client)
http.ListenAndServe(":8090", handler)
Logging example
Use WithRequestLogger to log every MCP request with method-specific detail:
logger := runtime.WithRequestLogger(func(ctx context.Context, req *runtime.MCPRequest) {
switch req.Method {
case "tools/call":
name, _ := req.Params["name"].(string)
if name == "" {
log.Printf("MCP tools/call")
return
}
log.Printf("MCP tools/call: %s", name)
case "tools/list":
log.Printf("MCP tools/list - client discovering tools")
case "initialize":
log.Printf("MCP initialize - client connecting")
case "notifications/initialized":
log.Printf("MCP notifications/initialized - handshake complete")
default:
log.Printf("MCP %s", req.Method)
}
})
mux := runtime.NewMCPServeMux(
runtime.ServerMetadata{Name: "greeter-mcp", Version: "v0.1.0"},
logger,
)
Example log output:
2026/02/11 09:41:02 MCP initialize - client connecting
2026/02/11 09:41:02 MCP notifications/initialized - handshake complete
2026/02/11 09:41:03 MCP tools/list - client discovering tools
2026/02/11 09:41:04 MCP tools/call: greeter.say_hello
Minimal client request (curl)
List tools:
curl -s http://localhost:8090/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Call a tool:
curl -s http://localhost:8090/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"greeter.say_hello","arguments":{"name":"Ada"}}}'
Production notes
- Add auth and token verification at the HTTP layer before the MCP handler.
- Configure CORS if the MCP client runs in a browser or remote environment.
- Set timeouts on the HTTP server and gRPC client to avoid hanging tool calls.
- Use structured logging by passing
WithRequestLoggerin your MCP mux.
Complete Production Example
For a comprehensive, production-ready implementation showing all the best practices, see:
This example demonstrates:
- Bearer token authentication with JSON-RPC error handling
- Request logging for all MCP protocol messages
- Health check endpoints for Kubernetes
- CORS configuration
- Proper handling of
notifications/initialized - Response recording for auth failure debugging
- gRPC ↔ HTTP dual server architecture
- Kubernetes deployment patterns
Perfect for teams building production MCP servers.
Example client (end-to-end)
This repo includes a tiny MCP client that calls the echo tool over HTTP:
# In one terminal, start the echo server:
go run ./examples/structecho
# In another terminal, call the tool:
go run ./examples/structecho-client
Example with real protobuf + gRPC
A full end-to-end test (gRPC server + MCP gateway + MCP client) lives in:
github.com/linkbreakers-com/grpc-mcp-gateway/examples/greeter
Run the test:
go test ./examples/greeter -run TestGreeterMCPFlow
In Production
This library is used in production at Linkbreakers. We open-sourced it to make it easy for any team with a Protobuf/gRPC API to add MCP support quickly, because we believe MCP will become an increasingly important way to integrate tools into AI workflows.
Linkbreakers MCP server: https://mcp.linkbreakers.com
MCP directory listing: https://mcp.so/server/linkbreakers
Schema generation
The generator produces strongly-typed JSON Schema for each tool's inputSchema, derived directly from the protobuf message definition. This is inspired by how grpc-gateway's protoc-gen-openapiv2 generates OpenAPI schemas.
What is generated:
- Field types: proto scalar kinds are mapped to JSON Schema types (
string,integer,number,boolean) with appropriateformatvalues (int32,int64,float,double,byte,date-time). - Enum fields: All enum values are listed in an
enumarray. The zero-value sentinel (e.g.TYPE_UNSPECIFIED) is excluded so MCP clients always pick a valid value. - Nested messages: Recursively expanded into object schemas with
properties. - Repeated fields: Mapped to
{"type": "array", "items": ...}. - Map fields: Mapped to
{"type": "object", "additionalProperties": ...}. - Well-known types:
google.protobuf.Timestamp→date-timestring,Struct→ open object, wrapper types → their underlying types, etc. google.api.field_behavior:OUTPUT_ONLYfields are excluded from input schemas.REQUIREDfields are added to therequiredarray.- Descriptions: Extracted from proto comments and included in the schema.
Example — given this proto message:
message CreateTaskRequest {
// The title of the task
string title = 1 [(google.api.field_behavior) = REQUIRED];
// The priority level
Task.Priority priority = 2;
// Tags to associate with the task
repeated string tags = 3;
}
message Task {
enum Priority {
PRIORITY_UNSPECIFIED = 0;
PRIORITY_LOW = 1;
PRIORITY_HIGH = 2;
}
}
The generator produces:
InputSchema: map[string]any{
"additionalProperties": false,
"properties": map[string]any{
"title": map[string]any{
"description": "The title of the task",
"type": "string",
},
"priority": map[string]any{
"description": "The priority level",
"enum": []string{"PRIORITY_LOW", "PRIORITY_HIGH"},
"type": "string",
},
"tags": map[string]any{
"description": "Tags to associate with the task",
"items": map[string]any{"type": "string"},
"type": "array",
},
},
"required": []string{"title"},
"type": "object",
},
Limitations
- Only unary RPCs are supported (streaming RPCs are skipped).
Project layout
cmd/protoc-gen-mcp-gateway: the protoc plugin (code generator + schema builder)proto/mcp/gateway/v1/annotations.proto: MCP annotation definitionsruntime: MCP <-> protobuf conversion helpers