{"slug": "i-measured-27257-mcp-connections-the-p90-session-waits-35s", "title": "I Measured 27,257 MCP Connections. The p90 Session Waits 35s.", "summary": "A developer analyzed 35 days of Claude Code MCP connection logs covering 27,257 connections and found that OAuth token refreshes inside the connection window make sessions 5.8× slower (3,170 ms median vs 550 ms), with the p90 session waiting 35 seconds due to fan-out across eight servers. The analysis also showed stdio transports are 3× faster at the median but worse in the tail than HTTP, and that 11,556 of 38,876 connection attempts never logged an established connection.", "body_md": "In July I wrote a 56-line shell script called `mcp-optional` whose entire job was to **remove** two MCP servers from my config.\n\nNot fix them. Remove them.\n\nBoth were stdio servers, so each one spawns its own Node process *per session*. With around 13 Claude Code sessions open on a 16GB M4, that was roughly 1.4GB of duplicated RAM, which meant swap thrash, which meant a hot laptop. Disabling them by default and re-enabling on demand fixed it.\n\nI filed that under \"memory problem, solved\" and stopped thinking about it.\n\nThis morning, chasing something unrelated, I started reading the MCP connection logs Claude Code leaves on disk. It turns out one of those two servers wasn't just the RAM tax. It's also the slowest thing I connect to, by a wide margin — and the reason isn't its code at all.\n\nHere's what 35 days of logs actually say.\n\nClaude Code writes a JSONL log per MCP server, per session, under `~/Library/Caches/claude-cli-nodejs/<project>/mcp-logs-<server>/`. Two lines matter:\n\n```\nStarting connection with timeout of 30000ms\nConnection established with capabilities: {\"hasTools\":true,...}\n```\n\nPair them inside one file and you get a real connection latency. I did that across every project directory on this machine:\n\nThis is one developer's machine, not a lab. That's the point — it's the distribution you actually live in.\n\n| percentile | connect time | \n|---|---|\n| median | **582 ms** | \n| p75 | 1,650 ms | \n| p90 | **3,678 ms** | \n| p95 | 6,428 ms | \n| p99 | **14,049 ms** | \n\nThe median looks great. Under six tenths of a second — nobody would ever file a bug.\n\nBut **39% of connections take longer than a second**, and the p99 is fourteen seconds. Against a client timeout of 30,000ms, the tail is not a rounding error. It's most of the way to the wall.\n\nThis is the finding that reframed the whole thing for me. I split every connection by whether a token refresh happened inside that same connection window:\n\n|  | n | median | p90 | \n|---|---|---|---|\n| token refresh in window | 748 | **3,170 ms** | 9,619 ms | \n| no refresh | 26,509 | **550 ms** | 3,400 ms | \n\n**5.8× slower.** Same servers, same network, same machine. The only difference is whether the client had to go get a new access token first.\n\nYour MCP server didn't take three seconds to start. Your MCP server took 550ms to start, and an OAuth round-trip took the other 2.6 seconds while the server sat there doing nothing.\n\nThat's why \"why is this server slow\" is usually the wrong question. Only 2.7% of my connections hit a refresh — but that 2.7% is where a disproportionate share of the visible pain lives, because it's the path that turns a fast connection into a slow one non-deterministically. You can't reproduce it on demand, so you blame the server.\n\n| transport | n | median | p90 | \n|---|---|---|---|\n| HTTP | 19,894 | 676 ms | **3,395 ms** | \n| stdio | 7,363 | **222 ms** | **4,693 ms** | \n\nstdio is 3× faster at the median — no surprise, there's no network. But look at p90: **stdio is worse in the tail.** Spawning a process has a floor of roughly nothing and a ceiling of \"npm decided to do something.\" An HTTP server that's already running is slower on average and far more predictable.\n\nIf you're choosing a transport, that trade is the actual decision. Not \"stdio is faster.\"\n\nPer-connection numbers hide the thing that actually costs you time, which is fan-out. Per session on this machine:\n\nThat p90 is the number that made me stop and re-read my own script. A third of the time I open a session, I'm waiting a meaningful fraction of a minute before the first token — not because any single server is broken, but because eight of them each drew from that fat tail and nothing amortizes.\n\nWorst offender by median, unsurprisingly: one of the two servers I'd already disabled for RAM reasons, at **2,261 ms median and 10,413 ms at p90**. I removed it in July for the wrong reason and got the right outcome.\n\nOf 38,876 connection attempts, **11,556 never logged an established line at all** — 29.7%.\n\nSome of that is log rotation cutting a file mid-handshake, so treat it as an upper bound rather than a failure rate. But it isn't evenly spread: a single remote connector accounts for 7,422 of them on its own. That's not noise, that's one integration failing over and over while everything upstream stays quiet about it.\n\nMy first pass had a max connect time of **119 seconds** and a p99 of 14.5s, and I nearly wrote a paragraph about it.\n\nThen I re-read the client's own log line: `timeout of 30000ms`. A connection cannot establish at 119 seconds if the client gives up at 30. Those samples weren't slow connections — they were a closed laptop. The wall clock kept running through sleep; the connection didn't.\n\nSo I capped every measurement at the client's declared 30s timeout and threw the rest out. That removed **24 of 27,281 samples — 0.09%**. Every number above is post-cap.\n\nI mention it because the uncapped version would have been a better story and a false one. If you run this on your own machine, cap it.\n\n`mcp-optional` does — `claude mcp remove` by default, `claude mcp add` when a task needs it. It's the highest-leverage 56 lines I have written this year, and I wrote it for the wrong reason.\nThe reason I care about any of this: at [Achiya Automation](https://achiya-automation.com/services/ai-agents/?utm_source=devto&utm_medium=article&utm_campaign=mcp-server-startup-time) I run agent tooling against real client infrastructure all day, and a 35-second session start that lands on one session in ten — with a third of them over 10 seconds — is a tax I pay dozens of times a day without ever seeing it on a bill.\n\nIf you've got MCP servers configured right now — **how many, and when did you last check whether you still use all of them?**\n\nI'd genuinely like to know whether median-8 is normal or whether I'm the outlier. And if you've measured a refresh-vs-no-refresh split on a different client, I want to see that number, because I only have one machine to look at.", "url": "https://wpnews.pro/news/i-measured-27257-mcp-connections-the-p90-session-waits-35s", "canonical_source": "https://dev.to/achiya-automation/i-measured-27257-mcp-connections-the-p90-session-waits-35s-55dp", "published_at": "2026-09-16 05:45:26+00:00", "updated_at": "2026-09-16 06:07:20.411138+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents", "mlops"], "entities": ["Claude Code", "MCP", "Node", "OAuth"], "alternates": {"html": "https://wpnews.pro/news/i-measured-27257-mcp-connections-the-p90-session-waits-35s", "markdown": "https://wpnews.pro/news/i-measured-27257-mcp-connections-the-p90-session-waits-35s.md", "text": "https://wpnews.pro/news/i-measured-27257-mcp-connections-the-p90-session-waits-35s.txt", "jsonld": "https://wpnews.pro/news/i-measured-27257-mcp-connections-the-p90-session-waits-35s.jsonld"}}