Most language servers implementations today communicate over standard input and output, which is why you have to start them with the --stdin flag. This means that there can be only one single client that talks with such a server. New clients must spawn new servers.
Nvim LSP can connect to existing running LSP servers via RPC (Sockets or TCP), but the server needs to be listening. To change the state of things, you would need to implement a new type of server that listens to multiple connections.
With that disclaimer out of the way. Here is a way that you can slap TCP functionality to existing servers. A new one will still spawn for every new connection though.
In recent nvim versions you can :help vim.lsp.rpc.connect, which describes a helper method that can connect to named pipes (windows), domain sockets (unix) or a host and a port via TCP. Replace your existing cmd = ... of your LSP with cmd = vim.lsp.rpc.connect(...).
This is how I've been using TCP for the TypeScript LSP.
socat TCP-LISTEN:12345,reuseaddr,fork \
EXEC:"/usr/local/bin/typescript-language-server --stdio"
Similarly, it can be done with a UNIX socket,
socat UNIX-LISTEN:/tmp/ts_ls_socket,reuseaddr,fork \
EXEC:"/usr/local/bin/typescript-language-server --stdio"
My reason was having the language server run in the same container where the code has all of its dependencies. But, even though it is a remote-connection, it still forks a new LSP process for each new connection, and kills the process on each disconnect — just like nvim itself does.
Obviously, once you have a server listening to a TCP port and you want or need to have it accept multiple connections. You can also add a proxy (like nginx) that will keep a constant single connection to the background server, while allowing multiple clients to connect and disconnect at will as many times as they need. Exact details on how to do that are beyond the scope of this answer.