skip to content

When should an MCP capability ship as an extension rather than in the core protocol?

level: principalimportance: nice to knowfreq 30%

answer

  1. core is a floor everyone must clear
  2. who is forced to implement it?
  3. is there an honest fallback?
  4. additive extension versus dated revision

basics

~20 s

Ship it as an extension when only some deployments need it and a peer without it can still be served sensibly. Core is the floor every implementation must clear, so anything universal and unavoidable belongs there — everything else belongs behind an opt-in identifier.

solid answer

~50 s

The core protocol is a floor: whatever sits there, every conforming implementation must build. So the first question is whether the feature is genuinely universal. If only some servers have long-running work, or only some clients can render interactive surfaces, making the feature mandatory taxes everyone for something most will never exercise — that is the case for an extension, and it is exactly the reasoning behind Tasks leaving core and becoming `io.modelcontextprotocol/tasks` in revision 2026-07-28. The second question is whether a clean fallback exists: an extension is only viable if a peer lacking it can be answered with core behaviour or told plainly no. The third is blast radius. A core change that alters existing semantics is backwards-incompatible and forces a new `YYYY-MM-DD` revision, splitting the fleet into eras; an extension is additive and negotiated per peer pair. The cost you accept in return is an uneven support matrix that every client must handle.

go deeper

for a junior

Know the distinction being drawn: core features are mandatory for every implementation, while extensions are optional and used only when both sides declare them.

for a middle

Be able to argue the case with a concrete example — Tasks left core and became io.modelcontextprotocol/tasks in revision 2026-07-28 because only some servers have long-running work.

for a senior

Show that you weigh the fallback before the feature: if a peer without the extension cannot be served sensibly or told plainly no, the feature does not belong behind an opt-in at all.

for a principal

Own the tradeoff end to end — the obligation a core addition places on every other implementer, the fragmentation an extension buys instead, and what you do when an extension becomes universal enough to be a shadow standard.

## Two places a feature can live MCP revision 2026-07-28 gives a new feature exactly two homes. **Core** means every conforming implementation must support it; it is the mandatory floor. **An extension** means the feature is declared in the `extensions` capability map by both peers and used only when both have opted in. Deciding between them is a genuine architecture call, and it is the kind of question a lead is expected to answer for their own protocol work too. ## The test for core Ask what happens to the implementer who does not want the feature. If the honest answer is "they must implement it anyway, and it is fair to ask", it is core. That is true of things without which the protocol does not function — how a request declares its version, how a tool is called, how a result is shaped. It is emphatically not true of features with partial demand. Not every server has work that outlives a request. Not every client is a graphical host that can present a UI surface. Making either mandatory would mean every trivial stdio server carrying machinery it never runs, and every minimal client implementing a lifecycle it never drives. ## The test for an extension Three conditions, all of which must hold: 1. **Partial demand.** A meaningful share of implementations genuinely does not need it. 2. **A clean fallback.** A peer that lacks the extension can be served with core behaviour, or told plainly that this request cannot be served. The spec requires one of those two responses; if neither is expressible, the feature cannot be an extension. 3. **Semantic independence.** The feature adds behaviour rather than redefining what an existing core message means. Redefinition is a backwards-incompatible change, and those belong to a revision, not to an opt-in flag some peers set. The Tasks migration satisfies all three, which is why revision 2026-07-28 could pull it out of core and re-publish it as `io.modelcontextprotocol/tasks` without breaking the protocol's shape. ## Extension versus revision bump These are often confused and they solve different problems. A **revision** is a `YYYY-MM-DD` string naming the date of the last backwards-incompatible change — the version is not bumped for backwards-compatible changes. A revision splits the deployed world into eras, and the practical consequence in 2026 is severe: a client speaking the modern per-request-metadata model cannot talk to a legacy handshake-era server, and there is no fall-forward in the other direction either. You spend a revision when semantics genuinely change. An **extension** costs none of that. It is additive and negotiated per peer pair. A server that adds one still interoperates perfectly with every client that has never heard of it, because the mutual opt-in simply fails to complete and core behaviour applies. This is why extensions are the cheap way to grow the protocol and revisions are the expensive way. ## What extensions cost Nothing is free, and a principal-level answer names the downsides: - **A support matrix.** With several extensions in flight, "what can this pair do" becomes a product of two maps rather than a single version string. Clients must handle every combination they may meet. - **Two code paths per feature, minimum.** The extension path and the degraded path, both of which need testing. Teams routinely test the first and ship the second untried. - **Fragmentation pressure.** A popular extension that everybody implements has effectively become a mandatory feature with none of the guarantees of core, and a shadow standard is worse than either option. - **Discovery cost.** A client cannot assume; it must read the peer's declaration, and it must re-read after the cached discovery result's `ttlMs` expires. ## Governance judgment The interesting principal-level questions sit past the mechanics. When an extension approaches universal adoption, do you fold it into core — accepting that you have just raised the mandatory floor and made a backwards-incompatible change for anyone who did not implement it — or leave it optional forever and accept a permanent two-tier ecosystem? Which extensions do you allow your own fleet to depend on, given that depending on one means declining clients that lack it? Do you define extensions under your own prefix at all, or wait for the specification to standardise something under `io.modelcontextprotocol`, trading time-to-market against the risk of maintaining a private dialect no one else speaks? There is no single right answer to any of those, which is exactly why the question is asked at this level. What is being assessed is whether you reason about the obligation you place on other implementers, not just about your own feature list.

  • How does adding an extension differ from cutting a new protocol revision?
    A revision is a YYYY-MM-DD string naming the last backwards-incompatible change, and it partitions the deployed fleet into eras that cannot talk to each other. An extension is additive and negotiated per peer pair, so a peer that lacks it still interoperates over core. You spend a revision when semantics change; you spend an extension when capability is merely uneven.
  • An extension of yours reaches near-universal adoption. Do you fold it into core?
    It is a judgment call with a real cost either way. Folding it in raises the mandatory floor and is backwards-incompatible for the stragglers, which means a new revision and an era split. Leaving it optional keeps interoperability but entrenches a shadow standard everyone implements without core's guarantees. The deciding factor is usually whether the remaining non-adopters have a legitimate reason to abstain.
  • What would disqualify a feature from being an extension at all?
    Having no honest fallback, or redefining an existing core message. The spec permits only two responses to an unsupported extension — revert to core behaviour or reject — so a feature where neither is expressible cannot be optional. And changing what an existing message means is backwards-incompatible by definition, which belongs to a revision rather than to a capability both peers may or may not set.

saying these in an interview costs you the question

  • Treats every new feature as a core protocol addition by default
  • Thinks shipping an extension requires its own YYYY-MM-DD revision
  • Ignores that extensions create a support matrix clients must handle
  • Assumes a server may require an extension with no fallback path
  • Confuses raising the mandatory floor with a backwards-compatible change

context