AFAIK it is not possible to redirect standard output from an emacs server directly with emacsclient alone. As you found, the only output of is the value that the s-expression evaluates to.
emacs --batch --eval looks like a good option. If you still want to use emacsclient for some reason, here's one approach that will work for capturing standard output. I'm not sure how to capture standard error in this manner.
emacsclient --eval does not capture any of the server's standard output streams, you will need to capture it as part of your s-expression:
emacsclient --eval "(with-output-to-string\
(princ (format \"%s\\n\" (frame-parameter frame 'name))))\
Anything printed to standard output during within the body of
with-output-to-string is captured and returned as a string value. You can then print that string output as Emacs otherwise (by using Emacs to interpret it):
emacsclient --eval '(with-output-to-string \
(lambda (frame) \
(princ (format "%s\\n" (frame-parameter frame \'name)))) \
| emacs --batch --eval '(princ \
(insert-file-contents "/dev/stdin") \
(read (current-buffer))) \
The same command (in one line):
emacsclient --eval '(with-output-to-string (princ "Hello, World!"))' | emacs --batch --eval '(princ (concat (with-temp-buffer (insert-file-contents "/dev/stdin") (read (current-buffer))) "\n"))'