Skip to content

Quality score

Trust answers “can I believe this listing”. Quality answers “is this a good MCP server to connect an agent to”. Both are transparent: the descriptor lists every check, its status and the evidence that decided it.

Checks run on what our credential-free, read-only probes observe. Tools are never called and no code audit is performed.

category weight what it looks at
protocol 25 2026-07-28 support, stateless answers, legacy-only transports, cacheable tool lists (ttlMs)
auth 15 for OAuth servers: Protected Resource Metadata, authorization server metadata, CIMD versus the deprecated DCR; for every server: no secret in the URL
hygiene 30 tool descriptions present and concise, object input schemas, readOnlyHint or destructiveHint annotations, all four directory hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint; the Claude and OpenAI directories each require some of them) on every tool, the token cost of loading every tool, “an API mapped one endpoint per tool”
stability 15 tool changes in the last 30 days, and any tool that kept its name but changed most of its description
dependencies 15 for servers with an npm or PyPI package: known advisories in the resolved dependency graph (failing on a high or critical one that has a fix), the official MCP SDK’s own advisories, and whether the graph resolved completely

Each check is pass (1 point), warn (half), fail (0) or na. A category’s value is the average of its applicable checks; the score is the weighted average of the categories that apply. Checks that do not apply leave the denominator, and a server with fewer than three applicable checks outside dependencies gets no score (null) rather than a flattering one: dependencies never score a server on their own, so a local-only package shows its dependency report without a score. Stability only counts after a week of recorded tool history: not having seen a change yet is not evidence of stability. Servers behind OAuth or an API key usually have no public tool list, so their hygiene and stability checks are na and the report says so.

Next to the number, every server gets a plain-language label. Labels describe the signals above; none of them says a server is safe, and no audit is implied.

label when
strong quality 90 or more and trust 75 or more
good quality 75 or more
needs work quality 40 to 74
poor quality under 40
new the server appeared in the registry less than 7 days ago
not scored fewer than three checks apply (usually a local package or a remote nobody could probe)
blocked the listing is on the blocklist

The label is in the descriptor (_meta["dev.protogrid/quality"].label), in /quality, and in every search result as quality_label next to quality_score. Colors on the portal and the badge use the same thresholds: green from 75, amber from 40, red below.

  • The descriptor’s _meta["dev.protogrid/quality"]: score, components, checks (id, category, status, detail), drivers (-id for failures, ~id for warnings), tool_count, token_estimate, tools_hash, tools_changed_at.
  • GET /v1/servers/{name}/quality adds the daily score for the last 90 days; GET /v1/servers/{name}/changes lists the tool-definition history (see the REST API).
  • Every server page on the portal has a Quality section with each check and its evidence, the token cost of the tool list and the latest tool-definition changes, with the description before and after.
  • tools_hash changes whenever any tool’s name, description, schemas or annotations change: pin it to notice a change before your agent trusts the new definitions.

Every server has a public SVG badge with its current quality score, at https://protogrid.dev/badge/{name}.svg. It follows the score within about five minutes and says not scored when too few checks apply. When the server’s owner has claimed it, the badge adds an owner verified segment; add ?owner=0 to the image URL for the compact version. Paste it into a README, linking to the server page:

[![protogrid quality](https://protogrid.dev/badge/io.github.acme/acme-mcp.svg)](https://protogrid.dev/servers/io.github.acme/acme-mcp)

The server page has the snippet ready to copy under “Badge for your README”.

For servers published as an npm or PyPI package, protogrid reads the dependency graph of the published version as a clean install would resolve it, and matches every package in it against known advisories. Nothing is downloaded, installed or run. Advisories are matched against every graph daily, so a newly published advisory shows up without the server changing. A new release is read right away; otherwise graphs are refreshed monthly, and daily for servers their owners claimed and monitor.

  • deps.known_vulns fails when a package in the graph has a high or critical advisory (or is a known malicious package) and a fixed version exists, and warns on any other advisory; the evidence names the advisory, the package and whether it is a direct or indirect dependency.
  • deps.mcp_sdk_version looks at the official MCP SDK (@modelcontextprotocol/sdk and its v2 packages on npm, mcp on PyPI) the same way and says which version to update to; its advisories are not counted again in deps.known_vulns.
  • deps.resolvable warns when the graph resolved with errors, because advisories may then be missing, and is na when the package version is not known to the resolver.

Remote-only servers have no package, so their dependency checks are na.

Data sources: dependency graphs from deps.dev and advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database, all under CC BY 4.0.