I've designed a lot of RPC protocols in my career. One pattern that's worked well basically goes as follows:
// Client calls: print('Hello World\n')
-> [1, "print", "Hello World!\n"]
// Server sends return value (or lack of return vvalue)
<- [-1]
// Client calls: add(1, 2)
-> [2, "add", 1, 2]