# Subscriptions & Notifications Real-time resource updates are built in. Works with STDIO, SSE, and WebSocket (see [Transports](Transports-Guide.md) for connectionId handling). ## Flow 1. Client calls `resources/subscribe` with a URI. 2. Server validates the resource and returns `{ id, uri, created_at, client_id }`. 3. Server sends `notifications/resources/updated` when content changes. 4. Client can unsubscribe via `resources/unsubscribe` or list via `resources/list_subscriptions`. ## Minimal Server Pattern ```rust use fastrmcp::prelude::*; use fastrmcp_macros::{resource, tool}; use std::sync::atomic::{AtomicU64, Ordering}; static COUNTER: AtomicU64 = AtomicU64::new(0); #[resource("counter://value")] async fn counter() -> Result { Ok(serde_json::json!({ "value": COUNTER.load(Ordering::SeqCst) }).to_string()) } #[tool] async fn increment() -> Result { Ok(COUNTER.fetch_add(1, Ordering::SeqCst) + 1) } #[tokio::main] async fn main() -> Result<()> { FastMCP::new("subs").version("1.0.0").run().await } ``` - Resources made with `#[resource]` are subscribable automatically. - To emit notifications manually (e.g., from a background task), use `server.subscription_manager().notify_uri(uri, content).await?` where `content` is `ResourceContent`. ## Protocol Shapes - Subscribe: ```json {"jsonrpc":"2.0","id":1,"method":"resources/subscribe","params":{"uri":"counter://value"}} ``` - Notification (server → client): ```json {"jsonrpc":"2.0","method":"notifications/resources/updated","params":{"subscription_id":"","uri":"counter://value","content":{"uri":"counter://value","mimeType":"application/json","text":"{\"value\":2}"},"timestamp":1699565000}} ``` - Unsubscribe: ```json {"jsonrpc":"2.0","id":2,"method":"resources/unsubscribe","params":{"subscriptionId":""}}} ``` - List: ```json {"jsonrpc":"2.0","id":3,"method":"resources/list_subscriptions"} ``` ## Server-Driven Updates - Background tasks can push updates on intervals or external triggers. Check `SubscriptionManager::subscription_count_for_uri` before expensive work. - SSE clients must include `connectionId` when posting messages; WebSocket clients can be targeted via `metadata.connectionId` in server-initiated requests (otherwise current connection). ## Pitfalls - Unknown URI → `ResourceNotFound` / `MethodNotFound`. - Missing `connectionId` on SSE POSTs when multiple clients are connected will be rejected (`400 Bad Request`). - Validate payload schemas in tools/resources to avoid `InvalidParams` errors that break subscription flows. Related: [Transports Guide](Transports-Guide.md) • [Troubleshooting](Troubleshooting.md#subscriptions) for debugging tips • [Examples](Examples.md#subscriptions) for a full demo. [Back to Home](Home.md)