Spec explainer
What is server/discover in MCP?
Last verified: 10 August 2026 · spec 2026-07-28 · ruleset 1.4.2
server/discover is how a client learns what a server supports now that initialize is gone. It is a required method that returns the protocol versions, capabilities and identity a server offers — as an ordinary request that establishes nothing and can be called any number of times.The short answer
“Servers MUST implement server/discover.”
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: server/discover
{ "jsonrpc": "2.0", "id": 0, "method": "server/discover", "params": {} }It is also the fastest way for a validator — ours included — to classify a server's era in a single round trip, which is why it is the first probe group we built.
How it differs from initialize
| initialize (legacy) | server/discover | |
|---|---|---|
| Creates state | Yes — a session | No |
| Required first | Yes, before any other method | No — optional, any time |
| Version outcome | One negotiated version per connection | A list; the client picks per request |
| Repeatable | No | Yes, freely |
server/discover as a rename of initialize and requiring clients to call it first. Nothing entitles you to that — a conformant client may open with tools/list and never call discovery at all. If your server refuses work until discovery has happened, you have rebuilt the handshake under a new name and will fail MCP-STL-003.What it returns
“`supportedVersions`: Protocol versions the server supports. The client should choose one of these for subsequent requests.”
{
"jsonrpc": "2.0", "id": 0,
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": { "tools": {} },
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "weather", "version": "1.0.0"
}
}
}
}The spec requires server/discover and describes what it must convey, but does not publish a worked request/response example the way it does for tools/call. The shape above is a reasonable construction from the described behaviour, not a literal quote — check your SDK's exact response schema before matching on field names.
serverInfo belongs on every result, not just this one
“Servers SHOULD include the following io.modelcontextprotocol/* field in every result's _meta, unless specifically configured not to do so, to identify themselves without relying on any prior connection state.”
Read the clause at the end carefully: without relying on any prior connection state. That is the whole reason this moved from a handshake field to a per-result one. Anything downstream — a gateway logging which server answered, a client showing the user what it is talking to — used to learn identity once at connection time. With no connection to learn it at, it has to ride along.
function ok(payload) {
return {
resultType: "complete",
...payload,
_meta: {
"io.modelcontextprotocol/serverInfo": SERVER_INFO,
},
}
}Extension identifiers
“Extension identifiers MUST follow the _meta key naming rules, with a mandatory prefix.”
io.modelcontextprotocol/protocolVersion ✓ spec-defined
io.modelcontextprotocol/serverInfo ✓ spec-defined
io.modelcontextprotocol/myOwnThing ✗ reserved prefix — not yours
com.example/draftId ✓ a prefix you control
dev.acme.tools/traceId ✓The reverse-DNS requirement is what keeps two independent extensions from colliding on a short name. Using the io.modelcontextprotocol/ prefix for your own field is the specific failure MCP-DSC-004 catches, and it is an easy one to commit by copying an example.
The 5 discovery rules we check
| Rule | What we check | Level | If it fails |
|---|---|---|---|
| MCP-DSC-001 | server/discover is implemented | MUST | fail |
| MCP-DSC-002 | DiscoverResult advertises supported protocol versions | MUST | fail |
| MCP-DSC-004 | Extension identifiers use a valid non-reserved reverse-DNS prefix | MUST | fail |
| MCP-DSC-005 | Results carry io.modelcontextprotocol/serverInfo in _meta | SHOULD | warn |
| MCP-DSC-003 | Advertised versions include a currently-supported revision | MAY | info |
Four of the five carry a verbatim spec sentence. MCP-DSC-003 — whether advertised versions include a currently-supported revision — has no single spec sentence behind it and is reported as info rather than a failure.
Check your discovery response
server/discover is the first thing the validator calls, and the only probe group live today — so this is the part of a report that is fully real right now.
Frequently asked
What is server/discover in MCP?
A required method in the 2026-07-28 revision that advertises which protocol versions a server supports, what capabilities it has, and who it is. It is how a client learns about a server now that the initialize handshake has been removed — one ordinary request, no session, no negotiation state.
Is server/discover required?
Yes. The specification states that servers MUST implement server/discover. It is not an optional convenience: without it a client has no way to learn a server's supported versions except by guessing one, sending a real request, and interpreting the error.
How is server/discover different from initialize?
initialize established a session and negotiated a single agreed version for that connection. server/discover establishes nothing — it is a plain request that returns information, and the client picks a version to use on subsequent requests. Calling it is optional for the client and it can be called any number of times, because nothing about it is stateful.
What does a DiscoverResult contain?
The protocol versions the server supports, so the client can choose one; the server's capabilities; and its identity. Like every result in this revision it also carries resultType, and it should include io.modelcontextprotocol/serverInfo in _meta so the server identifies itself without relying on connection state.
What is io.modelcontextprotocol/serverInfo?
A _meta field servers should include in every result, not just discovery, identifying the server by name and version. It exists because a stateless protocol has no handshake in which identity was established once — so identity has to travel with each response for anything downstream to attribute it.
How do MCP extension identifiers work?
They must follow the _meta key naming rules with a mandatory reverse-DNS prefix, and must not use a reserved prefix. io.modelcontextprotocol/* is reserved for the specification, so your own extensions belong under a prefix you control, such as com.example/my-extension.