skip to content

What does an MCP prompts/get messages array contain, and which roles are allowed?

level: middleimportance: should knowfreq 45%

answer

  1. a seeded conversation, not one string
  2. two roles only
  3. one block per message
  4. pointer or payload, your choice

basics

~20 s

prompts/get returns a messages array of PromptMessage objects. Each has a role of either user or assistant — there is no system role — and exactly one content block: text, image, audio, a resource_link pointing at a resource, or an embedded resource carrying the data inline.

solid answer

~50 s

The `messages` array in a `GetPromptResult` is a conversation seed, not a single string. Each `PromptMessage` has two fields: a `role`, which is either `"user"` or `"assistant"`, and `content`, which is exactly one content block. The assistant role lets a server ship few-shot examples or a pre-filled turn. The content block types are `text`, `image` and `audio` (the last two carrying base64 `data` plus a `mimeType`), `resource_link`, and an embedded resource whose `type` is `"resource"`. The last two are the interesting pair. A `resource_link` names a resource by `uri` and leaves the client to fetch it with `resources/read` — cheap to return, and the client decides whether to include it. An embedded resource inlines the resource's `contents` (`text` or base64 `blob`) directly in the message, so the data arrives in one round trip and the URI is preserved for provenance.

code

json · 25 lines
json
{
  "resultType": "complete",
  "description": "Review a config file",
  "messages": [
    {
      "role": "user",
      "content": { "type": "text", "text": "Review this config for unsafe defaults." }
    },
    {
      "role": "user",
      "content": {
        "type": "resource",
        "resource": {
          "uri": "file:///etc/app/config.yaml",
          "mimeType": "text/yaml",
          "text": "debug: true\nbind: 0.0.0.0\n"
        }
      }
    },
    {
      "role": "assistant",
      "content": { "type": "text", "text": "Findings:" }
    }
  ]
}

go deeper

for a junior

Recall that prompts/get returns a list of messages rather than one string, that each message is tagged user or assistant, and that a message can carry text, an image, or a reference to a file.

for a middle

Enumerate the content block types and explain the difference between an embedded resource, which inlines text or a base64 blob, and a resource_link, which only names a uri the client may read separately.

for a senior

Show judgment about payload: decide what to embed versus link based on size, whether the model strictly needs it, and whether the client should get a chance to filter it, and check resultType before touching messages.

for a principal

Own the context-budget policy across your server fleet: what prompts are allowed to inline, how much, and where the user's review step sits, since every embedded byte is context the host pays for on every invocation.

## The shape `prompts/get` returns an optional `description` and a required `messages` array. Each element is a `PromptMessage` with exactly two fields: - `role` — `"user"` or `"assistant"`. - `content` — a single content block, not an array. A prompt is therefore a small pre-built conversation, and that is the point: the server can seed a multi-turn exchange, not just one instruction. Note the arity carefully. A message holds **one** block; multiple pieces of content mean multiple messages. ## Two roles, and the missing third Only `user` and `assistant` are valid. There is no `system` role in a `PromptMessage`. Server-level instructions that a candidate might expect to put in a system message travel elsewhere: as leading `user` content in the prompt itself, or, at the server level, in the optional `instructions` string that the server returns from `server/discover` under revision 2026-07-28. The `assistant` role is what makes the array more than a template. A server can return a `user` message posing a task followed by an `assistant` message demonstrating the expected shape of an answer, giving the model few-shot grounding that a plain text template cannot express. ## The content block types - **text** — `{ "type": "text", "text": "..." }`. The common case. - **image** — `type: "image"` with base64 `data` and a `mimeType` such as `image/png`. - **audio** — `type: "audio"`, same `data` plus `mimeType` shape. - **resource_link** — `type: "resource_link"` with the `uri`, `name`, and usually `mimeType` and `description` of a resource the server exposes. It is a pointer, not the data. - **embedded resource** — `type: "resource"` wrapping a `resource` object whose `contents` carry the `uri` plus either `text` or a base64 `blob`, and a `mimeType`. ## Choosing between resource_link and an embedded resource This is the discriminating part of the question, and it is a real design decision. An **embedded resource** puts the bytes in the prompt result. One round trip, guaranteed availability, and the originating `uri` travels with the data so the host can attribute it and the model can cite it. The cost is size: everything you embed is paid for in the response and, usually, in context. A **resource_link** costs almost nothing to return and hands the decision to the client, which may fetch it with `resources/read`, show it to the user first, or ignore it. It also lets the client apply its own caching, because a `resources/read` result carries `ttlMs` and `cacheScope`. The cost is an extra round trip and the possibility the client never fetches it at all — so anything the prompt genuinely cannot work without should be embedded rather than linked. A practical rule: embed what the model must read; link what the user or the application should decide about. ## Where this sits in 2026-07-28 The message and content-block shapes were not what changed in the current revision; the surrounding contract was. Every result now carries a required `resultType`, so a client reads `resultType: "complete"` before reaching for `messages`. `prompts/get` is also one of only three methods that may answer `resultType: "input_required"` instead, in which case there is no `messages` array at all and the client is being asked for something before the prompt can be built. Treat a missing `resultType` from an older server as `"complete"`. The protocol is stateless in this revision, so the messages a prompt returns are computed from the request alone: the argument values supplied, plus whatever authorization the caller presented. There is no accumulated per-connection context for the server to fold in. ## Handing the messages to a model The host maps these role-tagged messages onto whatever its model API expects. That mapping is the host's business, not the protocol's — MCP deliberately stops at a provider-neutral message shape. In practice the host also shows the messages to the user first, because a prompt is the user-controlled primitive and the user is meant to be able to inspect or edit what they invoked before it is sent. ## Common mistakes Claiming a `system` role exists; treating `content` as an array; and assuming a `resource_link` delivers data — it delivers a URI the client must read separately.

  • When would you embed a resource in a prompt message rather than return a resource_link?
    Embed when the prompt is useless without the data — the bytes arrive in one round trip and the uri travels with them for provenance. Link when the payload is large, optional, or something the user or application should decide about, since a link lets the client fetch it with resources/read on its own terms, or skip it entirely.
  • How does a server supply system-level instructions if PromptMessage has no system role?
    Not through the message array. Instructions that apply to the whole server travel in the optional instructions string returned by server/discover in revision 2026-07-28, which is where that field moved after the initialize handshake was removed. Prompt-specific framing is written as leading user content, and the host maps everything onto its own model API's system slot if it has one.

saying these in an interview costs you the question

  • Claiming PromptMessage supports a system role
  • Treating content as an array of blocks per message
  • Believing resource_link delivers the resource data itself
  • Assuming prompt messages can only be plain text
  • Reading messages without checking resultType first

context