{"name":"MCP server report cards","method":"Read the way an MCP client reads a server before an agent uses it: the handshake, every page of the tool list, the prompts and resources, the sign-in challenge, the server card and the TLS certificate, once a week, with no payment and nothing that writes. Up to two tools the server itself marks read-only, with no required input, are called once with no arguments, and up to two text resources are read. Score: 100 minus 25 for each kind of error and 8 for each kind of warning; a stop finding confirmed by a second read a day later caps the grade at D.","method_version":1,"private_days":14,"second_read_hours":20,"stop_cap":59,"weights":{"error":25,"warning":8,"info":0},"rules":[{"rule":"mcp-unreachable","severity":"error","stop":false,"text":"The server didn't answer, twice.","fix":"Check that the remote URL in your registry entry is live and reachable over https."},{"rule":"mcp-not-mcp","severity":"error","stop":false,"text":"The server answered, but not with an MCP handshake.","fix":"Answer initialize (or server/discover) with a JSON-RPC result, as JSON or an event stream, at the URL the registry lists."},{"rule":"mcp-tls-invalid","severity":"error","stop":false,"text":"The TLS certificate doesn't verify.","fix":"Serve a certificate from a public CA for the remote's host, with its full chain."},{"rule":"mcp-tls-expiring","severity":"warning","stop":false,"text":"The TLS certificate expires within 14 days.","fix":"Renew it; clients stop connecting the day it expires."},{"rule":"mcp-auth-no-metadata","severity":"warning","stop":false,"text":"It asks for sign-in but doesn't say where to sign in.","fix":"Serve OAuth protected resource metadata (RFC 9728) and name it in the WWW-Authenticate challenge, as MCP's authorization spec requires."},{"rule":"mcp-auth-resource-mismatch","severity":"warning","stop":false,"text":"Its protected resource metadata names a different resource.","fix":"Set `resource` to the server's own URL, so clients bind tokens to it."},{"rule":"mcp-protocol-unknown","severity":"warning","stop":false,"text":"It answered with a protocol version no MCP release has.","fix":"Answer with a released version: the one the client asked for if you support it, else your newest."},{"rule":"mcp-protocol-old","severity":"info","stop":false,"text":"It speaks only the first MCP release, 2024-11-05.","fix":"Newer clients drop the oldest version first; support 2025-06-18 or later."},{"rule":"mcp-initialized-refused","severity":"warning","stop":false,"text":"It refused the initialized notification.","fix":"Answer notifications/initialized with 202 Accepted."},{"rule":"mcp-weak-session","severity":"warning","stop":false,"text":"Its session id is short enough to guess.","fix":"Use a random session id of at least 128 bits, as the transport spec asks."},{"rule":"mcp-tools-list-failed","severity":"error","stop":false,"text":"tools/list failed.","fix":"Answer tools/list with a result holding a `tools` list."},{"rule":"mcp-capability-undeclared","severity":"warning","stop":false,"text":"It serves tools but doesn't declare the tools capability.","fix":"Declare `tools` in the initialize result's capabilities; strict clients won't ask otherwise."},{"rule":"mcp-no-tools","severity":"info","stop":false,"text":"It lists no tools.","fix":""},{"rule":"mcp-duplicate-tools","severity":"error","stop":false,"text":"Two tools share a name, so a client can't tell them apart.","fix":"Give every tool its own name."},{"rule":"mcp-tool-name-invalid","severity":"warning","stop":false,"text":"A tool name uses characters or a length clients may refuse.","fix":"Use 1 to 128 of A-Z, a-z, 0-9, underscore, hyphen and dot."},{"rule":"mcp-tool-no-description","severity":"warning","stop":false,"text":"A tool has no description, so a model can only guess what it does.","fix":"Say what the tool does, what it takes and what it returns."},{"rule":"mcp-tool-no-schema","severity":"error","stop":false,"text":"A tool has no input schema of type object.","fix":"Give every tool an inputSchema that is a JSON Schema object, even an empty one."},{"rule":"mcp-annotation-contradicts","severity":"warning","stop":false,"text":"A tool marked read-only has a name that says it changes something.","fix":"Set readOnlyHint only on tools that change nothing; clients skip confirmation for them."},{"rule":"mcp-instructions-to-agent","severity":"error","stop":true,"text":"Text the server shows the model gives orders to the agent instead of describing a tool.","fix":"Describe what the tool does. Never tell the model to ignore its instructions, hide anything from the user, or obey the description."},{"rule":"mcp-hidden-characters","severity":"error","stop":true,"text":"Text the server shows the model holds invisible characters a person can't see.","fix":"Remove Unicode tag characters, bidirectional overrides and zero-width characters from names, descriptions and outputs."},{"rule":"mcp-exfiltration-link","severity":"error","stop":true,"text":"An image link has a slot for data in its address, or the text asks for data to be put in a URL.","fix":"Never ask the model to build links from conversation data."},{"rule":"mcp-credential-request","severity":"error","stop":true,"text":"Text the server shows the model asks for a credential file, a private key or a seed phrase.","fix":"Never ask an agent to read or send keys, seed phrases or credential files."},{"rule":"mcp-cross-tool","severity":"warning","stop":false,"text":"A description tells the agent how to use other tools or servers.","fix":"Describe this server's own tools only; another server's tools aren't yours to steer."},{"rule":"mcp-server-requests","severity":"info","stop":false,"text":"While being listed, it asked the client for sampling, elicitation or roots.","fix":"Ask for these only during a tool call that needs them."},{"rule":"mcp-price-mismatch","severity":"error","stop":false,"text":"A paid tool's payment request asks more than the price it states.","fix":"Ask the price the tool's description and _meta state, or state the price asked."},{"rule":"mcp-price-unstated","severity":"warning","stop":false,"text":"A paid tool asks for payment without stating its price beforehand.","fix":"State the price in the description or the tool's _meta, so an agent's policy can decide before it calls."},{"rule":"mcp-testnet-payment","severity":"warning","stop":false,"text":"A paid tool asks for payment on a test network only.","fix":"Offer a mainnet option, or say it's a test server."},{"rule":"mcp-card-mismatch","severity":"warning","stop":false,"text":"Its server card disagrees with what the server serves.","fix":"Keep the server card's remotes, protocol versions and tools in step with the server."},{"rule":"mcp-version-differs","severity":"info","stop":false,"text":"The version it reports differs from its newest registry entry.","fix":""},{"rule":"mcp-tools-changed","severity":"info","stop":false,"text":"Its tools changed since last week.","fix":""},{"rule":"mcp-model-flagged","severity":"info","stop":false,"text":"A model read flagged a description for a person to review. Not graded.","fix":""}],"never_graded":["Popularity, stars, downloads or how many agents use the server.","Whether the server is paid, or what it charges; only whether the payment request asks the stated price.","Anything that needs a sign-in, an argument we'd have to invent, or a call that could change something.","A model's opinion: the model read is a note for a person to review, never a grade.","Google Web Risk, or any list Agoranome may not cite on a public grade.","Whether anyone paid Agoranome: a Server standing plan buys the daily re-checks, never the grade."],"disputes":"research@agoranome.com","corrections":[],"registry":"https://registry.modelcontextprotocol.io/v0.1/servers","url":"https://agoranome.com/mcp-servers/method"}