skip to content

In MCP, where do a server's instructions and serverInfo live now that initialize is gone?

level: middleimportance: should knowfreq 48%

answer

  1. both moved out of the removed handshake
  2. one call now describes the server
  3. instructions is optional prose
  4. identity rides in _meta
  5. self-reported, so never authorize on it

basics

~10 s

Both moved into the server/discover response in MCP revision 2026-07-28: instructions is an optional top-level string on DiscoverResult, and serverInfo sits in that result's _meta under the key io.modelcontextprotocol/serverInfo. Both are self-reported and untrusted.

solid answer

~40 s

Revision 2026-07-28 removed the `initialize` handshake, and the two human- and model-facing fields that used to arrive in `InitializeResult` moved to `DiscoverResult`. `instructions` stays an optional free-form string describing how to use the server — a host typically surfaces it to the user or folds it into the model's context as guidance about that server. `serverInfo` moved into the result's `_meta` under `io.modelcontextprotocol/serverInfo`, alongside the name/version pattern used elsewhere; results of other calls SHOULD carry it too. Crucially both are **untrusted**: they are whatever the server chose to say about itself, so they belong in UI, logs and prompts, never in an authorization decision. A client that skips `server/discover` simply never sees `instructions` — nothing else breaks, because no other call depends on it.

go deeper

for a junior

Know that a server can describe itself with an optional instructions string, and that this text now comes back from server/discover rather than from any startup handshake.

for a middle

Be precise about placement: instructions is an optional top-level DiscoverResult field, while serverInfo sits in the result's _meta under io.modelcontextprotocol/serverInfo.

for a senior

Show the trust judgment — both fields are self-reported, so they belong in UI and logs but never in an authorization check, and server-authored instructions shown to the model deserve user visibility.

for a principal

Own the host policy: how server-supplied prose reaches the model, what a user sees before it does, and why a host must mint its own identifier per server instead of trusting a reported name.

## What was lost when initialize was removed Under MCP revisions up to 2025-11-25, a client's first message was `initialize`, and the `InitializeResult` that came back carried two things that were not really protocol mechanics at all: a free-form `instructions` string and a `serverInfo` block naming the implementation. Revision 2026-07-28 deleted the handshake outright, so both needed a new home. They landed on `server/discover`. ## instructions `instructions` is an optional top-level string on `DiscoverResult`. It is prose written by the server author for the *consumer* of the server — a short description of what this server is for and how to drive it. Typical content: "This server exposes the analytics warehouse. Prefer sql_query for aggregates; run schema_list first if you do not know the table names." Hosts use it in one of two ways, and often both: - **Shown to the user** when a server is first configured or inspected, so a human can tell what they just connected. - **Given to the model** as background about the server, similar in spirit to a system-level note. Because it is optional, a client must handle its absence gracefully — an absent `instructions` means the server declined to say anything general, not that something is wrong. And because a client MAY skip `server/discover` entirely, `instructions` is the one piece of server-provided text that a conformant client can legitimately never see. Nothing else in the protocol depends on it: tool, prompt and resource descriptions travel with their own list results. ## serverInfo `serverInfo` did not stay a top-level field. It moved into `_meta`, under the reserved-namespace key `io.modelcontextprotocol/serverInfo`, in the discovery result — and results generally SHOULD carry it in `_meta` as well. It is the mirror image of `io.modelcontextprotocol/clientInfo`, which a client optionally sends on requests. ## Both are untrusted, and that matters The specification is explicit that this self-reported identity information is untrusted. Two practical consequences: 1. **Never authorize on it.** A server claiming `"name": "github"` proves nothing. Whatever gates a privileged action must come from the authorization layer — for a remote server, the token the client presents and the server validates — not from a string the server typed about itself. 2. **Do not assume the name is unique or stable.** Two independently written servers can both call themselves the same thing, and a name can change between versions. Any host that aggregates several servers needs its own identifier for each connected server rather than leaning on the reported name. The same caution applies with extra force to `instructions`. It is text that a server controls and that a host may put in front of a model, which makes it a channel the server can use to try to influence model behaviour beyond the tool it was asked to run. Treat it as content from the server's trust level, and let the user see what a newly added server is asking the model to believe. ## Putting it together A host's normal flow at configure-time is: call `server/discover`, read `supportedVersions` and `capabilities` for compatibility, read `instructions` and the `_meta` `serverInfo` for presentation, cache the whole thing for the `ttlMs` the server gave under the `cacheScope` it named, and then proceed with ordinary primitive calls. Every later request carries its own version and capabilities in `_meta`, so nothing in that flow establishes state — the discovery answer is a cached description, not a session. ## The common wrong answer Candidates who learned MCP before 2026-07-28 will place both fields in `InitializeResult` and describe reading them once per connection during the handshake. The correction is short: the handshake was removed in 2026-07-28, `instructions` is now an optional `DiscoverResult` field, `serverInfo` now rides in `_meta`, and neither is something the protocol requires a client to fetch.

  • What should a host do with the instructions string once it has it?
    Surface it to the user when the server is configured, and optionally give it to the model as background on that server. Keep it visible rather than silently injecting it, since the text is server-controlled and may try to steer the model. Handle its absence as normal — the field is optional, and a client that skips discovery never receives it.
  • Under which _meta key does the server's identity arrive?
    `io.modelcontextprotocol/serverInfo`, in the result's `_meta`. It is the counterpart of `io.modelcontextprotocol/clientInfo`, which the client may send in request `_meta`. Both are SHOULD-level and both are explicitly untrusted self-reports.
  • Can a host rely on the reported server name to disambiguate two connected servers?
    No. The reported name is untrusted, not globally unique, and can change between versions, so two servers may claim the same one. A host that aggregates servers must assign its own identifier per connection and use that for prefixing and bookkeeping.

saying these in an interview costs you the question

  • Places instructions and serverInfo in InitializeResult as current behaviour
  • Says serverInfo is a top-level field of DiscoverResult
  • Treats the reported server name as proof of identity
  • Assumes every client receives instructions
  • Thinks instructions is required for tools to be usable

context