Content
# `protoc-gen-go-mcp`
[](https://github.com/redpanda-data/protoc-gen-go-mcp/actions/workflows/test.yml)
[](https://goreportcard.com/report/github.com/redpanda-data/protoc-gen-go-mcp)
[](https://codecov.io/gh/redpanda-data/protoc-gen-go-mcp)
**`protoc-gen-go-mcp`** is a [Protocol Buffers](https://protobuf.dev) compiler plugin that generates [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers for your `gRPC` or `ConnectRPC` APIs.
It generates `*.pb.mcp.go` files for each protobuf service, enabling you to delegate handlers directly to gRPC servers or clients. Under the hood, MCP uses JSON Schema for tool inputs—`protoc-gen-go-mcp` auto-generates these schemas from your method input descriptors.
> ⚠️ Currently supports [mark3labs/mcp-go](https://github.com/mark3labs/mcp-go) as the MCP server runtime. Future support is planned for official Go SDKs and additional runtimes.
## ✨ Features
- 🚀 Auto-generates MCP handlers from your `.proto` services
- 📦 Outputs JSON Schema for method inputs
- 🔄 Wire up to gRPC or ConnectRPC servers/clients
- 🧩 Easy integration with [`buf`](https://buf.build)
- 🎯 **Runtime LLM provider selection** - Choose between standard MCP and OpenAI-compatible schemas at runtime
## 🔧 Usage
### Generate code
Add entry to your `buf.gen.yaml`:
```
...
plugins:
- local:
- go
- run
- github.com/redpanda-data/protoc-gen-go-mcp/cmd/protoc-gen-go-mcp@latest
out: ./gen/go
opt: paths=source_relative
```
You need to generate the standard `*.pb.go` files as well. `protoc-gen-go-mcp` by defaults uses a separate subfolder `{$servicename}mcp`, and imports the `*pb.go` files - similar to connectrpc-go.
After running `buf generate`, you will see a new folder for each package with protobuf Service definitions:
```
tree pkg/testdata/gen/
gen
└── go
└── testdata
├── test_service.pb.go
├── testdataconnect/
│ └── test_service.connect.go
└── testdatamcp/
└── test_service.pb.mcp.go
```
### Wiring Up MCP with gRPC server (in-process)
Example for in-process registration:
```go
srv := testServer{} // your gRPC implementation
// Register all RPC methods as tools on the MCP server
testdatamcp.RegisterTestServiceHandler(mcpServer, &srv)
```
Each RPC method in your protobuf service becomes an MCP tool.
### Runtime LLM Provider Selection
**New!** You can now choose LLM compatibility at runtime without regenerating code:
```go
// Option 1: Use convenience function with runtime provider selection
provider := testdatamcp.LLMProviderOpenAI // or LLMProviderStandard
testdatamcp.RegisterTestServiceHandlerWithProvider(mcpServer, &srv, provider)
// Option 2: Register specific handlers directly
testdatamcp.RegisterTestServiceHandler(mcpServer, &srv) // Standard MCP
testdatamcp.RegisterTestServiceHandlerOpenAI(mcpServer, &srv) // OpenAI-compatible
// Option 3: Register both for different tool names
testdatamcp.RegisterTestServiceHandler(mcpServer, &srv)
testdatamcp.RegisterTestServiceHandlerOpenAI(mcpServer, &srv)
```
**Environment variable example:**
```go
providerStr := os.Getenv("LLM_PROVIDER")
var provider testdatamcp.LLMProvider
switch providerStr {
case "openai":
provider = testdatamcp.LLMProviderOpenAI
case "standard":
fallthrough
default:
provider = testdatamcp.LLMProviderStandard
}
testdatamcp.RegisterTestServiceHandlerWithProvider(mcpServer, &srv, provider)
```
➡️ See the [full example](./examples/basic) for details.
### Wiring up with grpc and connectrpc client
It is also possible to directly forward MCP tool calls to gRPC clients.
```go
testdatamcp.ForwardToTestServiceClient(mcpServer, myGrpcClient)
```
Same for connectrpc:
```go
testdatamcp.ForwardToConnectTestServiceClient(mcpServer, myConnectClient)
```
This directly connects the MCP handler to the connectrpc client, requiring zero boilerplate.
### Extra properties
It's possible to add extra properties to MCP tools, that are not in the proto. These are written into context.
```go
// Enable URL override with custom field name and description
option := runtime.WithExtraProperties(
runtime.ExtraProperty{
Name: "base_url",
Description: "Base URL for the API",
Required: true,
ContextKey: MyURLOverrideKey{},
},
)
// Use with any generated function
testdatamcp.RegisterTestServiceHandler(mcpServer, &srv, option)
testdatamcp.ForwardToTestServiceClient(mcpServer, client, option)
```
## LLM Provider Compatibility
The generator now creates both standard MCP and OpenAI-compatible handlers automatically. You can choose which to use at runtime:
### Standard MCP
- Full JSON Schema support (additionalProperties, anyOf, oneOf)
- Maps represented as JSON objects
- Well-known types use native JSON representations
### OpenAI Compatible
- Restricted JSON Schema (no additionalProperties, anyOf, oneOf)
- Maps converted to arrays of key-value pairs
- Well-known types (Struct, Value, ListValue) encoded as JSON strings
- All fields marked as required with nullable unions
### Migration from openai_compat flag
The old `openai_compat=true` protoc option is **deprecated but still supported** for backward compatibility. With the new approach:
**Before (compile-time):**
```yaml
# buf.gen.yaml
plugins:
- local: [.../protoc-gen-go-mcp]
out: ./gen/go
opt: paths=source_relative,openai_compat=true
```
**After (runtime):**
```go
// Choose at runtime
testdatamcp.RegisterTestServiceHandlerWithProvider(server, srv, testdatamcp.LLMProviderOpenAI)
```
## Development & Testing
### Commands
All commands use [just](https://github.com/casey/just):
```bash
just build # Build everything (Bazel)
just test-unit # Unit + golden tests (no API keys needed)
just test # All tests including conformance/integration (needs API keys)
just test-cover # Tests with coverage report
just generate # Regenerate proto code + descriptor set
just lint # Run golangci-lint
just fmt # Format code
just install # Install binary to GOPATH/bin
just gazelle # Sync BUILD files from go.mod
# View all available commands
just --list
```
### Development Workflow
```bash
# 1. Edit proto or generator code
# 2. Regenerate
just generate
# 3. Run tests
just test-unit
```
### Golden File Testing
The generator uses golden file testing to ensure output consistency. Tests re-run the generator in-process from compiled descriptors and compare against checked-in `*.pb.mcp.go` files.
**To add new tests:** Drop a `.proto` file in `pkg/testdata/proto/testdata/` and run `just generate`. The golden test automatically discovers all generated files and compares them.
## ⚠️ Limitations
- No interceptor support (yet). Registering with a gRPC server bypasses interceptors.
- Tool name mangling for long RPC names: If the full RPC name exceeds 64 characters (Claude desktop limit), the head of the tool name is mangled to fit.
## 🗺️ Roadmap
- Reflection/proxy mode
- Interceptor middleware support in gRPC server mode
- Support for the official Go MCP SDK (once published)
## 💬 Feedback
We'd love feedback, bug reports, or PRs! Join the discussion and help shape the future of Go and Protobuf MCP tooling.
Connection Info
You Might Also Like
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
Sequential Thinking
A structured MCP server for dynamic problem-solving and reflective thinking.