Scan walks the supplied gRPC server's registered services and returns the set of methods marked `(authorizer.v1.mcp_tool).exposed = true`. Methods that aren't exposed (the default) are silently skipped.
(srv *grpc.Server)
| 41 | // set of methods marked `(authorizer.v1.mcp_tool).exposed = true`. |
| 42 | // Methods that aren't exposed (the default) are silently skipped. |
| 43 | func Scan(srv *grpc.Server) ([]ToolBinding, error) { |
| 44 | var bindings []ToolBinding |
| 45 | for svcName := range srv.GetServiceInfo() { |
| 46 | // Look up the proto descriptor for this service by full name. |
| 47 | desc, err := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(svcName)) |
| 48 | if err != nil { |
| 49 | // Not all gRPC services come from compiled proto (e.g. the |
| 50 | // gRPC health checking and reflection services). Skip silently. |
| 51 | continue |
| 52 | } |
| 53 | svcDesc, ok := desc.(protoreflect.ServiceDescriptor) |
| 54 | if !ok { |
| 55 | continue |
| 56 | } |
| 57 | |
| 58 | methods := svcDesc.Methods() |
| 59 | for i := 0; i < methods.Len(); i++ { |
| 60 | m := methods.Get(i) |
| 61 | tool := mcpToolFromMethod(m) |
| 62 | if tool == nil || !tool.Exposed { |
| 63 | continue |
| 64 | } |
| 65 | |
| 66 | name := tool.ToolName |
| 67 | if name == "" { |
| 68 | name = camelToSnake(string(m.Name())) |
| 69 | } |
| 70 | |
| 71 | bindings = append(bindings, ToolBinding{ |
| 72 | Name: name, |
| 73 | Description: strings.TrimSpace(string(m.ParentFile().SourceLocations().ByDescriptor(m).LeadingComments)), |
| 74 | Destructive: tool.Destructive, |
| 75 | FullMethod: fmt.Sprintf("/%s/%s", svcName, m.Name()), |
| 76 | InputDescriptor: m.Input(), |
| 77 | OutputDescriptor: m.Output(), |
| 78 | }) |
| 79 | } |
| 80 | } |
| 81 | return bindings, nil |
| 82 | } |
| 83 | |
| 84 | // mcpToolFromMethod reads the (authorizer.v1.mcp_tool) option off a |
| 85 | // method descriptor. Returns nil when the option is absent or unset. |
no test coverage detected