Skip to content

Commit 7a91b9c

Browse files
author
oh-tarnished
committed
chore: add Dependabot configuration for automated dependency updates
- Introduced .github/dependabot.yml to manage dependency updates for Go, Rust, Python, and GitHub Actions. - Configured weekly update schedules with limits on open pull requests and appropriate labels for better organization.
1 parent 7b3b28c commit 7a91b9c

43 files changed

Lines changed: 1066 additions & 283 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Justfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ test-all: test test-python test-rust test-cpp
9090
# Generate pre-compiled proto libraries (Go + Python + Rust)
9191
generate-proto:
9292
cd proto && buf generate
93+
go fmt ./mcp/protobuf/... ./plugin/...
9394
@echo '__path__ = __import__("pkgutil").extend_path(__path__, __name__)' > mcp/protobuf/python/mcp/__init__.py
9495
@touch mcp/protobuf/python/mcp/protobuf/__init__.py
9596

@@ -115,6 +116,7 @@ build-cpp:
115116
# Rebuild the plugin and regenerate all example proto code
116117
generate: generate-proto install
117118
cd examples && buf generate
119+
go fmt ./examples/proto/generated/go/... ./plugin/...
118120
just generate-cpp
119121

120122
# Run all checks (fmt, vet, lint, test, build)

README.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ A `protoc` plugin and runtime that turns any gRPC service into a fully spec-comp
1616
- **Multi-language** — Generate MCP server code for Go, Python, Rust, and C++ from a single `.proto` file
1717
- **Tools** — Every unary RPC becomes an MCP tool with a JSON Schema derived from the protobuf request message
1818
- **Prompts** — Attach prompt templates to RPCs with schema-validated arguments via `(mcp.protobuf.prompt)`
19+
- **Field descriptions** — Add `(mcp.protobuf.field) = { description: "..." }` to message fields for schema descriptions
20+
- **Enum descriptions** — Add `(mcp.protobuf.enum)` and `(mcp.protobuf.enum_value)` for enum-level and per-value descriptions in the schema
1921
- **Resources** — Auto-detect MCP resources from `google.api.resource` annotations
2022
- **Elicitation** — Generate confirmation dialogs before tool execution via `(mcp.protobuf.elicitation)`
2123
- **Transports** — stdio, SSE, and streamable-http — run multiple concurrently in a single process
@@ -274,6 +276,52 @@ rpc DeleteItem(DeleteItemRequest) returns (google.protobuf.Empty) {
274276

275277
Elicitation is supported in all three languages with graceful degradation — if the client doesn't support elicitation, the tool proceeds without confirmation.
276278

279+
### Field: `mcp.protobuf.field`
280+
281+
Add JSON Schema metadata to a message field for the MCP tool inputSchema:
282+
283+
```protobuf
284+
message User {
285+
string name = 1 [
286+
(google.api.field_behavior) = IDENTIFIER,
287+
(mcp.protobuf.field) = {
288+
description: "The resource name of the user. You can parse the user id from the resource name."
289+
examples: "users/alice"
290+
examples: "users/bob"
291+
format: "uri" // optional: override format (uri, email, uuid, etc.)
292+
deprecated: false // optional: mark field as deprecated
293+
}
294+
];
295+
}
296+
```
297+
298+
- **description** — Human-readable description (recommended for LLMs)
299+
- **examples** — Example values to guide LLMs (repeated)
300+
- **deprecated** — Mark the field as deprecated in the schema
301+
- **format** — JSON Schema format override (e.g. `uri`, `email`, `uuid`)
302+
303+
### Enum: `mcp.protobuf.enum` and `mcp.protobuf.enum_value`
304+
305+
Add descriptions to enum types and individual enum values for the MCP tool inputSchema:
306+
307+
```protobuf
308+
enum Priority {
309+
option (mcp.protobuf.enum) = { description: "Priority level for a todo item." };
310+
311+
PRIORITY_UNSPECIFIED = 0 [(mcp.protobuf.enum_value) = { description: "Unspecified; use default priority." }];
312+
PRIORITY_LOW = 1 [(mcp.protobuf.enum_value) = { description: "Low priority; can be done when convenient." }];
313+
PRIORITY_MEDIUM = 2 [(mcp.protobuf.enum_value) = { description: "Normal priority; default for most todos." }];
314+
PRIORITY_HIGH = 3 [(mcp.protobuf.enum_value) = { description: "High priority; should be done soon." }];
315+
PRIORITY_URGENT = 4 [(mcp.protobuf.enum_value) = { description: "Urgent; do first." }];
316+
}
317+
```
318+
319+
The schema includes:
320+
- **description** — Combined enum-level and per-value descriptions
321+
- **enumDescriptions** — Map of value name → description for structured access
322+
323+
For enum fields, enum descriptions take precedence over `(mcp.protobuf.field)` description when both are present.
324+
277325
### Resources
278326

279327
Resources are auto-detected from `google.api.resource` annotations on proto messages. No additional MCP annotation is needed.
@@ -336,7 +384,7 @@ The tool's `inputSchema` is derived from the protobuf request message:
336384
- `buf.validate` constraints → `minLength`, `maxLength`, `pattern`, `minimum`, `maximum`, etc.
337385
- Well-known types (Timestamp, Duration, FieldMask, Struct, Any, wrappers) → appropriate JSON Schema
338386
- Protobuf `oneof` → JSON Schema `oneOf`/`anyOf`
339-
- Enums → JSON Schema `enum` with string values
387+
- Enums → JSON Schema `enum` with string values; `(mcp.protobuf.enum)` / `(mcp.protobuf.enum_value)``description` and `enumDescriptions`
340388

341389
## Transport Configuration
342390

examples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ The proto uses:
4242
- **`mcp.protobuf.tool`** — per-RPC tool name/description overrides
4343
- **`mcp.protobuf.prompt`** — per-RPC prompt templates with schema-based arguments
4444
- **`mcp.protobuf.elicitation`** — confirmation dialogs with schema-based forms
45+
- **`mcp.protobuf.field`** — field descriptions, examples, format for tool inputSchema
46+
- **`mcp.protobuf.enum`** / **`mcp.protobuf.enum_value`** — enum-level and per-value descriptions
4547
- **`google.api.resource`** — auto-detected MCP resources from AIP resource annotations
4648

4749
## Code Generation

examples/buf.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ deps:
55
commit: 004180b77378443887d3b55cabc00384
66
digest: b5:e8f475fe3330f31f5fd86ac689093bcd274e19611a09db91f41d637cb9197881ce89882b94d13a58738e53c91c6e4bae7dc1feba85f590164c975a89e25115dc
77
- name: buf.build/machanirobotics/grpc-mcp-gateway
8-
commit: e97bbcaa428041e7a861938e66ac40bc
9-
digest: b5:03ba8b2ab5eb092e24f527a3abf1fb7460f610e427232b75b027ae5b3d055d29132f30d60c386fc02882884b4f7763e6b154b56c410dc1b3fe1c637b3c1f47dc
8+
commit: c0303cd566d04bcea007151df3fe1dac
9+
digest: b5:b2290f9497d19ce88b696599201c489812d5cf1b5e8b17fd3adfa996f5ca96c34eb7a283c20c67a58f821d3227d2955391baaac2a5e81c11337a27ce36f2512b
Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,8 @@
11
# Code generated by protoc-gen-mcp. DO NOT EDIT.
2-
# versions: protoc-gen-mcp v1.2.3+dirty
2+
# versions: protoc-gen-mcp v1.3.4-0.20260225060520-7b3b28c62629+dirty
33
# source: todo/v1/todo_service.proto
4-
# Build: make -C generated (from cpp/) or cd generated && make
4+
# Build: make (from cpp/) — binary outputs to cpp/server. This file delegates to cpp/.
55

6-
CXX ?= g++
7-
CXXFLAGS ?= -std=c++17 -O2 -Wall
8-
9-
GEN_DIR := .
10-
RUST_DIR := $(GEN_DIR)/rust
11-
# cpp project src/ is at ../../cpp/src relative to proto/generated/cpp
12-
SRC_DIR := $(GEN_DIR)/../../cpp/src
13-
CXX_INCLUDE := $(RUST_DIR)/target/cxx_include
14-
RUST_LIB := $(RUST_DIR)/target/release/libtodo_v1_mcp_cpp.a
15-
16-
GRPC_CFLAGS := $(shell pkg-config --cflags grpc++ protobuf 2>/dev/null || echo "")
17-
GRPC_LIBS := $(shell pkg-config --libs grpc++ protobuf 2>/dev/null || echo "")
18-
19-
PROTO_CC := $(shell find $(GEN_DIR) \( -name '*.pb.cc' -o -name '*.grpc.pb.cc' \) 2>/dev/null)
20-
MCP_CC := $(shell find $(GEN_DIR) -name '*.mcp.cc' 2>/dev/null)
21-
MAIN_GEN := $(GEN_DIR)/main.cc
22-
HAS_USER_MAIN := $(wildcard $(SRC_DIR)/main.cc)
23-
USER_CC := $(filter-out $(SRC_DIR)/main.cc,$(wildcard $(SRC_DIR)/*.cc))
24-
25-
GEN_SRCS := $(if $(HAS_USER_MAIN),,$(MAIN_GEN)) $(MCP_CC) $(PROTO_CC)
26-
GEN_OBJS := $(patsubst $(GEN_DIR)/%.cc,$(GEN_DIR)/build/%.o,$(GEN_SRCS))
27-
SRC_OBJS := $(patsubst $(SRC_DIR)/%.cc,$(GEN_DIR)/build/src/%.o,$(USER_CC))
28-
SRC_OBJS += $(if $(HAS_USER_MAIN),$(GEN_DIR)/build/src/main.o,)
29-
OBJS := $(GEN_OBJS) $(SRC_OBJS)
30-
31-
OBJ_DIR := $(GEN_DIR)/build
32-
BINARY := server
33-
34-
.PHONY: all rust clean
35-
36-
all: rust $(BINARY)
37-
38-
rust:
39-
cd $(RUST_DIR) && cargo build --release
40-
41-
UNAME_S := $(shell uname -s)
42-
ifeq ($(UNAME_S),Darwin)
43-
RUST_LDFLAGS := -framework CoreFoundation -framework Security -framework SystemConfiguration
44-
else
45-
RUST_LDFLAGS :=
46-
endif
47-
48-
$(BINARY): rust $(OBJS)
49-
$(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(RUST_LIB) $(GRPC_LIBS) $(RUST_LDFLAGS) -lpthread -ldl
50-
51-
$(OBJ_DIR)/%.o: $(GEN_DIR)/%.cc
52-
@mkdir -p $(dir $@)
53-
$(CXX) $(CXXFLAGS) -I$(GEN_DIR) -I$(SRC_DIR) -I$(CXX_INCLUDE) $(GRPC_CFLAGS) -c -o $@ $<
54-
55-
$(OBJ_DIR)/src/%.o: $(SRC_DIR)/%.cc
56-
@mkdir -p $(dir $@)
57-
$(CXX) $(CXXFLAGS) -I$(GEN_DIR) -I$(SRC_DIR) -I$(CXX_INCLUDE) $(GRPC_CFLAGS) -c -o $@ $<
58-
59-
clean:
60-
rm -rf $(OBJ_DIR) $(BINARY)
61-
cd $(RUST_DIR) && cargo clean
6+
.PHONY: all clean
7+
all clean:
8+
$(MAKE) -C ../../../cpp $@

examples/proto/generated/cpp/main.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Code generated by protoc-gen-mcp. DO NOT EDIT.
2-
// versions: protoc-gen-mcp v1.2.3+dirty
2+
// versions:
3+
// protoc-gen-mcp v1.3.4-0.20260225060520-7b3b28c62629+dirty
34
// source: todo/v1/todo_service.proto
45

56
#include "grpc_server.h"

examples/proto/generated/cpp/rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Code generated by protoc-gen-mcp. DO NOT EDIT.
2-
# versions: protoc-gen-mcp v1.2.3+dirty
2+
# versions: protoc-gen-mcp v1.3.4-0.20260225060520-7b3b28c62629+dirty
33
# source: todo/v1/todo_service.proto
44

55
[package]

examples/proto/generated/cpp/rust/build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Code generated by protoc-gen-mcp. DO NOT EDIT.
2-
// versions: protoc-gen-mcp v1.2.3+dirty
2+
// versions:
3+
// protoc-gen-mcp v1.3.4-0.20260225060520-7b3b28c62629+dirty
34
// source: todo/v1/todo_service.proto
45

56
fn main() {

examples/proto/generated/cpp/rust/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Code generated by protoc-gen-mcp. DO NOT EDIT.
22
// versions:
3-
// protoc-gen-mcp v1.2.3+dirty
3+
// protoc-gen-mcp v1.3.4-0.20260225060520-7b3b28c62629+dirty
44
// Authors: Machani Robotics - Open Source 2026
55
// source: todo/v1/todo_service.proto
66

@@ -30,9 +30,11 @@ pub mod mcp_handler;
3030
fn start_todo_service_mcp_http(host: &str, port: u16, base_path: &str) {
3131
let rt = tokio::runtime::Runtime::new().expect("failed to create tokio runtime");
3232
rt.block_on(async {
33-
mcp_handler::serve_todo_service_mcp(host, port, base_path)
34-
.await
35-
.expect("MCP HTTP server failed");
33+
if let Err(e) = mcp_handler::serve_todo_service_mcp(host, port, base_path).await {
34+
eprintln!("MCP HTTP server failed: {e}");
35+
eprintln!("Hint: Port {port} may be in use. Try MCP_PORT=8083 ./server or kill the process using the port.");
36+
std::process::exit(1);
37+
}
3638
});
3739
}
3840

examples/proto/generated/cpp/rust/mcp_handler.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Code generated by protoc-gen-mcp. DO NOT EDIT.
22
// versions:
3-
// protoc-gen-mcp v1.2.3+dirty
3+
// protoc-gen-mcp v1.3.4-0.20260225060520-7b3b28c62629+dirty
44
// Authors: Machani Robotics - Open Source 2026
55
// source: todo/v1/todo_service.proto
66

@@ -15,11 +15,11 @@ fn make_tool(name: &str, description: &str, schema_json: &str) -> Tool {
1515
})).expect("generated tool schema must be valid")
1616
}
1717

18-
const TODO_SERVICE__CREATE_TODO_SCHEMA_JSON: &str = r##"{"properties":{"parent":{"type":"string"},"todo":{"properties":{"completed":{"type":"boolean"},"create_time":{"format":"date-time","type":["string","null"]},"description":{"type":"string"},"name":{"type":"string"},"priority":{"enum":["PRIORITY_UNSPECIFIED","PRIORITY_LOW","PRIORITY_MEDIUM","PRIORITY_HIGH","PRIORITY_URGENT"],"type":"string"},"title":{"type":"string"},"update_time":{"format":"date-time","type":["string","null"]}},"required":[],"type":"object"},"todo_id":{"type":"string"}},"required":["parent","todo","todo_id"],"type":"object"}"##;
19-
const TODO_SERVICE__DELETE_TODO_SCHEMA_JSON: &str = r##"{"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}"##;
20-
const TODO_SERVICE__GET_TODO_SCHEMA_JSON: &str = r##"{"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}"##;
21-
const TODO_SERVICE__LIST_TODOS_SCHEMA_JSON: &str = r##"{"properties":{"page_size":{"type":"integer"},"page_token":{"type":"string"},"parent":{"type":"string"}},"required":["parent"],"type":"object"}"##;
22-
const TODO_SERVICE__UPDATE_TODO_SCHEMA_JSON: &str = r##"{"properties":{"todo":{"properties":{"completed":{"type":"boolean"},"create_time":{"format":"date-time","type":["string","null"]},"description":{"type":"string"},"name":{"type":"string"},"priority":{"enum":["PRIORITY_UNSPECIFIED","PRIORITY_LOW","PRIORITY_MEDIUM","PRIORITY_HIGH","PRIORITY_URGENT"],"type":"string"},"title":{"type":"string"},"update_time":{"format":"date-time","type":["string","null"]}},"required":[],"type":"object"},"update_mask":{"type":"string"}},"required":["todo"],"type":"object"}"##;
18+
const TODO_SERVICE__CREATE_TODO_SCHEMA_JSON: &str = r##"{"description":"Creates a new todo item under a user. Requires parent (e.g. users/alice), a todo object with title/description/priority, and a unique todo_id.","properties":{"parent":{"description":"Parent resource name (e.g. users/alice). The todo will be created under this user.","type":"string"},"todo":{"properties":{"completed":{"description":"Whether the todo is done.","type":"boolean"},"create_time":{"format":"date-time","type":["string","null"]},"description":{"description":"Optional longer description or notes.","type":"string"},"name":{"description":"Resource name (e.g. users/alice/todos/abc123). Required when updating.","type":"string"},"priority":{"description":"Priority level for a todo item.. PRIORITY_UNSPECIFIED: Unspecified; use default priority.. PRIORITY_LOW: Low priority; can be done when convenient.. PRIORITY_MEDIUM: Normal priority; default for most todos.. PRIORITY_HIGH: High priority; should be done soon.. PRIORITY_URGENT: Urgent; do first.","enum":["PRIORITY_UNSPECIFIED","PRIORITY_LOW","PRIORITY_MEDIUM","PRIORITY_HIGH","PRIORITY_URGENT"],"enumDescriptions":{"PRIORITY_HIGH":"High priority; should be done soon.","PRIORITY_LOW":"Low priority; can be done when convenient.","PRIORITY_MEDIUM":"Normal priority; default for most todos.","PRIORITY_UNSPECIFIED":"Unspecified; use default priority.","PRIORITY_URGENT":"Urgent; do first."},"type":"string"},"title":{"description":"Short title for the todo.","type":"string"},"update_time":{"format":"date-time","type":["string","null"]}},"required":[],"type":"object"},"todo_id":{"description":"Unique ID for the todo (e.g. abc123). Becomes the final segment of the resource name.","examples":["abc123","todo-001"],"type":"string"}},"required":["parent","todo","todo_id"],"type":"object"}"##;
19+
const TODO_SERVICE__DELETE_TODO_SCHEMA_JSON: &str = r##"{"description":"Permanently deletes a todo item by its resource name. This action cannot be undone.","properties":{"name":{"description":"Resource name of the todo to delete (e.g. users/alice/todos/abc123).","type":"string"}},"required":["name"],"type":"object"}"##;
20+
const TODO_SERVICE__GET_TODO_SCHEMA_JSON: &str = r##"{"description":"Retrieves a single todo item by its resource name (e.g. users/alice/todos/abc123).","properties":{"name":{"description":"Resource name of the todo (e.g. users/alice/todos/abc123).","examples":["users/alice/todos/abc123"],"format":"uri","type":"string"}},"required":["name"],"type":"object"}"##;
21+
const TODO_SERVICE__LIST_TODOS_SCHEMA_JSON: &str = r##"{"description":"Lists all todo items for a user. Supports pagination via page_size and page_token.","properties":{"page_size":{"description":"Max number of todos to return (default 50).","type":"integer"},"page_token":{"description":"Token from previous response for next page.","type":"string"},"parent":{"description":"Parent resource name (e.g. users/alice). Lists todos for this user.","type":"string"}},"required":["parent"],"type":"object"}"##;
22+
const TODO_SERVICE__UPDATE_TODO_SCHEMA_JSON: &str = r##"{"description":"Updates an existing todo item. Send the todo with its resource name and the fields to update. Use update_mask to specify which fields to modify.","properties":{"todo":{"properties":{"completed":{"description":"Whether the todo is done.","type":"boolean"},"create_time":{"format":"date-time","type":["string","null"]},"description":{"description":"Optional longer description or notes.","type":"string"},"name":{"description":"Resource name (e.g. users/alice/todos/abc123). Required when updating.","type":"string"},"priority":{"description":"Priority level for a todo item.. PRIORITY_UNSPECIFIED: Unspecified; use default priority.. PRIORITY_LOW: Low priority; can be done when convenient.. PRIORITY_MEDIUM: Normal priority; default for most todos.. PRIORITY_HIGH: High priority; should be done soon.. PRIORITY_URGENT: Urgent; do first.","enum":["PRIORITY_UNSPECIFIED","PRIORITY_LOW","PRIORITY_MEDIUM","PRIORITY_HIGH","PRIORITY_URGENT"],"enumDescriptions":{"PRIORITY_HIGH":"High priority; should be done soon.","PRIORITY_LOW":"Low priority; can be done when convenient.","PRIORITY_MEDIUM":"Normal priority; default for most todos.","PRIORITY_UNSPECIFIED":"Unspecified; use default priority.","PRIORITY_URGENT":"Urgent; do first."},"type":"string"},"title":{"description":"Short title for the todo.","type":"string"},"update_time":{"format":"date-time","type":["string","null"]}},"required":[],"type":"object"},"update_mask":{"description":"Comma-separated field names to update (e.g. title,completed). Omit to update all provided fields.","type":"string"}},"required":["todo"],"type":"object"}"##;
2323

2424
pub struct TodoServiceMcpHandler {
2525
inner: cxx::UniquePtr<crate::ffi_todo_service::TodoServiceMcpImpl>,

0 commit comments

Comments
 (0)