I have the same but I wouldn't recommend gRPC. It adds a ton of overhead and complexity that you don't want. Plus you have to deal with all the complexity of Protobuf and the fact that everything becomes `Option<>`.
Instead I wrote my own RPC system using Serde and Bincode. Communication is over stdio, that way you can support SSH access extremely easily (like VSCode remote).
Unfortunately it was for a company so the code isn't public, but there really wasn't much code to the RPC system at all since you don't need to worry about versioning, authentication, transport, etc. I write a very simple schema language, used Nom to parse it and generate Rust, Typescript and Dart code. The Rust code generation is trivial since you can just `#[derive(Serialize...]`. Typescript / Dart was a bit more complicated (you have to implement Bincode) but it's not very difficult really.
By far the most complex thing is trying to integrate with SSH. If you call `ssh` directly then you end up having to parse non-machine-readable prompts and errors and so on. But if you use a proper SSH library then you end up having to implement ssh-agent, read `~/.ssh/config` etc. yourself which isn't fun either.