MCP 2026-07-28では、大きな仕様変更の1つとして、Roots・Sampling・Loggingの3機能が非推奨になりました。古い記事やサンプルコードではroots/list、sampling/createMessage、logging/setLevel、notifications/messageなどを見かけるため、「Rootsはもう使えないのか」「Samplingの代わりにLLMをどう呼べばよいのか」「MCP Serverからログを送れなくなるのか」と迷うかもしれません。
結論から言うと、2026年10月時点でこの3機能がすぐに削除されるわけではありません。2026-07-28の仕様では、SEP-2577によって「非推奨」になっただけで、削除するには別の手続きが必要で、非推奨から削除までは最低12か月あります。ただし新しくMCP Serverを設計するなら、これらを前提にしないよう公式が示しています。
公式の移行先は次のとおりです。
- Roots:Tool Parameter、Resource URI、Server Configurationで対象を渡す
- Sampling:LLM Provider APIへ直接接続する
- Logging:stdioならstderr、構造化された監視にはOpenTelemetryを使う
この記事では、3機能がなぜ非推奨になったのか、既存の実装にどう影響するのか、2026年以降のMCP Serverでは何に置き換えるべきかを、MCP公式のChangelogとPython SDKのドキュメント(2026年10月時点)に沿って解説します。
- Roots・Sampling・Loggingは「削除」ではなく「非推奨」
- 同じ2026-07-28で実際に削除されたもの
- なぜ3機能がまとめて整理されたのか
- MRTRがあれば、RootsやSamplingを使い続けてもよいのか
- Rootsは何をする機能だったのか
- Rootsの代わり1:Tool Parameterで対象を明示する
- Rootsの代わり2:Resource URIで対象を表す
- Rootsの代わり3:Server Configurationで固定する
- Roots廃止後もFilesystemのAllowlistは必要
- Samplingは何をする機能だったのか
- Samplingの代わりはLLM Provider APIの直接呼び出し
- ServerがCredentialとCostを管理する設計になる
- 既存のSamplingを2026-07-28で動かすには
- Loggingの代わりは標準loggingとstderr
- モデルに伝えたい情報はログではなくTool Resultで返す
- 詳細な監視はOpenTelemetryへ移す
- 既存のMCPサーバーはすぐ書き換える必要があるか
- 非推奨APIの利用をテストで検出する
- 「Clientに聞く」から「Requestに明示する」へ
- Roots・Sampling・Logging非推奨に関するよくある質問
- これからのMCPサーバーは3機能に依存しない設計にする
Roots・Sampling・Loggingは「削除」ではなく「非推奨」
最初に、非推奨(Deprecated)と削除(Removed)を区別します。公式のChangelogでは、この3機能は「仕様に残っているが、削除が予定されている機能」として扱われています。非推奨の間は完全に機能し、新しい実装は対応を追加すべきではない、とされています。
MCPのFeature Lifecycleのポリシーでは、非推奨から削除までに最低12か月の期間があり、削除には別のSEPが必要です。つまり、既存のMCP Serverにroots・sampling・loggingの実装があっても、すぐに削除する必要はありません。
一方で、これから作るServerで「WorkspaceはRootsで取得する」「LLM処理はSamplingで行う」「運用ログはMCP LoggingでClientへ送る」という設計を採用するのは避けたほうがよいでしょう。
同じ2026-07-28で実際に削除されたもの
混同しやすいのが、非推奨になった機能と、同じ仕様変更で実際に削除された機能です。公式のChangelogによると、次の3つは削除されています。
pinglogging/setLevelnotifications/roots/list_changed
Python SDKの公式ドキュメントでも、pingは「非推奨ではなく、プロトコルから削除された」と明記されています。2026-07-28接続でPingを送ると、ServerはMethod not foundを返します。
Loggingについては、機能自体は非推奨のままですが、logging/setLevelという呼び出しがなくなりました。ログレベルは、リクエストごとに_metaのio.modelcontextprotocol/logLevelで指定します。そしてServerは、この項目を含まないリクエストに対して、notifications/messageを送ってはいけない(MUST NOT)とされています。「Loggingはまだ動く」と思い込まず、どこまでがProtocol上で有効かを確認する必要があります。
なぜ3機能がまとめて整理されたのか
背景には、2026-07-28でMCPがStateless(セッションを持たない)になったことがあります。以前はClientとServerがSessionを維持し、ServerからClientへRequestを送る双方向の構造がよく使われていました。たとえばSamplingではsampling/createMessage、Rootsではroots/listを、ServerがClientへ送っていました。
2026-07-28では、Protocol Coreが1回ごとのRequest / Responseを基本とする形に変わり、従来のServer → Clientの独立したRequestの経路がなくなりました。途中で追加の情報が必要なときは、Serverがinput_requiredの結果を返し、Clientが入力を付けて元のRequestを再試行する、Multi Round-Trip Requests(MRTR)という方式になります。
MRTRの仕組みはMCPのtools・resources・promptsの違い|何をどこに実装するべきかや、確認フローの例としてMCPツールに破壊的操作を持たせるときの設計|削除・更新処理を安全にするで解説しています。
MRTRがあれば、RootsやSamplingを使い続けてもよいのか
ここは少しややこしいところです。公式のChangelogでは、MRTRは、これまでのroots/list・sampling/createMessage・elicitation/createのようなServer起点のRequestを置き換える方式として導入されています。つまり、SamplingのCreateMessageRequestやRootsのListRootsRequestは、InputRequiredResultのinput_requestsに入れて、Clientへ運べます。
これは矛盾ではありません。MRTRは「途中の入力が必要な処理を、Statelessなプロトコルの上でどう運ぶか」という配送の仕組みで、非推奨は「新しい設計をSamplingやRootsに依存させるべきか」という設計の方針だからです。既存の実装を2026-07-28で動かす手段としてMRTRを使えますが、新規の設計では公式が示す移行先に進むのが基本です。
Python SDKでは、接続の種類で挙動が違います。公式のDeprecatedページによると、次のようになります。
ctx.session.list_roots():2026年より前の(旧)接続でのみ動作する。新しい接続では、パスをTool引数かResource URIで受け取るか、ListRootsRequestをInputRequiredResultに入れるctx.session.create_message():どの接続でも警告が出る。2026-07-28接続では「Cannot send 'sampling/createMessage': this transport context has no back-channel」というエラーになる。InputRequiredResultを返してClientに再試行させるInputRequiredResultを旧接続(mode="legacy")で返すと、ネゴシエートされたバージョンに変換できず、Clientは-32603のエラーを受け取る
つまり、以前のコードがそのまま2026-07-28接続で動くわけではありません。非推奨だから「まだ動く」とだけ理解していると、新しい接続で突然エラーになります。
Rootsは何をする機能だったのか
Rootsは、MCP ClientがServerへ、作業対象のWorkspace Folderを知らせる仕組みです。たとえばIDEで/home/user/project-aを開いているとき、ServerがClientにRootsを問い合わせることで、「このWorkspaceを対象にすればよい」と判断できました。
ただし、Rootsは「この範囲を扱ってください」という案内(Guidance)であり、「この範囲の外には絶対アクセスできない」というSecurity Boundaryではありません。この点は以前から変わらず、Filesystem AccessはServer側のAllowlistやOSの権限で制御する必要があります(MCPサーバーからファイルを安全に読み込む方法|パストラバーサル対策)。
Rootsの代わり1:Tool Parameterで対象を明示する
最も単純な移行方法は、操作対象をTool Parameterとして明示することです。以前はroots/listでWorkspaceを取得して検索していたなら、次のように、対象を引数にします。
from mcp.server import MCPServer
mcp = MCPServer("Project Tools")
@mcp.tool()
def search_files(
workspace: str,
query: str,
) -> list[str]:
...
ただし、workspace="/"のような値をそのままFilesystem Accessに使ってはいけません。Server側で、Logical IDと実際のPathの対応表(Allowlist)を持つ設計が安全です。
from pathlib import Path
WORKSPACES = {
"project-a": Path("/srv/projects/project-a"),
"project-b": Path("/srv/projects/project-b"),
}
def get_workspace(workspace_id: str) -> Path:
root = WORKSPACES.get(workspace_id)
if root is None:
raise ValueError("Unknown workspace")
return root.resolve()
モデルにはLogical IDだけを渡させ、実際のFilesystem RootはServerが決めます。
Rootsの代わり2:Resource URIで対象を表す
対象をMCP Resourceとして表現できるなら、Resource URIも使えます。たとえばproject://project-a/src/main.pyやrepo://company-api/README.mdのようなURIをToolに渡し、ServerがURIから対象のProjectやFileを解決します。どのWorkspaceのどのResourceかが、Tool Callそのものに明示されるのが利点です。
Rootsの代わり3:Server Configurationで固定する
そもそもWorkspaceを毎回Clientから取得する必要がない場合もあります。「このMCP Serverは/company/docsだけを検索する」と決まっているなら、起動時の設定で固定できます。
import os from pathlib import Path ROOT = Path(os.environ["MCP_WORKSPACE"]).resolve()
MCP_WORKSPACE=/srv/company/docs python server.py
Dockerなら、特定のDirectoryだけを/workspaceへMountする方法もあります(MCPサーバーをDockerで動かす方法|stdioでハマりやすいポイント)。この方式なら、ClientへWorkspaceを問い合わせる必要自体がなくなります。
Roots廃止後もFilesystemのAllowlistは必要
RootsをTool Parameterへ移すと、「モデルがPathを指定できるようになって、かえって危険では」と思うかもしれません。その通りで、Rootsの代替はSecurity機能ではありません。def read_file(path: str): return open(path).read()のように変えるだけでは危険です。
許可Rootの固定、入力Pathの正規化(Canonicalize)、Root内にあることの確認、Symlinkの解決、という検証は引き続き必要です。Rootsが非推奨になっても、Filesystem Securityが不要になったわけではなく、「Workspaceの特定(Discovery)」と「アクセス制御(Access Control)」を分けて設計する、ということです。
Samplingは何をする機能だったのか
Samplingは、MCP ServerがMCP Clientを通じて、Client側のLLMに生成を依頼する仕組みでした。Tool内部で「Documentを取得し、ClientのLLMに要約を依頼し、結果を返す」といった処理ができ、Server自身がAnthropicやOpenAIのAPI Credentialを持たなくても、Clientがすでに持っているModelを使えるのが特徴でした。
Samplingの代わりはLLM Provider APIの直接呼び出し
公式の移行先は「LLM Provider APIとの直接統合」です。ServerまたはServerが使うApplication Serviceから、Provider APIへ直接接続します。MCP ToolとLLM Clientを別のLayerに分けておくと、Providerを変えてもTool Interfaceへ影響しにくくなります。
class LLMService:
async def generate(self, prompt: str) -> str:
# Anthropic・OpenAI・Geminiなどの
# Provider SDKをここで呼び出す
...
llm = LLMService()
@mcp.tool()
async def summarize_document(document_id: str) -> str:
text = load_document(document_id)
return await llm.generate(
"次の文章を要約してください。\n\n" + text
)
ServerがCredentialとCostを管理する設計になる
Samplingには「ServerがLLMのCredentialを持たなくてよい」という利点がありました。直接Provider APIを呼ぶ方式では、API Key、Model設定、Rate Limit、Costを、Server側で管理する必要があります。その代わりに、どのModelを使うか、Token上限をどうするか、Fallbackをどうするかを、Server側で明確に制御できます。
また、Model名をTool Argumentとしてモデルに自由に指定させるのはおすすめしません。高額なModel、社内で使用禁止のModel、権限のないProviderを指定される可能性があるためです。Model名はServer Configurationで決め、必要ならfast・balanced・high_qualityのようなLogical Profileだけを引数として公開し、実際のModel IDへの対応はServer側で行います。
既存のSamplingを2026-07-28で動かすには
すぐにProvider APIへ書き換えられない場合は、MRTRで運べます。Python SDKの公式ドキュメントでは、@mcp.tool()のHigh-level APIでは、ClientのLLMを使うSampleや、Rootsを取得するListRoots、ユーザーに確認するElicitを依存として宣言すれば、SDKがInputRequiredResultを返してくれる、と説明されています。
Low-level APIでは、自分でInputRequiredResultを返します。公式のドキュメントにある例は次のとおりです(これはElicitationの例ですが、input_requestsにCreateMessageRequestやListRootsRequestを入れる場合も同じ構造です)。
async def call_tool(ctx: ServerRequestContext, params: CallToolRequestParams) -> CallToolResult | InputRequiredResult:
answer = (params.input_responses or {}).get("region")
if not isinstance(answer, ElicitResult) or answer.content is None:
return InputRequiredResult(input_requests={"region": ASK_REGION}, request_state="provision-v1")
name = (params.arguments or {})["name"]
text = f"Provisioned {name!r} in {answer.content['region']}."
return CallToolResult(content=[TextContent(type="text", text=text)])
初回の呼び出しではparams.input_responsesが空なので、入力を求めるInputRequiredResultを返します。Clientが回答を付けて再試行すると、同じ名前(ここでは"region")で回答が届きます。この方式は2026-07-28の接続が前提で、旧接続で返すと-32603のエラーになります。また、Clientがその種類の入力要求(Samplingなど)に対応している必要があります。
Samplingを使う場合は、もう1つ注意があります。includeContextの"thisServer"と"allServers"も、公式のChangelogで非推奨になりました。これらの値は、Sampling機能そのものより前には削除されません。値を省略するか"none"を使います。
Loggingの代わりは標準loggingとstderr
MCPにはProtocol Level Loggingがあり、ServerからClientへnotifications/messageで、debug・info・warning・errorなどのログを送れました。2026-07-28ではこのCapabilityが非推奨になり、Python SDKではctx.log()・ctx.info()・ctx.warning()・ctx.error()などが非推奨のAPIとして扱われます。移行先は、通常のimport loggingです。
import logging
from mcp.server import MCPServer
logger = logging.getLogger(__name__)
mcp = MCPServer("Company MCP")
@mcp.tool()
def search_documents(query: str) -> str:
logger.info("search_documents started")
return "3 documents found"
stdio MCPでは、stdoutがProtocolの通信路なので、print()ではなくloggingを使い、ログはstderrへ出します(MCPのstdioサーバーが接続できない原因|stdoutにログを出してはいけない理由)。Remote MCPなら、通常のWeb Serviceと同じ構造化ログを既存の監視基盤へ送れます。Protocol Loggingの非推奨の詳細はMCPのProtocol Loggingが非推奨になった理由|stderrとOpenTelemetryでのログ設計で解説しています。
モデルに伝えたい情報はログではなくTool Resultで返す
Protocol Loggingがあったために、「ログをモデルへの途中経過のメッセージとして使う」設計をしていた場合は見直しが必要です。Application Logは運用者向けで、モデルには届きません。モデルに知らせる必要がある情報は、Tool Resultとして返します。
logger.warning("Search result was truncated")
return {
"items": items,
"truncated": True,
}
詳細な監視はOpenTelemetryへ移す
Loggingの非推奨で重要になるのがOpenTelemetryです。MCP Python SDKは、受信した各メッセージに対してOpenTelemetryのSpanを作り、Tool Callではgen_ai.operation.nameやgen_ai.tool.nameも付けます。OpenTelemetry SDKとExporterを入れるまでは何もしないNo-opとして動くので、Traceを収集したくなったときに追加できます。具体的なメトリクス・Alert・Samplingの設計はMCPサーバーを本番運用する方法|メトリクス・アラート・トレースの設計で解説しています。
既存のMCPサーバーはすぐ書き換える必要があるか
現在、正常に動いているServerなら、すべてを一度に書き換える必要はありません。非推奨機能は少なくとも12か月は残り、削除には別のSEPが必要だからです。ただし新機能を追加するときは、非推奨のAPIをこれ以上増やさないほうがよいでしょう。
- Roots:既存の
list_roots()は互換のために残しつつ、新しいFilesystem ToolはServer ConfigurationかResource URIで対象を受け取る - Sampling:既存の処理だけ
InputRequiredResult経由で維持し、新しいLLM処理はProvider API Wrapperを通す - Logging:既存Clientとの互換のためだけに残し、運用ログは標準LoggingとOpenTelemetryへ移す
この進め方なら、動いているものを壊さず、段階的に移行できます。
非推奨APIの利用をテストで検出する
Python SDKは、非推奨の機能を使うとMCPDeprecationWarningを出します。これは通常のDeprecationWarningではなくUserWarningのサブクラスで、意図的にそうなっています。Pythonの既定のフィルタはDeprecationWarningを__main__で実行されたコードにしか表示しないため、見落とされないようにするための設計です。
移行を進めるなら、CIで非推奨APIの新規利用をエラーにできます。pytestなら、設定ファイルのfilterwarningsに次のように書きます。
[pytest]
filterwarnings =
error::mcp.MCPDeprecationWarning
すでに大量の非推奨利用があるコードに入れると、一度にテストが失敗します。移行対象を整理してから導入するのが現実的です。一時的に警告を消したいだけなら、次のようにも書けます。
import warnings
from mcp import MCPDeprecationWarning
warnings.filterwarnings("ignore", category=MCPDeprecationWarning)
「Clientに聞く」から「Requestに明示する」へ
3機能の変更を設計の視点で見ると、共通した方向があります。以前は、ServerがClientに「Workspaceを教えて」「Modelを使わせて」「このLogを表示して」と要求していました。2026-07-28では、Protocol CoreがStatelessになり、ServerからClientへの常時のBack-channelに依存しない方向へ変わりました。
操作対象 → Tool Parameter / Resource URI Application状態 → 明示的なHandle / Server Configuration LLM実行 → Provider API 運用ログ → Application Logger Tracing → OpenTelemetry
Rootsなら「ServerがClientに聞く」から「ClientがRequestに対象を明示する」、Samplingなら「ClientのModelを借りる」から「ApplicationがModelを所有する」、Loggingなら「Clientに見せるログ」から「運用基盤へ送るログ」への変化です。これによりMCP Serverを、通常のHTTP基盤・Container・Load Balancer・監視基盤へ載せやすくなります。
Roots・Sampling・Logging非推奨に関するよくある質問
QRoots・Sampling・Loggingは、もう使えなくなりましたか?
A使えなくなったわけではありません。2026-07-28では非推奨になっただけで、非推奨の間は機能し続け、削除までに最低12か月あります。ただし新しい実装では採用しないよう公式が示しています。また、Python SDKでは接続の種類によって挙動が違い、2026-07-28の接続では従来のctx.session.create_message()はエラーになるなど、そのまま動かないものもあります。
Qpingやlogging/setLevelも非推奨ですか?
Aいいえ、これらは非推奨ではなく削除されています。2026-07-28のChangelogでは、ping・logging/setLevel・notifications/roots/list_changedが削除されました。ログレベルはリクエストごとに_metaのio.modelcontextprotocol/logLevelで指定する形に変わっています。
QMRTRがあるなら、Samplingを使い続けてもよいですか?
ASamplingの要求をInputRequiredResultで運ぶことはでき、既存の実装を2026-07-28で動かす手段にはなります。ただしそれは配送の仕組みの話で、新規の設計ではProvider APIへの直接接続が公式の移行先です。Clientが対応している必要もあります。
QRootsをTool Parameterにすると、モデルが任意のPathを指定できて危険ではありませんか?
ATool Parameterだけでは危険です。Logical IDをServer側のAllowlistでPathに解決する、入力Pathを正規化してRoot内かを確認する、Symlinkを解決する、といったServer側の検証が必要です。Rootsはもともと案内であり、Security Boundaryではありませんでした。
Q非推奨APIの利用をまとめて見つけるにはどうしますか?
APython SDKでは、非推奨の機能を使うとMCPDeprecationWarningが出ます。pytestのfilterwarningsにerror::mcp.MCPDeprecationWarningを指定すると、テストで新規利用を検出できます。既存コードに多数ある場合は、整理してから導入します。
これからのMCPサーバーは3機能に依存しない設計にする
2026年10月時点では、Roots・Sampling・Loggingはまだ利用できます。しかしSEP-2577でDeprecatedとなり、新しい実装ではこれらに依存しないことが求められています。
Workspaceや対象のDirectoryは、Tool Parameter・Resource URI・Server Configurationで明示します。File AccessのSecurityはRootsに頼らず、Server側のAllowlist、Canonical Path Validation、OS Permissionで強制します。LLMによる処理が必要なら、Samplingを前提にせず、Provider APIへ直接接続するService Layerを用意します。運用ログは標準のLoggingへ出し(stdioならstderr)、処理経路を追いたい場合はOpenTelemetryを使います。
既存のRoots・Samplingは、2026-07-28の接続ではInputRequiredResult経由で動かせる場合があります。しかし「MRTRがあるからDeprecatedを無視してよい」という意味ではありません。そしてping・logging/setLevel・notifications/roots/list_changedは、非推奨ではなくすでに削除されています。
Roots・Sampling・Loggingの非推奨は、単に3つの機能が整理される変更ではなく、MCPがセッションに依存した双方向のProtocolから、Statelessで通常のApplication基盤に載せやすいProtocolへ移行していることを示す変更です。ClientのWorkspace、ClientのLLM、ClientのLog ViewerにServerが暗黙に依存するのではなく、必要な情報と責務を明示的なInterfaceへ分けることが、これからの設計の基本になります。

