Understanding the problem: What's happening with your current command, ssh user@host ./run.sh a "b c", is that the local shell parses the command into "words" (applying and removing any quotes and/or escapes it sees), and gets "ssh", "user@host", "./run/sh", "a", and "b c". It takes the first (ssh) as the command, and passes the rest to it as arguments. ssh takes "user@host" as where to ssh to, and (here's the critical thing) it just sticks the rest together (separated by spaces) as the remote command to run. This gives "./run.sh a b c" as the remote command. That then gets passed to the remote shell, which (since the quotes are now gone) interprets "a", "b", and "c" as separate arguments.
In short: the quotes are getting applied and removed by the local shell, not the remote shell (which is the one you care about).
The solution: quote or escape the quotes so that the local shell treats them as just data to be passed through to the remote shell. Essentially, this means you needs two levels of quoting/escaping, so that the local shell will apply (and remove) one level, and the remote shell will apply (and remove) the second level.
Here's a simple, clean way to do it:
ssh user@host './run.sh a "b c"'
The local shell applies & removes the single-quotes, so the double-quotes get applied by the remote shell. Note that quotes generally don't nest within themselves/each other, but since double-quotes have no special meaning in a single-quoted string, it works in this case. You could also use double-quotes for both levels, but you need to escape the inner quotes:
ssh user@host "./run.sh a \"b c\""
In fact, the outer double-quotes in that aren't actually doing anything here (they make the whole thing one argument to ssh, but if they were multiple arguments they'd just get stuck back together anyway, so...). You could actually remove them:
ssh user@host ./run.sh a \"b c\"
There are actually lots of ways to do this, combining various quoting/escaping options on the local and remote shells:
ssh user@host ./run.sh a '"b c"'
ssh user@host "./run.sh a 'b c'"
ssh user@host './run.sh a b\ c'
ssh user@host ./run.sh a b\\ c
BTW, in general, echoing something is a really bad way to find out how your arguments are being parsed, because it just sticks its arguments together with spaces between. But since that's the same thing ssh does when creating the remote command, you can replace ssh user@host with echo to see what will actually be passed to the remote shell:
$ echo ./run.sh a "b c"
./run.sh a b c
$ echo './run.sh a "b c"'
./run.sh a "b c"
$ echo "./run.sh a \"b c\""
./run.sh a "b c"
$ echo "./run.sh a 'b c'"
./run.sh a 'b c'
$ echo ./run.sh a b\\ c
./run.sh a b\ c
ssh user@host './run.sh a "b c"'?