An MCP server that will not connect is nearly always a configuration problem rather than a protocol one, and the configuration is usually valid JSON. That combination is why the failure is confusing: nothing reports an error, and no server appears.
The first thing to check is the command path. A relative path such as ./scripts/server.js resolves against the working directory the client launched from, which is rarely the directory you were thinking of. Use an absolute path, or a command that is genuinely on PATH.
The second is whether the command exists in the environment the client uses. A GUI application does not inherit the shell environment you see in a terminal, so a version manager that works in your shell may be invisible to the client. This is the usual explanation for a server that runs perfectly when you invoke it by hand.
The third is environment variables. Writing a value as ${MY_TOKEN} looks like shell syntax, but most clients pass env values through literally rather than expanding them. The server then receives the literal string and fails to authenticate, which typically surfaces as a connection that opens and immediately closes.
The fourth is the top-level key. Most clients expect mcpServers. A configuration using a different key is still valid JSON, and the client simply finds no servers and reports nothing — silence rather than an error.
The fifth is transport confusion. A stdio server needs a command; an HTTP or SSE server needs a url. Declaring both, or neither, produces a configuration that reads sensibly and does not work.
Check these five before reaching for logs. Between them they account for the large majority of MCP connection failures, and all five are visible in the configuration file itself without launching anything.