Notifications

Purpose and Scope

A notification is a one-way message that an MCP server pushes toward a connected client. In the server guides, notifications are framed as the mechanism that tells clients that cached views are stale, most commonly because a list of tools, prompts, or resources changed. This page focuses on the server author’s responsibilities: when to publish change events, how registration handles publish automatically, what capability flags mean, and how notification behavior changes for protocol revision 2026-07-28. It also distinguishes list-change notifications from request-scoped progress and logging messages, because both travel as notifications but solve different operational problems.

Sources: docs/servers/notifications.md

Notifications are not a replacement for ordinary request results. A tool still returns content, resources still return contents, prompts still return messages, and completion callbacks still return suggestions. Notifications are the side channel that lets a client update its local state without polling every endpoint repeatedly. A well-behaved client normally treats a change notification as invalidation, then calls the corresponding list or read method again. That means the notification should be small and timely, while the authoritative state remains behind normal MCP methods such as tool listing, resource reading, prompt retrieval, or completion.

Sources: docs/servers/notifications.md, docs/servers/completion.md

Relevant Source Files

  • docs/servers/notifications.md — Defines server change notifications, list-changed helpers, automatic notifications from registration handles, low-level capability requirements, and handler-based publishing for subscription streams.
  • docs/servers/completion.md — Shows another server capability that is advertised automatically when a feature is registered, useful context for understanding capability-driven client behavior.
  • docs/servers/elicitation.md — Documents server-to-client request flows used by older protocol behavior, which helps distinguish notifications from interactive requests.
  • docs/servers/errors.md — Clarifies when failures are returned as tool-visible results or protocol errors rather than being reported by notification.
  • docs/servers/input-required.md — Describes the 2026-07-28 input-required pattern, an important protocol-era contrast with push-style server requests.
  • docs/servers/logging-progress-cancellation.md — Covers progress and logging notifications emitted inside request handlers, including the request-scoped notification helper.

Core Notification Types

The primary change notifications exposed by the high-level server are the list-changed events for tools, prompts, and resources. When a tool set changes outside the registration API’s visibility, the server can explicitly call the tool list change helper. Prompt and resource lists have sibling helpers with the same intent. The client-side expectation is simple: after receiving the tool-list notification, it should ask for the list again instead of assuming its old cache remains valid. The same cache-invalidation model applies to prompt and resource lists, so servers should publish only when the externally visible list has actually changed.

Sources: docs/servers/notifications.md

Resource update notifications are more specific than resource-list changes. A resource list change says that the catalog of available resources may have changed, while a resource update says that a known resource URI has new content. The guide’s HTTP handler example publishes an update for a concrete resource URI after configuration changes. A client that asked for that resource update stream receives a notification carrying the URI, then re-reads the resource. This distinction helps clients avoid expensive rediscovery when only the contents of an already-known resource changed.

Sources: docs/servers/notifications.md

Progress and logging are also notifications, but they are request scoped rather than catalog scoped. A long-running tool can inspect the incoming request metadata for a progress token, then send progress notifications with increasing progress values while the call is still running. Logging uses a request helper as well, but the docs mark MCP logging as deprecated as of the 2026-07-28 protocol revision and recommend standard runtime logging or OpenTelemetry instead. Server authors should therefore treat progress as an active user-experience feature and treat logging notifications as compatibility behavior rather than a new observability foundation.

Sources: docs/servers/logging-progress-cancellation.md

Registration Handles and Automatic Change Events

The preferred way to keep list-change notifications correct is to mutate registered server objects through the handles returned by registration calls. The server notification guide shows a tool handle returned from registering a report tool, then updates and disables that tool through the handle. Each mutation sends its own matching list-changed notification. The same pattern applies to enabling and removing a registration, and the guide states that resource and prompt handles send the corresponding resource-list and prompt-list notifications. This keeps state changes and client invalidation tied together instead of relying on scattered manual calls.

Sources: docs/servers/notifications.md

Manual send helpers are still useful, but they should be reserved for changes the registration handle cannot observe. For example, if a server builds its tool set from an external job registry and that registry changes independently, an explicit tool-list notification tells clients to refresh. If the same server merely updates a tool description through the registered handle, calling the manual helper again would create a duplicate signal. Duplicates are not usually fatal, because clients should re-fetch authoritative state, but unnecessary churn can trigger extra requests and produce confusing traces during development.

Sources: docs/servers/notifications.md

Automatic capability advertisement follows the same first-party pattern as completion support. The completion guide explains that wrapping a prompt or resource argument with the completion helper registers the completion handler and advertises the completion capability without extra declaration. The notification guide uses the same kind of high-level convenience: registering tools, prompts, and resources makes the high-level server advertise matching list-change support. This is important because clients decide which notification types to request based on advertised capabilities, not on assumptions about server implementation details.

Sources: docs/servers/notifications.md, docs/servers/completion.md

Capability Contracts and Low-Level Servers

Capability flags are part of the contract between a server and a client. With the high-level server, registering a tool causes the server to advertise tool support with list-change capability, and similar behavior exists for prompts and resources. With the low-level server API, the source guide shows capabilities being declared when the server is constructed. That difference matters because the low-level API does not infer all feature behavior from convenience registration calls. A low-level server that intends to send tool-list changes must declare the tool capability with list-change support up front.

Sources: docs/servers/notifications.md

The low-level contract is intentionally strict: the server refuses to send a notification whose capabilities do not cover that notification type. The guide calls out that sending a tool-list change without a tools capability throws. This protects clients from receiving events they could not have negotiated or subscribed to. It also protects server authors from accidentally publishing protocol-visible behavior before the server’s advertised surface is ready. When debugging missing notifications, check both sides of the contract: the server must advertise the relevant list-change capability, and the client must request or handle the matching event.

Sources: docs/servers/notifications.md

Execution Flow

A typical list-change flow starts when application state changes. If the change is performed through a tool, prompt, or resource registration handle, the SDK emits the appropriate notification automatically. If the state change comes from outside the handle, the server calls the explicit helper. The client observes the notification method and treats it as invalidation, not as the changed data itself. It then calls the matching list method, updates its cache, and continues using normal MCP calls. This keeps notification payloads small and keeps validation concentrated in the normal request and response schemas.

Sources: docs/servers/notifications.md, docs/servers/errors.md

For Streamable HTTP deployments using the high-level handler factory, the guide warns that the server instance may be per request. In that arrangement, publishing through a captured server instance is the wrong mental model because open subscription streams belong to the handler infrastructure. The docs use the handler’s notification facade to publish resource updates and list changes to the relevant streams. This is a scaling-friendly pattern: request-local server construction can coexist with long-lived subscription streams, as long as cross-request publications go through the handler that owns those streams.

Sources: docs/servers/notifications.md

Protocol revision 2026-07-28 changes how clients receive change notifications. The notification guide states that change notifications reach a client only on a subscription stream that the client opens. The related client docs describe a listen request with filters for tool-list, prompt-list, resource-list, and per-resource updates, and note that the server narrows the requested filter to its advertised capabilities. Server authors should therefore design notifications as opt-in stream events for modern connections, while still understanding older push-style behavior when maintaining compatibility with earlier protocol revisions.

Sources: docs/servers/notifications.md

Relationship to Input, Errors, and Long-Running Work

Notifications should not be used for interactive questions. The elicitation guide shows the older server-to-client request pattern where a tool handler asks the user for information and waits for a client handler to answer. The input-required guide explains the newer 2026-07-28 pattern: a handler returns an input-required result, the client satisfies embedded requests, and the original call is retried with responses. These flows are request and result protocols, not cache invalidation events. If the server needs an answer before completing work, use elicitation or input-required behavior rather than a fire-and-forget notification.

Sources: docs/servers/elicitation.md, docs/servers/input-required.md

Notifications should also not be used to report ordinary failures. The errors guide separates tool errors, which are successful tool-call results marked as errors for the model to read, from protocol errors, which are JSON-RPC errors the model does not see. A failed tool should return a recovery-oriented message or throw so the SDK can produce the documented tool-error shape. A malformed resource request should raise a protocol error. Notifications are best saved for state changes, progress, and compatible logging because they do not provide the structured request failure semantics clients and models need.

Sources: docs/servers/errors.md, docs/servers/logging-progress-cancellation.md

Practical Checklist

Before shipping notification behavior, first identify the state being invalidated. Use tool-list, prompt-list, and resource-list notifications for catalog changes, and resource-updated notifications for changed content at a known URI. Second, prefer registration handles for changes made inside the server API, and use explicit helpers only for external state changes. Third, verify capabilities: high-level registrations generally advertise the needed list-change support, while low-level servers must declare it. Fourth, for HTTP handler deployments and modern subscription-based connections, publish through the handler facade so open streams receive the event.

Sources: docs/servers/notifications.md

Finally, test from the client’s point of view. The guide examples use an in-memory client that logs notification methods and then re-fetches state. Reproduce that pattern for your own server by asserting that exactly the expected notification arrives when a registration is added, updated, disabled, enabled, or removed. Also test the quiet path: a client that did not ask for progress should not receive progress messages, and a modern client that did not open a matching subscription stream should not receive change events. These tests catch duplicate notifications, missing capabilities, and incorrect publication paths early.

Sources: docs/servers/notifications.md, docs/servers/logging-progress-cancellation.md

Read client-subscriptions next to understand how modern clients open subscriptions/listen streams and install notification handlers. Read logging-progress-cancellation for request-scoped progress and cancellation patterns. Read low-level-server before implementing notifications with the lower-level API, because capability declaration becomes explicit there. If your handler needs user input rather than cache invalidation, use input-required for 2026-07-28 behavior and server-elicitation only when working with older compatible flows.