DEV Community

Cover image for Do MCP servers check your ID? A security scorecard of 78 public endpoints
Pennyforge
Pennyforge

Posted on

Do MCP servers check your ID? A security scorecard of 78 public endpoints

Pennyforge Studio · 2026-10-06 · cohort n=78 · $0 · reproducible (probe script + raw JSON available on request, 16-second wall)

Last week we published a compatibility probe of 78 public MCP endpoints: the servers in the registry's first alphabetical slice that answered an initialize. This run we stopped measuring "does it answer" and started measuring something else: what does a stranger with zero credentials get — and does the server follow the spec revision it claims to speak? Same cohort, same day window, new questions.

The headline table

measure result
endpoints that answer initialize anonymously (no credentials, no headers) 76/78 (97%)
endpoints that then expose their FULL tool inventory to that stranger 74/78 (95%)
tools a stranger with zero credentials can see 793 — 100% carry a description string
endpoints that gate anything at the protocol level 2 — both with NO WWW-Authenticate header
endpoints that ever send a WWW-Authenticate header (the OAuth 2.1 + RFC 9728 discovery the 2026-07-28 revision standardizes when authorization is on) 0/78
endpoints on the 2026-07-28 revision 7/78 (9%) — unchanged across our three dated points
endpoints that still issue Mcp-Session-Id headers — a header the 2026-07-28 revision removed from the spec entirely (SEP-2567) 9/78 (12%)

Two concrete dated bugs

1. A 401 you cannot discover. agentxray.ai/api/mcp: initialize is wide open; tools/list returns 401 {"detail":"invalid or missing MCP token"} with no WWW-Authenticate header. A conforming client following the spec's own discovery chain (401 → resource_metadata per RFC 9728 → authorization-server metadata per RFC 8414/OIDC) has nothing to latch onto: the credential scheme is a private convention. The spec even shows the 401 shape this server skipped:

WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"
Enter fullscreen mode Exit fullscreen mode

2. A revision-mix interop wall. 7/78 endpoints (9%) accept the legacy handshake but reject a standard tools/list with HTTP 400: -32602 "Missing required _meta field: io.modelcontextprotocol/clientCapabilities". The twist is that this is the new spec's fault line: the 2026-07-28 revision makes every request carry protocolVersion + clientCapabilities in _meta (SEP-2575 — the initialize handshake is gone; the protocol is now stateless and version rides per-request). So one of these seven, ad.getle/leads, negotiates 2026-07-28 and is actually conformant — it is our legacy-form request that is wrong. The other six negotiate 2025-11-25 while already enforcing the new request shape: partial migration — the exact interop mess a versioned spec exists to prevent. Nine percent of the cohort is only reachable through the new request shape, and six of those nine are mid-migration.

The exposure surface, by size

74 endpoints expose their full tool list to an anonymous stranger: median 5 tools; 25 expose 10 or more. The largest: 184 tools (borealhost), 65 (bitroad), 35 (betslipdoctor), 35 (getle), 23 (betterpost). Every one of the 793 tools carries a description — the string an LLM client reads and trusts when deciding what to call. In the tool-poisoning terms that security people now use: 793 third-party-authored descriptions, readable and callable by anyone, on infrastructure with no protocol-level identity.

What the 2026-07-28 spec actually says (fetched first-hand for this post)

  • Stateless by construction: the initialize/notifications/initialized handshake is removed; every request carries protocolVersion + clientCapabilities in _meta; Mcp-Session-Id is gone from Streamable HTTP (SEP-2575, SEP-2567). Version mismatch → UnsupportedProtocolVersionError. server/discover is MUST — the designated way to advertise supported versions.
  • Roots, Sampling, Logging are deprecated (SEP-2577) but "remain fully functional during the deprecation window"; Tasks moved out of core into an official extension (SEP-2663).
  • Authorization is optional per implementation — but when supported: OAuth 2.1, RFC 9728 Protected Resource Metadata is MUST for servers and for client discovery, RFC 8707 resource indicator is MUST, and the anti-token-passthrough rule is explicit: "MCP servers MUST NOT accept or transit any other tokens." RFC 7591 dynamic client registration is deprecated in favor of Client ID Metadata Documents.
  • The NSA weighed in. "Model Context Protocol (MCP): Security Design Considerations for AI-Driven Automation" (U/OO/6030316-26, May 2026, 17 pages) opens with: "MCP's rapid proliferation has outpaced the development of its security model." It names arbitrary-code-execution (CWE-77/78/94/95) as the class that "easily arise in MCP environments."
  • Two CVEs make it concrete. CVE-2025-6514: OS command injection in mcp-remote via a crafted authorization_endpoint URL — 9.6 CRITICAL. CVE-2025-49596: the MCP Inspector's proxy ran unauthenticated (RCE, fixed in 0.14.1) — 9.4 CRITICAL. Both verified against cve.org for this post.

The honest counterweight: the scanner space is not empty. Snyk, Cisco and Tencent all maintain MCP security scanners, all pushed within the last week. What none of them are is a dated, reproducible, neutral cohort table — the "who's checking your ID, and which revision is actually deployed" index. This post is that table; the script makes it re-runnable by anyone.

Version mix — stable at the third dated point

negotiated revision 2026-10-05 2026-10-06
2026-07-28 7 7
2025-11-25 41 41
2025-06-18 20 20
older 8 8

Ten weeks after the 2026-07-28 revision — with its handshake, its session header and its ping all removed — this cohort is 9% on it. The revision's own backward-compatibility machinery (per-request version negotiation, server/discover) is only partially deployed even on the servers that adopted it.

Method, labels, caveats

All wire measurements are first-hand: a 16-second probe (anonymous initialize in legacy and modern form, tools/list with session + negotiated version, header capture; 8 workers). "Anonymous" = no auth header, standard user-agent; we sent credentials no one should recognize. The 2 endpoints that never initialized (one HTTP 530, one 200-with-non-RPC) are marked unresolved, not failed. Because the spec makes authorization optional per implementation, "0/78 use OAuth discovery" is a statement about this cohort's deployed state — the two bare-401 servers are the closest thing to a violation (they gate without any discoverable mechanism). Spec, NSA and CVE claims are cited to the primary sources above and were all fetched for this post.

Next dated point: the registry's c–d slice — same script, new cohort, doubled table — lands around mid-October, timed just after AGNTCon/MCPCon (10-22/23).

Part of our dated MCP probe series. The script, the raw JSON and the previous posts are linked above / available on request. Pennyforge is a one-person studio; this was all measured from our own machine this week at $0 in API costs.

Top comments (0)