Awesome Go

protoc-gen-mcp

CategoryGenerators
SubcategoryGenerators
Stars5

Generate typed MCP tools, prompts, and resources from Protocol Buffers

About protoc-gen-mcp

This large README is shown as a plain-text preview. Read the full README at the source

# protoc-gen-mcp

<p align="center">
  <a href="https://github.com/easyp-tech/protoc-gen-mcp/actions/workflows/tests.yml"><img alt="CI" src="https://github.com/easyp-tech/protoc-gen-mcp/actions/workflows/tests.yml/badge.svg"></a>
  <a href="https://coveralls.io/github/easyp-tech/protoc-gen-mcp?branch=master"><img alt="Coverage Status" src="https://coveralls.io/repos/github/easyp-tech/protoc-gen-mcp/badge.svg?branch=master"></a>
  <a href="https://pkg.go.dev/github.com/easyp-tech/protoc-gen-mcp"><img alt="Go Reference" src="https://pkg.go.dev/badge/github.com/easyp-tech/protoc-gen-mcp.svg"></a>
  <a href="https://github.com/easyp-tech/protoc-gen-mcp/releases/latest"><img alt="Release" src="https://img.shields.io/github/v/release/easyp-tech/protoc-gen-mcp?sort=semver"></a>
  <a href="https://github.com/easyp-tech/protoc-gen-mcp/blob/master/LICENSE"><img alt="License" src="https://img.shields.io/github/license/easyp-tech/protoc-gen-mcp"></a>
  <a href="https://github.com/easyp-tech/protoc-gen-mcp/blob/master/go.mod"><img alt="Go version" src="https://img.shields.io/github/go-mod/go-version/easyp-tech/protoc-gen-mcp?logo=go&logoColor=white"></a>
</p>


`protoc-gen-mcp` generates Go, Python, Kotlin, Java, and TypeScript MCP
bindings from protobuf definitions — covering **tools**, **prompts**, and
**resources**. JavaScript users consume the compiled TypeScript output and
declarations.

## Supported MCP Primitives

| Primitive | Go | Python | Kotlin | Java | TypeScript |
|-----------|:--:|:------:|:------:|:----:|:----------:|
| **Tools** | ✅ Full | ✅ Full | ✅ Full | ✅ Full | ✅ Full |
| **Prompts** | ✅ Full | ✅ Full | ✅ Full | ✅ Full | ✅ Full |
| **Resources** | ✅ Full | ⚠️ Interface | ⚠️ Interface | ⚠️ Interface | ⚠️ Interface |

## MVP

- protobuf is the source of truth
- generator emits typed Go, Python, Kotlin, Java, and TypeScript MCP bindings
- **Tools**: generated from `service` RPC methods with `(mcp.options.v1.method)`
- **Prompts**: generated from `message` types with `(mcp.options.v1.prompt)`
- **Resources**: generated from `message` types with `(mcp.options.v1.resource)`
  — static (fixed URI) and template (parameterized URI) resources
- Go runtime uses the official Go MCP SDK
- Python runtime targets the official MCP Python SDK with `google.protobuf`
- Kotlin runtime targets the official `io.modelcontextprotocol:kotlin-sdk-server`
  SDK
- Java runtime targets the official `io.modelcontextprotocol.sdk:mcp` SDK
- TypeScript runtime targets the official `@modelcontextprotocol/sdk` SDK,
  Protobuf-ES, and Ajv-backed raw JSON Schema validation
- generated Python handlers default to dataclasses and explicit `oneof`
  wrapper types from `*_mcp.py`; `python_handler=protobuf` opts into raw
  `*_pb2` handler request/response classes with the same registration helper;
  `python_handler=dataclass+protobuf` generates both surfaces side by side
- generated Kotlin handlers implement `<Service>ToolHandler` and are registered
  through `register<Service>Tools(server: Server, impl: <Service>ToolHandler, namespace: String? = null)`
- generated Java handlers implement nested `<Service>ToolHandler` interfaces
  inside a generated `<ProtoFile>Mcp` sidecar and are registered through
  `register<Service>Tools(McpServerTransportProvider transportProvider, <Service>ToolHandler impl, String namespace)`
- generated TypeScript handlers implement `<Service>ToolHandler` and are
  registered through `register<Service>Tools(server, impl, namespace?)`
- Direct lang=javascript generation is intentionally deferred; JavaScript
  projects use compiled TypeScript target `.js` files plus `.d.ts` declarations
- request and response JSON follows ProtoJSON rules
- runtime validation is driven by generated JSON Schema

## Repository Workflows

Use `easyp` for repository generation and checks.
The repository is currently aligned to `easyp v0.15.2-rc1`.

```bash
easyp --cfg easyp.yaml lint -p mcp -r .
easyp --cfg easyp.yaml generate -p mcp -r .
easyp --cfg easyp.test.yaml lint -p internal/testproto -r .
easyp --cfg easyp.test.yaml generate -p internal/testproto -r .
gradle --no-daemon -p examples/jvm :java-server:compileJava :kotlin-server:compileKotlin
gradle --no-daemon -p examples/jvm :java-server:installDist :kotlin-server:installDist
go test ./internal/examplemcp -run 'Test(Java|Kotlin).*OverStdio' -count=1
(cd examples/node/sdk-spike && npm ci && npm run typecheck && npm run build)
(cd examples/10_python_protobuf_standalone && make lint && make clean generate)
(cd examples/8_typescript_standalone && make lint && make clean build)
(cd examples/9_javascript_standalone && make clean build)
go test ./examples -run 'TestStandalonePython(Protobuf)?ExampleOverStdio' -count=1
go test ./examples -run 'TestStandalone(TypeScript|JavaScript)ExampleOverStdio' -count=1
go test ./...
goreleaser check
```

`easyp.yaml` is the main config for shipped protobuf APIs. `easyp.test.yaml`
is the development and test config for repository fixtures.

`mcp/options/v1/options.proto` carries its own explicit `go_package`, so
consumers do not need a special Easyp `go_package_prefix` override just to use
the MCP options package.

CI is implemented in [tests.yml](.github/workflows/tests.yml)
and runs config validation, Easyp lint, Easyp generation, a generated-file
freshness check, JVM compile/install gates, JVM stdio parity checks, Node
compile/build gates, generated Node stdio checks through `go test ./...`, and
standalone Python/Node example tests. Releases are implemented in
[release.yml](.github/workflows/release.yml)
and use [`.goreleaser.yaml`](.goreleaser.yaml)
to publish tagged builds of the `protoc-gen-mcp` binary. This repository does
not publish separate Java, Kotlin, TypeScript, or JavaScript runtime artifacts;
downstream projects compile generated source against their language SDK
dependencies.

## TypeScript And JavaScript Support

TypeScript support is implemented for Node stdio servers and verified through
the official MCP TypeScript SDK, Protobuf-ES, and Ajv. User-owned standalone
project layouts are shown in
[`examples/8_typescript_standalone`](examples/8_typescript_standalone/) and
[`examples/9_javascript_standalone`](examples/9_javascript_standalone/).

- Node prerequisites for the in-repo walkthrough are Go 1.24+, Node.js, npm,
  `easyp v0.15.2-rc1`, and the npm dependencies pinned by the examples.
- The Node generator mode is `lang=typescript`.
- The tested stack is `@modelcontextprotocol/[email protected]`,
  `@bufbuild/[email protected]`, `@bufbuild/protoc-gen-es`, and `[email protected]`.
- Protobuf message classes are generated by Protobuf-ES as `_pb.ts` files with
  NodeNext-compatible `.js` import specifiers.
- `protoc-gen-mcp` generates `*_mcp.ts` sidecars that install low-level
  `tools/list` and `tools/call` handlers on the official SDK `Server`.
- Generated TypeScript preserves the shared raw JSON Schema and compiles it
  with Ajv, then maps request/response payloads through Protobuf-ES ProtoJSON.
- JavaScript consumption uses the compiled `.js` output and generated `.d.ts`
  declarations from the TypeScript target. Direct lang=javascript generation
  is intentionally deferred until compiled TypeScript output proves
  insufficient for common JavaScript projects.

Use the standalone TypeScript example when you want a full user-project
generation flow. Use the JavaScript example when you want to inspect how a
plain `.js` server imports compiled generated output without a separate
renderer.

## JVM Support

JVM support is implemented and CI-verified through the runnable
[`examples/jvm`](examples/jvm/README.md) workspace. User-owned standalone
project layouts are shown in
[`examples/6_java_standalone`](examples/6_java_standalone/) and
[`examples/7_kotlin_standalone`](examples/7_kotlin_standalone/).

- JVM prerequisites for the in-repo walkthrough are Go 1.24+, JDK 17+, and
  Gradle 9.2+.
- The JVM generator modes are `lang=java` and `lang=kotlin`.
- The Java path compiles generated protobuf Java output plus a generated
  `lang=java` MCP sidecar against the official
  `io.modelcontextprotocol.sdk:mcp` SDK.
- The Kotlin path follows the tested dual-generation flow from
  `examples/jvm/kotlin-server/build.gradle.kts`: Java protobuf output, Kotlin
  protobuf output, and then the `lang=kotlin` MCP sidecar are all required.
- The canonical runnable JVM verification path uses `installDist` plus the
  installed scripts under `examples/jvm/*/build/install/.../bin/*`, matching
  `internal/examplemcp/jvm_stdio_test.go` and CI.
- Standalone JVM protos can be Java/Kotlin-native and omit `go_package`; the
  generator synthesizes internal protogen metadata for `lang=java` and
  `lang=kotlin`.

Use the root README for the language matrix and repository workflow, inspect
the standalone Java/Kotlin directories for user-project shape, and use
[examples/jvm/README.md](examples/jvm/README.md) for the cross-language JVM
verification workspace.

## Test MCP Server

The repository also includes a runnable MCP server for manual client checks:

```bash
# stdio (default)
go run ./cmd/example-mcp-server

# Streamable HTTP (MCP spec 2025-11-25), localhost only by default
go run ./cmd/example-mcp-server -transport=http -addr=127.0.0.1:8080 -path=/mcp

python ./cmd/example-python-mcp-server/main.py
```

It serves the generated tools from `internal/testproto/example/v1` and is used
by the stdio smoke tests in `internal/examplemcp/stdio_test.go`.
The example server currently exposes:

- `example_CreateReport`
- `example_Health`
- `example_DescribeAdvancedShapes`
- `example_DescribeScalarShapes`

### Go Streamable HTTP (`mcpruntime`)

Go servers can expose the same generated tools over **Streamable HTTP** instead
of (or in addition to) stdio:

```go
mux := http.NewServeMux()
mux.Handle("/mcp", mcpruntime.NewStreamableHTTPHandler(server, mcpruntime.StreamableHTTPOptions{
    AllowedOrigins: []string{"http://localhost:3000"},
}))
// Prefer binding to 127.0.0.1 for local deployments (DNS-rebinding mitigation).
http.ListenAndServe("127.0.0.1:8080", mux)
```

Or:

```go
mcpruntime.ServeStreamableHTTP(ctx, "127.0.0.1:8080", server, mcpruntime.StreamableHTTPOptions{
    Path: "/mcp",
})
```

Behavior highlights:

- Single MCP endpoint: `POST` (JSON-RPC), `GET` (SSE listen), `DELETE` (session end)
- Multi-client sessions via `MCP-Session-Id` on `initialize`
- Origin validation (localhost Origins allowed by default when the allowlist is empty)
- Optional SSE POST responses with `PreferSSE: true`
- `Last-Event-ID` replay for GET streams (in-memory buffer)
- Legacy HTTP+SSE (2024-11-05) is **not** implemented

## Testing With MCP Inspector

Use the official
[MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) for
interactive stdio checks while developing a server. The Inspector runs through
`npx` and starts the MCP server command you pass after the Inspector package.

For the Go example server:

```bash
npx -y @modelcontextprotocol/inspector go run ./cmd/example-mcp-server
```

For the Python example server:

```bash
npx -y @modelcontextprotocol/inspector python ./cmd/example-python-mcp-server/main.py
```

For the standalone raw protobuf Python example, create the example virtualenv
first and then point the Inspector at the local server:

```bash
(cd examples/10_python_protobuf_standalone && make setup)
(cd examples/10_python_protobuf_standalone && npx -y @modelcontextprotocol/inspector .venv/bin/python server.py)
```

For installed JVM examples, build the scripts first and then point the
Inspector at the installed application:

```bash
gradle --no-daemon -p examples/jvm :java-server:installDist :kotlin-server:installDist
npx -y @modelcontextprotocol/inspector ./examples/jvm/java-server/build/install/java-server/bin/java-server
npx -y @modelcontextprotocol/inspector ./examples/jvm/kotlin-server/build/install/kotlin-server/bin/kotlin-server
```

For standalone Node examples, build first and then point the Inspector at the
Node server entrypoint:

```bash
(cd examples/8_typescript_standalone && make build)
npx -y @modelcontextprotocol/inspector node ./examples/8_typescript_standalone/dist/server.js

(cd examples/9_javascript_standalone && make build)
npx -y @modelcontextprotocol/inspector node ./examples/9_javascript_standalone/src/server.js
```

When the Inspector UI opens, connect to the server, open the Tools tab, run
List Tools, then call a generated tool such as `example_Health` or
`example_CreateReport`. This is the fastest manual check that generated tool
names, schemas, annotations, ProtoJSON inputs, structured outputs, and server
stdio wiring are visible to an MCP client.

## Examples

We provide several standalone, runnable examples demonstrating generated MCP
tools, protobuf `options`, validation constraints, and integration with the
official Go, Python, Kotlin, Java, TypeScript, and JavaScript SDK paths. Check
out the
[examples/](examples/) directory for:
- [1_helloworld](examples/1_helloworld/) - Minimal Quickstart setup.
- [2_weather_api](examples/2_weather_api/) - Read-only queries, validation limits, Oneofs.
- [3_file_manager](examples/3_file_manager/) - Destructive tools and schema-based string parameter constraints.
- [4_crm_system](examples/4_crm_system/) - A full mock system with FieldMask partial updates, custom icons mapping, schemas nested types, and advanced array filters.
- [5_python_standalone](examples/5_python_standalone/) - A Python-only user-style project with its own `pyproject.toml`, `easyp.yaml`, generated bindings, and stdio server.
- [10_python_protobuf_standalone](examples/10_python_protobuf_standalone/) - A Python-only user-style project that opts into `python_handler=dataclass+protobuf` and implements the raw `*_mcp_pb.py` sidecar with `*_pb2` classes.
- [6_java_standalone](examples/6_java_standalone/) - A Java user-style project with its own Gradle build, `easyp.yaml`, protobuf contract, and generated MCP sidecar.
- [7_kotlin_standalone](examples/7_kotlin_standalone/) - A Kotlin user-style project with its own Gradle build, `easyp.yaml`, protobuf contract, and generated MCP sidecar.
- [8_typescript_standalone](examples/8_typescript_standalone/) - A TypeScript user-style project with its own npm package, `tsconfig.json`, `easyp.yaml`, Protobuf-ES output, generated MCP sidecar, and stdio server.
- [9_javascript_standalone](examples/9_javascript_standalone/) - A JavaScript consumption proof that imports compiled generated `.js` output and `.d.ts` metadata from the TypeScript standalone project.
- [jvm](examples/jvm/README.md) - A Java/Kotlin official SDK workspace with
  Gradle-managed protobuf generation, `lang=java` / `lang=kotlin` sidecars,
  `installDist` scripts, and stdio verification.

## Agent Skill

Install the [skills.sh](https://skills.sh/) agent skill to let your AI coding
assistant build MCP servers with protoc-gen-mcp:

```bash
npx skills add easyp-tech/protoc-gen-mcp-skill
```

The skill source lives in a separate repository:
[easyp-tech/protoc-gen-mcp-skill](https://github.com/easyp-tech/protoc-gen-mcp-skill).

The skill teaches agents the full workflow: define proto → configure easyp →
generate → implement handler → serve. It covers proto options, requiredness
policy, ProtoJSON contract, and common patterns.

## Generation With Easyp

The intended workflow is `easyp`, not manual `protoc` invocation. For mixed
Go/Python/JVM/Node projects, `easyp` can drive `protoc-gen-go`, the standard
Python protobuf generator, Protobuf-ES, and `protoc-gen-mcp` from one config.

Before running generation, make sure `protoc-gen-go` is installed and available
in `PATH` if your config uses the standard Go plugin:

```bash
go install google.golang.org/protobuf/cmd/[email protected]
```

Example `easyp.yaml`:

```yaml
lint:
  use:
    - PACKAGE_DEFINED
    - PACKAGE_VERSION_SUFFIX
    - RPC_NO_CLIENT_STREAMING
    - RPC_NO_SERVER_STREAMING

generate:
  inputs:
    - directory:
        path: mcp
        root: "."
  plugins:
    - name: go
      out: .
      opts:
        paths: source_relative
    - name: python
      with_imports: true
      out: .
    - command: ["go", "run", "github.com/easyp-tech/protoc-gen-mcp/cmd/protoc-gen-mcp@latest"]
      out: .
      opts:
        paths: source_relative
    - command: ["go", "run", "github.com/easyp-tech/protoc-gen-mcp/cmd/protoc-gen-mcp@latest"]
      out: .
      opts:
        paths: source_relative
        lang: python
        python_runtime: google.protobuf
        # Optional: use raw *_pb2 handler request/response classes instead of
        # the default generated dataclass API.
        # python_handler: protobuf
        # Optional: generate both surfaces in one pass. This keeps *_mcp.py as
        # the dataclass sidecar and adds *_mcp_pb.py for raw *_pb2 handlers.
        # python_handler: dataclass+protobuf
    - command: ["go", "run", "github.com/easyp-tech/protoc-gen-mcp/cmd/protoc-gen-mcp@latest"]
      out: .
      opts:
        paths: source_relative
        lang: java
    - command: ["go", "run", "github.com/easyp-tech/protoc-gen-mcp/cmd/protoc-gen-mcp@latest"]
      out: .
      opts:
        paths: source_relative
        lang: kotlin
    - command: ["./node_modules/.bin/protoc-gen-es"]
      with_imports: true
      out: src/generated
      opts:
        target: ts
        import_extension: js
    - command: ["go", "run", "github.com/easyp-tech/protoc-gen-mcp/cmd/protoc-gen-mcp@latest"]
      out: src/generated
      opts:
        paths: source_relative
        lang: typescript
```

Typical commands:

```bash
easyp --cfg easyp.yaml validate-config
easyp --cfg easyp.yaml lint -p mcp -r .
easyp --cfg easyp.yaml generate -p mcp -r .
```

That generates language-specific protobuf output plus MCP sidecars such as
`*.pb.go`, `*_pb2.py`, `*.mcp.go`, `*_mcp.py`, Protobuf-ES `_pb.ts`, and
TypeScript `*_mcp.ts` files. The Python target currently supports only
`python_runtime=google.protobuf`; handler mode defaults to
`python_handler=dataclass`, and `python_handler=protobuf` opts into raw
`*_pb2` handlers. `python_handler=dataclass+protobuf` generates both surfaces
in one pass: `*_mcp.py` remains the dataclass sidecar and `*_mcp_pb.py` exposes
the raw protobuf handler sidecar. Generated Python output also emits a small
`mcp/__init__.py` bridge so `mcp.options.*` protobuf modules can coexist with
the official `mcp` SDK package in one import tree. No special Easyp override is
required for `mcp.options.v1`, because the package declares `go_package`
directly in `options.proto`. For reproducible builds, prefer pinning a specific
tag instead of `@latest`.

For JVM consumers, the language selectors are `lang=java` and `lang=kotlin`.
The Java path generates a Java sidecar alongside protobuf Java output. The
Kotlin path must follow the same rule as the in-repo Gradle example: Java
protobuf output, Kotlin protobuf output, and the `lang=kotlin` MCP sidecar are
all part of the working build graph. User-authored JVM protos do not need a
Go `go_package` option just to satisfy `protoc-gen-mcp`. See
[examples/6_java_standalone](examples/6_java_standalone/),
[examples/7_kotlin_standalone](examples/7_kotlin_standalone/), and
[examples/jvm/README.md](examples/jvm/README.md) for runnable layouts.

For TypeScript consumers, generate Protobuf-ES `_pb.ts` files first and then run
`protoc-gen-mcp` with `lang=typescript` into the same generated-source tree.
Use `import_extension=js` so emitted imports work under Node ESM and
`moduleResolution: NodeNext`. The generated MCP sidecar imports the official
`@modelcontextprotocol/sdk` low-level `Server`, preserves raw JSON Schemas,
validates them through Ajv, and maps payloads through Protobuf-ES ProtoJSON.
See [examples/8_typescript_standalone](examples/8_typescript_standalone/) for a
complete standalone project with pinned npm dependencies and checked-in
generated sources.

For JavaScript consumers, do not use `lang=javascript`; direct

Frequently Asked Questions

What is protoc-gen-mcp?

protoc-gen-mcp is a Generators library for the Go programming language. Generate typed MCP tools, prompts, and resources from Protocol Buffers

How do I install protoc-gen-mcp?

Install protoc-gen-mcp with the Go module system using `go get easyp-tech/protoc-gen-mcp`. Check the repository for the current installation instructions.

What category does protoc-gen-mcp belong to?

protoc-gen-mcp is listed under Generators, specifically Generators.

← Back to Generators