Skip to content

Commit 82b04a3

Browse files
authored
feat: deprecate roots, sampling, and logging (SEP-2577) (#884)
SEP-2577 deprecates the Roots, Sampling, and Logging features. The deprecation is advisory: the features stay fully functional and there is no wire-level change. Mark the corresponding Rust APIs as deprecated so downstream users get compiler warnings and migration guidance. - Forward attributes through the service `method!` macros and deprecate `Peer::create_message`, `Peer::list_roots`, `Peer::set_level`, and `Peer::notify_logging_message`. - Forward per-field attributes through the capability `builder!` macro and deprecate the generated `enable_roots`, `enable_sampling`, and `enable_logging` builders, plus the hand-written `enable_roots_list_changed`, `enable_sampling_tools`, and `enable_sampling_context`. - Document the deprecation on the capability types and fields, and in the README feature sections. - Allow `deprecated` at the crate's own call sites so the build stays warning-clean, and refresh the message schema snapshots.
1 parent 254f04a commit 82b04a3

13 files changed

Lines changed: 132 additions & 38 deletions

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,8 @@ context.peer.notify_prompt_list_changed().await?;
471471

472472
## Sampling
473473

474+
> **Deprecated (SEP-2577):** Sampling is deprecated and will be removed in a future release. It remains fully functional for now. See [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577).
475+
474476
Sampling flips the usual direction: the server asks the client to run an LLM completion. The server sends a `create_message` request, the client processes it through its LLM, and returns the result.
475477

476478
**MCP Spec:** [Sampling](https://modelcontextprotocol.io/specification/2025-11-25/client/sampling)
@@ -544,6 +546,8 @@ impl ClientHandler for MyClient {
544546

545547
## Roots
546548

549+
> **Deprecated (SEP-2577):** Roots is deprecated and will be removed in a future release. It remains fully functional for now. See [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577).
550+
547551
Roots tell servers which directories or projects the client is working in. A root is a URI (typically `file://`) pointing to a workspace or repository. Servers can query roots to know where to look for files and how to scope their work.
548552

549553
**MCP Spec:** [Roots](https://modelcontextprotocol.io/specification/2025-11-25/client/roots)
@@ -612,6 +616,8 @@ client.notify_roots_list_changed().await?;
612616

613617
## Logging
614618

619+
> **Deprecated (SEP-2577):** Logging is deprecated and will be removed in a future release. It remains fully functional for now. See [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577).
620+
615621
Servers can send structured log messages to clients. The client sets a minimum severity level, and the server sends messages through the peer notification interface.
616622

617623
**MCP Spec:** [Logging](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/logging)

conformance/src/bin/server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(deprecated)]
12
use std::{collections::HashSet, sync::Arc};
23

34
use rmcp::{

crates/rmcp/src/model/capabilities.rs

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pub struct ToolsCapability {
6060
pub list_changed: Option<bool>,
6161
}
6262

63+
/// Roots capability. Deprecated by SEP-2577; remains functional and will be
64+
/// removed in a future release.
65+
/// See <https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577>.
6366
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
6467
#[serde(rename_all = "camelCase")]
6568
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
@@ -97,6 +100,9 @@ pub struct TaskRequestsCapability {
97100
pub tools: Option<ToolsTaskCapability>,
98101
}
99102

103+
/// Sampling task capability. Deprecated by SEP-2577; remains functional and
104+
/// will be removed in a future release.
105+
/// See <https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577>.
100106
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
101107
#[serde(rename_all = "camelCase")]
102108
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
@@ -231,6 +237,10 @@ pub struct ElicitationCapability {
231237
}
232238

233239
/// Sampling capability with optional sub-capabilities (SEP-1577).
240+
///
241+
/// Deprecated by SEP-2577; remains functional and will be removed in a future
242+
/// release.
243+
/// See <https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577>.
234244
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
235245
#[serde(rename_all = "camelCase")]
236246
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
@@ -250,8 +260,6 @@ pub struct SamplingCapability {
250260
/// # use rmcp::model::ClientCapabilities;
251261
/// let cap = ClientCapabilities::builder()
252262
/// .enable_experimental()
253-
/// .enable_roots()
254-
/// .enable_roots_list_changed()
255263
/// .build();
256264
/// ```
257265
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
@@ -266,9 +274,10 @@ pub struct ClientCapabilities {
266274
/// support with no settings.
267275
#[serde(skip_serializing_if = "Option::is_none")]
268276
pub extensions: Option<ExtensionCapabilities>,
277+
/// Capability for filesystem roots (deprecated by SEP-2577).
269278
#[serde(skip_serializing_if = "Option::is_none")]
270279
pub roots: Option<RootsCapabilities>,
271-
/// Capability for LLM sampling requests (SEP-1577)
280+
/// Capability for LLM sampling requests (SEP-1577, deprecated by SEP-2577).
272281
#[serde(skip_serializing_if = "Option::is_none")]
273282
pub sampling: Option<SamplingCapability>,
274283
/// Capability to handle elicitation requests from servers for interactive user input
@@ -283,7 +292,6 @@ pub struct ClientCapabilities {
283292
/// ```rust
284293
/// # use rmcp::model::ServerCapabilities;
285294
/// let cap = ServerCapabilities::builder()
286-
/// .enable_logging()
287295
/// .enable_experimental()
288296
/// .enable_prompts()
289297
/// .enable_resources()
@@ -304,6 +312,7 @@ pub struct ServerCapabilities {
304312
/// support with no settings.
305313
#[serde(skip_serializing_if = "Option::is_none")]
306314
pub extensions: Option<ExtensionCapabilities>,
315+
/// Capability for server log message notifications (deprecated by SEP-2577).
307316
#[serde(skip_serializing_if = "Option::is_none")]
308317
pub logging: Option<JsonObject>,
309318
#[serde(skip_serializing_if = "Option::is_none")]
@@ -320,7 +329,7 @@ pub struct ServerCapabilities {
320329

321330
#[cfg(any(feature = "server", feature = "macros"))]
322331
macro_rules! builder {
323-
($Target: ident {$($f: ident: $T: ty),* $(,)?}) => {
332+
($Target: ident {$($(#[$fa:meta])* $f: ident: $T: ty),* $(,)?}) => {
324333
paste! {
325334
#[derive(Default, Clone, Copy, Debug)]
326335
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
@@ -352,20 +361,20 @@ macro_rules! builder {
352361
}
353362
}
354363
}
355-
builder!($Target @toggle $($f: $T,) *);
364+
builder!($Target @toggle $($(#[$fa])* $f: $T,)*);
356365

357366
};
358-
($Target: ident @toggle $f0: ident: $T0: ty, $($f: ident: $T: ty,)*) => {
359-
builder!($Target @toggle [][$f0: $T0][$($f: $T,)*]);
367+
($Target: ident @toggle $(#[$fa0:meta])* $f0: ident: $T0: ty, $($(#[$fa:meta])* $f: ident: $T: ty,)*) => {
368+
builder!($Target @toggle [][$(#[$fa0])* $f0: $T0][$($(#[$fa])* $f: $T,)*]);
360369
};
361-
($Target: ident @toggle [$($ff: ident: $Tf: ty,)*][$fn: ident: $TN: ty][$fn_1: ident: $Tn_1: ty, $($ft: ident: $Tt: ty,)*]) => {
362-
builder!($Target @impl_toggle [$($ff: $Tf,)*][$fn: $TN][$fn_1: $Tn_1, $($ft:$Tt,)*]);
363-
builder!($Target @toggle [$($ff: $Tf,)* $fn: $TN,][$fn_1: $Tn_1][$($ft:$Tt,)*]);
370+
($Target: ident @toggle [$($ff: ident: $Tf: ty,)*][$(#[$fna:meta])* $fn: ident: $TN: ty][$(#[$fn1a:meta])* $fn_1: ident: $Tn_1: ty, $($(#[$fta:meta])* $ft: ident: $Tt: ty,)*]) => {
371+
builder!($Target @impl_toggle [$($ff: $Tf,)*][$(#[$fna])* $fn: $TN][$fn_1: $Tn_1, $($ft:$Tt,)*]);
372+
builder!($Target @toggle [$($ff: $Tf,)* $fn: $TN,][$(#[$fn1a])* $fn_1: $Tn_1][$($(#[$fta])* $ft: $Tt,)*]);
364373
};
365-
($Target: ident @toggle [$($ff: ident: $Tf: ty,)*][$fn: ident: $TN: ty][]) => {
366-
builder!($Target @impl_toggle [$($ff: $Tf,)*][$fn: $TN][]);
374+
($Target: ident @toggle [$($ff: ident: $Tf: ty,)*][$(#[$fna:meta])* $fn: ident: $TN: ty][]) => {
375+
builder!($Target @impl_toggle [$($ff: $Tf,)*][$(#[$fna])* $fn: $TN][]);
367376
};
368-
($Target: ident @impl_toggle [$($ff: ident: $Tf: ty,)*][$fn: ident: $TN: ty][$($ft: ident: $Tt: ty,)*]) => {
377+
($Target: ident @impl_toggle [$($ff: ident: $Tf: ty,)*][$(#[$fna:meta])* $fn: ident: $TN: ty][$($ft: ident: $Tt: ty,)*]) => {
369378
paste! {
370379
impl<
371380
$(const [<$ff:upper>]: bool,)*
@@ -375,6 +384,7 @@ macro_rules! builder {
375384
false,
376385
$([<$ft:upper>],)*
377386
>> {
387+
$(#[$fna])*
378388
pub fn [<enable_ $fn>](self) -> [<$Target Builder>]<[<$Target BuilderState>]<
379389
$([<$ff:upper>],)*
380390
true,
@@ -387,6 +397,7 @@ macro_rules! builder {
387397
state: PhantomData
388398
}
389399
}
400+
$(#[$fna])*
390401
pub fn [<enable_ $fn _with>](self, $fn: $TN) -> [<$Target Builder>]<[<$Target BuilderState>]<
391402
$([<$ff:upper>],)*
392403
true,
@@ -431,6 +442,10 @@ builder! {
431442
ServerCapabilities {
432443
experimental: ExperimentalCapabilities,
433444
extensions: ExtensionCapabilities,
445+
#[deprecated(
446+
since = "1.8.0",
447+
note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
448+
)]
434449
logging: JsonObject,
435450
completions: JsonObject,
436451
prompts: PromptsCapability,
@@ -509,7 +524,15 @@ builder! {
509524
ClientCapabilities{
510525
experimental: ExperimentalCapabilities,
511526
extensions: ExtensionCapabilities,
527+
#[deprecated(
528+
since = "1.8.0",
529+
note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
530+
)]
512531
roots: RootsCapabilities,
532+
#[deprecated(
533+
since = "1.8.0",
534+
note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
535+
)]
513536
sampling: SamplingCapability,
514537
elicitation: ElicitationCapability,
515538
tasks: TasksCapability,
@@ -520,6 +543,10 @@ builder! {
520543
impl<const E: bool, const EXT: bool, const S: bool, const EL: bool, const TASKS: bool>
521544
ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<E, EXT, true, S, EL, TASKS>>
522545
{
546+
#[deprecated(
547+
since = "1.8.0",
548+
note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
549+
)]
523550
pub fn enable_roots_list_changed(mut self) -> Self {
524551
if let Some(c) = self.roots.as_mut() {
525552
c.list_changed = Some(true);
@@ -533,6 +560,10 @@ impl<const E: bool, const EXT: bool, const R: bool, const EL: bool, const TASKS:
533560
ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<E, EXT, R, true, EL, TASKS>>
534561
{
535562
/// Enable tool calling in sampling requests
563+
#[deprecated(
564+
since = "1.8.0",
565+
note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
566+
)]
536567
pub fn enable_sampling_tools(mut self) -> Self {
537568
if let Some(c) = self.sampling.as_mut() {
538569
c.tools = Some(JsonObject::default());
@@ -541,6 +572,10 @@ impl<const E: bool, const EXT: bool, const R: bool, const EL: bool, const TASKS:
541572
}
542573

543574
/// Enable context inclusion in sampling (soft-deprecated)
575+
#[deprecated(
576+
since = "1.8.0",
577+
note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
578+
)]
544579
pub fn enable_sampling_context(mut self) -> Self {
545580
if let Some(c) = self.sampling.as_mut() {
546581
c.context = Some(JsonObject::default());
@@ -571,6 +606,7 @@ impl<const E: bool, const EXT: bool, const R: bool, const S: bool, const TASKS:
571606
mod test {
572607
use super::*;
573608
#[test]
609+
#[allow(deprecated)]
574610
fn test_builder() {
575611
let builder = <ServerCapabilitiesBuilder>::default()
576612
.enable_logging()
@@ -673,6 +709,7 @@ mod test {
673709
}
674710

675711
#[test]
712+
#[allow(deprecated)]
676713
fn test_client_extensions_capability() {
677714
// Test building ClientCapabilities with extensions (MCP Apps support)
678715
let mut extensions = ExtensionCapabilities::new();

crates/rmcp/src/service/client.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ where
270270
}
271271

272272
macro_rules! method {
273-
(peer_req $method:ident $Req:ident() => $Resp: ident ) => {
273+
($(#[$meta:meta])* peer_req $method:ident $Req:ident() => $Resp: ident ) => {
274+
$(#[$meta])*
274275
pub async fn $method(&self) -> Result<$Resp, ServiceError> {
275276
let result = self
276277
.send_request(ClientRequest::$Req($Req {
@@ -283,7 +284,8 @@ macro_rules! method {
283284
}
284285
}
285286
};
286-
(peer_req $method:ident $Req:ident($Param: ident) => $Resp: ident ) => {
287+
($(#[$meta:meta])* peer_req $method:ident $Req:ident($Param: ident) => $Resp: ident ) => {
288+
$(#[$meta])*
287289
pub async fn $method(&self, params: $Param) -> Result<$Resp, ServiceError> {
288290
let result = self
289291
.send_request(ClientRequest::$Req($Req {
@@ -298,7 +300,8 @@ macro_rules! method {
298300
}
299301
}
300302
};
301-
(peer_req $method:ident $Req:ident($Param: ident)? => $Resp: ident ) => {
303+
($(#[$meta:meta])* peer_req $method:ident $Req:ident($Param: ident)? => $Resp: ident ) => {
304+
$(#[$meta])*
302305
pub async fn $method(&self, params: Option<$Param>) -> Result<$Resp, ServiceError> {
303306
let result = self
304307
.send_request(ClientRequest::$Req($Req {
@@ -313,7 +316,8 @@ macro_rules! method {
313316
}
314317
}
315318
};
316-
(peer_req $method:ident $Req:ident($Param: ident)) => {
319+
($(#[$meta:meta])* peer_req $method:ident $Req:ident($Param: ident)) => {
320+
$(#[$meta])*
317321
pub async fn $method(&self, params: $Param) -> Result<(), ServiceError> {
318322
let result = self
319323
.send_request(ClientRequest::$Req($Req {
@@ -329,7 +333,8 @@ macro_rules! method {
329333
}
330334
};
331335

332-
(peer_not $method:ident $Not:ident($Param: ident)) => {
336+
($(#[$meta:meta])* peer_not $method:ident $Not:ident($Param: ident)) => {
337+
$(#[$meta])*
333338
pub async fn $method(&self, params: $Param) -> Result<(), ServiceError> {
334339
self.send_notification(ClientNotification::$Not($Not {
335340
method: Default::default(),
@@ -340,7 +345,8 @@ macro_rules! method {
340345
Ok(())
341346
}
342347
};
343-
(peer_not $method:ident $Not:ident) => {
348+
($(#[$meta:meta])* peer_not $method:ident $Not:ident) => {
349+
$(#[$meta])*
344350
pub async fn $method(&self) -> Result<(), ServiceError> {
345351
self.send_notification(ClientNotification::$Not($Not {
346352
method: Default::default(),
@@ -354,7 +360,13 @@ macro_rules! method {
354360

355361
impl Peer<RoleClient> {
356362
method!(peer_req complete CompleteRequest(CompleteRequestParams) => CompleteResult);
357-
method!(peer_req set_level SetLevelRequest(SetLevelRequestParams));
363+
method!(
364+
#[deprecated(
365+
since = "1.8.0",
366+
note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
367+
)]
368+
peer_req set_level SetLevelRequest(SetLevelRequestParams)
369+
);
358370
method!(peer_req get_prompt GetPromptRequest(GetPromptRequestParams) => GetPromptResult);
359371
method!(peer_req list_prompts ListPromptsRequest(PaginatedRequestParams)? => ListPromptsResult);
360372
method!(peer_req list_resources ListResourcesRequest(PaginatedRequestParams)? => ListResourcesResult);

0 commit comments

Comments
 (0)