ScreenshotNeo

BlogAI agents

How to Fix MCP Server Fetch Failed Errors

Diagnose “MCP server fetch failed” by isolating transport, startup, authentication, network, protocol, and tool execution problems.

By the ScreenshotNeo team1 October 20268 min read

“MCP server fetch failed” is a symptom, not a diagnosis. The failure may happen while a local stdio process starts, while a client reaches a remote endpoint, during authentication or protocol negotiation, or after the connection succeeds when a tool makes its own outbound request.

Find the failing stage first. Then check the matching layer: process startup, transport, endpoint and network reachability, credentials, protocol versions, session state, or the tool’s downstream service. Save the complete error, client and server versions, transport, HTTP status or startup output, and the configuration change you made. Remove tokens, API keys and sensitive endpoint identifiers before sharing logs.

1. Locate the failing stage

Read the host log and classify the error before changing settings.

Stage Typical evidence Start here
Local startup “failed to start”, command-not-found, immediate process exit Command, arguments, working directory, environment variables and child-process stderr
Connection “failed to connect”, network error, timeout Scheme, hostname, DNS, TCP port, proxy, firewall and private-network routes
Initialization or handshake “handshaking failed”, unsupported protocol, invalid initialization Transport configuration and client/server protocol revisions
Authentication 401, 403, expired token, missing header Credential source, scopes, audience, clock and provider-specific setup
Session or request 400 or 404 after connecting, invalid session ID Server mode, session headers and the server’s own status semantics
Tool execution Connected server, then a tool result with isError: true Tool credentials, downstream API, outbound network and server logs

MCP supports local stdio, remote Streamable HTTP, and legacy SSE transports. The TypeScript SDK documents Streamable HTTP as the current remote transport, with SSE available for older SSE-only servers: TypeScript SDK documentation.

2. Remote HTTP: verify the endpoint exactly

Use the URL supplied by the server provider. Check all of these independently:

  1. The scheme is correct. For Oracle Autonomous AI Database, the official troubleshooting page specifically says: “Verify that the endpoint uses https, not http.”
  2. The hostname and path match the provider’s instructions.
  3. Any region identifier is correct.
  4. Any database, project or tenant identifier belongs in the endpoint exactly as documented.
  5. The client is using the intended proxy and TLS configuration.

Do not copy Oracle’s hostname or endpoint format to another MCP provider. Oracle’s region and database checks apply to its Autonomous AI Database endpoint only: Oracle MCP server troubleshooting.

Capture the HTTP response before changing configuration

curl -v --fail-with-body \
  -H 'Accept: application/json, text/event-stream' \
  'https://YOUR-MCP-HOST.example/mcp'

Record the status, response headers and body. A status code is evidence, not a universal meaning. In the TypeScript SDK’s stateful Streamable HTTP mode, an invalid session ID returns 404, while a non-initialization request that lacks a required session ID returns 400. Other servers and modes may differ; follow the server’s documentation.

Test from the runtime that actually runs the client

A laptop test does not prove that an IDE subprocess, container, VM or private network can reach the same endpoint.

# DNS
nslookup YOUR-MCP-HOST.example

# TCP reachability
nc -vz YOUR-MCP-HOST.example 443

# TLS and HTTP details
curl -v https://YOUR-MCP-HOST.example/health

For private endpoints, inspect route tables, security rules, DNS visibility and egress policy. Oracle’s private-endpoint guidance separates DNS resolution, TCP port 443 and HTTPS checks: Oracle connectivity troubleshooting. Adapt the host, port and path to your deployment.

3. Local stdio: inspect the process boundary

With stdio, the MCP host starts a child process and communicates over stdin/stdout. A fetch error can mean the process never started or exited before initialization.

  1. Run the exact command manually from the same user, working directory and shell.
  2. Use absolute paths while diagnosing. Confirm the executable and every argument resolve.
  3. Copy required environment variables into the host configuration. GUI-launched clients often have a smaller environment than your terminal.
  4. Keep protocol messages on stdout. Send application logs to stderr so they do not corrupt the stdio stream.
  5. Read the complete startup output and check whether the child remains alive after launch.
# Replace these values with the command configured in your MCP host
command -v YOUR_SERVER_COMMAND
YOUR_SERVER_COMMAND --help
printf '%s\n' "$REQUIRED_ENV_VAR"

An issue reported in the official MCP servers repository describes one mcp-server-fetch startup failure where dependency resolution selected an incompatible major version; the reporter says a version constraint fixed that case. Treat it as a case example, not a universal instruction to pin dependencies: MCP servers issue tracker.

4. Separate authentication from transport

If DNS and TCP work but the server returns 401 or 403, inspect credentials rather than retries.

  • Confirm the header name and token format required by that provider.
  • Check that the token belongs to the correct tenant, project, region or audience.
  • Verify expiry and the machine clock.
  • Ensure the client process can read the secret without printing it into logs.
  • For OAuth, complete the provider’s authorization flow and confirm the requested scopes.

Do not paste access tokens into issue reports. Redact authorization headers and cookies while preserving the status code and non-sensitive response body.

5. Diagnose protocol negotiation and sessions

When logs mention initialization, capabilities or an unsupported revision, compare the client and server’s supported MCP protocol revisions and transport settings. The TypeScript SDK performs version negotiation and reports failure when a client pins a version the server does not offer. A generic “fetch failed” string alone does not prove a version mismatch: SDK connection and negotiation documentation.

For stateful Streamable HTTP, check that the client preserves the session identifier returned during initialization and sends it on subsequent requests. A 404 can indicate an invalid session ID in the SDK’s documented mode; a 400 can indicate a request made without a required session ID. Confirm the server’s mode before interpreting either code.

6. A connected server can still have a failing tool

MCP protocol errors are distinct from tool execution errors. A client may connect and list tools successfully, then receive a result with isError: true because that tool cannot reach its own API.

  1. Run a harmless capability or listing request to prove the MCP connection.
  2. Call the failing tool with the smallest valid input.
  3. Inspect the tool server’s downstream credentials, URL, rate limit and outbound firewall policy.
  4. Check whether the tool runs inside a container or private subnet with different DNS and egress.
  5. Read the tool server log for the underlying HTTP status or exception.

A 2024 Brave Search server issue reports a server that appeared connected over stdio followed by a tool-level “fetch failed.” It is an individual report, not evidence of a general Brave or MCP cause: MCP servers issue tracker.

7. Minimal diagnostic clients

cURL: inspect reachability and headers

curl -v \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Authorization: Bearer REDACTED_FOR_LOGS' \
  'https://YOUR-MCP-HOST.example/mcp'

Python: preserve status, headers and body

import os
import requests

endpoint = os.environ["MCP_ENDPOINT"]
headers = {
    "Accept": "application/json, text/event-stream",
    "Authorization": f"Bearer {os.environ['MCP_TOKEN']}",
}
response = requests.get(endpoint, headers=headers, timeout=30)
print("status:", response.status_code)
print("content-type:", response.headers.get("content-type"))
print(response.text[:4000])

Node.js: inspect the response without hiding failures

const endpoint = process.env.MCP_ENDPOINT;
const token = process.env.MCP_TOKEN;

const res = await fetch(endpoint, {
  headers: {
    accept: 'application/json, text/event-stream',
    authorization: `Bearer ${token}`
  },
  signal: AbortSignal.timeout(30000)
});

console.log('status:', res.status);
console.log('content-type:', res.headers.get('content-type'));
console.log((await res.text()).slice(0, 4000));

These probes test HTTP reachability and response details. They do not replace an MCP initialization exchange, session handling or tool call.

8. Common errors and fixes

Message or symptom Likely layer Fix
Command not found or process exits immediately stdio startup Use an absolute executable path, verify the working directory and environment, and read stderr.
Connection timed out Network path Run DNS, TCP and HTTPS tests from the client runtime; inspect proxy, firewall and private routes.
Could not resolve host DNS Check resolver configuration, split-horizon DNS and container or VM DNS settings.
401 or 403 Authentication Check token source, expiry, scopes, audience and provider-specific headers.
400 during an established session Session/request shape Confirm initialization completed and required session headers are present.
404 after initialization Session or endpoint Verify the session ID and exact path; consult the server’s status semantics.
Unsupported protocol version Negotiation Compare client/server SDK versions and supported revisions; remove an unnecessary pinned version.
Connected, but tool returns isError: true Tool downstream Debug the tool’s API credentials, URL, egress and rate limits.
Works in a terminal but not an IDE Runtime environment Compare PATH, environment variables, proxy settings, user identity and working directory.

9. Reliability, performance and cost

Reliability

  • Capture startup logs and HTTP evidence before retrying.
  • Use bounded timeouts and exponential backoff only for transient network failures.
  • Do not retry 401, 403, malformed-request or unsupported-version responses without changing the cause.
  • Keep client and server versions documented, especially after upgrades.
  • For stateful HTTP, preserve sessions correctly; for stateless deployments, follow the server’s advertised mode.

Performance

  • DNS, TLS and process startup each add latency; measure them separately.
  • Reuse HTTP connections when the client library supports it.
  • Run the client near the remote server or downstream API when network latency dominates.
  • For tools that fetch large responses, inspect response size and streaming behavior before increasing timeouts.

Cost

MCP itself does not define a universal price for transport failures. Check the provider’s billing rules for API calls, retries and downstream tool requests. Avoid blind retry loops that can multiply billable calls.

10. A concise evidence checklist

  • Exact error text and timestamp
  • Client host, version and runtime (desktop app, container, VM or service)
  • Server name and version
  • Transport: stdio, Streamable HTTP or SSE
  • Endpoint scheme, host and path with secrets removed
  • HTTP status, response headers and sanitized body, if any
  • Full startup and handshake logs
  • Whether connection succeeds before a tool fails
  • Recent configuration, dependency or network changes

Or skip the browser setup

If the MCP tool you are debugging ultimately needs a dependable website capture, ScreenshotNeo provides a direct screenshot API and an MCP server. One GET request returns PNG, JPEG, WebP or PDF, and the MCP tools include take_screenshot, get_page_info and capture_pdf.

Use the same call from cURL, Python or Node.js:

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for options. Cookie banners, newsletter popups and chat widgets are removed before capture; bot checks, blank pages and failed loads are never billed, and response headers identify the page verdict and billing state. The MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account.

FAQ

Does “fetch failed” always mean the URL is wrong?

No. It can describe process startup, DNS, TLS, authentication, negotiation, sessions or a downstream tool request.

Should I switch from stdio to HTTP?

Only when the deployment requires a remote server or the server documents that transport. First identify the failing layer.

Is a 404 proof that the MCP server is offline?

No. In some stateful Streamable HTTP implementations it means the session ID is invalid. Check the server’s mode and logs.

Why does the server show connected while the tool fails?

Connection and tool execution are separate. The tool may be unable to reach its own API or may have invalid downstream credentials.

What should I include when asking for help?

Include the host and server versions, transport, exact sanitized error, status or startup log, and the stage where failure occurs. Never include secrets.