|
1 | 1 | # Changes |
| 2 | + |
| 3 | +In a web application, the buttons, links, and data that you see change based on the context. Whether the user is currently logged in, whether there is any data available, what role the user has, etc. MCP servers are no different. The information and tools they provide can change at any time. |
| 4 | + |
| 5 | +MCP provides a robust system for **notifying clients about changes** so that UIs and agents can stay in sync with the server's current capabilities and data. |
| 6 | + |
| 7 | +This exercise will teach you how to implement and respond to change notifications in MCP, including: |
| 8 | + |
| 9 | +- **list_changed notifications** for tools, prompts, and resources |
| 10 | +- Special handling for resource template list changes |
| 11 | +- Resource update notifications and subscriptions |
| 12 | +- Recommended practices for keeping clients and users up-to-date |
| 13 | + |
| 14 | +<callout-info> |
| 15 | + Change notifications are essential for building responsive, real-time AI apps. |
| 16 | + They let clients update menus, toolbars, and resource lists automatically. |
| 17 | +</callout-info> |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## 1. List Change (Tools, Prompts, and Resources) |
| 22 | + |
| 23 | +Whenever the set of available tools, prompts, or resources changes, the server should send a `list_changed` notification. This tells the client to refresh its list and fetch the latest definitions. |
| 24 | + |
| 25 | +- **Tools:** If a tool is added, removed, or updated, send a `notifications/tools/list_changed` request. |
| 26 | +- **Prompts:** If a prompt is enabled, disabled, or updated, send a `notifications/prompts/list_changed` request. |
| 27 | +- **Resources:** If a static resource or resource template is registered, unregistered, or its metadata changes, send a `notifications/resources/list_changed` request. |
| 28 | + |
| 29 | +<callout-success> |
| 30 | + Clients that support `list_changed` can provide a seamless, always-up-to-date |
| 31 | + experience for users, no manual refresh required! |
| 32 | +</callout-success> |
| 33 | + |
| 34 | +#### Example: Enabling/Disabling a Tool in Mission Control |
| 35 | + |
| 36 | +Suppose your space station operations console has a "Dock Module" tool that should only be available when a docking port is free. When a new port becomes available, enable the tool and send a `tools/list_changed` notification. If all ports are occupied, disable the tool and notify again. |
| 37 | + |
| 38 | +```ts |
| 39 | +// Pseudocode |
| 40 | +if (freeDockingPorts.length > 0 && !dockModuleTool.enabled) { |
| 41 | + dockModuleTool.enable() |
| 42 | +} else if (freeDockingPorts.length === 0 && dockModuleTool.enabled) { |
| 43 | + dockModuleTool.disable() |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +The TypeScript SDK automatically sends `list_changed` notifications when tools are enabled or disabled. To avoid over-sending notifications, you should check whether the tool is already enabled or disabled before enabling or disabling it. |
| 48 | + |
| 49 | +<callout-info> |
| 50 | + [In the |
| 51 | + future](https://github.com/modelcontextprotocol/typescript-sdk/pull/746), |
| 52 | + `list_changed` will be batched to avoid sending too many notifications. |
| 53 | +</callout-info> |
| 54 | + |
| 55 | +## 2. Resource List Change (Templates and Expansions) |
| 56 | + |
| 57 | +Resources are special because there's a difference between what the |
| 58 | +ResourceTemplate "expands" into and whether that resource template is available |
| 59 | +in the first place: |
| 60 | + |
| 61 | +```ts lines=4-6,17-18 |
| 62 | +const ingredientsResource = agent.server.registerResource( |
| 63 | + 'ingredient', |
| 64 | + new ResourceTemplate('sandwich://ingredients/{id}', { |
| 65 | + list: async () => { |
| 66 | + // what this returns can change as a result of database changes etc. |
| 67 | + }, |
| 68 | + }), |
| 69 | + { |
| 70 | + title: 'Ingredient', |
| 71 | + description: 'A single sandwich ingredient by ID', |
| 72 | + }, |
| 73 | + async (uri, { id }) => { |
| 74 | + // ... |
| 75 | + }, |
| 76 | +) |
| 77 | + |
| 78 | +// this can also change as a result of user's access |
| 79 | +ingredientsResource.enable() // or disable() |
| 80 | +``` |
| 81 | + |
| 82 | +Resources in MCP can be either static (a single file, a database record) or dynamic via **resource templates** (e.g., a directory of files, a database table, or even a set of modules on a space station π). Resource templates allow the server to expose a pattern or collection of resources that can change over time. |
| 83 | + |
| 84 | +A `notifications/resources/list_changed` notification is sent when: |
| 85 | + |
| 86 | +- A new resource template is enabled/disabled |
| 87 | +- The set of expansions for a template changes (e.g., a new module docks, a new experiment log appears, or a file is added to a directory) |
| 88 | +- The metadata for a resource or template changes (e.g., the title of a module changes) |
| 89 | + |
| 90 | +## 3. Resource Subscriptions (Updates to Specific URIs) |
| 91 | + |
| 92 | +While `list_changed` tells clients about changes in what resources are available, **resource subscriptions** are about changes to the content of a specific resource URI. Clients can subscribe to updates for a particular resource (e.g., a specific module or experiment log) and receive a `notifications/resources/updated` notification when its content changes. |
| 93 | + |
| 94 | +- Clients subscribe to resource URIs using the `subscribe` capability |
| 95 | +- The server tracks subscriptions and notifies only interested clients |
| 96 | + |
| 97 | +#### Example: Subscribing to Module Status Updates |
| 98 | + |
| 99 | +A client wants to stay updated on a specific space station module: |
| 100 | + |
| 101 | +```json |
| 102 | +{ |
| 103 | + "jsonrpc": "2.0", |
| 104 | + "id": 1, |
| 105 | + "method": "resources/subscribe", |
| 106 | + "params": { "uri": "spacestation://modules/habitat-alpha" } |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +When the module's status changes (e.g., a new experiment starts, or the module is undocked), the server sends: |
| 111 | + |
| 112 | +```json |
| 113 | +{ |
| 114 | + "jsonrpc": "2.0", |
| 115 | + "method": "notifications/resources/updated", |
| 116 | + "params": { |
| 117 | + "uri": "spacestation://modules/habitat-alpha", |
| 118 | + "title": "Habitat Alpha Module" |
| 119 | + } |
| 120 | +} |
| 121 | +``` |
| 122 | + |
| 123 | +<callout-muted> |
| 124 | + Subscriptions are for updates to the content of a specific resource URI, not |
| 125 | + for changes in the set of available resources. Use `list_changed` for the |
| 126 | + latter. |
| 127 | +</callout-muted> |
| 128 | + |
| 129 | +--- |
| 130 | + |
| 131 | +## Sequence Diagram |
| 132 | + |
| 133 | +This all might work a little bit like this: |
| 134 | + |
| 135 | +```mermaid |
| 136 | +sequenceDiagram |
| 137 | + participant User |
| 138 | + participant HostApp |
| 139 | + participant Client |
| 140 | + participant Server |
| 141 | +
|
| 142 | + User->>HostApp: Start application |
| 143 | + HostApp->>Client: Initialize client |
| 144 | + Client->>Server: Initialization request |
| 145 | + Server-->>Client: Capabilities response |
| 146 | + %% --- |
| 147 | + Note over User,Server: (Later, when things change...) |
| 148 | + Server-->>Client: notifications/tools/list_changed |
| 149 | + Server-->>Client: notifications/resources/list_changed |
| 150 | + Server-->>Client: notifications/prompts/list_changed |
| 151 | + Client-->>HostApp: Forward list_changed notification |
| 152 | + HostApp->>Client: Fetch updated definitions |
| 153 | + Client->>Server: Fetch updated definitions |
| 154 | + Server-->>Client: Updated definitions |
| 155 | + Client-->>HostApp: Forward updated definitions |
| 156 | + HostApp->>User: Update UI |
| 157 | + %% --- |
| 158 | + Note over User,Server: (Subscription flow) |
| 159 | + HostApp->>Client: Subscribe to resource |
| 160 | + Client->>Server: Subscribe to resource |
| 161 | + Server-->>Client: Subscription confirmed |
| 162 | + Client-->>HostApp: Subscription confirmed |
| 163 | + %% --- |
| 164 | + Note over User,Server: (Later, when resource changes...) |
| 165 | + Server-->>Client: notifications/resources/updated |
| 166 | + Client-->>HostApp: Forward resource update |
| 167 | + HostApp->>User: Update UI |
| 168 | +``` |
| 169 | + |
| 170 | +## References |
| 171 | + |
| 172 | +- π [Server Spec: Resources](https://modelcontextprotocol.io/specification/2025-06-18/server/resources) |
| 173 | +- π [Server Spec: Tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) |
| 174 | +- π [Server Spec: Prompts](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts) |
0 commit comments