{"id":50776853,"url":"https://github.com/cadenya/mcp-grpc-gateway","last_synced_at":"2026-06-12T00:07:14.238Z","repository":{"id":359905833,"uuid":"1247921201","full_name":"cadenya/mcp-grpc-gateway","owner":"cadenya","description":"MCP 🤝🏻 gRPC. Use gRPC reflection to expose services as MCP tools. Use proto annotations to configure tool names and descriptions.","archived":false,"fork":false,"pushed_at":"2026-06-02T22:29:29.000Z","size":175,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T00:16:51.660Z","etag":null,"topics":["grpc","mcp","mcp-client","mcp-server","protobuf"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cadenya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-24T00:41:40.000Z","updated_at":"2026-06-02T22:28:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cadenya/mcp-grpc-gateway","commit_stats":null,"previous_names":["cadenya/mcp-grpc-gateway"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/cadenya/mcp-grpc-gateway","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cadenya%2Fmcp-grpc-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cadenya%2Fmcp-grpc-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cadenya%2Fmcp-grpc-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cadenya%2Fmcp-grpc-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cadenya","download_url":"https://codeload.github.com/cadenya/mcp-grpc-gateway/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cadenya%2Fmcp-grpc-gateway/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34223013,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","mcp","mcp-client","mcp-server","protobuf"],"created_at":"2026-06-12T00:07:13.501Z","updated_at":"2026-06-12T00:07:14.229Z","avatar_url":"https://github.com/cadenya.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MCP gRPC Gateway\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/diagram.png\" alt=\"MCP client calling MCP gRPC Gateway, which forwards to your gRPC service\" width=\"520\"\u003e\n\u003c/p\u003e\n\nMCP gRPC Gateway exposes existing gRPC services as stateless MCP tools over HTTP. It connects to a downstream gRPC server, discovers service descriptors through gRPC reflection or a proto descriptor file, converts unary RPC request messages into JSON Schema tool inputs, and invokes the selected RPC when an MCP client calls the tool.\n\nThe gateway is designed for teams that already describe service contracts in protobuf and want MCP support without hand-writing a parallel tool server. Protobuf annotations can provide tool names and tool descriptions, while reflection or descriptor files let the gateway reload tool definitions as services change. In practice, your gRPC service remains the source of truth and the gateway can pick up newly deployed tools without a gateway redeploy.\n\n## Run The Gateway\n\nMCP gRPC Gateway runs as a small HTTP service in front of a gRPC server. Point it at a gRPC host that has server reflection enabled:\n\n```bash\nmcp-grpc-gateway --grpc-host your-grpc-service:50051\n```\n\nBy default, the gateway listens on `127.0.0.1:8080` and exposes the MCP endpoint at `/mcp`.\n\n```text\nhttp://127.0.0.1:8080/mcp\n```\n\nThe gateway also exposes a health endpoint at `/health` by default:\n\n```text\nhttp://127.0.0.1:8080/health\n```\n\nUse `--health-path` or `HEALTH_PATH` to expose health at a different path:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --health-path /readyz\n```\n\nTo expose it from a container, VM, or Kubernetes pod, bind to all interfaces explicitly:\n\n```bash\nmcp-grpc-gateway \\\n  --addr 0.0.0.0:8080 \\\n  --grpc-host your-grpc-service:50051\n```\n\nYou can limit which reflected services become MCP tools with `--service`, and you can require explicit protobuf tool annotations with `--require-tool-annotations`:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --service yourapp.v1.ObjectivesService \\\n  --require-tool-annotations\n```\n\n## Install\n\nInstall the gateway from source with Go:\n\n```bash\ngo install go.cadenya.com/mcp-grpc-gateway/cmd/mcp-grpc-gateway@latest\n```\n\nFor local development from a checked-out repository:\n\n```bash\ngo install ./cmd/mcp-grpc-gateway\n```\n\n## Docker\n\nRun the published Docker image:\n\n```bash\ndocker run --rm -p 8080:8080 cadenyaagents/mcp-grpc-gateway:latest \\\n  --addr 0.0.0.0:8080 \\\n  --grpc-host your-grpc-service:50051\n```\n\nThe runtime image has no shell or package manager and runs as a non-root user.\n\n## Releases\n\nGitHub releases are driven by tags. Pushing a `v*` tag runs GoReleaser, publishes release archives and checksums, pushes Docker release tags, and labels the Buf module with the same tag.\n\n```bash\ngit tag v0.1.0\ngit push origin v0.1.0\n```\n\nFor `v0.1.0`, the release workflow publishes:\n\n```text\nGitHub release: v0.1.0\nDocker tags: cadenyaagents/mcp-grpc-gateway:0.1.0, :0.1, :0, :latest, :sha-\u003ccommit\u003e\nBuf label: buf.build/cadenya-agents/mcp-grpc-gateway:v0.1.0\n```\n\n## MCP Transport\n\nThis gateway only supports stateless MCP over HTTP. It mounts the MCP Go SDK's Streamable HTTP transport with stateless JSON responses, so each request is handled independently and the gateway does not issue or require `Mcp-Session-Id` headers.\n\nThe endpoint is intended for HTTP `POST` requests with JSON responses. **It does not expose stdio, stateful SSE sessions, resumable streams, or event-store backed session recovery.**\n\n## Forwarding Headers\n\nHTTP headers are not forwarded to gRPC by default. You can opt in to specific headers with `--forward-header`; each matching HTTP header is attached to the downstream gRPC request as metadata.\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --service \"yourapp.v1.Service\" \\\n  --forward-header Authorization\n```\n\nRepeat the flag to allow more headers:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --service \"yourapp.v1.Service\" \\\n  --forward-header Authorization \\\n  --forward-header X-Request-ID\n```\n\n## Service Filters\n\nBy default the gateway loads all non-reflection services exposed by the downstream gRPC server's reflection API. This is useful for production servers that host multiple gRPC services on the same listener.\n\nUse `--service` when you want to expose only specific services. The flag may be repeated, and tools from the selected services are appended into one MCP server.\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --service \"yourapp.v1.ObjectivesService\" \\\n  --service \"yourapp.v1.UsersService\"\n```\n\nTool names must be unique across all loaded services. If two RPCs produce the same MCP tool name, the first one is kept and the gateway emits a warning log with the colliding service name and tool name.\n\n## gRPC Client TLS\n\nThe gateway connects to downstream gRPC services without TLS by default. Enable TLS with `--grpc-tls`; the existing `--tls` flag is kept as an alias.\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --grpc-tls\n```\n\nBy default TLS uses the system root CAs. Provide a custom CA bundle when your gRPC service uses a private CA:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --grpc-tls \\\n  --grpc-ca-file /etc/certs/ca.pem\n```\n\nFor mTLS, provide both the client certificate and private key:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --grpc-tls \\\n  --grpc-ca-file /etc/certs/ca.pem \\\n  --grpc-client-cert-file /etc/certs/client.crt \\\n  --grpc-client-key-file /etc/certs/client.key\n```\n\nUse `--grpc-server-name` when the certificate DNS name differs from `--grpc-host`.\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host 10.0.0.12:50051 \\\n  --grpc-tls \\\n  --grpc-server-name api.internal.example.com\n```\n\nEach TLS flag also has an environment variable: `GRPC_TLS`, `GRPC_CA_FILE`, `GRPC_CLIENT_CERT_FILE`, `GRPC_CLIENT_KEY_FILE`, and `GRPC_SERVER_NAME`.\n\n## MCP Server Metadata\n\nMCP server metadata belongs to the gateway process, not the reflected gRPC services. A single MCP server can aggregate tools from multiple gRPC services, so service-level protobuf annotations are not used to set the MCP server name, title, version, instructions, or website URL.\n\nConfigure those values with CLI flags:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --mcp-name \"objectives-gateway\" \\\n  --mcp-title \"Objectives Gateway\" \\\n  --mcp-version \"1.0.0\" \\\n  --mcp-instructions \"Use these tools to inspect workspace objectives.\" \\\n  --mcp-website-url \"https://yourapp.example.com\"\n```\n\nThe same values can be set with environment variables:\n\n```bash\nMCP_NAME=objectives-gateway\nMCP_TITLE=\"Objectives Gateway\"\nMCP_VERSION=1.0.0\nMCP_INSTRUCTIONS=\"Use these tools to inspect workspace objectives.\"\nMCP_WEBSITE_URL=https://yourapp.example.com\n```\n\nCLI flags override environment variables. By default, the gateway reports `mcp-grpc-gateway` as the MCP server name and `dev` as the version.\n\n## Annotations\n\nBy default your RPC definitions in your gRPC endpoint will be exposed 1:1 for RPC names as tools. You can override tool names and add tool descriptions for LLMs with method annotations.\n\n```proto\nsyntax = \"proto3\";\n\npackage yourapp.v1;\n\nimport \"grpcmcpgateway/v1/annotations.proto\";\n\nservice Service {\n  rpc GetRecentObjectives(RecentObjectivesRequest) returns (ObjectiveObjectivesResponse) {\n    option (grpcmcpgateway.v1.tool) = {\n      name: \"recent_objectives\"\n      description: \"Retrieves all of the recent objectives for the workspace that is authenticated\"\n    };\n  }\n}\n```\n\n### Text-only tool output with `content_template`\n\nBy default a tool returns its gRPC response as JSON, available both as text and as structured content. Set `content_template` on a tool annotation to instead return a single block of text rendered from the response with a [Go `text/template`](https://pkg.go.dev/text/template). When `content_template` is set, the tool returns only the rendered text and no structured content — useful for shaping a response into LLM-friendly prose.\n\n```proto\nservice Service {\n  rpc DescribeSession(DescribeSessionRequest) returns (DescribeSessionResponse) {\n    option (grpcmcpgateway.v1.tool) = {\n      name: \"describe_session\"\n      description: \"Describes the session as a tutorial-ready summary.\"\n      content_template: \"{{ .content }}\"\n    };\n  }\n}\n\nmessage DescribeSessionResponse {\n  string content = 1;\n}\n```\n\nTemplate fields use the response's camelCase JSON names (for example a `created_at` proto field is `{{ .createdAt }}`). Fields that are absent or empty render as empty text rather than failing the call, so guard optional sections in the template if you need different output when a value is missing.\n\nResponses commonly nest other messages and repeated fields; reach nested fields with dotted paths and iterate repeated fields with `range`:\n\n```proto\nmessage Trip {\n  string title = 1;\n  Address address = 2;\n  repeated Stop stops = 3;\n}\nmessage Address { string city = 1; string country = 2; }\nmessage Stop { string label = 1; }\n```\n\n```\ncontent_template:\n  \"{{ .title }} to {{ .address.city }}, {{ .address.country }}\\nStops:{{ range .stops }} {{ .label }}{{ end }}\"\n```\n\nIf you want developers to explicitly disclose which RPCs become MCP tools, start the gateway with `--require-tool-annotations`. In that mode, only unary RPCs with `grpcmcpgateway.v1.tool` annotations are exposed.\n\n```bash\nmcp-grpc-gateway --grpc-host your-grpc-service:50051 --require-tool-annotations\n```\n\n## Buf Examples\n\nTo use the annotations from another Buf-managed gRPC service:\n\n1. Add the dependency to your `buf.yaml`.\n\n```yaml\nversion: v2\ndeps:\n  - buf.build/cadenya-agents/mcp-grpc-gateway\n```\n\n2. Update your Buf dependencies.\n\n```bash\nbuf dep update\n```\n\n3. Import the annotations in your service proto.\n\n```proto\nimport \"grpcmcpgateway/v1/annotations.proto\";\n```\n\n4. Add MCP tool annotations.\n\n```proto\nservice ObjectivesService {\n  option (grpcmcpgateway.v1.service) = {\n    tool_prefix: \"objectives_\"\n  };\n\n  rpc ListObjectives(ListObjectivesRequest) returns (ListObjectivesResponse) {\n    option (grpcmcpgateway.v1.tool) = {\n      name: \"list\"\n      description: \"Lists objectives for the current workspace.\"\n    };\n  }\n}\n```\n\nService-level `tool_prefix` is prepended to every tool name in that service. In the example above, the MCP tool is exposed as `objectives_list`. This is useful when one gateway aggregates multiple services that might otherwise use the same tool names.\n\n## Proto Descriptor Files\n\nWhen gRPC reflection is not available on the downstream server, you can provide a binary protobuf `FileDescriptorSet` instead. This is the same format Envoy uses for gRPC-JSON transcoding.\n\nGenerate the descriptor set with Buf:\n\n```bash\nbuf build -o descriptors.binpb\n```\n\nThen start the gateway with `--proto-descriptor`:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --proto-descriptor descriptors.binpb\n```\n\nWhen `--proto-descriptor` is set, the gateway reads service definitions from the file and does not use gRPC reflection. The `--service` filter still works to limit which services are exposed:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --proto-descriptor descriptors.binpb \\\n  --service yourapp.v1.ObjectivesService\n```\n\nBackground reloads still apply — the gateway re-reads the descriptor file on each reload interval, so you can update the file in place and the gateway picks up the changes without a restart.\n\nThe flag can also be set with the `PROTO_DESCRIPTOR` environment variable.\n\n## Tool Snapshot Reloads\n\nThe gateway keeps a reflected snapshot of your gRPC services and periodically reloads it. When a reload succeeds, new MCP sessions use the new tool set. When reflection fails during a rolling deploy, the gateway keeps serving the last known-good snapshot.\n\nBy default snapshots reload every minute:\n\n```bash\nmcp-grpc-gateway --grpc-host your-grpc-service:50051 --reload-interval 1m\n```\n\nYou can disable background reloads by setting the interval to `0`:\n\n```bash\nmcp-grpc-gateway --grpc-host your-grpc-service:50051 --reload-interval 0\n```\n\n## Tool Call Timeouts\n\nDownstream gRPC tool calls have a 30 second deadline by default. Configure it with `--tool-call-timeout` or `TOOL_CALL_TIMEOUT`.\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --tool-call-timeout 10s\n```\n\nSet the timeout to `0` to disable the gateway-level deadline.\n\n## Logging\n\nThe gateway logs with Go's structured `slog` package. Logs are written to stderr, with `text` output by default.\n\n```bash\nmcp-grpc-gateway --grpc-host your-grpc-service:50051 --log-level debug --log-format json\n```\n\nSupported log levels are `debug`, `info`, `warn`, and `error`. Supported formats are `text` and `json`.\n\n## OpenTelemetry\n\nTracing is disabled unless an OTLP gRPC endpoint is configured. When enabled, the gateway emits spans for tool snapshot reloads, MCP HTTP requests, and downstream gRPC tool calls.\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --otel-endpoint collector:4317\n```\n\nFor local collectors that do not use TLS, add `--otel-insecure`:\n\n```bash\nmcp-grpc-gateway \\\n  --grpc-host your-grpc-service:50051 \\\n  --otel-endpoint localhost:4317 \\\n  --otel-insecure\n```\n\nThe gateway uses W3C Trace Context and Baggage propagation. Incoming MCP HTTP request headers such as `traceparent`, `tracestate`, and `baggage` are extracted, and trace context is injected into downstream gRPC metadata for tool calls.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcadenya%2Fmcp-grpc-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcadenya%2Fmcp-grpc-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcadenya%2Fmcp-grpc-gateway/lists"}