In MCP, when should a prompt message embed a resource instead of a resource_link?
answer
- Two ways to attach content
- Inline bytes versus a pointer
- type resource versus type resource_link
- One is a render-time snapshot
- The other needs a resources/read call
basics
~20 sEmbed the resource when the prompt is meaningless without that content already in the message — the server inlines a snapshot of the bytes. Send a resource_link when the client should decide whether, and when, to read it.
solid answer
~50 sA `prompts/get` result is an array of role-tagged messages, and each message carries one content block. Two of those block types point at resource data. An **embedded resource** (`type: "resource"`) nests the actual contents — a `uri`, usually a `mimeType`, and either `text` or a base64 `blob` — so the bytes travel inside the result and are a snapshot taken when the prompt was rendered. A **resource_link** (`type: "resource_link"`) carries only the `uri`, a `name` and optional metadata; the client resolves it with `resources/read` if it chooses to. Embed small, mandatory context the prompt cannot work without, or data the client has no way to read itself. Link large, optional or fast-changing content, and anything the host should let the user approve before it enters the conversation. In revision 2026-07-28 the result must be self-contained either way — a server cannot lean on an earlier call having primed anything.
code
json · 24 lines{
"messages": [
{
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": "file:///project/CHANGELOG.md",
"mimeType": "text/markdown",
"text": "# 2.1.0\n- fixed retry backoff\n"
}
}
},
{
"role": "user",
"content": {
"type": "resource_link",
"uri": "file:///project/logs/build.log",
"name": "build.log",
"mimeType": "text/plain"
}
}
]
}go deeper
Know that a prompt returns role-tagged messages and that a message can carry a file's content, not just text. Be able to say that one form inlines the data and the other just points at it.
Explain both block shapes by name: an embedded resource nests uri, mimeType and text or blob; a resource_link carries uri and name and must be resolved with resources/read. Say which one costs a round trip and which one costs payload size.
Reason about size, staleness and access: embed bounded content the prompt cannot work without, link large or optional content, and remember the embedded copy is a snapshot from render time. Mention that the host is where the human approves data entering the conversation.
Own the catalogue-level tradeoff. Decide a house rule for when server-side data is inlined versus referenced, weigh context cost against round trips across many prompts, and note that linking leaves the host a reviewable decision point that embedding removes.
## What a prompt actually returns In MCP a prompt is a server-supplied message template that a **user** deliberately invokes — a host typically surfaces prompts as a command menu or slash command. The client lists them with `prompts/list` and renders one with `prompts/get`, passing whatever arguments the prompt declared. The result contains a `messages` array. Each entry is a `PromptMessage`: a `role` (`"user"` or `"assistant"`) plus exactly one **content block**. Content blocks are not limited to prose. A block may be text, an image, audio, an **embedded resource**, or a **resource link**. The last two are the interesting design choice, because they are two different answers to the same question: how does file-like or database-like context get into the prompt? ## The embedded resource block An embedded resource has `type: "resource"` and nests a `resource` object holding the data itself: a `uri` identifying it, normally a `mimeType`, and either `text` (for textual data) or `blob` (base64 for binary). The bytes are physically inside the JSON result of `prompts/get`. Consequences of that: - **No extra round trip.** The client has everything the moment the prompt is rendered. - **It is a snapshot.** The content is whatever the server read at render time. If the underlying file changes a second later, the message still holds the old bytes. - **The server needs read access.** Embedding only works for data the server can reach. - **It inflates the payload.** A large file becomes a large result, and it lands in the model's context whether or not it turns out to be relevant. ## The resource_link block A resource link has `type: "resource_link"` and carries a `uri` and `name`, plus optional `mimeType` and `description` — essentially the same descriptor shape a resource listing uses. It is a pointer, not the payload. If the client wants the content, it calls `resources/read` with that URI. Consequences: - **The client decides.** It may resolve one link, all of them, or none. Nothing forces it to fetch. - **It stays fresh.** The read happens when the client performs it, not when the prompt was rendered. - **It is cheap.** Ten candidate files cost ten short descriptors, not ten file bodies. - **It can fail later.** The URI must still be readable when the client gets around to it, and the client must actually implement resource reading. ## Choosing between them Embed when the prompt is not usable without the content: a code-review prompt whose whole point is "here is the diff", a template that must quote an exact configuration block, or data that lives behind the server and has no client-readable URI. Bounded size is the practical gate — a few kilobytes of the thing the prompt is about. Link when the content is large, optional, or one of several candidates; when it changes often enough that a snapshot would mislead; or when you want the host to have a decision point before the data enters the conversation. Linking is also the polite choice for anything sensitive: the user sees *what* would be pulled in before it is pulled in, and the host can apply its own rules. ## Consent and the host boundary MCP states its security principles — user consent and control, data privacy, tool safety — but cannot enforce them at the protocol level; the host is the enforcement boundary. That matters here in a concrete way. Embedded content has already crossed into the payload by the time a human reviews the prompt; a link leaves the fetch as a separate, reviewable act. Neither is "secure" by itself, but the link shape gives the host something to gate. ## Revision notes (2026-07-28) MCP is stateless as of revision 2026-07-28: each request is self-contained and a server must not rely on prior requests over the same connection. A prompt result therefore has to stand on its own; there is no session in which earlier context was established. Note also that a resource link does **not** create a subscription. Watching a resource for changes is done by opening a `subscriptions/listen` stream with `resourceSubscriptions` — the older `resources/subscribe` and `resources/unsubscribe` methods were removed in 2026-07-28. ## What interviewers listen for The weak answer treats the two blocks as interchangeable, or assumes a client automatically dereferences links. The strong answer names both block shapes precisely, states the snapshot-versus-pointer difference, and then reasons about size, freshness, who can read the URI, and where the human gets to say yes.
- If the server embeds a resource, what does the client still learn about where it came from?The embedded `resource` object carries the `uri` alongside the `text` or `blob`, so the client knows the identity of what it received and can re-read it later with `resources/read` if it wants a fresh copy. The `mimeType` tells it how to render or treat the bytes. The URI is identity, not a promise that the client has access to it.
- Does including a resource_link in a prompt message make the client watch that resource for changes?No. A link is inert — it names a resource and nothing more. In revision 2026-07-28 a client watches a resource by opening a `subscriptions/listen` stream with that URI in `resourceSubscriptions`; the older `resources/subscribe` and `resources/unsubscribe` methods were removed in that revision. Nothing about appearing in a prompt subscribes anyone to anything.
- How would you keep a prompt useful when the context it needs is far too large to embed?Emit links rather than bodies, and shape the prompt's messages so the model is told what each link is and when to read it. Give each link a meaningful `name` and `description`, and let prompt arguments narrow the candidate set before rendering. The client then reads only what it needs, and the payload stays small no matter how big the corpus is.
saying these in an interview costs you the question
- Assumes the client always fetches a resource_link automatically
- Thinks an embedded resource stays live rather than being a snapshot
- Believes prompt messages can only carry plain text
- Thinks embedding data bypasses the host's consent boundary
- Says a resource_link subscribes the client to that resource