Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -945,13 +945,13 @@

@mcp.tool()
async def generate_poem(topic: str, ctx: Context) -> str:
"""Generate a poem using LLM sampling."""
prompt = f"Write a short poem about {topic}"

result = await ctx.session.create_message(
result = await ctx.session.create_message( # pyright: ignore[reportDeprecated]
messages=[
SamplingMessage(
role="user",

Check warning on line 954 in README.v2.md

View check run for this annotation

Claude / Claude Code Review

README.v2.md still teaches deprecated APIs and shows an unexplained pyright suppression

README.v2.md (the package's published readme) still presents the freshly deprecated Sampling/Logging surface as the recommended API with no SEP-2577 note, and the only README change in this PR injects a bare `# pyright: ignore[reportDeprecated]` into the copy-paste sampling example with no explanation of what is being suppressed or why. Consider adding a brief SEP-2577 deprecation note next to the Sampling and Logging README sections (or an explanatory comment in the snippet) so readers aren't s
Comment on lines 948 to 954

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 README.v2.md (the package's published readme) still presents the freshly deprecated Sampling/Logging surface as the recommended API with no SEP-2577 note, and the only README change in this PR injects a bare # pyright: ignore[reportDeprecated] into the copy-paste sampling example with no explanation of what is being suppressed or why. Consider adding a brief SEP-2577 deprecation note next to the Sampling and Logging README sections (or an explanatory comment in the snippet) so readers aren't steered into deprecated APIs with zero signal.

Extended reasoning...

What the issue is

This PR deprecates the user-facing Roots/Sampling/Logging methods per SEP-2577 (ServerSession.create_message, ServerSession.send_log_message, the Context logging helpers, etc.) and adds a migration-guide entry — but README.v2.md, which is the package's published readme (readme = "README.v2.md" in pyproject.toml), still presents these as the recommended APIs with no deprecation signal at all:

  • The tutorial examples around lines 363/372 and 710/719 use ctx.info() / ctx.debug().
  • The Context logging API list at ~691-695 documents ctx.debug / info / warning / error / log.
  • The advanced session methods list at ~1104-1105 includes ctx.session.send_log_message and ctx.session.create_message.

The string "SEP-2577" / "deprecat" appears nowhere in the README except in one place — the only README change in this PR.

The PR-introduced part

The README's code blocks are auto-synced from examples/snippets via scripts/update_readme_snippets.py, so the # pyright: ignore[reportDeprecated] added to examples/snippets/servers/sampling.py necessarily leaks into the published sampling tutorial at line 951. This is the only pyright suppression comment anywhere in README.v2.md, i.e. this PR is the first to put an unexplained type-checker suppression into user-facing copy-paste tutorial code. A reader pasting the snippet either keeps a mystery suppression or removes it and gets an unexplained reportDeprecated error from strict pyright — with no hint anywhere in the README about why.

Concrete walkthrough

  1. A new user reads the published README on PyPI, follows the Sampling section, and copies the generate_poem example at lines 948-954.
  2. They see # pyright: ignore[reportDeprecated] on the create_message call but no surrounding text mentions any deprecation; the README otherwise actively recommends this API.
  3. If they delete the comment (it looks like internal noise), pyright in strict mode flags create_message as deprecated — the first time they learn about SEP-2577, with no pointer to the migration guide.
  4. If they keep it, they ship code suppressing a warning they were never told about, and the same applies to every ctx.info() / send_log_message example in the README that carries no annotation at all.

Why existing changes don't cover this

Only docs/migration.md was updated with the SEP-2577 entry. The README — which is what users actually see on PyPI/GitHub and what teaches these features — was touched only by the mechanical snippet sync, so the deprecation messaging and the published tutorial content are now inconsistent.

Mitigations / why this is a nit

The deprecation is advisory only: the methods keep working, capability negotiation is unchanged, and the migration guide explicitly says no migration is required during the deprecation window. So the README is not functionally wrong, and the suppression in the snippet is forced by the repo's strict pyright config plus the snippet-sync mechanism. This is a documentation/UX completeness gap rather than a functional bug.

How to fix

Add a one- or two-line SEP-2577 deprecation note (with a link to the migration-guide entry this PR adds) next to the README's Sampling and Logging sections, and/or replace the bare suppression in examples/snippets/servers/sampling.py with a short explanatory comment (e.g. # Sampling is deprecated as of 2026-07-28 (SEP-2577) but still supported) so the synced README snippet is self-explanatory.

content=TextContent(type="text", text=prompt),
)
],
Expand Down
21 changes: 20 additions & 1 deletion docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,26 @@

## Deprecations

<!-- Add deprecations below -->
### Roots, Sampling, and Logging methods deprecated (SEP-2577)

[SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577) deprecates the Roots, Sampling, and Logging features as of the 2026-07-28 spec. The deprecation is advisory only: there are no wire-level changes, capability negotiation is unchanged, and every method keeps working for sessions negotiating 2025-11-25 and earlier.

The user-facing methods for these features now carry `typing_extensions.deprecated`, so type checkers, IDEs, and the runtime surface a deprecation warning where they are called:

- Sampling: `ServerSession.create_message()`, `ClientPeer.sample()`
- Roots: `ServerSession.list_roots()`, `ClientPeer.list_roots()`, `ClientSession.send_roots_list_changed()`, `Client.send_roots_list_changed()`
- Logging: `ServerSession.send_log_message()`, `ClientSession.set_logging_level()`, `Client.set_logging_level()`, and `MCPServer` `Context.log()`. The `Context.debug()` / `info()` / `warning()` / `error()` helpers delegate to `log()`, so they warn through it rather than carrying their own marker.

Check warning on line 1227 in docs/migration.md

View check run for this annotation

Claude / Claude Code Review

Migration guide omits the lowlevel mcp.server.context.Context.log() deprecation

The new Deprecations section's Logging bullet lists only `MCPServer` `Context.log()`, but this PR also adds `@deprecated` to the lowlevel `mcp.server.context.Context.log()` (src/mcp/server/context.py:96), which is a distinct class. Consider adding `mcp.server.context.Context.log()` to the bullet (or noting both Context classes are covered) so users of the lowlevel Context can find their method in the list.
Comment thread
Kludex marked this conversation as resolved.
Resolved

The runtime warning is emitted as `mcp.MCPDeprecationWarning`, which subclasses `UserWarning` (not `DeprecationWarning`) so it is visible by default. To silence it, filter that category:

```python
import warnings
from mcp import MCPDeprecationWarning

warnings.filterwarnings("ignore", category=MCPDeprecationWarning)
```

No migration is required during the deprecation window. New code should avoid building on these features, since they may be removed in a future spec version.

## Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ async def test_sampling(prompt: str, ctx: Context) -> str:
"""Tests server-initiated sampling (LLM completion request)"""
try:
# Request sampling from client
result = await ctx.session.create_message(
result = await ctx.session.create_message( # pyright: ignore[reportDeprecated]
messages=[SamplingMessage(role="user", content=TextContent(type="text", text=prompt))],
max_tokens=100,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequ

# Send the specified number of notifications with the given interval
for i in range(count):
await ctx.session.send_log_message(
await ctx.session.send_log_message( # pyright: ignore[reportDeprecated]
level="info",
data=f"Notification {i + 1}/{count} from caller: {caller}",
logger="notification_stream",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequ
for i in range(count):
# Include more detailed message for resumability demonstration
notification_msg = f"[{i + 1}/{count}] Event from '{caller}' - Use Last-Event-ID to resume if disconnected"
await ctx.session.send_log_message(
await ctx.session.send_log_message( # pyright: ignore[reportDeprecated]
level="info",
data=notification_msg,
logger="notification_stream",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequ
content=[types.TextContent(type="text", text="Error: checkpoint_every must be between 1 and 20")]
)

await ctx.session.send_log_message(
await ctx.session.send_log_message( # pyright: ignore[reportDeprecated]
level="info",
data=f"Starting batch processing of {items} items...",
logger="process_batch",
Expand All @@ -86,7 +86,7 @@ async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequ
await anyio.sleep(0.5)

# Report progress
await ctx.session.send_log_message(
await ctx.session.send_log_message( # pyright: ignore[reportDeprecated]
level="info",
data=f"[{i}/{items}] Processing item {i}",
logger="process_batch",
Expand All @@ -95,7 +95,7 @@ async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequ

# Checkpoint: close stream to trigger client reconnect
if i % checkpoint_every == 0 and i < items:
await ctx.session.send_log_message(
await ctx.session.send_log_message( # pyright: ignore[reportDeprecated]
level="info",
data=f"Checkpoint at item {i} - closing SSE stream for polling",
logger="process_batch",
Expand Down
2 changes: 1 addition & 1 deletion examples/snippets/servers/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ async def generate_poem(topic: str, ctx: Context) -> str:
"""Generate a poem using LLM sampling."""
prompt = f"Write a short poem about {topic}"

result = await ctx.session.create_message(
result = await ctx.session.create_message( # pyright: ignore[reportDeprecated]
messages=[
SamplingMessage(
role="user",
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ filterwarnings = [
"error",
# pywin32 internal deprecation warning
"ignore:getargs.*The 'u' format is deprecated:DeprecationWarning",
# SEP-2577 deprecates the roots/sampling/logging methods; the SDK still calls
# them internally (e.g. `ctx.debug` -> `log` -> `send_log_message`), so the
# advisory warning is silenced. Tests asserting it opt back in with pytest.warns.
"ignore:.*is deprecated as of 2026-07-28 \\(SEP-2577\\).:mcp.MCPDeprecationWarning",
]

[tool.markdown.lint]
Expand Down
3 changes: 2 additions & 1 deletion src/mcp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
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,
Expand Down Expand Up @@ -96,6 +96,7 @@
"ListToolsResult",
"LoggingLevel",
"LoggingMessageNotification",
"MCPDeprecationWarning",
"MCPError",
"Notification",
"PingRequest",
Expand Down
9 changes: 7 additions & 2 deletions src/mcp/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
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
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,
Expand Down Expand Up @@ -195,9 +198,10 @@
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]

Check warning on line 204 in src/mcp/client/client.py

View check run for this annotation

Claude / Claude Code Review

Deprecated wrappers double-warn, second warning blames SDK internals

These deprecated wrapper methods delegate to other `@deprecated`-decorated methods with only a `# pyright: ignore[reportDeprecated]`, which silences the static diagnostic but not the runtime warning — so a single user call to `Client.set_logging_level()`, `Client.send_roots_list_changed()`, or the mcpserver `Context.log()` emits two `MCPDeprecationWarning`s, the second pointing at SDK internals (e.g. `client.py:204`). Consider wrapping the internal delegation in `warnings.catch_warnings()` (as `
Comment thread
Kludex marked this conversation as resolved.
Resolved

async def list_resources(
self,
Expand Down Expand Up @@ -312,7 +316,8 @@
"""List available tools from the server."""
return await self.session.list_tools(params=PaginatedRequestParams(cursor=cursor, _meta=meta))

@deprecated("`send_roots_list_changed` 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]
6 changes: 4 additions & 2 deletions src/mcp/client/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
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
Expand Down Expand Up @@ -386,6 +386,7 @@ async def send_progress_notification(
)
)

@deprecated("The logging capability is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def set_logging_level(
self,
level: types.LoggingLevel,
Expand Down Expand Up @@ -550,6 +551,7 @@ async def list_tools(self, *, params: types.PaginatedRequestParams | None = None

return result

@deprecated("`send_roots_list_changed` 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())
Expand Down
4 changes: 3 additions & 1 deletion src/mcp/server/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
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
Expand Down Expand Up @@ -92,6 +93,7 @@ def headers(self) -> Mapping[str, str] | None:
"""
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.

Expand Down
13 changes: 8 additions & 5 deletions src/mcp/server/mcpserver/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 (
Expand All @@ -14,6 +15,7 @@
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:
Expand Down Expand Up @@ -189,6 +191,7 @@ async def elicit_url(
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,
Expand All @@ -205,7 +208,7 @@ async def log(
(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,
Expand Down Expand Up @@ -267,16 +270,16 @@ async def close_standalone_sse_stream(self) -> None:
# Convenience methods for common log levels
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]

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]

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]

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]
8 changes: 7 additions & 1 deletion src/mcp/server/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
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

Expand Down Expand Up @@ -126,6 +127,7 @@ def check_client_capability(self, capability: types.ClientCapabilities) -> bool:
"""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,
Expand Down Expand Up @@ -154,6 +156,7 @@ async def send_resource_updated(self, uri: str | AnyUrl) -> None:
)

@overload
@deprecated("`create_message` is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def create_message(
self,
messages: list[types.SamplingMessage],
Expand All @@ -173,6 +176,7 @@ async def create_message(
...

@overload
@deprecated("`create_message` is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def create_message(
self,
messages: list[types.SamplingMessage],
Expand All @@ -191,6 +195,7 @@ async def create_message(
"""Overload: With tools, returns array-capable content."""
...

@deprecated("`create_message` is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def create_message(
self,
messages: list[types.SamplingMessage],
Expand Down Expand Up @@ -267,6 +272,7 @@ async def create_message(
metadata=metadata_obj,
)

@deprecated("`list_roots` 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:
Expand Down
11 changes: 11 additions & 0 deletions src/mcp/shared/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
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."""

Expand Down
6 changes: 6 additions & 0 deletions src/mcp/shared/peer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
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,
Expand Down Expand Up @@ -83,6 +85,7 @@ async def notify(self, method: str, params: Mapping[str, Any] | None) -> None:
await self._outbound.notify(method, params)

@overload
@deprecated("`sample` is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def sample(
self,
messages: list[SamplingMessage],
Expand All @@ -100,6 +103,7 @@ async def sample(
opts: CallOptions | None = None,
) -> CreateMessageResult: ...
@overload
@deprecated("`sample` is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def sample(
self,
messages: list[SamplingMessage],
Expand All @@ -116,6 +120,7 @@ async def sample(
meta: Meta | None = None,
opts: CallOptions | None = None,
) -> CreateMessageResultWithTools: ...
@deprecated("`sample` is deprecated as of 2026-07-28 (SEP-2577).", category=MCPDeprecationWarning)
async def sample(
self,
messages: list[SamplingMessage],
Expand Down Expand Up @@ -195,6 +200,7 @@ async def elicit_url(
result = await self.send_raw_request("elicitation/create", dump_params(params, meta), opts)
return ElicitResult.model_validate(result, by_name=False)

@deprecated("`list_roots` 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.

Expand Down
Loading
Loading