docs: refresh translations for recent English changes (#3379)
This commit is contained in:
parent
d8b638304e
commit
c5d7d0b6d0
18 changed files with 3149 additions and 1047 deletions
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [2c79b6338e09b7ac, 7edc43b3fae11314, 1086e77ce561cd7f, a3f71823df5efc31, 9fc7109f72201cae, 7bf25983df655b66, 6330e1f4c6029683, 2f1749c8c133fa1c, b3530fcf4d11fd56, ebc33704fbd74262, cd0e9c933350390e]
|
||||
sections: [2c79b6338e09b7ac, 7edc43b3fae11314, 1086e77ce561cd7f, a3f71823df5efc31, 9fc7109f72201cae, d50fe7faead8cf68, 7bf25983df655b66, 6330e1f4c6029683, 2f1749c8c133fa1c, 8db7116fc8ddd0ee, ebc33704fbd74262, cd0e9c933350390e]
|
||||
tool: 1
|
||||
---
|
||||
# 低レベルの Server {#the-low-level-server}
|
||||
|
|
@ -116,6 +116,17 @@ asyncio.run(main())
|
|||
|
||||
サーバーは 2 つのフィールドを比較しません。この SDK の `Client` は比較します。宣言した `output_schema` を満たさない `structured_content` を返すと、`call_tool` は `Invalid structured content returned by tool search_books` で始まり、続けて `jsonschema` の失敗内容を引用する `RuntimeError` を送出します。スキーマを約束するのは簡単ですが、守るのは自分の仕事です。戻り値の型とスキーマの全段階については **[構造化出力](../servers/structured-output.md)** を参照してください。
|
||||
|
||||
## ダイアレクトは JSON Schema 2020-12 {#the-dialect-is-json-schema-2020-12}
|
||||
|
||||
`input_schema` と `output_schema` は JSON Schema であり、[MCP 仕様](https://modelcontextprotocol.io/specification/latest/basic#json-schema-usage) がそのダイアレクトを定めています。`$schema` キーのないスキーマは **JSON Schema 2020-12** です。`MCPServer` が生成するスキーマはこのデフォルトに依存しています(Pydantic は 2020-12 を書き出し、キーを省略します)。手書きの dict にも同じ基準が適用されるので、2020-12 の語彙がすべて使えます。
|
||||
|
||||
```python title="server.py" hl_lines="8 14-15"
|
||||
--8<-- "docs_src/lowlevel/tutorial007.py"
|
||||
```
|
||||
|
||||
* `input_schema` のルートは `"type": "object"` でなければなりません。その横に置く `oneOf`、`additionalProperties`、`anyOf`、`if`/`then`/`else`、`prefixItems`、ローカルな `$ref` を伴う `$defs`、そのほかの 2020-12 キーワードは、書いたとおりにクライアントに届きます。
|
||||
* `$schema` キーは不要です。古いドラフトにオプトインする場合にだけ追加してください。この SDK の `Client` はツールの `output_schema` に照らして `structured_content` を検証しますが、バリデーターは `$schema` から選び、キーがなければ 2020-12 を使います。
|
||||
|
||||
## `_meta`:モデルではなくアプリケーションのために {#\_meta-for-the-application-not-the-model}
|
||||
|
||||
`content` は答えのうちモデルが読む部分です。`structured_content` は同じ答えを型付きデータにしたものです。`_meta` は 3 つ目のチャネルで、答えの一部ではまったくなく、**クライアントアプリケーション**のために結果に同乗するデータです。
|
||||
|
|
@ -166,7 +177,7 @@ asyncio.run(main())
|
|||
--8<-- "docs_src/lowlevel/tutorial006.py"
|
||||
```
|
||||
|
||||
* 最初の引数はメソッド文字列です。通知には対になる `add_notification_handler` があります。
|
||||
* 最初の引数はメソッド文字列です。通知には対になる `add_notification_handler` があります。そのハンドラーは stdio と、ハンドシェイク世代の HTTP 接続で発火します。`2026-07-28` の Streamable HTTP 経路では、クライアントの通知 POST は `202` で受理されるだけでディスパッチされません。このリビジョンは HTTP 上でのクライアントからサーバーへの通知を定義していないからです。
|
||||
* `params_type` は、受信した `params` をハンドラーの実行**前**に検証するためのモデルです。つまり、カスタムメソッドはツールが受けられない検証を受けられます。`_meta` フィールドがほかのメソッドと同じようにパースされるよう、`RequestParams` をサブクラス化してください。
|
||||
* ハンドラーは `BaseModel`、`dict`、または `None` を返します。SDK がそれを JSON-RPC の結果にシリアライズします。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [6048b4f308edbb8c, 068bda0f21ee9c1b, c3e565b61acd75c5, c62422b159c6ed09, 47204fab253cc45c]
|
||||
sections: [6048b4f308edbb8c, 46056f318ef205e4, c3e565b61acd75c5, c62422b159c6ed09, 420968f514138f43]
|
||||
tool: 1
|
||||
---
|
||||
# ミドルウェア {#middleware}
|
||||
|
|
@ -42,7 +42,7 @@ tools/call took 0.1 ms
|
|||
ここがポイントです。ミドルウェアは受信する**すべての**メッセージを包みます。
|
||||
|
||||
* 接続のセットアップ。`server/discover`、あるいはレガシーセッションでは `initialize` と `notifications/initialized` です。
|
||||
* すべてのリクエストとすべての通知。通知の場合は `ctx.request_id is None` であり、`call_next(ctx)` は `None` を返し、何を返しても破棄されます。
|
||||
* サーバーに届くすべてのリクエストとすべての通知。通知の場合は `ctx.request_id is None` であり、`call_next(ctx)` は `None` を返し、何を返しても破棄されます。(`2026-07-28` の Streamable HTTP 経路では、クライアントの通知 POST はトランスポートで `202` として受領されるだけでディスパッチされないため、ミドルウェアにも届きません。このリビジョンは HTTP 上でのクライアントからサーバーへの通知を定義していません。)
|
||||
* サーバーにハンドラーがないメソッドでさえ対象です。`call_next` は `MCPError(-32601, "Method not found")` を送出し、それがミドルウェアを「通り抜けて」クライアントへ向かいます。
|
||||
|
||||
## ミドルウェアの中でできること {#what-you-can-do-inside-one}
|
||||
|
|
@ -75,7 +75,7 @@ SDK が同梱するミドルウェアはちょうど 1 つで、すでにサー
|
|||
## まとめ {#recap}
|
||||
|
||||
* ミドルウェアは `async (ctx, call_next) -> result` です。`MCPServer(middleware=[...])` として渡すか(または `mcp.middleware` に追加し)、低レベルの `Server` では `server.middleware` に追加します。
|
||||
* 受信する**すべての**メッセージ(`server/discover`、`initialize`、リクエスト、通知、未知のメソッド)を包み、外側から順に実行されます。
|
||||
* サーバーに届く**すべての**受信メッセージ(`server/discover`、`initialize`、リクエスト、通知、未知のメソッド)を包み、外側から順に実行されます。
|
||||
* `ctx.request_id is None` で、通知とリクエストを見分けます。
|
||||
* `call_next` を呼ぶ代わりに例外を送出すると、メッセージを 1 つ拒否できます。接続は維持されます。
|
||||
* SDK 自身の OpenTelemetry トレースもミドルウェアであり、すでにリストに載っています。**[OpenTelemetry](../run/opentelemetry.md)** を参照してください。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [ebef1e7a0df854f4, a4c687d3d627d516, 8e79141fc2985342, b345dd05b9c3c7ab, 80ce41579825a6fa, 5f0fa90494de8f65, 83d10514eaa62fa5, 9190555aa39a5d28, 84a4c9d8bf14dddb, 927d71cf40b58c30]
|
||||
sections: [ebef1e7a0df854f4, 8355cfaf1f76c9d5, 8e79141fc2985342, 46bdb07c7537e8a5, 80ce41579825a6fa, 5f0fa90494de8f65, 83d10514eaa62fa5, 9190555aa39a5d28, 84a4c9d8bf14dddb, 927d71cf40b58c30]
|
||||
tool: 1
|
||||
---
|
||||
# Client {#the-client}
|
||||
|
|
@ -27,9 +27,10 @@ translation:
|
|||
|
||||
* `MCPServer`(または低レベルの `Server`)のインスタンス:**プロセス内**で接続します。
|
||||
* URL 文字列(`Client("http://localhost:8000/mcp")`):Streamable HTTP。本番向けの経路です。
|
||||
* **トランスポート**:`async with ... as (read, write)` できるものなら何でも。たとえばサブプロセスをラップする `stdio_client(...)` です。
|
||||
* `StdioServerParameters`:**サブプロセス**として起動するコマンドで、その stdin と stdout を通じて対話します。
|
||||
* **トランスポート**:`async with ... as (read, write)` できるものなら何でも。たとえば、自分の HTTP クライアントをラップする `streamable_http_client(url, http_client=...)` です。
|
||||
|
||||
このページの残りの内容は、3 つのどれでも同じです。ヘッダー、サブプロセス、タイムアウト、そして `Transport` プロトコルについては、専用のページ **[クライアントのトランスポート](transports.md)** があります。
|
||||
このページの残りの内容は、4 つのどれでも同じです。ヘッダー、サブプロセス、タイムアウト、そして `Transport` プロトコルについては、専用のページ **[クライアントのトランスポート](transports.md)** があります。
|
||||
|
||||
### 接続済みクライアントが持つもの {#whats-on-a-connected-client}
|
||||
|
||||
|
|
@ -82,7 +83,7 @@ tool.description # 'Search the catalog by title or author.'
|
|||
|
||||
`call_tool(name, arguments)` はツールを実行し、`CallToolResult` を返します。
|
||||
|
||||
```python title="client.py" hl_lines="26-33"
|
||||
```python title="client.py" hl_lines="27-34"
|
||||
--8<-- "docs_src/client/tutorial003.py"
|
||||
```
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ result.is_error # False
|
|||
例外を送出するツールが、クライアント側で例外を送出することは**ありません**。`is_error=True` の付いた通常の結果として返ってきます。
|
||||
|
||||
!!! check
|
||||
`lookup_book` に `"Solaris"`(カタログにない書名)を問い合わせると、関数は `ValueError` を送出します。それでも呼び出しは正常に返ります。
|
||||
`lookup_book` に `"Solaris"`(カタログにない書名)を問い合わせると、関数は `ToolError` を送出します。それでも呼び出しは正常に返ります。
|
||||
|
||||
```python
|
||||
result.is_error # True
|
||||
|
|
@ -121,7 +122,7 @@ result.is_error # False
|
|||
result.structured_content # None
|
||||
```
|
||||
|
||||
例外のメッセージは `content` に入りました。そこなら**モデル**が読んで、やり直せます。これは意図的なものです。ツールのエラーはクラッシュではなく、会話の一部です。`structured_content` を信用する前に、必ず `is_error` を確認してください。
|
||||
`ToolError` のメッセージは `content` に入りました。そこなら**モデル**が読んで、やり直せます。これは意図的なものです。ツールのエラーはクラッシュではなく、会話の一部です。(仮にツールが別の例外でクラッシュしていたら、`content` には `Error executing tool lookup_book` とだけ入ります。)`structured_content` を信用する前に、必ず `is_error` を確認してください。
|
||||
|
||||
!!! warning
|
||||
`is_error=True` がカバーするのは、自分で書いた `raise` だけではありません。サーバーに存在すらしないツールを要求しても(`call_tool("does_not_exist", {})`)、何も送出されません。同じ形の結果が返り、`is_error=True` で `content` には `Unknown tool: does_not_exist` が入ります。`Client` のメソッドが `MCPError` を送出するのは、サーバーが結果ではなく JSON-RPC の**エラー**で応答したときだけです。サーバーがどんなときにどちらを返すかは **[エラーの処理](../servers/handling-errors.md)** で扱っています。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [9cac816674181eb0, 0700f337babcd4dd, 2bde0dd58cdf00f5, ff7401df479af877, 3d0832f39b0d7059, d4bf7e4479637768, 05e20c0a798860e7]
|
||||
sections: [9cac816674181eb0, 0700f337babcd4dd, 2bde0dd58cdf00f5, 40b4916d82eaf1d4, 3d0832f39b0d7059, dfa4446556badef0, 5bd93be2ab2ecb9c]
|
||||
tool: 1
|
||||
---
|
||||
# クライアントのトランスポート {#client-transports}
|
||||
|
|
@ -74,17 +74,17 @@ TLS について 1 点。`httpx2` は、同梱の CA リストではなく、オ
|
|||
|
||||
## stdio {#stdio}
|
||||
|
||||
**stdio** サーバーはサブプロセスです。クライアントがそれを起動し、stdin に JSON-RPC を書き込み、stdout から JSON-RPC を読み取ります。デスクトップのホストが手元のマシンでサーバーを動かす方法がこれです。ホストとは、このコードに UI を加えたもの「そのもの」です。**[本物のホストに接続する](../get-started/real-host.md)** は、同じ関係をホストの側から設定ファイルとして見たものです。
|
||||
**stdio** サーバーはサブプロセスです。クライアントがそれを起動し、stdin に JSON-RPC を書き込み、stdout から JSON-RPC を読み取ります。デスクトップのホストが手元のマシンでサーバーを動かす方法がこれです。ホストとは、まさにこのコードに UI を加えたものです。**[本物のホストに接続する](../get-started/real-host.md)** は、同じ関係をホストの側から設定ファイルとして見たものです。
|
||||
|
||||
`StdioServerParameters` でプロセスを記述し、`stdio_client` でトランスポートに変換して、「それ」を `Client` に渡します。
|
||||
`StdioServerParameters` でプロセスを記述し、それを `Client` に渡します。
|
||||
|
||||
```python title="client.py" hl_lines="4-8 12"
|
||||
```python title="client.py" hl_lines="3-7 11"
|
||||
--8<-- "docs_src/client_transports/tutorial004.py"
|
||||
```
|
||||
|
||||
`Client` はパラメーターオブジェクトをそのままでは受け取りません。`StdioServerParameters` は設定であり、`stdio_client(server)` はそこからプロセスを起動する方法を知っているトランスポートです。必ず包んでください。
|
||||
ブロックに入るとプロセスが起動します。抜けるとサブプロセスは終了されます。stdin を閉じ、待機し、居残っていれば強制終了します。自分で後始末をすることはありません。
|
||||
|
||||
`async with` ブロックを抜けると、サブプロセスも終了されます。stdin を閉じ、待機し、居残っていれば強制終了します。自分で後始末をすることはありません。
|
||||
子プロセスの stderr は自分の stderr に流れます。別の場所に送るには、`stdio_client`(`mcp` にあります)でトランスポートを自分で組み立て、代わりにそれを渡してください。`Client(stdio_client(server, errlog=log_file))` のように書きます。
|
||||
|
||||
!!! warning
|
||||
子プロセスは環境変数を継承**しません**。最小限の許可リスト(POSIX では `HOME`、`LOGNAME`、`PATH`、`SHELL`、`TERM`、`USER`)だけを受け取るので、自分が書いたとは限らないプロセスに機密情報が漏れることはありません。
|
||||
|
|
@ -99,16 +99,16 @@ TLS について 1 点。`httpx2` は、同梱の CA リストではなく、オ
|
|||
|
||||
`Client` から見れば、上記はすべて同じものです。
|
||||
|
||||
**トランスポート**とは、`(read, write)` というメッセージストリームのペアを yield する非同期コンテキストマネージャーのことです。正式には `mcp.client` の `Transport` プロトコルです。`Client` は引数を型で解決します。サーバーオブジェクトならインプロセスで接続し、`str` なら `streamable_http_client(url)` になり、それ以外は直接トランスポートとして入ります。この最後の規則があるからこそ、`stdio_client(...)`、`streamable_http_client(...)`、`sse_client(...)` はすべて同じ場所に収まり、自分で独自のものを書くこともできます。
|
||||
**トランスポート**とは、`(read, write)` というメッセージストリームのペアを yield する非同期コンテキストマネージャーのことです。正式には `mcp.client` の `Transport` プロトコルです。`Client` は引数を型で解決します。サーバーオブジェクトならインプロセスで接続し、`str` なら `streamable_http_client(url)` になり、`StdioServerParameters` なら `stdio_client(params)` になり、それ以外は直接トランスポートとして入ります。この最後の規則があるからこそ、`stdio_client(...)`、`streamable_http_client(...)`、`sse_client(...)` はすべて同じ場所に収まり、自分で独自のものを書くこともできます。
|
||||
|
||||
## まとめ {#recap}
|
||||
|
||||
* `Client(mcp)`(サーバーオブジェクト)はインメモリで接続します。テストと組み込みに使ってください。
|
||||
* `Client("http://.../mcp")`(URL)は、本番用のトランスポートである Streamable HTTP で接続します。
|
||||
* ヘッダー、認証、プロキシ、タイムアウトは、`streamable_http_client(url, http_client=...)` に渡す `httpx2.AsyncClient` に設定します。`headers=` キーワードはありません。
|
||||
* stdio は `Client(stdio_client(StdioServerParameters(...)))` であり、パラメーターオブジェクト単体では決してありません。
|
||||
* stdio は `Client(StdioServerParameters(...))` です。自分で `stdio_client(...)` に包むのは、子プロセスの stderr をリダイレクトしたいときだけです。
|
||||
* サブプロセスが受け取るのは自分の環境ではなく、許可リストに基づく環境です。`env=` でそこに追加します。
|
||||
* トランスポートとは、`async with x as (read, write)` と書けるものすべてです。`Client` は、サーバーオブジェクトでも URL でもないものをそのままこのプロトコルに渡します。
|
||||
* トランスポートとは、`async with x as (read, write)` と書けるものすべてです。`Client` は、サーバーオブジェクトでも URL でも `StdioServerParameters` でもないものを、そのままこのプロトコルに渡します。
|
||||
* `Client` の構築でトランスポートが選ばれ、`async with` でそれが開かれます。
|
||||
|
||||
トランスポートが開いたら、両者はプロトコルバージョンについて合意する必要があります。普段は意識することはありません。意識することになったら、**[プロトコルバージョン](../protocol-versions.md)** のページを参照してください。
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
translation:
|
||||
sections: [20541a40dbdd5980, 01262a123ad9501d, 429db5b574a2ac08, 56b2d49da412cb28, 6a1717123fe4513c]
|
||||
sections: [490237e61c3a7a44, 01262a123ad9501d, 429db5b574a2ac08, e2d0d273fbd2d74b, 64ab0331e868f3d4, 6c8878ce2d1f6d56, 4068f23e371bf0b3, eaef75b8725bc931]
|
||||
tool: 1
|
||||
---
|
||||
# 非推奨の機能 {#deprecated-features}
|
||||
|
||||
2026-07-28 の仕様では、5 つのものが役目を終えます。SDK は今もその 5 つすべてを実装しており、そのすべてに**非推奨の警告**が付くようになりました。
|
||||
2026-07-28 の仕様では、5 つのものが役目を終えます。SDK は今もその 5 つすべてを実装しており、そのすべてに**非推奨の警告**が付くようになりました。SDK のヘルパーが 1 つ、仕様とは別の理由で非推奨になっており、[ページの最後](#deprecated-sdk-helpers)に挙げています。
|
||||
|
||||
下の表は、非推奨になった機能それぞれについて、なくなる理由と、代わりに土台にすべきものを挙げています。
|
||||
|
||||
|
|
@ -49,6 +49,55 @@ MCPDeprecationWarning: The logging capability is deprecated as of 2026-07-28 (SE
|
|||
|
||||
シグナルは 2 つ、この順番です。`MCPDeprecationWarning` は、どの接続でもメソッドを呼び出した瞬間に発生します。エラーは、そのあと SDK が送信を試みたときに返ってくるものです。この 2 つの機能がエンドツーエンドで動作するのは、対応するコールバックをクライアントが登録した `mode="legacy"` の接続だけです。
|
||||
|
||||
## レガシーセッションでの `ping` {#ping-on-a-legacy-session}
|
||||
|
||||
**ping** は、相手がまだ応答しているかを確かめるために、どちらの側からでも送れる空のリクエストです。2026-07-28 の仕様はこれを削除します([SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575))。現行仕様のクライアントが送るリクエストはどれも、それ自体がサーバーの存在を証明していますし、現行仕様のサーバーには ping を送るチャネルがありません。SDK の 2 つのメソッドはどちらも、ハンドシェイク世代のセッションでは引き続き動作します。クライアント側からは次のように書きます。
|
||||
|
||||
```python
|
||||
async def main() -> None:
|
||||
async with Client("http://localhost:8000/mcp", mode="legacy") as client:
|
||||
await client.send_ping() # warns; returns an EmptyResult
|
||||
```
|
||||
|
||||
サーバー側からは、任意のハンドラーの中で次のように書きます。
|
||||
|
||||
```python
|
||||
@mcp.tool()
|
||||
async def check_client(ctx: Context) -> str:
|
||||
"""A tool that still pings the client mid-call."""
|
||||
await ctx.session.send_ping() # no warning; an EmptyResult while the client is connected
|
||||
return "client answered"
|
||||
```
|
||||
|
||||
* `client.send_ping()` は呼び出しのたびに `MCPDeprecationWarning` で警告します。デフォルト(`2026-07-28`)の接続では、サーバーは代わりに `MCPError: Method not found` と応答します。
|
||||
* `ctx.session.send_ping()` には警告がありません。現行仕様の接続では、ほかのサーバー起点のリクエストと同じく、バックチャネル(back-channel)がないというエラーを送出します。
|
||||
* どちらの側も、ping に応答するために何かを登録する必要はありません。
|
||||
|
||||
## ルートの変更通知 {#roots-change-notifications}
|
||||
|
||||
ルートのケイパビリティを宣言した 2025 年世代のクライアントは、`notifications/roots/list_changed` を送ることで、ワークスペースのフォルダーが変わったことをサーバーに伝えられます。サーバーはそれを受けて `roots/list` をもう一度リクエストします。2026-07-28 の仕様は、プッシュ型のルートのフローの残りとともに、この通知を削除します。クライアント側では、`list_roots_callback=` を渡すこと(**[クライアントのコールバック](client/callbacks.md)**)が `"roots": {"listChanged": true}` の宣言にあたり、1 回の呼び出しでその約束を果たします。
|
||||
|
||||
```python
|
||||
async def open_folder(client: Client, uri: str, name: str) -> None:
|
||||
"""The user opened another folder: expose it through the roots callback, then tell the server."""
|
||||
workspace.append(Root(uri=FileUrl(uri), name=name))
|
||||
await client.send_roots_list_changed()
|
||||
```
|
||||
|
||||
サーバー側では、低レベルの `Server` が受信側のハンドラーを受け取ります。
|
||||
|
||||
```python
|
||||
async def roots_changed(ctx: ServerRequestContext, params: NotificationParams | None) -> None:
|
||||
"""The client's roots changed: ask for the new list."""
|
||||
roots = (await ctx.session.list_roots()).roots
|
||||
|
||||
|
||||
server = Server("Bookshop", on_roots_list_changed=roots_changed)
|
||||
```
|
||||
|
||||
* `workspace` は `list_roots_callback` が返すリストです。`client.send_roots_list_changed()` は警告を出し、`mode="legacy"` のクライアントが必要です。現行仕様の接続では、通知は黙って捨てられます。サーバーからの後続の `roots/list` は同じセッションに届くので、呼び出したあともセッションは開いたままにしてください。
|
||||
* `MCPServer` にはこの通知のフックがありません。低レベルの `Server` では `on_roots_list_changed=` がハンドラーを登録します(これも非推奨で、構築時に警告を出します)。通知はペイロードを運ばないので、ハンドラーは `ctx.session.list_roots()` を呼んで新しいリストを取得します。
|
||||
|
||||
## 警告を抑止する {#silencing-the-warning}
|
||||
|
||||
新しいコードでは、しないでください。
|
||||
|
|
@ -66,21 +115,30 @@ warnings.filterwarnings("ignore", category=MCPDeprecationWarning)
|
|||
API はこれだけです。メソッドごとのスイッチはありませんし、必要もありません。カテゴリが 1 つである利点は、1 行で黙らせ、1 行で元に戻せることです。
|
||||
|
||||
!!! check
|
||||
フィルターを逆向きにかければ、無料で回帰テストが手に入ります。pytest の設定の `filterwarnings` に `"error::mcp.MCPDeprecationWarning"` を追加すると、非推奨の呼び出しは警告ではなく**例外を送出**します。まだ `ctx.info()` を呼んでいる `old_log` という名前のツールは通らなくなり、次のように報告し始めます。
|
||||
フィルターを逆向きにかければ、無料で回帰テストが手に入ります。pytest の設定の `filterwarnings` に `"error::mcp.MCPDeprecationWarning"` を追加すると、非推奨の呼び出しは警告ではなく**例外を送出**します。まだ `ctx.info()` を呼んでいる `old_log` という名前のツールは通らなくなります。呼び出しは `is_error=True` と `Error executing tool old_log` を伴って返り、キャプチャされたサーバーのログが原因を名指しします。
|
||||
|
||||
```text
|
||||
Error executing tool old_log: The logging capability is deprecated as of 2026-07-28 (SEP-2577).
|
||||
mcp.shared.exceptions.MCPDeprecationWarning: The logging capability is deprecated as of 2026-07-28 (SEP-2577).
|
||||
```
|
||||
|
||||
pytest の設定を 1 行足すだけで、非推奨の呼び出しがテストを失敗させずにコードベースへ紛れ込むことは二度とありません。
|
||||
|
||||
## 非推奨の SDK ヘルパー {#deprecated-sdk-helpers}
|
||||
|
||||
これらは仕様の変更ではなく、よりよい代替がある SDK の内部実装にすぎません。同じ `MCPDeprecationWarning` で警告し、3.0 で削除されます。
|
||||
|
||||
| 非推奨 | 代わりにすること |
|
||||
|---|---|
|
||||
| `FuncMetadata.call_fn_with_arg_validation()` | `FuncMetadata.validate_arguments()` を呼んでから `FuncMetadata.call_fn()` を呼びます。これを呼んでいたのは、`FuncMetadata` を直接扱うコード(たとえば独自の `Tool` サブクラス)だけです。 |
|
||||
|
||||
## まとめ {#recap}
|
||||
|
||||
* 2026-07-28 の仕様は、**ルート**、サーバー起点の**サンプリング**、プロトコルの**ロギング**を非推奨にし(いずれも [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577))、**進捗**をサーバーからクライアントへの方向に限定し、**`ping`** を削除します。
|
||||
* 「代わりにすること」の列が次の行き先を示しています。サンプリングとルートには **[マルチラウンドトリップリクエスト](handlers/multi-round-trip.md)**、ロギングには **[ロギング](handlers/logging.md)**、進捗には **[進捗](handlers/progress.md)** です。`ping` には何も必要ありません。
|
||||
* 非推奨は勧告にすぎません。通信上の変更はなく、2026 年より前のセッションに対してはすべてが引き続き動作します。そして目に見える `MCPDeprecationWarning` が出ます(`UserWarning` なので、デフォルトで有効です)。
|
||||
* サンプリングとルートにはさらに、2026-07-28 のセッションにはないバックチャネル(back-channel)が必要です。現行仕様の接続では警告を出し、そのあと例外を送出します。
|
||||
* サンプリングとルートにはさらに、2026-07-28 のセッションにはないバックチャネルが必要です。現行仕様の接続では警告を出し、そのあと例外を送出します。
|
||||
* `warnings.filterwarnings("ignore", category=MCPDeprecationWarning)` でカテゴリ全体を黙らせます。pytest で `"error::mcp.MCPDeprecationWarning"` を指定すれば、テストの失敗に変わります。
|
||||
* SDK のヘルパー `FuncMetadata.call_fn_with_arg_validation()` は、これとは別に非推奨になっており、3.0 で削除されます。
|
||||
* 新しいコードは、これらのどれの上にも築くべきではありません。
|
||||
|
||||
このドキュメントのほかのページはすべて、現行の API を扱っています。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [3c4f2f06b4e978b6, 22520eecae3d1961, f4e1709db18d635a, 2eb57992049671d9, 1ba83e9af37cc1b4, 4822586344b08d9e, 1c93afef72478992, b6b448f9eddd51dc, fe55370fd931815b]
|
||||
sections: [3c4f2f06b4e978b6, 51ea5fbcb0e93563, 32d8808606ffdae0, 2eb57992049671d9, 1ba83e9af37cc1b4, 4822586344b08d9e, 1c93afef72478992, b6b448f9eddd51dc, fe55370fd931815b]
|
||||
tool: 1
|
||||
---
|
||||
# 実際のホストに接続する {#connect-to-a-real-host}
|
||||
|
|
@ -11,7 +11,7 @@ translation:
|
|||
|
||||
## 1 つのサーバー、すべてのホスト {#one-server-every-host}
|
||||
|
||||
```python title="server.py" hl_lines="3 33-34"
|
||||
```python title="server.py" hl_lines="4 34-35"
|
||||
--8<-- "docs_src/real_host/tutorial001.py"
|
||||
```
|
||||
|
||||
|
|
@ -39,9 +39,9 @@ uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
|
|||
ホストは最小限の `PATH` でサーバーを起動するため、そこに `uv` が入っていないことがあります。`uv` とだけ書いた部分を、`which uv`(macOS/Linux)または `where uv`(Windows)で得られる絶対パスに置き換えてください。`mcp install` が書き込むのもまさにこの形です。
|
||||
|
||||
!!! note "このページはローカルの話"
|
||||
ここで扱うものはすべて、ホストと同じマシン上でサーバーを動かします。ホストがファイルを stdio 経由で起動する形です。個人用のツールや 1 台のマシンで使うツールなら、まさにこれが正解です。ファイルを持って**いない**人たちにサーバーを渡すには、コマンドではなく **URL** を配ります。つまり、同じ `mcp` オブジェクトを Streamable HTTP で提供します。**[サーバーの実行](../run/index.md)** はその判断を 1 つの表にまとめており、**[デプロイとスケール](../run/deploy.md)** はそこから実際のホスト名に至るまでの道のりです。
|
||||
ここで扱うものはすべて、ホストと同じマシン上でサーバーを動かします。ホストがファイルを stdio 経由で起動する形です。個人用のツールや 1 台のマシンで使うツールなら、まさにこれが正解です。ファイルを持っていない人たちにサーバーを渡すには、コマンドではなく **URL** を配ります。つまり、同じ `mcp` オブジェクトを Streamable HTTP で提供します。**[サーバーの実行](../run/index.md)** はその判断を 1 つの表にまとめており、**[デプロイとスケール](../run/deploy.md)** はそこから実際のホスト名に至るまでの道のりです。
|
||||
|
||||
また、ホストとは内部に MCP クライアントを持つアプリケーションにすぎないので、自分の Python コードがホストの役を演じることもできます。**[クライアントのトランスポート](../client/transports.md)** ではこの同じファイルを `stdio_client(...)` でサブプロセスとして起動し、**[テスト](testing.md)** ではプロセスを一切使わずにメモリ内で接続します。
|
||||
また、ホストとは内部に MCP クライアントを持つアプリケーションにすぎないので、自分の Python コードがホストの役を演じることもできます。**[クライアントのトランスポート](../client/transports.md)** ではこの同じファイルを `Client(StdioServerParameters(...))` でサブプロセスとして起動し、**[テスト](testing.md)** ではプロセスを一切使わずにメモリ内で接続します。
|
||||
|
||||
## Claude Desktop {#claude-desktop}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: ['4926721070127497', c52a1de2b6b32f40, 2e410b412c25f314, 627195f7159e24ef]
|
||||
sections: ['4926721070127497', c52a1de2b6b32f40, 8e792bf8c7489ec6, 627195f7159e24ef]
|
||||
tool: 1
|
||||
---
|
||||
# テスト {#testing}
|
||||
|
|
@ -80,7 +80,7 @@ async def test_call_add_tool(client: Client):
|
|||
|
||||
問題が起こりうる場所は 2 種類あり、このフラグが関わるのはそのうちの一方だけです。
|
||||
|
||||
**ツール**の内部で発生した例外は、プロトコル上の失敗ではありません。`is_error=True` の付いた通常の結果になり、モデルがそのメッセージを読みます。`raise_exceptions` はこの挙動を変えません。指定してもしなくても、`call_tool` は同じ `is_error=True` の結果を返します。これについては専用のページがあります。**[エラーの処理](../servers/handling-errors.md)** を参照してください。
|
||||
**ツール**の内部で発生した例外は、プロトコル上の失敗ではありません。`is_error=True` の付いた通常の結果になります(`ToolError` だった場合は、モデルがそのメッセージを読みます)。`raise_exceptions` はこの挙動を変えません。指定してもしなくても、`call_tool` は同じ `is_error=True` の結果を返します。これについては専用のページがあります。**[エラーの処理](../servers/handling-errors.md)** を参照してください。
|
||||
|
||||
ツール本体の**外側**で起きた失敗は事情が異なります。`Client(mcp)` で得られる接続では、クライアントの目に触れる前に、サーバーがその失敗を汎用の `"Internal server error"` にサニタイズします。予期しないクラッシュの詳細は、リモートの呼び出し側に決して漏らしてはいけないからです。しかしテストでは、これはまさに望まない挙動です。そして `raise_exceptions=True` が変えるのはまさにこの点で、テストからはサニタイズ後のメッセージではなく本来のメッセージが見えるようになります。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [335ca2a0b266f003, d1ad562d3fe87bc0, 0bb1396c86daeba4, d1cb1235bb9ee267, 833179c09d239c83, e5d6dec2d2e655e8]
|
||||
sections: [335ca2a0b266f003, d1ad562d3fe87bc0, 25b49f89c9e6f9d0, d1cb1235bb9ee267, 833179c09d239c83, e5d6dec2d2e655e8]
|
||||
tool: 1
|
||||
---
|
||||
# エリシテーション {#elicitation}
|
||||
|
|
@ -83,7 +83,7 @@ translation:
|
|||
このスキーマがフォームです。`Field(description=...)` がラベルになり、デフォルト値は入力欄にあらかじめ入って、そのフィールドを省略可能にします。これは、**[ツール](../servers/tools.md)** のページがツールの引数について説明しているのと同じ、Pydantic から JSON Schema への変換の仕組みです。
|
||||
|
||||
!!! warning
|
||||
エリシテーションのスキーマは、ツールの入力スキーマほど表現力がありません。フラットなプリミティブ型のフィールドだけです。`str`、`int`、`float`、`bool`、または文字列の `Literal`(`enum` になります)。モデルの中にモデルを入れると、クライアントに何かを送る前に `ctx.elicit` が例外を送出します。
|
||||
エリシテーションのスキーマは、ツールの入力スキーマほど表現力がありません。フラットなプリミティブ型のフィールドだけです。`str`、`int`、`float`、`bool`、または文字列の `Literal`(`enum` になります)。モデルの中にモデルを入れると、クライアントに何かを送る前に `ctx.elicit` が例外を送出します。ツール呼び出しは `Error executing tool <name>` で失敗し、サーバーログにはその理由が残ります。
|
||||
|
||||
```text
|
||||
TypeError: Elicitation schema field 'address' rendered as {'$ref': '#/$defs/Address'}, which is not a valid PrimitiveSchemaDefinition
|
||||
|
|
@ -104,7 +104,7 @@ translation:
|
|||
断られてもエラーではありません。断られたことが何を意味するか(ここでは、予約しないこと)はツールが決め、モデルには普通に答えます。
|
||||
|
||||
!!! tip
|
||||
答えは、コードに届く前にモデルに照らして検証されます。`bool` に `"maybe"` を送ってくるクライアントがいても、予約が壊れることはありません。呼び出しはスキーマ不一致のエラーで失敗し、`if` は実行されません。
|
||||
答えは、コードに届く前にモデルに照らして検証されます。`bool` に `"maybe"` を送ってくるクライアントがいても、予約が壊れることはありません。`ctx.elicit` が `ValueError` を送出し、呼び出しは失敗し、`if` は実行されません。
|
||||
|
||||
## ユーザーを URL へ誘導する {#send-the-user-to-a-url}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [c93a3e1aefd77955, 7851abd5ec54393b, f49d1ca2f330f9cd, c03764bd9dfeef7b, 4a0391691a674ae4, 2df5cd279eabf9f5]
|
||||
sections: [c93a3e1aefd77955, 7851abd5ec54393b, f49d1ca2f330f9cd, 4cc0a00347c3f534, 4a0391691a674ae4, 2df5cd279eabf9f5]
|
||||
tool: 1
|
||||
---
|
||||
# ロギング {#logging}
|
||||
|
|
@ -49,6 +49,8 @@ MCP にはプロトコルレベルの**ロギングのケイパビリティ**が
|
|||
|
||||
`logging.basicConfig()` は、すでに存在するハンドラーを置き換えることはありません。サーバーを作成する前に自分でロギングを設定していれば、その設定が優先されます。
|
||||
|
||||
失敗を記録するためだけに、すべてのハンドラーに `try`/`except` を書く必要もありません。ツールやリソースの関数が例外を送出すると、SDK が代わりにログを出力します。何がどのレベルで記録されるかは、**[エラーの処理](../servers/handling-errors.md#any-other-exception)** で説明しています。
|
||||
|
||||
## 試してみる {#try-it}
|
||||
|
||||
MCP Inspector でサーバーを実行してください。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [fea8d769ff9edeba, ce8e2ad42f29ef71, 0d705efb19cf99c2, 7a53ead3e704a7f0, 9adc400e8c88e854, 318893ad8e2e9924, 6b63ab96b34476c0]
|
||||
sections: [fea8d769ff9edeba, ce8e2ad42f29ef71, 0d705efb19cf99c2, 2fd7cf825e6d2b2c, 9adc400e8c88e854, 318893ad8e2e9924, 6b63ab96b34476c0]
|
||||
tool: 1
|
||||
---
|
||||
# サーバーの実行 {#running-your-server}
|
||||
|
|
@ -71,7 +71,7 @@ Inspector は本物のホストとまったく同じことをします。`server
|
|||
* `streamable_http_path`:MCP エンドポイントの場所です。デフォルトは `/mcp` です。
|
||||
* `json_response=True`:各 POST に SSE ストリームではなく単一の JSON ボディで応答します。このボディにはレスポンスしか入る余地がありません。そのため、リクエストの途中でクライアントを呼び返すツール(`ctx.elicit()` やサンプリング)は、この区間で `NoBackChannelError` を送出します。進行中の呼び出しに紐づく通知(`ctx.report_progress()` による進捗や呼び出しごとのログメッセージ)は破棄されますが、独立した `GET` ストリームは無関係な通知を引き続き運びます。
|
||||
* `stateless_http=True`:リクエストごとに新しいトランスポートを作り、セッションを追跡しません。
|
||||
* `max_request_body_size`:受け付ける POST ボディの最大サイズ(バイト単位)です。デフォルトは 4 MiB で、これより大きいリクエストはパースやセッション作成の前に HTTP 413 を受け取ります。正当な MCP メッセージがこのサイズを超える場合にだけ引き上げてください。
|
||||
* `max_request_body_size`:受け付けるリクエストボディの最大サイズ(バイト単位)です。デフォルトは 4 MiB で、これより大きいリクエストはパースやセッション作成の前に HTTP 413 を受け取ります。正当な MCP メッセージがこのサイズを超える場合にだけ引き上げてください。
|
||||
* `event_store`、`retry_interval`、`transport_security`:再開可能性と DNS リバインディング保護です。localhost 以外の場所にデプロイするまでは後回しでかまいません。`transport_security` については **[デプロイとスケール](deploy.md)** で扱います。
|
||||
|
||||
!!! warning
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
---
|
||||
translation:
|
||||
sections: [e33d441f12d50535, 7099694c603e0f5f, c1df4cf9673433e6, c9cd294541422e6e, 6cec073617bfd037, efa92b8f99e908c8, 6a22a29e27fb4601]
|
||||
sections: [7be05607887e6853, e7375894888d9750, c36f73fc7e3af13b, 2fec2d7e129e62fe, 809b0e0a7c27295a, b4395a04d2a5d906, 1a436007f5f54779, c6b2078ed1e63ba5]
|
||||
tool: 1
|
||||
---
|
||||
# エラーの処理 {#handling-errors}
|
||||
|
||||
ツールの失敗には 2 通りあり、SDK はそれぞれをまったく違う形で扱います。
|
||||
ツールの失敗には 3 通りあり、SDK はそれぞれを違う形で扱います。
|
||||
|
||||
通常の例外を送出すると、**モデル**がそれを目にします。`MCPError` を送出すると、**プロトコル**がそれを目にします。
|
||||
`ToolError` を送出すると、**モデル**がメッセージを目にします。`MCPError` を送出すると、**プロトコル**がそれを目にします。それ以外を送出するとクラッシュです。モデルには呼び出しが失敗したことだけが伝わり、トレースバックはログに記録されます。
|
||||
|
||||
このページは、そのどちらを選ぶかについてです。
|
||||
このページは、そのどれを選ぶかについてです。
|
||||
|
||||
## モデルが直せるエラー {#an-error-the-model-can-fix}
|
||||
|
||||
何かを検索するツールを用意し、その検索を空振りさせてみます。
|
||||
|
||||
```python title="server.py" hl_lines="11-12"
|
||||
```python title="server.py" hl_lines="2 12-13"
|
||||
--8<-- "docs_src/handling_errors/tutorial001.py"
|
||||
```
|
||||
|
||||
この 2 行に MCP らしいところは何もありません。`get_author` は、どんな Python 関数でもそうするように、ただの `ValueError` を送出しているだけです。
|
||||
`mcp.server.mcpserver.exceptions` にある `ToolError` は、何かがうまくいかなかったことをツールがモデルに伝える手段です。
|
||||
|
||||
カタログにないタイトルで呼び出して、結果を見てみましょう。
|
||||
|
||||
|
|
@ -30,19 +30,21 @@ result.structured_content # None
|
|||
```
|
||||
|
||||
* リクエストは**成功**しています。結果が返っており、呼び出し側では何も送出されていません。
|
||||
* `is_error` は `True` で、例外のメッセージ(ツール名が前に付きます)が `content` に入っています。まさにモデルが読む場所です。
|
||||
* `is_error` は `True` で、メッセージ(ツール名が前に付きます)が `content` に入っています。まさにモデルが読む場所です。
|
||||
* `structured_content` は `None` です。失敗した呼び出しには、構造化すべき戻り値がありません。
|
||||
|
||||
これが**ツールエラー**で、ツールが送出する「あらゆる」例外のデフォルトの扱いです。そして、ほとんどの場合これこそが望む挙動です。
|
||||
これが**ツールエラー**で、ほとんどの場合これこそが望む挙動です。
|
||||
|
||||
ツールを呼び出しているのはモデルです。引数を選んだのもモデルです。つまりツールエラーは会話の 1 ターンになります。モデルは「No book titled 'Nothing' in the catalog.」を読み、タイトルを推測し損ねたことに気づき、もっと良いタイトルで呼び直します。`raise` を 1 つ書いただけで、自己修正するエージェントが手に入りました。
|
||||
|
||||
サーバー側では、`ToolError` はログに `INFO` が 1 行出るだけで、トレースバックはありません。想定していた失敗なので、調べることは何もありません。
|
||||
|
||||
!!! tip
|
||||
ツールからエラーメッセージを `return` しないでください。返された文字列は `is_error=False` なので、モデルにとっても(そしてあらゆるクライアント UI にとっても)ツールは正常に動作し、その文字列が答えだったように見えます。`raise` してください。シグナルはこのフラグです。
|
||||
|
||||
## モデルが直せないエラー {#an-error-the-model-cannot-fix}
|
||||
|
||||
今度は `ValueError` を `MCPError` に置き換えます。
|
||||
今度は `ToolError` を `MCPError` に置き換えます。
|
||||
|
||||
```python title="server.py" hl_lines="1 3 14"
|
||||
--8<-- "docs_src/handling_errors/tutorial002.py"
|
||||
|
|
@ -74,16 +76,35 @@ result.structured_content # None
|
|||
|
||||
2 つの経路は、2 つの異なる問いに答えるものです。
|
||||
|
||||
* 「実行」の失敗、つまりツールがやろうとしたことがうまくいかなかった場合は、**任意の例外を送出**します。呼び出しを選んだのはモデルなので、モデルがその結果を目にし、立て直す機会を得るべきです。綴りの間違ったタイトル、タイムアウトした上流の API、存在しない行。どれもツールエラーです。
|
||||
* 「実行」の失敗、つまりツールがやろうとしたことがうまくいかなかった場合は、**`ToolError` を送出**します。呼び出しを選んだのはモデルなので、モデルがその結果を目にし、立て直す機会を得るべきです。綴りの間違ったタイトル、タイムアウトした上流の API、存在しない行。どれもツールエラーです。
|
||||
* 「リクエストそのもの」を拒否すべきときは **`MCPError` を送出**します。ツールが依存するケイパビリティをクライアントが持っていない、サーバーが誰にも応答できる状態にない、呼び出し側が必要な手順を飛ばした。どれもモデルが再試行しても直らないので、メッセージを渡しても得るものはありません。
|
||||
|
||||
決め手になる問いは 1 つです。**もっと賢いモデルならこれを避けられたか**。はい → 通常の例外。いいえ → `MCPError`。
|
||||
決め手になる問いは 1 つです。**もっと賢いモデルならこれを避けられたか**。はい → `ToolError`。いいえ → `MCPError`。
|
||||
|
||||
この基準で見ると、`get_author` の 2 番目のバージョンは選択を誤っています。より良いタイトルで直るのですから、モデルはメッセージを見るべきでした。あれは仕組みを見せるためのもので、推奨するためのものではありません。
|
||||
|
||||
!!! info
|
||||
`MCPError` は `from mcp import MCPError` でインポートでき、`code`、`message`、省略可能な `data` ペイロードを受け取ります。そこに入れた内容がそのままクライアントに届きます。SDK は送出された `MCPError` をサニタイズせず、そのまま転送します。
|
||||
|
||||
## その他の例外 {#any-other-exception}
|
||||
|
||||
今度はチェックを外し、辞書の検索がそれ自体で失敗するのに任せます。
|
||||
|
||||
```python title="server.py" hl_lines="11"
|
||||
--8<-- "docs_src/handling_errors/tutorial004.py"
|
||||
```
|
||||
|
||||
`CATALOG[title]` は `KeyError` を送出します。想定していなかった例外なので、SDK はクラッシュとして扱います。
|
||||
|
||||
```python
|
||||
result.is_error # True
|
||||
result.content # [TextContent(text="Error executing tool get_author")]
|
||||
```
|
||||
|
||||
呼び出しは依然として `is_error=True` を返すので、モデルは失敗したことを知り、先へ進めます。受け取らないのは例外のテキストです。コードから出た `KeyError` や、3 つ下の層のライブラリのドライバーが吐いた SQL の山は、サーバーの内部を説明してしまうかもしれません。そのため、サーバーの外には決して出ません。
|
||||
|
||||
それを受け取るのはサーバー側です。サーバーはクラッシュを `ERROR` レベルで完全なトレースバック付きで記録し、`Tool 'get_author' raised an unexpected exception` と出力します。したがって、`WARNING` レベルの本番ログはどの `ToolError` でも静かなままで、本当に何かが壊れた瞬間に声を上げます。
|
||||
|
||||
## 存在しないリソース {#a-resource-that-doesnt-exist}
|
||||
|
||||
リソースも同じ線引きをします。そして、よくあるケースのために名前付きの例外を 1 つ用意しています。
|
||||
|
|
@ -104,7 +125,7 @@ result.structured_content # None
|
|||
}
|
||||
```
|
||||
|
||||
ここには `is_error=True` のような中間的な結果がないことに注目してください。リソースの読み取りは、内容を返すか失敗するかのどちらかです。リソースにはプロトコルの経路しかありません。テンプレートをはじめ、リソースに関するその他すべては **[リソース](resources.md)** にあります。
|
||||
ここには `is_error=True` のような中間的な結果がないことに注目してください。リソースの読み取りは、内容を返すか失敗するかのどちらかです。リソースにはプロトコルの経路しかありません。`ResourceError` は「見つからない」以外の失敗のための同じ仕組みで(`-32603` とメッセージ)、どちらもログには `INFO` が 1 行出るだけです。`MCPError` を除くその他の例外はクラッシュです。クライアントには URI だけを示す `-32603` が届き、トレースバックは `ERROR` レベルでログに記録されます。テンプレートをはじめ、リソースに関するその他すべては **[リソース](resources.md)** にあります。
|
||||
|
||||
## 送出する必要のないエラー {#errors-you-never-raise}
|
||||
|
||||
|
|
@ -115,16 +136,17 @@ result.structured_content # None
|
|||
つまり、書かなくてよい `raise` 文がまるごと一群あるということです。自分の型ヒントを改めて検証しないでください。
|
||||
|
||||
!!! info
|
||||
このページの内容はすべて**クライアント**から見えるものです。テストを書くときに使うインメモリの `Client` にも、まったく同じものが見えます。`raise_exceptions=True` でもツールエラーがトレースバックに戻ることはありません。このフラグが作用できる時点では、例外はすでに `is_error=True` の結果になっています。結果に対してアサートしてください。このパターンは **[テスト](../get-started/testing.md)** で扱っています。
|
||||
このページで**クライアント**から見えるものはすべて、テストを書くときに使うインメモリの `Client` からも見えます。`raise_exceptions=True` でも、失敗したツールの例外が呼び出し側に返されることはありません。このフラグが作用できる時点では、例外はすでに `is_error=True` の結果になっています。結果に対してアサートしてください。クラッシュのトレースバックが必要なら、それはサーバーのログにあり、pytest の `caplog` で捕捉できます。このパターンは **[テスト](../get-started/testing.md)** で扱っています。
|
||||
|
||||
## まとめ {#recap}
|
||||
|
||||
* ツールの中で**任意の例外**を送出する → 呼び出しは `is_error=True` を返し、メッセージが `content` に入ります。モデルはそれを読み、再試行できます。これがデフォルトです。
|
||||
* ツールの中で **`ToolError`** を送出する → 呼び出しは `is_error=True` を返し、メッセージが `content` に入ります。モデルはそれを読み、再試行できます。
|
||||
* **`MCPError`** を送出する → 呼び出しそのものが JSON-RPC エラーで失敗します。モデルには何も見えず、ホストが対処します。`code`、`message`、`data` はそのまま残ります。
|
||||
* 決め手の問い:「もっと賢いモデルならこれを避けられたか」。はい → 例外。いいえ → `MCPError`。
|
||||
* 決め手の問い:「もっと賢いモデルならこれを避けられたか」。はい → `ToolError`。いいえ → `MCPError`。
|
||||
* **その他の例外**はクラッシュ → モデルには `Error executing tool <name>` とだけ書かれた `is_error=True`、サーバー側にはトレースバック付きの `ERROR` レコードが残ります。
|
||||
* リソースのハンドラーから `ResourceNotFoundError` を送出する → プロトコルの `-32602` になり、URI が `data` に入ります。
|
||||
* 不正な引数は関数が実行される前にスキーマと照合して拒否されます。そのために `raise` する必要はありません。
|
||||
* `from mcp import MCPError` でインポートします。エラーコードの定数は `mcp.types` から取得します。
|
||||
* インポート:`from mcp import MCPError`、`from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError`、そしてエラーコードの定数は `mcp.types` から取得します。
|
||||
|
||||
エラーの処理はここまでです。サーバーが「公開する」ものはこれですべてです。すべてのハンドラーが実行中に読み取れるもの、そして実行中にクライアントに対して行えることは、次のセクション **[ハンドラーの中で](../handlers/index.md)** で扱います。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [496394d24d221bf1, 4ceb4591180dc6c3, 0fd63e4682d02e0c, 969ede0bd3686a16, 043f526230dd243d, 6ee3e9bcfd24047a]
|
||||
sections: [496394d24d221bf1, 4ceb4591180dc6c3, 0fd63e4682d02e0c, 969ede0bd3686a16, 864137b5e9c61e91, 043f526230dd243d, db1ef91db7d6b3f3]
|
||||
tool: 1
|
||||
---
|
||||
# メディア {#media}
|
||||
|
|
@ -81,6 +81,24 @@ result.structured_content # None
|
|||
!!! check
|
||||
`data=` の場合はファイル名がないので、推測する材料がありません。`format=` を忘れると、SDK はデフォルトにフォールバックします。画像なら `image/png`、音声なら `audio/wav` です。この方法で MP3 のバイト列から `Audio` を作ると、クライアントには `mime_type="audio/wav"` と伝えられ、それを忠実に信じてデコードに失敗します。`data=` を渡すときは `format=` も渡してください。
|
||||
|
||||
## リソースを埋め込む {#embedding-a-resource}
|
||||
|
||||
ツールはドキュメントを返すこともできます。テキストまたはバイト列に、それが置かれている URI と MIME タイプを添えたものです。これが **`EmbeddedResource`** で、コンテンツブロックのもう 1 つの種類です。単純な `str` と違い、コンテンツが何であるかをクライアントに伝えるので、クライアントはそれを添付ファイルとして表示したり、すでに知っているリソースだと認識したりできます。
|
||||
|
||||
```python title="server.py" hl_lines="7 14 16-18"
|
||||
--8<-- "docs_src/media/tutorial005.py"
|
||||
```
|
||||
|
||||
* `brand://guidelines` は普通のリソースです(リソースについては **[リソース](resources.md)** で扱います)。このツールはリクエストに応じて同じドキュメントをモデルに渡します。`guidelines()` を直接呼び出すことで、情報源を 1 つに保っています。
|
||||
* `EmbeddedResource` と `TextResourceContents` は `mcp.types` にあります。画像のようなヘルパーはありません。組み立てたブロックはそのまま結果に入り、`structured_content` はありません。
|
||||
* リソースを登録したときの URI を使ってください。そうすれば、添付ファイルと `brand://guidelines` が同じドキュメントだとクライアントが判断できます。登録されているかどうかにかかわらず、どんな URI でも有効です。
|
||||
|
||||
```python
|
||||
result.content # [EmbeddedResource(type="resource", resource=TextResourceContents(uri="brand://guidelines", mime_type="text/markdown", text="# Brand guidelines\n\n..."))]
|
||||
```
|
||||
|
||||
バイナリのコンテンツには、`TextResourceContents` の代わりに `BlobResourceContents(uri=..., mime_type=..., blob=...)` を使い、バイト列を base64 エンコードして `blob` に入れます。クライアントが後で `resources/read` できるポインターだけを送りたい場合は、代わりに `ResourceLink(name=..., uri=...)` を返してください。これもコンテンツブロックです。
|
||||
|
||||
## アイコン {#icons}
|
||||
|
||||
`Icon` はメタデータであって、コンテンツではありません。画像そのものは運ばず、URI で画像を指し示します。クライアントはそれを取得して、サーバーの名前やツール、リソース、プロンプトの横に表示することがあります。
|
||||
|
|
@ -110,6 +128,7 @@ client.server_info.icons # [Icon(src="https://example.com/brand-kit.png", mime_
|
|||
|
||||
* ツールから `Image` または `Audio` を返すと、クライアントは `ImageContent` / `AudioContent` ブロックを受け取ります。バイト列が base64 エンコードされ、MIME タイプが付きます。
|
||||
* `path=` から作って拡張子に MIME タイプを決めさせるか、メモリ上の `data=` に明示的な `format=` を添えて作ります。
|
||||
* `EmbeddedResource` を返すとドキュメント(テキストまたは base64 の blob に、その URI と MIME タイプを添えたもの)を結果に入れられ、`ResourceLink` を返すとポインターだけを送れます。
|
||||
* メディアの結果には `structured_content` も出力スキーマもありません。
|
||||
* `Icon` はポインターです。`src` URI に、省略可能な `mime_type`、`sizes`、`theme` を加えたものです。
|
||||
* `icons=[...]` はサーバー、ツール、リソース、プロンプトのどれにも使え、クライアントは対応するオブジェクト上でそれらを見つけます。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, ffe823cb0fedd488, f33651add1b59094]
|
||||
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, d30d3c20168b88b2, f5ef38dad59d6f76, 6e38a699ba57fbdf, 2b984a3bf37a0ddd]
|
||||
tool: 1
|
||||
---
|
||||
# プロンプト {#prompts}
|
||||
|
|
@ -137,7 +137,52 @@ uv run mcp dev server.py
|
|||
```
|
||||
|
||||
!!! info
|
||||
**[ツール](tools.md)** を読んでいれば、このページの内容はもうすべて知っています。同じデコレーター、同じく docstring が説明になる仕組み、同じ `Annotated`/`Field` です。変わるのは、誰が起動するか(ユーザー)と、結果がどこへ行くか(会話の中)だけです。
|
||||
**[ツール](tools.md)** を読んでいれば、ここまでの内容はもうすべて知っています。同じデコレーター、同じく docstring が説明になる仕組み、同じ `Annotated`/`Field` です。変わるのは、誰が起動するか(ユーザー)と、結果がどこへ行くか(会話の中)だけです。
|
||||
|
||||
## テキスト以外のコンテンツ {#more-than-text}
|
||||
|
||||
`UserMessage` と `AssistantMessage` は、`str` を受け取れる場所ならどこでも、コンテンツブロックや `Image` / `Audio` ヘルパーも受け取れます。プロンプトでよく出てくるケースは 2 つ、ドキュメントの添付と画像の添付です。
|
||||
|
||||
### ファイルを埋め込む {#embedding-a-file}
|
||||
|
||||
```python title="server.py" hl_lines="5 12 21 23"
|
||||
--8<-- "docs_src/prompts/tutorial004.py"
|
||||
```
|
||||
|
||||
* スタイルガイドは `style://python` にあるリソースで(リソースについては **[リソース](resources.md)** で扱います)、`server.py` の隣にある `style-guide.md` から読み込まれます。そこに任意の Markdown ファイルを置いてください。
|
||||
* `EmbeddedResource(resource=TextResourceContents(...))`(どちらも `mcp.types` にあります)は、URI と MIME タイプ付きのファイルを最初のメッセージとして運びます。そのファイルに言及するリクエストは、プレーンテキストとして後に続きます。
|
||||
* ガイドを f-string に貼り付けるのではなく埋め込むことで、クライアントはそれを添付ファイルとして表示でき、後から `style://python` を開き直せます。モデルはファイルをそのままの形で受け取ります。バイナリファイルの場合は、base64 の `blob` を持つ `BlobResourceContents` を使ってください。
|
||||
|
||||
レンダリングすると、最初のメッセージの `content` は `resource` ブロックです。
|
||||
|
||||
```json
|
||||
{"type": "resource", "resource": {"uri": "style://python", "mimeType": "text/markdown", "text": "* Prefer early returns.\n..."}}
|
||||
```
|
||||
|
||||
### 画像を添付する {#attaching-an-image}
|
||||
|
||||
```python title="server.py" hl_lines="4 15"
|
||||
--8<-- "docs_src/prompts/tutorial005.py"
|
||||
```
|
||||
|
||||
* `Image` は **[画像、音声、アイコン](media.md)** で紹介するヘルパーです。プロンプトがレンダリングされるとき、`UserMessage` はこれを `ImageContent` ブロック(ファイルは base64 エンコードされ、MIME タイプは `.png` から推測されます)に変換します。`Audio` も同じように `AudioContent` になります。
|
||||
* `server.py` の隣に `architecture.png` という名前の PNG を何か置いてください。プロンプトの引数は文字列なので、画像は常にサーバー側から来ます。`component` が与えるのは言葉だけです。
|
||||
|
||||
```json
|
||||
{"type": "image", "data": "iVBORw0KGgoAAAANSUhEUg...", "mimeType": "image/png"}
|
||||
```
|
||||
|
||||
## 実行時にリストを変更する {#changing-the-list-at-runtime}
|
||||
|
||||
プロンプトは、クライアントが接続している間にも追加できます。たとえば、ユーザーが指示を自分専用のメニュー項目として保存できるようにする場合です。プロンプトを登録してから、通知します。
|
||||
|
||||
```python title="server.py" hl_lines="5 23-27"
|
||||
--8<-- "docs_src/prompts/tutorial006.py"
|
||||
```
|
||||
|
||||
* `mcp.add_prompt(Prompt.from_function(fn, name=..., description=...))` は `@mcp.prompt()` とまったく同じように関数を登録し、`mcp.remove_prompt(name)` はその逆です。`add_prompt` は同名の既存エントリを上書きせずそのまま残すので、このツールは保存が置き換えになるよう、先に古いエントリを削除しています。`prompts/list` には変更がすぐに反映されます。
|
||||
* `await ctx.notify_prompts_changed()` は、`subscriptions/listen` ストリームで待ち受けているすべての `2026-07-28` クライアントに `notifications/prompts/list_changed` を送ります(**[サブスクリプション](../handlers/subscriptions.md)**)。`await ctx.session.send_prompt_list_changed()` は、呼び出し元のクライアントが 2026 年より前の世代のときに、そのクライアントへ送ります(**[レガシークライアントへの対応](../run/legacy-clients.md)**)。両方を呼んでください。どちらも、伝える相手がいなければ何もしません。
|
||||
* 通知を受け取ったクライアントは、もう一度 `prompts/list` を呼びます。Python の `Client` では `async with client.listen(prompts_list_changed=True) as sub:` がそれにあたり、`PromptsListChanged` イベントが届きます。
|
||||
|
||||
## まとめ {#recap}
|
||||
|
||||
|
|
@ -147,5 +192,7 @@ uv run mcp dev server.py
|
|||
* `str` を返すと 1 つのユーザーメッセージになります。`UserMessage` / `AssistantMessage` のリストを返すと、複数ターンの会話の出発点を用意できます。
|
||||
* `title=` と `Field(description=...)` は、クライアントが UI に表示するものです。
|
||||
* 必須の引数が欠けていると、リクエスト全体が失敗します。プロンプト単位のエラー結果はありません。
|
||||
* `EmbeddedResource` や `Image` を `UserMessage` でラップすると、ドキュメントや画像を添付できます。
|
||||
* 実行時にプロンプトを追加・削除するには `mcp.add_prompt(...)` / `mcp.remove_prompt(...)` を使い、その後 `await ctx.notify_prompts_changed()` と `await ctx.session.send_prompt_list_changed()` を呼びます。
|
||||
|
||||
プロンプト(やリソーステンプレート)の引数をサーバー側でオートコンプリートする機能については、**[補完](completions.md)** を参照してください。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [a838d57f003aed44, 857d03886a0137ed, 42d9efcb9f542867, 2290ff08435b5573, e866c192e11d1c14, 6cdbad079f7b47f0, d4b607372fb28b51, 18dbf726ac45e0b7, c6f7d2a148aa49f4, c851964bb3301907, d715db6f8dccc9cc, ef86634aa70498a7]
|
||||
sections: [a838d57f003aed44, 857d03886a0137ed, 42d9efcb9f542867, 2290ff08435b5573, 91be9b73602abcf1, 6cdbad079f7b47f0, d4b607372fb28b51, 18dbf726ac45e0b7, c7eff2a5698225fa, c851964bb3301907, 8f296f1f09e4c400, d715db6f8dccc9cc, a0c344a48450dbe4]
|
||||
tool: 1
|
||||
---
|
||||
# 構造化出力 {#structured-output}
|
||||
|
|
@ -103,7 +103,7 @@ result.structured_content # {"temperature": 16.2, "humidity": 0.83, "conditions
|
|||
--8<-- "docs_src/structured_output/tutorial003.py"
|
||||
```
|
||||
|
||||
`TypedDict` は実行時にはただの `dict` なので、組み立てて返すのもそれです。スキーマもバリデーションも `structured_content` も、`BaseModel` 版と同一です(説明だけは付きません。`TypedDict` には説明を書く場所がないからです)。
|
||||
`TypedDict` は実行時にはただの `dict` なので、組み立てて返すのもそれです。スキーマもバリデーションも `structured_content` も、`BaseModel` 版と同じルールに従います。クラスの docstring や `Annotated[..., Field(description=...)]` を足せばそれが説明になり、dict に入れなかった `NotRequired` のキーは `structured_content` にも入りません。
|
||||
|
||||
## データクラス {#a-dataclass}
|
||||
|
||||
|
|
@ -185,16 +185,16 @@ result.structured_content # {"London": 16.2, "Reykjavik": 4.4}
|
|||
アノテーションは `WeatherData` を約束しています。ところが、上流のレスポンスが `humidity` を送ってこなくなりました。
|
||||
|
||||
!!! check
|
||||
`get_weather` を呼び出しても、中身が半分欠けたオブジェクトがこっそりクライアントに渡ることはありません。呼び出しは失敗し、エラーの冒頭の数行にそのフィールド名が示されます。
|
||||
`get_weather` を呼び出しても、中身が半分欠けたオブジェクトがこっそりクライアントに渡ることはありません。呼び出しは失敗します。クライアントは `Error executing tool get_weather` とともに `is_error=True` を受け取るので、モデルは、ありもしない天気を自信満々に読み上げる代わりに、呼び出しが失敗したと分かります。フィールド名は開発者向けに、サーバーログの `ERROR` レベルに出力されます。
|
||||
|
||||
```text
|
||||
Error executing tool get_weather: 1 validation error for WeatherData
|
||||
Tool 'get_weather' raised an unexpected exception
|
||||
...
|
||||
pydantic_core._pydantic_core.ValidationError: 1 validation error for WeatherData
|
||||
humidity
|
||||
Field required [type=missing, input_value={'temperature': 16.2, 'conditions': 'Overcast'}, input_type=dict]
|
||||
```
|
||||
|
||||
このテキストは `is_error=True` の付いたツール結果として返ってくるので、モデルは、ありもしない天気を自信満々に読み上げる代わりに、呼び出しが失敗したと分かります。
|
||||
|
||||
ちなみに、`-> WeatherData` のツールから単なる `dict` を返してもかまいません。`json.loads` が返したのはまさにそれです。バリデーションの対象は Python の型ではなく、値です。
|
||||
|
||||
## オプトアウト {#opting-out}
|
||||
|
|
@ -209,6 +209,10 @@ result.structured_content # {"London": 16.2, "Reykjavik": 4.4}
|
|||
|
||||
その逆の `structured_output=True` は、自動検出を必須要件に変えます。戻り値の型からスキーマを作れないツールは、テキストにフォールバックするのではなく、インポート時に例外を送出します。
|
||||
|
||||
## コンテンツブロックとメディア {#content-blocks-and-media}
|
||||
|
||||
コンテンツブロックとメディア(`TextContent`、`EmbeddedResource`、`Image`、`Audio` など)は、何もしなくてもオプトアウトされます。単体で返しても、`list`、`tuple`、`Sequence` の要素にしても、ユニオンの一方にしても同じです。これらはモデルが読むためのものなので、自動検出はそこからスキーマを導き出しません(`Image` と `Audio` については **[画像、音声、アイコン](media.md)** で扱っています)。それでも `structured_output=True` を渡せば、コンテンツブロックのクラスにはスキーマが強制されます。
|
||||
|
||||
## 型ヒントのないクラス {#a-class-without-type-hints}
|
||||
|
||||
頼んでもいないのに非構造化になってしまう道が 1 つだけあります。**本体にアノテーションが 1 つもない**クラスを返すことです。
|
||||
|
|
@ -237,6 +241,6 @@ result.structured_content # {"London": 16.2, "Reykjavik": 4.4}
|
|||
* スカラー、リスト、タプル、ユニオンは `{"result": ...}` でラップされます。モデル、`TypedDict`、データクラス、アノテーション付きクラス、`dict[str, ...]` はもともとオブジェクトなので、そのままです。
|
||||
* どの結果も `content`(モデル向けのテキスト)**と** `structured_content`(アプリケーション向けのデータ)の両方を持ちます。
|
||||
* 返したものはスキーマに照らして検証されます。食い違いは壊れた結果ではなく、ツールエラーになります。
|
||||
* `structured_output=False` を渡すと、そのツールはオプトアウトします。型ヒントのないクラスは黙ってオプトアウトするので、気をつけてください。
|
||||
* `structured_output=False` を渡すと、そのツールはオプトアウトします。コンテンツブロック、`Image`、`Audio` はデフォルトでオプトアウトします。型ヒントのないクラスは黙ってオプトアウトするので、気をつけてください。
|
||||
|
||||
これで、ツールが返せるものはすべて押さえました。次は 2 つ目のプリミティブ、**[リソース](resources.md)** です。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [e4cc390d56573409, 8566e2b68594e9ad, 2c97b9f888398951, 048e5471dfa71aea, 3076b1e16ad95950, edbedf2a16e71311, 3d8ef8da89fa87c1, f6c0e02e6ea5a363]
|
||||
sections: [e4cc390d56573409, f30cf8103a6e918c, 2c97b9f888398951, 048e5471dfa71aea, 3076b1e16ad95950, edbedf2a16e71311, 3d8ef8da89fa87c1, f6c0e02e6ea5a363]
|
||||
tool: 1
|
||||
---
|
||||
# ツール {#tools}
|
||||
|
|
@ -39,6 +39,8 @@ SDK はこれらの型ヒントから JSON Schema を生成し、`tools/list`
|
|||
|
||||
どちらの引数にもデフォルト値がないため、両方とも `required` に入っています。これはすぐ後で直します。(`title` キーは Pydantic が生成した付随物です。契約にあたるのは、プロパティとその型、そして `required` です。)
|
||||
|
||||
`$schema` キーもありません。MCP はこのキーのないスキーマを **JSON Schema 2020-12** として扱い、Pydantic が生成するのもまさにこの形式です。そのため、**[低レベル Server](../advanced/low-level-server.md#the-dialect-is-json-schema-2020-12)** でスキーマを手書きするようになるまで、選ぶべきものは何もありません。
|
||||
|
||||
!!! tip
|
||||
ここでの型ヒントはドキュメントではありません。**契約そのもの**です。クライアントが `"limit": "ten"` を送ってきても、関数が実行される前に SDK が拒否します。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [4a7033e1ed8ad602, 55dcbfff0c6271bf, 101ef9d14bf4ec46, 4b6c4a845438abc7, f98b46bafbee4acd]
|
||||
sections: [4a7033e1ed8ad602, 55dcbfff0c6271bf, 317f4256a650cab6, 4b6c4a845438abc7, f98b46bafbee4acd]
|
||||
tool: 1
|
||||
---
|
||||
# URI テンプレートとパスの安全性 {#uri-templates-and-path-safety}
|
||||
|
|
@ -98,7 +98,7 @@ SDK はハンドラーの実行前に、次のいずれかに当てはまるパ
|
|||
|
||||
組み込みのチェックはよくあるケースを止めますが、サンドボックスの境界までは知りようがありません。ファイルシステムにアクセスする場合は、`safe_join` を使ってパスを解決し、ベースディレクトリの内側に収まっていることを検証してください。
|
||||
|
||||
```python title="server.py" hl_lines="4 14"
|
||||
```python title="server.py" hl_lines="5 15"
|
||||
--8<-- "docs_src/uri_templates/tutorial002.py"
|
||||
```
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ SDK はハンドラーの実行前に、次のいずれかに当てはまるパ
|
|||
これらのチェックはヒューリスティックな事前フィルターです。ファイルシステムへのアクセスでは、依然として `safe_join` が封じ込めの境界です。
|
||||
|
||||
!!! tip
|
||||
ハンドラーがリクエストに応えられない場合(ファイルが存在しない、ID が不明など)は、例外を送出してください。SDK がそれをエラーレスポンスに変換します。プロトコルエラーとツールエラーの違いについては、**[エラーの処理](handling-errors.md)** を参照してください。
|
||||
ハンドラーがリクエストに応えられない場合(ファイルが存在しない、ID が不明など)は、上の `read_manual` と同じように `ResourceNotFoundError` を送出してください。クライアントには、指定したメッセージと URI を含む `-32602` が返ります。想定外の例外は、代わりに汎用の `-32603` になります。**[エラーの処理](handling-errors.md#a-resource-that-doesnt-exist)** を参照してください。
|
||||
|
||||
## 低レベル Server でのリソース {#resources-on-the-low-level-server}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [2efaecdef109a5c5, fcacd3e66b8635a4, 25323d737dcf0261, 4835ed1772f1d113, 137454d469c867f5, 6392596bd6df54f0, 41126fa9c4fe432f, 480b6d7897e30ab4, d83bb682e708dde0, ebbed3449c499db4, 323ef84f6b4bebde, 30fd31be74169d9a, 656943c6cb567218, c2dc3b1007d2e987, 7cf5386b997d04e9, 0b59feed8384456e, 0cba47bae78d04eb, 954dc21efdb532a3]
|
||||
sections: [2efaecdef109a5c5, fcacd3e66b8635a4, 25323d737dcf0261, 8a6e351ec756904d, 137454d469c867f5, 6392596bd6df54f0, 41126fa9c4fe432f, 480b6d7897e30ab4, d83bb682e708dde0, ebbed3449c499db4, 323ef84f6b4bebde, 30fd31be74169d9a, 656943c6cb567218, c2dc3b1007d2e987, 7cf5386b997d04e9, 0b59feed8384456e, 0cba47bae78d04eb, e4355f4c7cf4fb2e]
|
||||
tool: 1
|
||||
---
|
||||
# トラブルシューティング {#troubleshooting}
|
||||
|
|
@ -79,11 +79,11 @@ async def main() -> None:
|
|||
|
||||
`__aexit__` が切断です。だからこそ、呼び忘れる `client.close()` というものが存在しません。**[テスト](get-started/testing.md)** は、まさにこのパターンの上に組み立てられています。
|
||||
|
||||
## `Error executing tool <name>: <message>` と `Unknown tool: <name>` {#error-executing-tool-name-message-and-unknown-tool-name}
|
||||
## `Error executing tool <name>: <message>`、`Error executing tool <name>`、`Unknown tool: <name>` {#error-executing-tool-name-message-error-executing-tool-name-and-unknown-tool-name}
|
||||
|
||||
読んでいるのは**結果**であって、例外ではありません。`call_tool` は例外を送出しておらず、ツールが失敗しても送出することは決してありません。
|
||||
|
||||
サーバーが知らない都市で `forecast` を呼ぶと、ツールが送出した例外は、リクエストが「成功」と記された形で返ってきます。
|
||||
サーバーが知らない都市で `forecast` を呼ぶと、ツールが送出した `ToolError` は、リクエストが「成功」と記された形で返ってきます。
|
||||
|
||||
```python
|
||||
result.is_error # True
|
||||
|
|
@ -95,6 +95,8 @@ result.structured_content # None
|
|||
|
||||
直すのはクライアント側です。**`result.is_error` を確認してください**。`call_tool` を `try/except` で囲んでも、これらはどれも捕まりません。捕まえるものがないからです。これは意図した設計であり、このページで身につけておくと一番役に立つ点です。呼び出しを選んだのは「モデル」なので、メッセージを受け取ってやり直す機会を得るのもモデルです。詳しくは **[エラーの処理](servers/handling-errors.md)** を参照してください。例外を「送出する」側の `MCPError` の経路も含めて説明しています。
|
||||
|
||||
メッセージのない素の形、`Error executing tool <name>` は、ツールが**クラッシュした**ことを意味します。ツールが想定していなかった例外が抜け出した(または戻り値が出力スキーマに通らなかった)場合で、その例外の文字列は通信路には載せません。トレースバックは**サーバーのログ**に `ERROR` で、`Tool '<name>' raised an unexpected exception` として記録されています。
|
||||
|
||||
## `TypeError: The @tool decorator was used incorrectly. Did you forget to call it? Use @tool() instead of @tool` {#typeerror-the-tool-decorator-was-used-incorrectly-did-you-forget-to-call-it-use-tool-instead-of-tool}
|
||||
|
||||
`@mcp.tool()` ではなく `@mcp.tool` と書いています。`tool()` はデコレーターの「ファクトリー」です。括弧がないと、Python は関数をその `name=` パラメーターに渡してしまいます。
|
||||
|
|
@ -393,7 +395,7 @@ mcp = MCPServer("Weather", request_state_security=RequestStateSecurity(keys=[key
|
|||
## まとめ {#recap}
|
||||
|
||||
* `ExceptionGroup: unhandled errors in a TaskGroup` がエラーであることは決してありません。**最後の行**を読んでください。`async with Client(...)` ブロックの「内側」で `MCPError` を捕まえれば、包まれること自体を完全に避けられます。
|
||||
* `call_tool` は、ツールが失敗しても例外を送出しません。`Error executing tool ...` と `Unknown tool: ...` は結果です。`result.is_error` を確認してください。
|
||||
* `call_tool` は、ツールが失敗しても例外を送出しません。`Error executing tool ...` と `Unknown tool: ...` は結果です。`result.is_error` を確認してください。ツール名の後にメッセージがなければクラッシュしたという意味で、トレースバックはサーバーログにあります。
|
||||
* `Client must be used within an async context manager` -> `async with` を使ってください。`Use @tool() instead of @tool` -> 括弧を付けてください。
|
||||
* サーバーログの `Tool already exists:` は、同名の 2 つのツールが 1 つに潰れた唯一の合図です。
|
||||
* 1 つの 421、3 つの綴り:`Server returned an error response`(python の `Client`)、`421 Misdirected Request` / `Invalid Host header`(それ以外すべて)、`Invalid Host header: <host>`(サーバーログ)。直し方:`transport_security=TransportSecuritySettings(allowed_hosts=[...])`。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [cfe01c0c5863dfa2, 11d93f1fa09eadf5, a7392996acf1ad8f, 875eb2889263424e]
|
||||
sections: [cfe01c0c5863dfa2, 1c58c5cfcc37d455, a7392996acf1ad8f, 875eb2889263424e]
|
||||
tool: 1
|
||||
---
|
||||
# v2 の新機能 {#whats-new-in-v2}
|
||||
|
|
@ -41,9 +41,9 @@ v1 では 3 つの層が入れ子になっていました。生のストリー
|
|||
--8<-- "docs_src/client/tutorial001.py"
|
||||
```
|
||||
|
||||
`Client` が受け取るのは、サーバーオブジェクト(インメモリでトランスポートなし。テストで使う形です)、URL(Streamable HTTP)、または `stdio_client(...)` のような任意のトランスポートのコンテキストマネージャーです。`async with` に入ると接続し、サーバーがどの世代を話すかにかかわらずプロトコルバージョンをネゴシエートします。その後は `client.server_capabilities` と `client.protocol_version` がそのまま使え、サーバーが自身を名乗る場合は `client.server_info` も使えます(2026 年世代では識別情報が省略可能なので、`Implementation | None` になりました)。v1 で登録したサンプリングとエリシテーションのコールバックは引き続き動作します(コールバックの本体には、このページのほかの項目と同じ snake_case への属性名の変更が及びます)。加えて 2026 形式の「結果に埋め込まれたリクエスト」(後述)にも応答するようになり、1 つずつではなく並行して実行されます。低レベルのインターフェースが必要な人のために `ClientSession` は今も下にあり、`client.session` で取り出せます。ただしこちらも変わっています(新しいディスパッチャーエンジンの上で動き、自身のシグネチャも一部変わりました)。下りていく前に**[移行ガイド](migration.md#clientsession-now-runs-on-jsonrpcdispatcher-basesession-removed)**を読んでください。
|
||||
`Client` が受け取るのは、サーバーオブジェクト(インメモリでトランスポートなし。テストで使う形です)、URL(Streamable HTTP)、`StdioServerParameters`(stdio のサブプロセス)、または `sse_client(...)` のようなそれ以外の任意のトランスポートのコンテキストマネージャーです。`async with` に入ると接続し、サーバーがどの世代を話すかにかかわらずプロトコルバージョンをネゴシエートします。その後は `client.server_capabilities` と `client.protocol_version` がそのまま使え、サーバーが自身を名乗る場合は `client.server_info` も使えます(2026 年世代では識別情報が省略可能なので、`Implementation | None` になりました)。v1 で登録したサンプリングとエリシテーションのコールバックは引き続き動作します(コールバックの本体には、このページのほかの項目と同じ snake_case への属性名の変更が及びます)。加えて 2026 形式の「結果に埋め込まれたリクエスト」(後述)にも応答するようになり、1 つずつではなく並行して実行されます。低レベルのインターフェースが必要な人のために `ClientSession` は今も下にあり、`client.session` で取り出せます。ただしこちらも変わっています(新しいディスパッチャーエンジンの上で動き、自身のシグネチャも一部変わりました)。下りていく前に**[移行ガイド](migration.md#clientsession-now-runs-on-jsonrpcdispatcher-basesession-removed)**を読んでください。
|
||||
|
||||
**[Client](client/index.md)** で紹介し、**[クライアントのトランスポート](client/transports.md)**で 3 つの接続形態を、**[クライアントのコールバック](client/callbacks.md)**でコールバックそのものを扱います。**[テスト](get-started/testing.md)**では、v1 の `create_connected_server_and_client_session()` ヘルパーに代わるインメモリのパターンを示します。
|
||||
**[Client](client/index.md)** で紹介し、**[クライアントのトランスポート](client/transports.md)**で 4 つの接続形態を、**[クライアントのコールバック](client/callbacks.md)**でコールバックそのものを扱います。**[テスト](get-started/testing.md)**では、v1 の `create_connected_server_and_client_session()` ヘルパーに代わるインメモリのパターンを示します。
|
||||
|
||||
### 低レベルの `Server` は改名ではなく再構築 {#the-low-level-server-was-rebuilt-not-renamed}
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[types.ContentB
|
|||
名前の変更は自分から存在を知らせてくれます。次のものは知らせてくれません。
|
||||
|
||||
* **同期関数はワーカースレッドで動きます。** `def` のツール(リソース、プロンプト、リゾルバーも同様)はイベントループをブロックしなくなりました。その代わり、本体はイベントループのスレッド上では動かなくなったので、特定のスレッドに縛られたコードには影響します。`async def` のハンドラーはそのままです。詳しくは**[移行ガイド](migration.md#sync-handler-functions-now-run-on-a-worker-thread)**を参照してください。
|
||||
* **ツールの中で送出した `MCPError`(v1 の `McpError`)はプロトコルエラーになりました。** モデルがそれを見ることはありません。ほかの例外はすべて、これまでどおりモデルが読んで対応できる `is_error=True` の結果になります。この切り分けは**[エラーの処理](servers/handling-errors.md)**で説明しています。
|
||||
* **ツールの中で送出した `MCPError`(v1 の `McpError`)はプロトコルエラーになりました。** モデルがそれを見ることはありません。ほかの例外はすべて、これまでどおり `is_error=True` の結果になりますが、モデルに届くメッセージは `ToolError` のものだけです。それ以外の例外は `Error executing tool <name>` と表示されるようになり、トレースバックはサーバーのログに残ります。この切り分けは**[エラーの処理](servers/handling-errors.md)**で説明しています。
|
||||
* **結果は送り出す前に検証されます。** `input_schema` が `{}` の手組みの `Tool` は、`tools/list` で失敗するようになりました(仕様は `"type": "object"` を要求します)。`@mcp.tool()` で作ったサーバーがこれに出会うことはありません。スキーマは SDK が書くからです。
|
||||
* **クライアントは受け取ったものを検証します。** `list_tools()` と `call_tool()` は、ネゴシエートしたプロトコルバージョンに照らしてサーバーの応答を検査します。そのため、v1 の寛容なパースが見逃していた「少しだけ不正な」サーバーは `pydantic.ValidationError` を送出するようになりました。自分で管理していないサーバーに接続するなら、そうしたサーバーを見つけるのは自分だと思っておいてください。詳しくは**[移行ガイド](migration.md#client-validates-inbound-traffic-against-the-protocol-schema)**を参照してください。
|
||||
* **URI テンプレートは本物の RFC 6570 になりました。** `{+path}`、`{?query}` などが使え、マッチングは正規表現的な緩さではなく厳密になり、取り出した値に含まれるパストラバーサルはデフォルトで拒否されます。厳格になったテンプレートは、最初のリクエストではなくデコレーターの適用時に失敗します。詳しくは **[URI テンプレート](servers/uri-templates.md)**を参照してください。
|
||||
|
|
|
|||
Loading…
Reference in a new issue