In all honesty, we do this with REST now. Just define interface with OpenAPI - then create clients, servers in virtually any language you like.
Over HTTP, basically you just have a single endpoint which always takes POST requests, and always responds with 200 status, even on errors. If you're using this in a frontend JS application, you'd want a wrapper over fetch() which rejects the promise if the RPC response has an error in the message.