Skip to main content

10,000+ MCP Servers in Production: What the 2026 Numbers Say About Treating MCP as Infrastructure, Not a Toy

12 min readDora NodaDora Noda
Share
On this page

Twenty concurrent connections killed it. Not twenty thousand — twenty. When Stacklok's engineers pointed a load tester at an MCP server running over the stdio transport, 20 of 22 requests failed, and the two that survived took an average of twenty seconds each. The same server, the same tool, over Streamable HTTP: 100% success at five milliseconds average.

That gap — three orders of magnitude in latency, the difference between "works" and "on fire" — is the single most important thing the 2026 numbers teach us about the Model Context Protocol. MCP has crossed from experimental agent glue into production infrastructure, with 10,000+ active public servers and 97 million monthly SDK downloads. And infrastructure gets capacity-planned, load-tested, and SLA'd — or it fails at twenty connections.

The numbers, up front

Start with the census, because the scale is what makes everything else in this post non-optional. Anthropic launched MCP in November 2024 at roughly 2 million monthly SDK downloads. OpenAI adopted it in April 2025 (22 million), Microsoft wired it into Copilot Studio that July (45 million), AWS added support that November (68 million), and by March 2026 every major provider was on board: over 10,000 active public MCP servers and 97 million monthly SDK downloads across Python and TypeScript. In December 2025 Anthropic donated the protocol to the Agentic AI Foundation under the Linux Foundation, co-founded with Block, making it a vendor-neutral open standard.

Around 28% of Fortune 500 companies have integrated MCP servers into their AI systems, and Gartner predicts 75% of API gateway vendors will support MCP by the end of 2026. The deployment mix is shifting underneath those totals: roughly 86% local to 14% remote — but remote has grown 4x since May 2025. Every remote server is a network service with users, latency budgets, and failure modes.

Now the performance ladder — every rung below is a published, checkable number, with the source attached:

SetupLoadResultSource
stdio transport, yardstick echo tool on kind20 concurrent, 10 RPS, 5s2 of 22 requests succeeded; avg latency 20.01s, max 30.02sStacklok/ToolHive benchmark
SSE transport, same server20 concurrent, 10 RPS, 5s100% success; avg 18.56msSame benchmark
SSE transport, sustained20 concurrent, 50 RPS, 60s100% success (1,861 requests); avg 564.57ms, max 2.00sSame benchmark
Streamable HTTP, shared session pool20 concurrent, 10 RPS, 5s100% success; avg 5.31msSame benchmark
Streamable HTTP, shared vs unique sessionssustained load290–300 RPS shared vs 30–36 RPS unique — a 10x gapSame benchmark
chuk-mcp (IBM), Starlette/Uvicorn HTTPup to 1,000 concurrent700+ concurrent connections sustained (test stopped at timeout, not capacity); 36,348 RPS peak at 100 concurrent; zero MCP errorschuk-mcp benchmarks

One honest disclosure before we build on this table: during research, I found no independently published benchmark demonstrating 10,000+ concurrent connections at sub-50ms on a single MCP server. The closest verified rungs are above — hundreds of concurrent connections, tens of thousands of RPS, single-digit-millisecond averages on trivial tools. So this post asserts no unsourced peak. Instead: the verified ladder, why it looks this way, and the load-test recipe below to prove your own server's rung.

That is what treating MCP as infrastructure means: measured numbers, not marketing numbers.

Transport is the make-or-break decision

Stacklok's headline finding deserves to be quoted directly: transport choice is the make-or-break decision for scaling MCP. The stdio numbers above are not a tuning problem. The stdio transport spawns the server as a child process and speaks over stdin/stdout, which means it supports only a single client connection at a time.

Pointing concurrent load at it is asking a design to do something it was never shaped for — hence 8 timeouts and a 20-second average. For a local Claude Desktop setup it is perfect (roughly 1ms latency, no network at all). For anything multi-user or multi-agent, it collapses before the load even starts.

The subtler finding is the 10x gap between shared and unique session pools on Streamable HTTP: 290–300 RPS when clients reuse sessions versus 30–36 RPS when each request mints its own. Stacklok's summary — "session management is everything" — was written about the sessionful era, where a client dialed in with an initialize handshake, received an Mcp-Session-Id, and stayed pinned to whoever picked up. Session reuse wasn't an optimization; it was the difference between production throughput and a server that fell over under its own handshake overhead.

Read the caveats as infrastructure discipline, not dismissal. Stacklok is explicit: the yardstick echo tool does no real work, so real servers benchmark slower; the tests ran on a local kind cluster with port-forwarding, minimizing latency; and the load tool was purpose-built, not battle-hardened. Realistic remote latency for Streamable HTTP lands in the 10–100ms range per request, and 50–300ms for remote servers depending on region and load. The ladder above is a ceiling measured under friendly conditions — your floor will be lower, which is exactly why you measure your own.

The stateless turn: the 2026-07-28 spec

Here is the plot twist the 2025 benchmark couldn't see coming. Sixteen months after Streamable HTTP shipped with its phone-call session model, the 2026-07-28 spec revision ripped the phone out: the protocol core is now stateless. No initialize/initialized handshake, no Mcp-Session-Id carried across requests. Each JSON-RPC message is a separate HTTP request, with Mcp-Method and Mcp-Name headers for gateway routing.

Operationally, this lets MCP servers behave like every other stateless web tier. The sessionful model needed sticky sessions — requests pinned to the instance holding the session — which complicated load balancing, rolling deploys, and failover. The stateless core works behind any load balancer with no affinity: stateless Streamable HTTP is now the production default, frameworks target MCP 2026-07-28 as the default build, and every major SDK shipped a v2 against it. Operators are converging on "stateless on, always" as fleet policy — stateful sessions get orphaned when instances recycle, and the protocol no longer needs them.

One caveat, and it matters: the protocol is stateless, but the work is still stateful. Long-running tasks, multi-step tool flows, and conversational context still live somewhere — they just live in your backends (databases, queues, task stores) instead of in a protocol-level session pinned to one server process. The spec change doesn't delete state; it moves state to the layer that already knows how to replicate, persist, and expire it. If your MCP server keeps per-conversation state in process memory behind the new stateless transport, you haven't simplified operations — you've built a lottery where the prize is talking to the wrong replica.

The production checklist

With the numbers and the spec turn established, here is the concrete bar — the mechanisms that separate a demo MCP server from one you can capacity-plan. Each item maps to something you'd already demand of a REST API, because that is the entire thesis: hold MCP to the API bar.

Serve stateless Streamable HTTP behind a load balancer. No stdio in production, no session affinity, no single-instance snowflakes. SSE is officially deprecated in favor of Streamable HTTP, so don't build new surface on it. Horizontal scaling should be "add replicas," full stop.

Pool connections, enforce backpressure, set timeouts. Every MCP server fronts something — a database, a search index, a deployment API — and agent traffic is bursty by nature: one reasoning loop can fan out dozens of tool calls in seconds. Pool the upstream connections, bound queue depths, shed load with retryable status codes instead of queueing unboundedly, and time out tool calls so one hung backend doesn't pin every worker. The Stacklok sustained-load row (avg latency climbing from 19ms to 565ms as RPS rose) is what missing backpressure looks like from the outside.

Health-check the real client path, not just the port. A TCP listener that answers on /healthz while tools/list times out is a server that lies to your load balancer. Before you ship, walk the launch checklist: initialize, ping, and tools/list from a real client path, plus at least one safe tool call exercised in staging and production, with rate limits that include retry guidance. Health checks distinct from the app the server fronts are the point — the MCP layer can fail while the backend is fine, and vice versa.

Authenticate with OAuth 2.1 and scope tokens to least privilege. This is the checklist item the ecosystem is currently failing: 38% of MCP servers ship with no auth at all, per coverage of the OWASP MCP Top 10. A tool surface that agents can invoke is a privilege surface — treat it like one. Require and validate tokens (JWTs from your identity provider work; Azure API Management's MCP support documents exactly this pattern), bind scopes per tool, and enforce per-agent, per-tool rate limits with quotas. A malicious or compromised server has been shown to amplify token consumption 142x via recursive reasoning loops — rate limits and payload guardrails are cost controls, not just security controls.

Log, trace, and audit everything. Per-tool-call audit logs (who, which tool, which arguments, what result), request metrics with p50/p99 latency, and traces that connect an agent's tool call to the upstream work it triggered. When an agent does something surprising at 3 AM — and it will — the audit log is the only witness. Gateways and proxies (Kong's AI Gateway, Azure API Management, dedicated MCP proxies with sliding-window rate limiting and audit trails) exist precisely because bolting this onto every server by hand doesn't scale.

Prove it: the load-test recipe

Checklists assert; load tests prove. Here is a minimal recipe to find your own server's rung on the ladder, using k6 (Locust works equally well) against a staging instance:

javascript
// mcp-load.js — ramp concurrent tool-call sessions against /mcp
import http from 'k6/http';
import { check } from 'k6';
 
export const options = {
  stages: [
    { duration: '60s', target: 20 },   // Stacklok's basic row
    { duration: '120s', target: 100 }, // chuk-mcp's peak-RPS rung
    { duration: '120s', target: 500 }, // beyond any published rung
  ],
  thresholds: {
    http_req_failed: ['rate<0.01'],
    http_req_duration: ['p(99)<500'],
  },
};
 
const payload = JSON.stringify({
  jsonrpc: '2.0',
  id: 1,
  method: 'tools/call',
  params: { name: 'YOUR_SAFE_READ_ONLY_TOOL', arguments: {} },
});
 
export default function () {
  const res = http.post('https://staging.example.com/mcp', payload, {
    headers: { 'Content-Type': 'application/json' },
  });
  check(res, { 'tool call ok': (r) => r.status === 200 });
}

Run it with k6 run mcp-load.js, then read the result the way infrastructure demands. "Passes as infrastructure" looks like this: 100% success at your target concurrency, bounded p99 with no cliff as load rises, and graceful degradation beyond capacity — retryable errors and shed load, not timeouts and cascading failure. If p99 climbs 30x between stages the way Stacklok's SSE sustained row did, you have found your backpressure gap before your users did. Use a safe read-only tool, run against staging with production-shaped data, and re-run after every change to the tool surface — tools are API endpoints, and endpoints get load-tested on change.

Hold your deploy MCP server to the API bar

Now aim all of this at the highest-privilege MCP surface a platform can ship: deploy, rollback, logs, and scale as agent-invokable tools. This is where the "lightweight wrapper" temptation is strongest — the REST API already exists, so the MCP server becomes a thin translation shim with no auth of its own, no rate limits of its own, no load tests of its own. That shim inherits every privilege of the API it fronts and none of the protections. It is the 38%-no-auth statistic wearing a deploy pipeline.

The bar is simple to state and genuinely hard to meet: the MCP server gets the same auth, the same per-tool rate limits, the same audit logging, the same SLOs, and the same load-test gate as the REST/GraphQL API it parallels. Same identity provider, same token scopes (an agent that can read logs cannot necessarily roll back production), same p99 budgets, same "prove it in staging" recipe from the previous section.

Scope tools narrowly by default — get, list, describe, and log tailing before apply, exec, or rollback — following the shape the community Kubernetes and Docker MCP servers converged on: read-mostly exposure with writes deliberately withheld or gated. And put approval gates on the irreversible tools. An agent calling rollback should face the same confirmation a human clicking the button does, because it is the same action with the same blast radius.

Do this and the MCP server stops being a second, weaker API and becomes a second client of the same hardened core. One auth story, one audit story, one capacity plan — two protocol surfaces. That is what "MCP as infrastructure" cashes out to: not a toy beside the platform, but part of the platform.

Capacity-plan it like any API

A year ago, "run an MCP server" meant spawning a local process over stdio and watching your editor light up. The 2026 numbers describe a different world: 10,000+ public servers, 97 million monthly SDK downloads, remote deployments quadrupling, a stateless spec revision built for load balancers, and published benchmarks that tell you exactly which transport survives contact with concurrency. The protocol grew up. The operations have to grow up with it — pooling, backpressure, real-path health checks, OAuth, rate limits, audit logs, and a load test that proves the bar instead of asserting it.

The teams that internalize this early get a compounding advantage: every MCP tool they ship lands on infrastructure that was already built to be measured. The teams that don't get to rediscover, at twenty concurrent connections, that agent traffic is production traffic.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Agents are first-class operators there: deploy, logs, and scale over the same API surface your dashboard uses. Star the repo on GitHub or deploy your first app today.

Sources

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide