MCP server check beta
RFC 9728 / 8414 discovery probe · scored as criterion F3
A remote MCP server (Model Context Protocol) is an HTTPS endpoint speaking JSON-RPC over the Streamable HTTP transport that a client like Claude can connect to. Whether that connection is a two-minute action or a support ticket comes down to one thing: what the server advertises about itself. AgentFit probes that advertised surface without credentials and scores it as criterion F3.
Run AgentFit inside Claude
AgentFit runs its own remote MCP server at
https://agentfit.dev/mcp — and scores
oauth-mcp on the very rubric below. (This page,
/mcp-check, is the explainer; /mcp is the live
endpoint.) No sign-up: the OAuth step auto-approves — no
login screen — exactly like the website's
anonymous audits.
- Claude Code:
claude mcp add --transport http agentfit https://agentfit.dev/mcp - claude.ai / Claude Desktop: Settings → Connectors → Add
custom connector →
https://agentfit.dev/mcp - Gemini / ChatGPT: best-effort / developer-mode only (remote-MCP support varies by client).
Then ask: "audit https://docs.stripe.com". The tool returns a live
share_url immediately and the full scored report when it
finishes (~10–30s). Tools: audit(base_url, format) and
get_report(run_id), scope agentfit:audit. If a
call says your authorization expired, reconnect — tokens are short-lived by
design. Prefer not to install anything?
Paste a URL on the homepage →
One audit of the same site per network per 24 hours, and the MCP server
shares that quota with the website — if you have just scored a site on the
home page, asking an agent to score it again today will be refused. Pick a
different site, or read the existing run back with get_report.
What "MCP-ready" means here
An ideal remote MCP server is an OAuth 2.1 protected
resource that publishes standards-based metadata, so an agent can
go from "I have a URL" to "I have an audience-bound token" with nobody
copying client secrets around. Concretely, it serves Protected Resource
Metadata at a well-known URL
(RFC 9728);
names its authorization server there; answers an unauthenticated request
with a 401 and a WWW-Authenticate challenge
pointing back at that metadata; and its authorization server publishes
RFC 8414
metadata advertising PKCE with S256
(RFC 7636)
plus a way for a brand-new client to register itself — Dynamic Client
Registration, or the Client ID Metadata Documents that the newer MCP
authorization revisions prefer.
We grade the advertised discovery surface. That distinction runs through this whole page: publishing correct metadata is necessary for an agent to connect at all, and it is the part an outside auditor can verify honestly.
The discovery chain, step by step
This is exactly what AgentFit requests, in order, and what counts as a correct answer.
Step 0 — finding the server at all
There is no ratified .well-known/mcp, so discovery is anchored
on the OAuth metadata. Every audit makes one GET to
/.well-known/oauth-protected-resource at the host root. If that
returns a valid, same-host, MCP-specific document, discovery is done.
Otherwise we probe conventional endpoints (/mcp,
/sse, /api/mcp) and the path-suffixed metadata
variant only when llms.txt or a same-host homepage link
mentions mcp or sse. A site with no MCP surface
therefore pays exactly one extra request.
Two guards keep the answer meaningful. We report an MCP server only
when the resource or endpoint is same-host and its path
carries mcp (or sse, corroborated by an MCP
mention) — a generic OAuth API with resource metadata is not an MCP server.
And a link to somebody else's MCP server in your
llms.txt is filtered out rather than credited to you.
Step 1 — Protected Resource Metadata (RFC 9728)
GET /.well-known/oauth-protected-resource
GET /.well-known/oauth-protected-resource/mcp (path-suffixed variant)
A correct answer is 200 with a JSON body — not HTML, which we
sniff for and reject — containing:
resource— non-empty, and on the same scheme and host that served the metadata. Aresourcepointing at a different host is the confused-deputy red flag this check exists to catch. We do not require an exact path match: a host-root identifier is valid, and serving the bare document with a sub-pathresourcesuch ashttps://example.com/mcpis common and correct.authorization_servers— at least one entry that is a public HTTPS URL.- Nice to have:
resource_name,resource_documentation,bearer_methods_supported, and ascopes_supportedlist that is actually least-privilege. A scope literally called*,allorfull_accessfails; an absent list is recorded as unverified, not as a failure — RFC 9728 §2 makes it OPTIONAL.
Step 2 — the unauthenticated challenge
GET <endpoint> → 401
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
A 401 carrying a Bearer challenge passes. Anything
else — 200, 400, 405 — is recorded as
unverified, never as a failure, and the reason is worth
stating: an unauthenticated GET cannot see POST-only protection, cannot
carry the protocol-version header some servers require, and cannot
distinguish a deliberate anonymous-initialize carve-out from a missing
guard. We would rather say "could not verify" than invent a verdict.
Step 3 — Authorization Server Metadata (RFC 8414)
We follow the first entry of authorization_servers — after an
SSRF check, because that URL is chosen by the site being audited, and we
refuse to fetch anything non-HTTPS or resolving to a private, loopback,
link-local or cloud-metadata address. The hop is time-boxed so a slow
authorization server cannot stall the audit. For an authorization server at
https://as.example.com/tenant1 we try, in order:
https://as.example.com/.well-known/oauth-authorization-server/tenant1
https://as.example.com/.well-known/openid-configuration/tenant1
https://as.example.com/.well-known/oauth-authorization-server
https://as.example.com/.well-known/openid-configuration
Note the ordering: RFC 8414 inserts the well-known segment between host
and path, which is the variant most commonly misimplemented. The first
response that is 200, is JSON, and carries a non-empty
issuer wins. We then check that issuer equals the
authorization-server base URL after normalisation — the classic mix-up
defence.
Step 4 — what the authorization server must advertise
code_challenge_methods_supportedcontainsS256. This is the one that most often separates apartialtier from a clean one.registration_endpoint(DCR) orclient_id_metadata_document_supported: true(CIMD). Without one of them, every new client is a manual onboarding ticket.authorization_response_iss_parameter_supported: true(RFC 9207) — nice to have.- The protected-resource metadata URL, the MCP endpoint and the
authorization-server base URL are all HTTPS. (We do not re-check the
authorization_endpointandtoken_endpoint— they are inside the metadata document, not part of discovery.)
The tiers, and how they score
oauth-mcp— 3 points. Metadata present and self-consistent, an authorization server that answered, andS256advertised.partial— 2 points. An MCP surface exists but something required failed, or the authorization server was unreachable. An unreachable authorization server pins you at partial and never flaps up — we do not award a tier on a request that did not answer.endpoint-only— 1 point. An MCP endpoint responds, but there is no OAuth metadata to discover.- 0 points. No MCP server found on a reachable site; or the site itself was unreachable, in which case the result is reported as an error rather than as an absence.
How common is a clean MCP surface
Corpus snapshot of 27 July 2026, measured under rubric v3 and currently
being re-measured under v4. Our checks target MCP Authorization revision
2025-11-25; an unauthenticated probe cannot observe which
revision a server implements, so we do not report one.
Of the 5,827 sites with a valid AgentFit run as of 27 July
2026, 121 — 2.08% — advertise an MCP
server through OAuth discovery metadata. By tier: 111 reach
oauth-mcp, 8 are partial, 2 are
endpoint-only. Our own two servers are not among them: since
issue #21 the domains we own are out of every corpus statistic on this
site.
Adoption is concentrated, not broad: 75 of the 121 are hosted on ReadMe, which turned the feature on across its fleet. Only 43 sit on sites with no recognised documentation platform. A count of MCP servers is, to a first approximation, a count of platform decisions.
A server card is not a server. 242 sites publish an MCP server card at a well-known path — 190 of them via Mintlify — but only 8 sites do both: publish a card and advertise a protected MCP endpoint through OAuth metadata. 234 publish a card with no discoverable endpoint behind it.
Among the 121 the discovery basics hold up. Every one keeps its discovery
and OAuth URLs on HTTPS. Protected-resource metadata parses on
119 of 121 (98.3%). The authorization-server hop succeeded
for 116 of 121, and every one of those 116 advertises PKCE
S256 — the five gaps are authorization servers that did not
answer, not servers without PKCE.
What is missing is the polish. Of the 119 with parseable resource metadata,
81 (68.1%) carry no human-readable metadata and 85
(71.4%) declare no scopes_supported at all, so
least-privilege cannot be verified. Of the 116 authorization servers we
reached, 115 (99.1%) do not set
authorization_response_iss_parameter_supported and 13
(11.2%) have an issuer that does not match
their own base URL — which is the mix-up defence. The iss figure moved from
97.5% when our own two servers left the population: they were two of the
three that set the parameter, which is the sharpest illustration of why an
auditor does not belong in its own statistics.
Each percentage is taken over the servers on which that check could actually run, not over all 121. A check that could not run is unverified, and mixing it into a failure rate would be the exact conflation this page argues against.
One measurement limit, stated plainly: the unauthenticated
401 + WWW-Authenticate challenge could be
confirmed on only 12 of the 121 endpoints. The other 109 are recorded as
unverified, not as failures — we could not get a usable answer, which is a
fact about the probe, not about the server.
The failures we actually see
- HTML where JSON should be. A CDN or SPA fallback
answers
200with an app shell for every unknown path, including/.well-known/oauth-protected-resource. An HTTP 200 is a server's opinion, not a content guarantee — we sniff and reject. - Cross-host
resource. Metadata on one hostname declaring a resource on another. This is the exact case the same-host check is for. - Metadata only at the OIDC path. It works with OIDC-aware clients, which is why we try both — but publishing the RFC 8414 document too costs nothing.
- Path insertion done backwards. Serving
/tenant1/.well-known/oauth-authorization-serverinstead of/.well-known/oauth-authorization-server/tenant1. One honest caveat: for the OIDC document, OpenID Connect Discovery 1.0 §4 specifies the appended form (/tenant1/.well-known/openid-configuration), which we do not probe. If that is the only place you publish, we will report the authorization server as unreachable and cap you atpartial— publish the RFC 8414 form as well. - No
S256advertised, or no registration path at all — either one leaves you atpartial. scopes_supported: ["*"], which is not least privilege by any reading.
What we cannot check from the outside
We verify the advertised surface, not runtime enforcement. Whether a server
genuinely validates token audience (RFC 8707), refuses token passthrough,
rejects plain PKCE at the token endpoint, matches redirect URIs
exactly, rotates refresh tokens or hardens its consent screen is invisible
to an unauthenticated auditor — those need a real OAuth flow or a forged
token. Advertising S256 is not the same as enforcing it. We
report those as design claims we did not test, never as passes. The MCP
authorization spec is also still moving, which is why this detector is
marked beta.
FAQ
Do you need credentials to run this check?
No. Every request is unauthenticated and reads only public
.well-known documents plus one challenge probe of the MCP
endpoint. Nothing is submitted, and no account is required.
My server is protected but the check says unverified, not pass. Why?
Almost certainly the challenge probe. We issue a plain GET, which cannot see POST-only protection or supply a protocol-version header. We record that as unverified rather than guessing — it never counts against you.
Why does an unreachable authorization server cap me at partial?
Because from an agent's point of view an authorization server that does not answer is one that does not work. We refuse to promote a tier on the strength of a request that timed out.
I run a generic OAuth API with resource metadata. Why no MCP result?
By design. We report an MCP server only when the resource or endpoint is same-host with an MCP-bearing path, so ordinary OAuth APIs are not mislabelled as MCP servers.
Do you follow the authorization server URL I publish?
Yes — one authorization server, probed at up to four well-known paths, over HTTPS, time-boxed, and only after verifying it does not resolve to a private, loopback, link-local or cloud-metadata address. That URL is attacker-controlled input from where we sit, and we treat it that way.
What can an external MCP check not verify?
Runtime enforcement. Whether a server validates token audience, refuses token passthrough, rejects plain PKCE at the token endpoint, matches redirect URIs exactly or hardens its consent screen needs a real OAuth flow or a forged token. Advertising S256 is not the same as enforcing it, so those are reported as design claims we did not test, never as passes.
Does the MCP spec still change?
Yes — the authorization model has taken material revisions, most recently shifting the preferred client-registration story toward Client ID Metadata Documents. Our checks accept both DCR and CIMD, and the detector is marked beta for that reason.
How much is this worth in the score?
3 points of 100, as criterion F3 in category F, Agent capability: 3 for a clean oauth-mcp discovery surface, 2 for partial, 1 for an endpoint with no OAuth metadata. The browser-side sibling, WebMCP, is criterion F2 and worth 1 point.
Full rubric: 28 criteria, six categories. Browser side: WebMCP.
Free, no sign-up, about 30 seconds — F3 plus 27 other criteria with HTTP evidence.