Most of us here have shipped an MCP server by now, and the debugging stories are all suspiciously similar. These are the three failure patterns behind almost every "my server is broken" thread, and none of them are actually bugs in the server.
Transport Is A Decision, Not A Detail
MCP gives you two transports and the choice constrains everything downstream. stdio runs your server as a subprocess of the AI client: no network config, no auth layer, no firewall rules, and the process starts and stops with the client. That is why nearly every development-time server uses it.
Streamable HTTP runs the server as a network service the client reaches over HTTP with JSON-RPC. It is the transport that supports remote deployment, authentication, load balancing and multiple users at once. If you are building anything shared, a database, an API, a memory layer, start here, because porting later means rewriting the transport rather than tweaking it.
Worth knowing that the original spec also shipped an SSE transport. It has since been superseded by Streamable HTTP, so older tutorials referencing SSE will walk you into a dead end.
Bug One: The Server That Cannot Find Your PATH
This is the most common stdio failure by a wide margin. The server process inherits the environment of the client that launched it, not the environment of your shell. Your virtualenv is missing. Your API keys are missing. Sometimes node itself is not on the path.
The ten second test: run the exact command and args from your client config in a plain terminal. If it works there and not in the client, it is environment, not code.
The server connects, the client shows nothing. This is almost always capability negotiation, or a tool that threw during initialization and got dropped quietly.
Point the MCP Inspector at your server. It lists the registered tools, resources and prompts, and lets you invoke them with test parameters. If a tool shows up in the Inspector but not in your client, the problem is client config or the model's invocation, not your server. That single split removes most of the guesswork.
Bug Three: Parameter Mismatches
The model sends arguments that do not match your schema: missing required fields, wrong types, extra keys the schema rejects. This reads like a model problem and is usually a schema description problem, because the model only knows what your descriptions told it.
For HTTP servers, curl the endpoint directly. Send the initialization request, confirm the capability list comes back, then send a tool invocation and check the response. That proves reachable, authenticated and functional before the AI client is anywhere near the loop.
The Security Part People Postpone
stdio servers inherit the local user's entire security context, which is fine on your laptop and not fine for anything shared. HTTP servers get OAuth 2.1, where the client carries a token and the server scopes access per identity, which also buys you rate limits and an audit trail. API keys are the simpler route and are genuinely enough for single user or small team deployments, they just lack expiration, refresh and per-user scoping. The MCP server setup and integration guide walks through the OAuth flow and the production deploy end to end if you want the specifics.
Beyond auth, think about what each tool exposes. A tool running SQL against production needs input validation and query scoping. A filesystem tool needs path validation. A tool calling an external API needs rate limiting. Same concerns as any networked service, except this caller can fire hundreds of rapid programmatic calls that a human never would.
What is the worst MCP debugging session you have had, and which of the three was it?