Deprecate roots, sampling, and logging methods per SEP-2577 (#2926)

This commit is contained in:
Marcelo Trylesinski 2026-06-20 17:25:41 +01:00 • committed by GitHub
commit 4573e4ac33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 206 additions and 123 deletions

View file

@ -4,7 +4,7 @@ from .client.session_group import ClientSessionGroup
from .client.stdio import StdioServerParameters, stdio_client
from .server.session import ServerSession
from .server.stdio import stdio_server
from .shared.exceptions import MCPError, UrlElicitationRequiredError
from .shared.exceptions import MCPDeprecationWarning, MCPError, UrlElicitationRequiredError
from .types import (
CallToolRequest,
ClientCapabilities,
@ -96,6 +96,7 @@ __all__ = [
"ListToolsResult",
"LoggingLevel",
"LoggingMessageNotification",
"MCPDeprecationWarning",
"MCPError",
"Notification",
"PingRequest",

View file

@ -6,6 +6,8 @@ from contextlib import AsyncExitStack
from dataclasses import KW_ONLY, dataclass, field
from typing import Any
from typing_extensions import deprecated
from mcp.client._memory import InMemoryTransport
from mcp.client._transport import Transport
from mcp.client.session import ClientSession, ElicitationFnT, ListRootsFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
@ -13,6 +15,7 @@ from mcp.client.streamable_http import streamable_http_client
from mcp.server import Server
from mcp.server.mcpserver import MCPServer
from mcp.shared.dispatcher import ProgressFnT
from mcp.shared.exceptions import MCPDeprecationWarning
from mcp.types import (
CallToolResult,
CompleteResult,
@ -197,9 +200,10 @@ class Client:
message=message,
)
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def set_logging_level(self, level: LoggingLevel, *, meta: RequestParamsMeta | None = None) -> EmptyResult:
"""Set the logging level on the server."""
return await self.session.set_logging_level(level=level, meta=meta)
return await self.session.set_logging_level(level=level, meta=meta) # pyright: ignore[reportDeprecated]
async def list_resources(
self,
@ -314,7 +318,8 @@ class Client:
"""List available tools from the server."""
return await self.session.list_tools(params=PaginatedRequestParams(cursor=cursor, _meta=meta))
@deprecated("The roots capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def send_roots_list_changed(self) -> None:
"""Send a notification that the roots list has changed."""
# TODO(Marcelo): Currently, there is no way for the server to handle this. We should add support.
await self.session.send_roots_list_changed()
await self.session.send_roots_list_changed() # pyright: ignore[reportDeprecated]

View file

@ -10,13 +10,13 @@ import anyio
import anyio.abc
import anyio.lowlevel
from pydantic import BaseModel, TypeAdapter, ValidationError
from typing_extensions import Self, TypeVar
from typing_extensions import Self, TypeVar, deprecated
from mcp import types
from mcp.client._transport import ReadStream, WriteStream
from mcp.shared._compat import resync_tracer
from mcp.shared.dispatcher import CallOptions, DispatchContext, Dispatcher, ProgressFnT
from mcp.shared.exceptions import MCPError
from mcp.shared.exceptions import MCPDeprecationWarning, MCPError
from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher
from mcp.shared.message import ClientMessageMetadata, SessionMessage
from mcp.shared.session import RequestResponder
@ -386,6 +386,7 @@ class ClientSession:
)
)
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def set_logging_level(
self,
level: types.LoggingLevel,
@ -550,6 +551,7 @@ class ClientSession:
return result
@deprecated("The roots capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def send_roots_list_changed(self) -> None:
"""Send a roots/list_changed notification."""
await self.send_notification(types.RootsListChangedNotification())

View file

@ -20,9 +20,10 @@ from typing import Any, TypeVar, overload
import anyio
from pydantic import BaseModel
from typing_extensions import deprecated
from mcp.shared.dispatcher import CallOptions, Outbound
from mcp.shared.exceptions import NoBackChannelError
from mcp.shared.exceptions import MCPDeprecationWarning, NoBackChannelError
from mcp.shared.peer import Meta, dump_params
from mcp.types import (
ClientCapabilities,
@ -209,6 +210,7 @@ class Connection:
"""
await self.send_raw_request("ping", dump_params(None, meta), opts)
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def log(self, level: LoggingLevel, data: Any, logger: str | None = None, *, meta: Meta | None = None) -> None:
"""Send a `notifications/message` log entry on the standalone stream. Best-effort."""
params: dict[str, Any] = {"level": level, "data": data}

View file

@ -3,12 +3,13 @@ from dataclasses import dataclass
from typing import Any, Generic, Protocol
from pydantic import BaseModel
from typing_extensions import TypeVar
from typing_extensions import TypeVar, deprecated
from mcp.server.connection import Connection
from mcp.server.session import ServerSession
from mcp.shared.context import BaseContext
from mcp.shared.dispatcher import DispatchContext
from mcp.shared.exceptions import MCPDeprecationWarning
from mcp.shared.message import CloseSSEStreamCallback
from mcp.shared.peer import Meta
from mcp.shared.transport_context import TransportContext
@ -92,6 +93,7 @@ class Context(BaseContext[TransportContext], Generic[LifespanT_co]):
"""
return self.transport.headers
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def log(self, level: LoggingLevel, data: Any, logger: str | None = None, *, meta: Meta | None = None) -> None:
"""Send a request-scoped `notifications/message` log entry.

View file

@ -4,6 +4,7 @@ from collections.abc import Iterable
from typing import TYPE_CHECKING, Any, Generic
from pydantic import AnyUrl, BaseModel
from typing_extensions import deprecated
from mcp.server.context import LifespanContextT, RequestT, ServerRequestContext
from mcp.server.elicitation import (
@ -14,6 +15,7 @@ from mcp.server.elicitation import (
elicit_with_validation,
)
from mcp.server.lowlevel.helper_types import ReadResourceContents
from mcp.shared.exceptions import MCPDeprecationWarning
from mcp.types import LoggingLevel
if TYPE_CHECKING:
@ -189,6 +191,7 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
related_request_id=self.request_id,
)
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def log(
self,
level: LoggingLevel,
@ -205,7 +208,7 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
(string, dict, list, number, bool, etc.) per the MCP specification.
logger_name: Optional logger name
"""
await self.request_context.session.send_log_message(
await self.request_context.session.send_log_message( # pyright: ignore[reportDeprecated]
level=level,
data=data,
logger=logger_name,
@ -265,18 +268,22 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
await self._request_context.close_standalone_sse_stream()
# Convenience methods for common log levels
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def debug(self, data: Any, *, logger_name: str | None = None) -> None:
"""Send a debug log message."""
await self.log("debug", data, logger_name=logger_name)
await self.log("debug", data, logger_name=logger_name) # pyright: ignore[reportDeprecated]
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def info(self, data: Any, *, logger_name: str | None = None) -> None:
"""Send an info log message."""
await self.log("info", data, logger_name=logger_name)
await self.log("info", data, logger_name=logger_name) # pyright: ignore[reportDeprecated]
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def warning(self, data: Any, *, logger_name: str | None = None) -> None:
"""Send a warning log message."""
await self.log("warning", data, logger_name=logger_name)
await self.log("warning", data, logger_name=logger_name) # pyright: ignore[reportDeprecated]
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def error(self, data: Any, *, logger_name: str | None = None) -> None:
"""Send an error log message."""
await self.log("error", data, logger_name=logger_name)
await self.log("error", data, logger_name=logger_name) # pyright: ignore[reportDeprecated]

View file

@ -12,12 +12,13 @@ used to live here are now owned by `JSONRPCDispatcher` and `ServerRunner`.
from typing import Any, TypeVar, cast, overload
from pydantic import AnyUrl, BaseModel
from typing_extensions import deprecated
from mcp import types
from mcp.server.connection import Connection
from mcp.server.validation import validate_sampling_tools, validate_tool_use_result_messages
from mcp.shared.dispatcher import CallOptions, Dispatcher, ProgressFnT
from mcp.shared.exceptions import NoBackChannelError, StatelessModeNotSupported
from mcp.shared.exceptions import MCPDeprecationWarning, NoBackChannelError, StatelessModeNotSupported
from mcp.shared.message import ServerMessageMetadata
from mcp.types import methods as _methods
@ -126,6 +127,7 @@ class ServerSession:
"""Check if the client supports a specific capability."""
return self._connection.check_capability(capability)
@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def send_log_message(
self,
level: types.LoggingLevel,
@ -154,6 +156,7 @@ class ServerSession:
)
@overload
@deprecated("The sampling capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def create_message(
self,
messages: list[types.SamplingMessage],
@ -173,6 +176,7 @@ class ServerSession:
...
@overload
@deprecated("The sampling capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def create_message(
self,
messages: list[types.SamplingMessage],
@ -191,6 +195,7 @@ class ServerSession:
"""Overload: With tools, returns array-capable content."""
...
@deprecated("The sampling capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def create_message(
self,
messages: list[types.SamplingMessage],
@ -267,6 +272,7 @@ class ServerSession:
metadata=metadata_obj,
)
@deprecated("The roots capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def list_roots(self) -> types.ListRootsResult:
"""Send a roots/list request."""
if self._stateless:

View file

@ -5,6 +5,17 @@ from typing import Any, cast
from mcp.types import INVALID_REQUEST, URL_ELICITATION_REQUIRED, ElicitRequestURLParams, ErrorData, JSONRPCError
class MCPDeprecationWarning(UserWarning):
"""A custom deprecation warning for the MCP SDK.
Unlike the built-in `DeprecationWarning`, this inherits from `UserWarning` so
it is shown by default, helping users discover deprecated features without
enabling warnings explicitly.
Reference: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries
"""
class MCPError(Exception):
"""Exception type raised when an error arrives over an MCP connection."""

View file

@ -13,8 +13,10 @@ from collections.abc import Mapping
from typing import Any, cast, overload
from pydantic import BaseModel
from typing_extensions import deprecated
from mcp.shared.dispatcher import CallOptions, Outbound
from mcp.shared.exceptions import MCPDeprecationWarning
from mcp.types import (
CreateMessageRequestParams,
CreateMessageResult,
@ -83,6 +85,7 @@ class ClientPeer:
await self._outbound.notify(method, params)
@overload
@deprecated("The sampling capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def sample(
self,
messages: list[SamplingMessage],
@ -100,6 +103,7 @@ class ClientPeer:
opts: CallOptions | None = None,
) -> CreateMessageResult: ...
@overload
@deprecated("The sampling capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def sample(
self,
messages: list[SamplingMessage],
@ -116,6 +120,7 @@ class ClientPeer:
meta: Meta | None = None,
opts: CallOptions | None = None,
) -> CreateMessageResultWithTools: ...
@deprecated("The sampling capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def sample(
self,
messages: list[SamplingMessage],
@ -195,6 +200,7 @@ class ClientPeer:
result = await self.send_raw_request("elicitation/create", dump_params(params, meta), opts)
return ElicitResult.model_validate(result, by_name=False)
@deprecated("The roots capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def list_roots(self, *, meta: Meta | None = None, opts: CallOptions | None = None) -> ListRootsResult:
"""Send a `roots/list` request.