Tutorial

How to Debug MCP 404 and Connection Errors

Fix MCP 404 and connection errors by checking transport config, testing endpoints, verifying auth, and reading server logs. Step-by-step debug guide.

Debug MCP 404 and connection errors by systematically checking the transport layer, endpoint URL, authentication headers, and server-side logs. MCP servers fail with 404 when the URL path is wrong, the server is not running, or a reverse proxy strips the path prefix. Connection errors (ECONNREFUSED, timeout, ENOTFOUND) point to network or DNS issues. This guide walks through each failure mode in order of likelihood, with concrete commands to test at each step.

Prerequisites

  • A running MCP server (local or remote)
  • curl or httpie installed for endpoint testing
  • Access to the MCP server configuration file
  • Python 3.8+ for scripted debugging

Walkthrough

Step 1: Check transport configuration

Verify the MCP client config points to the correct transport type (stdio, SSE, or HTTP) and URL.

Python
import json, os

# Common MCP config locations:
# Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
# .mcp.json in project root
# VS Code settings.json

def check_mcp_config(config_path: str) -> dict:
    with open(config_path) as f:
        config = json.load(f)
    servers = config.get('mcpServers', {})
    issues = []
    for name, cfg in servers.items():
        if 'url' in cfg:
            url = cfg['url']
            if not url.startswith('http'):
                issues.append(f'{name}: URL missing http/https prefix')
            if url.endswith('/'):
                issues.append(f'{name}: trailing slash may cause 404')
        elif 'command' not in cfg:
            issues.append(f'{name}: no url or command defined')
        print(f'{name}: {cfg.get("url", cfg.get("command", "unknown"))}')
    return {'servers': list(servers.keys()), 'issues': issues}

# Check a config file:
# check_mcp_config(os.path.expanduser('~/.mcp.json'))
print('Check your .mcp.json or claude_desktop_config.json for URL accuracy')

Step 2: Test the URL with curl

Test the MCP server endpoint directly with curl to isolate whether the issue is client-side or server-side.

Python
# Run these curl commands to test your MCP server:
# Replace URL with your actual MCP server address

import subprocess

def test_endpoint(url: str, api_key: str = '') -> dict:
    headers = ['-H', f'x-api-key: {api_key}'] if api_key else []
    # Test basic connectivity
    try:
        result = subprocess.run(
            ['curl', '-s', '-o', '/dev/null', '-w', '%{http_code}', url] + headers,
            capture_output=True, text=True, timeout=10)
        status = result.stdout.strip()
        print(f'HTTP {status} from {url}')
        if status == '404':
            print('  -> Check URL path. Common fix: remove or add trailing /sse or /mcp')
        elif status == '401' or status == '403':
            print('  -> Authentication issue. Check API key or token.')
        elif status == '000':
            print('  -> Connection refused. Server not running or wrong port.')
        return {'url': url, 'status': status}
    except subprocess.TimeoutExpired:
        print(f'Timeout connecting to {url}')
        return {'url': url, 'status': 'timeout'}

test_endpoint('https://api.scavio.dev/api/v1/search')

Step 3: Verify authentication

Confirm the API key or token is being sent correctly. MCP 404s sometimes mask auth failures on certain server implementations.

Python
import requests

def verify_auth(url: str, api_key: str) -> dict:
    # Test with auth
    try:
        resp_auth = requests.post(url,
            headers={'x-api-key': api_key, 'Content-Type': 'application/json'},
            json={'platform': 'google', 'query': 'test'}, timeout=10)
        print(f'With auth: HTTP {resp_auth.status_code}')
    except Exception as e:
        print(f'With auth: {e}')
        resp_auth = None

    # Test without auth
    try:
        resp_no_auth = requests.post(url,
            json={'platform': 'google', 'query': 'test'}, timeout=10)
        print(f'Without auth: HTTP {resp_no_auth.status_code}')
    except Exception as e:
        print(f'Without auth: {e}')
        resp_no_auth = None

    return {
        'auth_status': resp_auth.status_code if resp_auth else 'error',
        'no_auth_status': resp_no_auth.status_code if resp_no_auth else 'error',
    }

verify_auth('https://api.scavio.dev/api/v1/search', os.environ.get('SCAVIO_API_KEY', ''))

Step 4: Check server logs for root cause

If curl succeeds but MCP client fails, the issue is in the client-server handshake. Check server logs for the actual error.

Python
# Common MCP server log locations:
# Docker: docker logs <container_name>
# systemd: journalctl -u mcp-server
# Local: check stdout/stderr of the server process

def diagnose(test_results: dict) -> str:
    status = str(test_results.get('status', ''))
    diagnoses = {
        '404': 'URL path mismatch. Try: /sse, /mcp, /v1/search, or remove trailing slash.',
        '401': 'API key invalid or missing. Regenerate at provider dashboard.',
        '403': 'API key valid but lacks permission. Check plan tier.',
        '500': 'Server-side error. Check server logs. Retry in 60s.',
        '502': 'Reverse proxy cannot reach backend. Check server is running.',
        '503': 'Server overloaded. Implement retry with backoff.',
        'timeout': 'Server unreachable. Check DNS, firewall, and port.',
        '000': 'Connection refused. Server not running on that host:port.',
    }
    return diagnoses.get(status, f'Unexpected status {status}. Check server logs.')

print(diagnose({'status': '404'}))
print(diagnose({'status': 'timeout'}))

Python Example

Python
import requests, os

def debug_mcp(url, api_key):
    try:
        r = requests.post(url, headers={'x-api-key': api_key},
            json={'platform': 'google', 'query': 'test'}, timeout=10)
        print(f'Status: {r.status_code}')
        if r.status_code == 200:
            print('Connection OK')
        elif r.status_code == 404:
            print('Check URL path: try /sse, /mcp, or /v1/search')
    except requests.exceptions.ConnectionError:
        print('Connection refused: server not running?')
    except requests.exceptions.Timeout:
        print('Timeout: check firewall/DNS')

debug_mcp('https://api.scavio.dev/api/v1/search', os.environ.get('SCAVIO_API_KEY', ''))

JavaScript Example

JavaScript
async function debugMcp(url, apiKey) {
  try {
    const r = await fetch(url, {
      method: 'POST',
      headers: {'x-api-key': apiKey, 'Content-Type': 'application/json'},
      body: JSON.stringify({platform: 'google', query: 'test'}),
      signal: AbortSignal.timeout(10000)
    });
    console.log(`Status: ${r.status}`);
    if (r.status === 404) console.log('Check URL path');
  } catch (e) {
    console.log(`Error: ${e.message}`);
  }
}
debugMcp('https://api.scavio.dev/api/v1/search', process.env.SCAVIO_API_KEY);

Expected Output

JSON
A systematic debug checklist that identifies the root cause of MCP 404 and connection errors through transport, URL, auth, and log analysis.

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

A running MCP server (local or remote). curl or httpie installed for endpoint testing. Access to the MCP server configuration file. Python 3.8+ for scripted debugging. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Fix MCP 404 and connection errors by checking transport config, testing endpoints, verifying auth, and reading server logs. Step-by-step debug guide.