In an `action()` target, `script`, `sources`, and `inputs` are all used as ninja file dependencies. There is no concrete difference between `sources` and `inputs` for action(), but the convention recommended by `gn help action` is to use `sources` for the things you think of as the inputs to the action per se (such as `.proto` source files) and to use inputs for auxiliary things like other tools or configuration files that the script might use. So the right approach here is to make sure that the actual protoc binary that is invoked by the Python script used as `script` in the `action()` is listed in `inputs`, along with any other files that Python or things it spawns might read, including other `.py` files (but excluding the `script` file itself, since that's already implicitly tracked).
If it's not so easy to determine all the right paths to those things in the GN template code, then the other approach is to use `depfile` in the `action()` and add logic to your Python code that will emit that file with the dynamic list of inputs used, including the protoc binary path.
See `gn help action` and `gn help depfile` for more details. You can almost certainly find some existing examples using `depfile` and look at how those scripts generate the dep file text format.