How to Troubleshoot MCP Server Connection Issues: Complete Diagnostic Guide
MCP server connection issues typically stem from transport misconfiguration, missing environment variables, network restrictions, or improper timeout handling in the server implementation.
Model Context Protocol (MCP) servers expose tools that LLM agents invoke over transport layers like STDIO, HTTP, or SSE. When clients cannot reach the server, systematic troubleshooting of the transport stack, credentials, and error handling logic will resolve most failures. This guide uses implementation details from the ComposioHQ/awesome-codex-skills reference repositories to diagnose and fix connection problems.
Common Connection Failure Points
Connection failures in MCP architectures usually originate in one of five layers. Examine each systematically to isolate the root cause.
Transport Configuration
Verify the server and client use matching transport protocols. The Python MCP server supports stdio, streamable_http, and sse modes, configured during initialization. If you launched the server with mcp.run() for STDIO, ensure evaluation scripts use the -t stdio flag. For HTTP transports, confirm the URL (http://localhost:8000) and port binding match between the server startup command and client connection parameters. Reference implementations in mcp-builder/reference/python_mcp_server.md demonstrate how transport flags must align across the connection lifecycle.
Environment and Credentials
Missing API keys or tokens are a frequent cause of silent connection failures. Ensure required secrets like OPENAI_API_KEY or GITHUB_TOKEN are exported in the shell environment and properly read by the server using os.getenv or Pydantic settings. The evaluation documentation in mcp-builder/reference/evaluation.md specifically notes that connection errors often indicate the server cannot access credentials needed for underlying API calls.
Network Reachability
Test basic connectivity before debugging application logic. From the client machine, run nc -zv <host> <port> or curl -I <url> to verify the server endpoint is accessible. Check for firewall rules, VPC restrictions, or container networking issues that might block the port. DNS resolution failures will also manifest as connection timeouts.
Server-Side Error Handling
Robust servers must wrap all outbound network calls with timeout handling and convert exceptions into user-friendly error messages. According to mcp-builder/reference/python_mcp_server.md, tools should return strings starting with "Error:" rather than raising raw exceptions, which preserves the MCP protocol connection and allows the LLM to react gracefully. The _handle_api_error helper function demonstrates this pattern by catching httpx.TimeoutException and httpx.HTTPStatusError before they bubble up.
Logging and Diagnostics
Enable detailed logging to capture request/response cycles. In Python FastMCP implementations, use ctx.log_info() or ctx.log_error() methods. For STDIO transports, examine server stdout and stderr directly, as protocol messages stream through these channels. The Node.js reference in mcp-builder/reference/node_mcp_server.md (line 907) emphasizes logging all network operations to diagnose timeout and connection errors.
Step-by-Step Troubleshooting Checklist
Follow this sequence to isolate MCP connection failures:
-
Confirm transport alignment — Verify the server transport flag matches the client evaluation script. If running HTTP mode, ensure the server listens on
0.0.0.0rather thanlocalhostwhen accessed remotely. -
Validate environment variables — Export all required secrets (
export GITHUB_TOKEN=...) and verify the server process can access them. Missing keys often trigger connection failures during the initial tool listing phase. -
Test network connectivity — Use
telnetorcurlto verify the host and port are reachable from the client machine. Timeouts here indicate infrastructure issues outside the MCP implementation. -
Inspect server logs — Look for
httpx.TimeoutExceptionorhttpx.HTTPStatusErrorentries. The_handle_api_errorimplementation logs exact status codes that triggered failures. -
Check timeout settings — The default
httpx.AsyncClienttimeout is 30 seconds. Increase this to 60 seconds or higher for slow external APIs, or implement retry logic as shown in the reference implementations. -
Verify tool error handling — Ensure all tools return formatted error strings rather than raising unhandled exceptions. This keeps the protocol connection intact.
-
Run the evaluation harness — Execute
scripts/evaluation.pywith the-tflag matching your transport mode. This automated check will surface misconfigured transports or missing credentials.
Code Solutions for Connection Resilience
Implement these patterns from the ComposioHQ reference code to prevent and handle connection issues gracefully.
Adding Timeout and Retry Logic
Wrap external API calls with configurable timeouts and exponential backoff. This pattern mirrors the error handling in mcp-builder/reference/python_mcp_server.md:
import httpx
from typing import Any
MAX_RETRIES = 3
TIMEOUT_SEC = 60.0 # Increased from default 30s
async def _make_api_request(endpoint: str, method: str = "GET", **kwargs) -> Any:
"""Reusable HTTP client with timeout and retry logic."""
for attempt in range(1, MAX_RETRIES + 1):
try:
async with httpx.AsyncClient() as client:
resp = await client.request(
method,
f"{API_BASE_URL}/{endpoint}",
timeout=TIMEOUT_SEC,
**kwargs,
)
resp.raise_for_status()
return resp.json()
except (httpx.TimeoutException, httpx.HTTPStatusError) as e:
print(f"[Attempt {attempt}] Request failed: {e}")
if attempt == MAX_RETRIES:
raise
Formatting Errors for LLM Consumption
Structure tool outputs to maintain protocol stability when connections fail:
@mcp.tool(
name="example_fetch_resource",
annotations={
"title": "Fetch Example Resource",
"readOnlyHint": True,
"idempotentHint": True,
},
)
async def example_fetch_resource(params: ResourceInput) -> str:
"""Retrieve remote resource with graceful error handling."""
try:
data = await _make_api_request(f"resources/{params.id}")
return json.dumps(data, indent=2)
except Exception as exc:
# Returns "Error: ..." to keep MCP connection alive
return _handle_api_error(exc)
Testing with the Evaluation Harness
Verify connectivity using the built-in evaluation script:
# Terminal 1: Start HTTP server
python my_mcp_server.py &
# Terminal 2: Run evaluation
python scripts/evaluation.py \
-t http \
-c python \
-a my_mcp_server.py \
-e GITHUB_TOKEN=$GITHUB_TOKEN \
-o eval_report.md \
my_evaluation.xml
If this produces "connection error," verify the server is listening on the expected interface and that no firewall blocks the port.
Key Reference Files
These files in the ComposioHQ/awesome-codex-skills repository contain authoritative implementation details:
mcp-builder/reference/python_mcp_server.md— Transport configuration options,_handle_api_errorhelper implementation, and FastMCP context logging methods.mcp-builder/reference/node_mcp_server.md— Node.js equivalent of timeout handling and connection error management (see line 907).mcp-builder/reference/mcp_best_practices.md— Architectural guidance for connection lifecycle management and proper error handling strategies.mcp-builder/reference/evaluation.md— Automated troubleshooting via the evaluation harness, including the Connection Errors diagnostic section (lines 78-86).scripts/evaluation.py— Executable harness for testing transport modes and credential configurations.
Summary
- Transport mismatch between server and client is the most common connection failure—always verify flags like
-t stdioor-t httpalign with the server's startup mode. - Missing environment variables cause cryptic connection errors during tool execution—validate all API keys are exported before starting the server.
- Network timeouts default to 30 seconds in
httpx.AsyncClient—increase this value or add retry logic for unreliable external APIs. - Protocol stability requires converting exceptions to
"Error:"strings rather than raising them, preserving the MCP connection for LLM retry logic. - Diagnostic logging via
ctx.log_*or stdout examination provides visibility into STDIO transport failures.
Frequently Asked Questions
How do I fix "connection refused" when connecting to an MCP server?
"Connection refused" typically indicates the server is not listening on the expected port or interface. Verify the server started successfully and binds to 0.0.0.0 rather than 127.0.0.1 for remote connections. Check that no firewall or Docker network isolation blocks the port, and confirm the client URL includes the correct port number (e.g., http://localhost:8000).
Why does my MCP server work with STDIO but fail on HTTP transport?
HTTP mode requires explicit transport configuration and network accessibility. Ensure you started the server with the HTTP transport flag (e.g., transport="streamable_http") and that the evaluation script uses -t http. Additionally, HTTP servers must handle CORS headers and binding interfaces correctly, whereas STDIO simply uses process pipes.
How can I debug timeout errors in MCP tool calls?
Enable verbose logging to identify whether the timeout occurs during the MCP handshake or the underlying API call. Increase the httpx.AsyncClient timeout from the default 30 seconds, or implement the retry pattern shown in _make_api_request. Check mcp-builder/reference/node_mcp_server.md line 907 for the Node.js equivalent timeout configuration.
What should I do if the evaluation script reports connection errors immediately?
Run the checklist steps: first verify required environment variables (-e flags) are passed correctly, then test network reachability with curl. If using HTTP mode, ensure the server process is actually running and listening (check with netstat -tlnp or lsof -i :8000). Finally, examine the server logs for startup errors that prevent the transport from initializing.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →