Every connection failure ends with the same line,
Error connecting to the MCP server: and the target. The line that names the cause is above it.
Some failures also print a Python traceback from the HTTP library; its last
line carries the underlying error, such as certificate is expired.
The sections are ordered by how often each outcome appeared when mcpscore
audited the 13,695 remote endpoints listed in the official MCP registry in
August 2026: authentication 24.6%, unreachable 9.5%, payment required 3.0%,
not MCP 2.2%, no completed handshake 1.1%, rate limited 0.8%.
The server requires authentication
Symptom:401 or 403 without credentials. This is
not an error. mcpscore scores what it can observe without a session: TLS,
the WWW-Authenticate challenge and the OAuth discovery metadata.
Fix: pass a credential to audit behind the gate:
--fail-under, with exit code 3, because a
score from ten checks cannot demonstrate a threshold:
min-score fails a partial audit the
same way.
The whole flow, including OAuth sign-in, is in
Audit a server behind auth.
The server rejected your credentials
Symptom:--token, --header or $MCPSCORE_TOKEN, and the
server still answered 401 or 403.
Fix: check that the token is current and has the scopes the server
requires. --token sends it as Authorization: Bearer; a server that
expects another header needs --header 'X-Api-Key: ...' instead.
The server is unreachable
Symptom:nodename nor servname provided, or not known for DNS, All connection attempts failed for a closed port, and
certificate is expired or certificate is not trusted for TLS. Add -v to
see the full traceback.
Fix: check the URL from the same machine with
curl -sS -o /dev/null -w '%{http_code}\n' https://your-server.example/mcp.
If curl fails the same way, the problem is the network or the certificate,
not mcpscore. A certificate error is a real finding: MCP clients refuse that
server too.
Which certificates does mcpscore trust?
mcpscore checks certificates against your operating system’s trust store. It doesn’t ship a CA bundle of its own, and it doesn’t usecertifi:
To use a different bundle on any platform, set
SSL_CERT_FILE to a PEM file or
SSL_CERT_DIR to a hashed certificate directory. If both are set,
SSL_CERT_FILE wins.
OS updates change what mcpscore trusts. When a certificate authority is added
or distrusted, mcpscore picks up the change once your system updates it. On
Linux, that comes through your distribution’s ca-certificates package. The
npm package works the same way: it starts the Python engine, which does the
checking, so Node.js’s built-in certificates are never used for an audit.
The server answered with an HTTP error
Symptom:401 or 403. The common ones:
To see what the server says to a
POST, send it the request that opens
a session. Servers on 2025-11-25 and earlier start with initialize:
protocolVersion and serverInfo
(Lifecycle §Initialization).
A modern-only 2026-07-28 server has no initialize and may reject it. Ask
it with server/discover, which every modern server implements:
supportedVersions and its
capabilities
(Lifecycle §Protocol Version Negotiation).
If both requests fail, the endpoint is not an MCP server.
The endpoint is not an MCP server
Symptom:Expected response with content type 'text/event-stream', got 'text/html'.
Cause: the URL answered, but not with MCP. It is usually a website, a
REST API or a proxy’s error page on the right host but the wrong path.
Fix: find the MCP endpoint path in the server’s docs and audit that
URL. The curl request in the previous section shows what the URL returns.
The server redirected
Symptom:http:// to https://, or to another host, is not followed.
Fix: audit the URL the message names. If that URL is http:// while
yours was https://, the server sits behind a TLS-terminating proxy it does
not trust; the message suggests the https:// form to try.
The handshake timed out
Symptom:Connection timeout for server: when the TCP connection never opened.
Cause: the server accepted the connection and did not complete the MCP
handshake within 30 seconds, or the host dropped the connection attempt.
Cold-starting serverless hosts and servers that do slow work in their
startup code hit this.
Fix: re-run once the server is warm. If it times out every time, move
slow startup work out of the initialize path.
A local server does not start
These come from--stdio and from a .py or .js target, which mcpscore
launches itself.
Symptom: Command not found: 'my-server'. Please ensure it is installed and on PATH.
Cause: the first word after --stdio is not an executable on PATH,
and not an existing file.
Fix: use the full path, such as --stdio ./bin/my-server, or install the
command.
Symptom: 'server.py' is a script, not an executable command. Launch it with its interpreter: --stdio python server.py
Cause: --stdio runs a command, and a script without a shebang and the
executable bit is not one.
Fix: run the command the message prints. For a Python script it also
prints the uv run form to use inside a uv project.
Symptom: Permission denied launching './server'. Make it executable (chmod +x) or launch it with its interpreter
Cause: the file exists but is not executable.
Fix: chmod +x ./server, or put its interpreter first.
Symptom: Server script not found: ./server.py
Cause: the .py or .js target path does not exist.
Fix: check the path relative to the directory you run mcpscore from.
Symptom: server.py could not start: No module named 'openmeteo_requests'
Cause: a .py target runs with mcpscore’s own Python, which has none of
your project’s dependencies.
Fix: run the command the message suggests. It starts the server in its
own environment:
uv runwhen uv is installed and apyproject.tomlorrequirements.txtsits in the script’s folder or above it- otherwise the project’s
.venvPython - otherwise
<python-with-its-dependencies>: put the path of the Python that has your dependencies installed there
-v shows the server’s traceback.
Symptom:
server stderr: prefix. The exception is a .py target that fails on a
missing module: that gets the one-line message above, and -v shows the lines.
Fix: read the server stderr: lines. They usually name a missing file,
a missing dependency or a missing environment variable. Pass variables with
--env NAME.
The command line was rejected
Symptom: the usage summary, then a line starting withUsage error:,
exit code 1. For example:
--stdio takes the rest of the command
line, so every mcpscore option must come before it. All flags are listed in
the CLI reference.
A gate failed
Symptom: the audit completes, thenGate failed — and exit code 3:
--fail-under; or
the readiness percentage is below --fail-under-readiness; or a rule at or
above a [gate] fail_on severity failed.
Fix: the failed rules are the ❌ lines above the score, each with a
Fix: line. Improve your score covers the rules most
servers fail. To change what the gate counts, see
Configure rules.
A failed --smoke check exits 4 with Gate failed — --smoke: 2 smoke check(s) failed. Smoke mode explains each check.
A gate never fails for a local server
Symptom: the score is below--fail-under, yet the exit code is 0
and there is no Gate failed line. Near the top:
--stdio takes the rest of the command line as the server
command, so an option after it goes to your server. The same happens to
--config, --token, --env and --json, without a warning, since a server
may take those options itself.
Fix: move every mcpscore option before --stdio:
mcpscore --fail-under 90 --stdio uv run server.py.
What’s next
- Audit a server behind auth for
--token,--headerand--oauth. - Improve your score once the audit runs.
- CLI reference for every flag.