An MCP client declares version metadata, discovers server capabilities, and sends compatible requests.
|

MCP Lifecycle and Capability Negotiation

MCP clients and servers must agree on protocol behavior before they use optional features safely. The exact mechanism depends on the protocol revision, so older tutorials can now be misleading.

In the current specification, every request carries protocol version and client capability metadata. A server accepts the request or returns an unsupported-version error. Clients can also discover server identity, versions, and capabilities.

TL;DR

  • Current requests declare protocol version and client capabilities in request metadata.
  • Compatibility is evaluated per request; the latest revision has no required negotiation handshake.
  • A client may use server discovery to learn supported versions and capabilities.
  • Optional features should only be used when supported.
  • Older revisions used an initialization handshake, so version-aware implementations need an interoperability plan.

Why lifecycle guidance changed

Earlier MCP revisions described an initialization phase where client and server negotiated version and capabilities, followed by operation and shutdown. Many articles and SDK examples still teach that model.

The current protocol is stateless at the core request level. Required metadata travels with each request, allowing the server to evaluate it independently. This reduces reliance on connection state.

Do not mix rules from different revisions. Use the specification version implemented by your SDK and server.

Per-request metadata

Each request declares the protocol version and relevant client capabilities. Clients should also identify their implementation unless configured otherwise.

The metadata answers:

  • Which protocol rules is the client using?
  • Which optional client features can it support?
  • Which implementation sent the request?

Because this travels with the request, the server need not infer it from a previous handshake.

Server discovery

A client can send discovery to learn server identity, supported versions, and capabilities. Discovery helps select compatible behavior before attempting feature-specific operations.

If a server does not support the declared version, it returns an unsupported-version error that allows a bounded retry with a mutually supported version.

Discovery results may be cacheable, but need a freshness policy. Capabilities can change across upgrades, permissions, or deployment configuration.

What capabilities mean

Capabilities advertise protocol features. A server may expose tools, resources, prompts, notifications, or extensions. A client may advertise features it can handle, such as elicitation.

A capability is not a user permission. It says the implementation speaks a feature. Authorization decides whether the current user may call a tool or read a resource.

QuestionCapabilityAuthorization
Can the implementation speak the feature?YesNo
May this user perform the operation?NoYes
Is the operation currently available?SometimesSometimes
Does the model see it?NoHost policy decides

A compatibility example

An AI host connects to a remote policy server.

  1. The client sends discovery using current request metadata.
  2. The server reports supported versions and resource capability.
  3. The client selects a mutually supported version.
  4. The host enables resource browsing but avoids unsupported prompt operations.
  5. Each request carries the selected version and client capabilities.
  6. A later version error triggers refreshed discovery and a bounded policy.

The user still needs permission to read a policy resource. Compatibility only makes the request understandable.

Working with older servers

Some deployed SDKs and servers implement an earlier stateful handshake. A client supporting multiple revisions should identify the target revision and follow it rather than mixing old and new messages.

Useful strategies include pinning known-compatible versions, using SDK adapters, recording versions in traces, and testing downgrade behavior.

Avoid silent fallback that changes security behavior. If an older revision lacks a required control, fail clearly.

Termination and cancellation

Transport connections still have lifecycles even when requests are stateless. Local subprocesses need clean shutdown and forced termination fallback. HTTP requests need timeouts, cancellation, and retry policies.

Cancellation does not guarantee a downstream side effect was rolled back. A cancelled payment or ticket call may require reconciliation.

Observability checklist

Record:

  • Client and server identity and version.
  • Protocol version declared on the request.
  • Capabilities used by the host.
  • Request method, ID, duration, and outcome.
  • Version errors and fallback decisions.
  • Cancellation, timeout, retry, and ambiguous outcomes.

Do not log secrets merely because they appear in protocol messages.

Common mistakes

  • Copying an older initialization sequence into a current implementation.
  • Treating capabilities as user permissions.
  • Attempting optional operations without checking support.
  • Caching discovery forever.
  • Retrying version errors without a bounded policy.
  • Assuming transport closure reverses an external action.

My Take

Version and capability handling should be visible architecture, not hidden SDK magic. Builders still need to know which revision they run, which features are active, and what happens when compatibility fails.

Continue learning

Review [How MCP Works](/how-mcp-works/) and [MCP Architecture](/mcp-architecture/).

Sources

Similar Posts