AgentCore ゲートウェイで誘発を使用する
誘発は、MCP サーバーがツール呼び出し中にクライアントに追加情報をリクエストできるようにする MCP 機能です。ツールがユーザーの確認、認証、または追加の入力を必要とする場合、サーバーは誘発リクエストをクライアントに送り返します。AgentCore Gateway は、MCP サーバーターゲットからの誘発リクエストをクライアントに転送し、リクエストをゲートウェイが生成idした識別子に置き換えます。
前提条件
ゲートウェイで誘発を使用するには、以下が必要です。
-
セッションが有効 — 誘発にはセッションサポートが必要です。「ゲートウェイで MCP セッションを使用する」を参照してください。
-
レスポンスストリーミングが有効 — 起動リクエストは、オープン接続中にサーバー送信イベント (SSE) チャンクとして送信されます。ゲートウェイの trueで streamingConfiguration.enableResponseStreamingを に設定しますprotocolConfiguration.mcp。
-
MCP サーバーターゲットタイプ — 誘発は MCP サーバーターゲットでのみサポートされています。誘発は MCP サーバーから発信され、ゲートウェイを介してクライアントに転送されます。
-
クライアントが誘発機能を宣言する — クライアントは、ゲートウェイが誘発initializeリクエストを転送するリクエスト中に誘発のサポートを宣言する必要があります。
サポートされている誘発モード
AgentCore Gateway は、MCP 仕様で定義された 3 つの誘発モードをサポートしています。
| モード |
説明 |
|
フォームモード
|
サーバーは、クライアントが入力するフィールドを含む構造化フォームを送信します。ユーザーの確認、設定、または入力データの収集に使用されます。レスポンスを待っている間、リクエストは開いたままになります。
|
|
URL モード (リクエストベース)
|
サーバーは、アクション (通常は認証) を完了するためにユーザーがアクセスする必要がある URL を送信します。アクションの完了を待っている間、リクエストは開いたままになります。
|
|
URL モード (例外ベース)
|
サーバーは URL URLElicitationRequiredErrorを含む をスローします。リクエストは終了し、ユーザーは URL でアクションを完了し、クライアントは元のツール呼び出しを再試行します。
|
機能ネゴシエーション
ゲートウェイは、次の場合にのみ MCP サーバーターゲットへの誘発サポートを宣言します。
-
クライアントは、 中に誘発サポートを宣言しましたinitialize。
-
MCP プロトコルバージョンは誘発モードをサポートしています。formモードにはバージョン 2025-03-26 以降が必要で、urlモードにはバージョン 2025-11-25以降が必要です。
-
ゲートウェイは、クライアントによって宣言された特定の誘発機能 (フォーム、URL、またはその両方) と一致します。
-
クライアントは Mcp-Session-Idヘッダーを使用してtools/callリクエストを送信します。
-
Gateway は、ツール呼び出しを MCP サーバーターゲットに転送します。
-
ターゲットは SSE ストリームを開き、最初のイベントとしてelicitation/createリクエストを送信します。
-
Gateway はelicitation/createリクエストを SSE ストリームのクライアントに転送し、リクエスト を置き換えますid。
-
クライアントはフォームをユーザーに提示し、レスポンスを収集します。
-
クライアントは、同じ を使用して、誘発レスポンス (アクション: acceptまたは decline) を含む新しいリクエストを送信しますMcp-Session-Id。
-
Gateway はレスポンスを MCP サーバーターゲットに転送します。
-
ターゲットは HTTP 202 Accepted で承認します。
-
ターゲットはツール呼び出しを完了し、元の SSE ストリームで最終結果を送信します。
-
Gateway は最終結果をクライアントに転送し、ストリームを閉じます。
URL モード (例外ベース) 誘発フロー
-
クライアントは Mcp-Session-Idヘッダーを使用してtools/callリクエストを送信します。
-
Gateway は、ツール呼び出しを MCP サーバーターゲットに転送します。
-
ターゲットは、URL と誘発 ID を含む JSON-RPC エラーURLElicitationRequiredErrorとして をスローします。
-
Gateway は をクライアントに転送URLElicitationRequiredErrorし、リクエスト を置き換えますid。
-
クライアントは、指定された URL にユーザーをリダイレクトしてアクション (通常は OAuth 認証) を完了します。
-
ユーザーがアクションを完了すると、クライアントは元のtools/callリクエストを再試行します。
-
ゲートウェイは再試行をターゲットに転送します。ターゲットは、URL 誘発が満たされたため、ツール呼び出しを完了します。
-
Gateway は、最終的なツール結果をクライアントに転送します。
誘発を伴う並列ツール呼び出し
クライアントは、誘発が保留中であっても、同じセッション内で複数のtools/callリクエストを開始できます。各誘発は、その によって個別に追跡されますid。誘発レスポンスを送信する場合、クライアントはゲートウェイによって送信されたidのと同じ をelicitation/createリクエストに含める必要があります。
MCP サーバーターゲット開発者向けガイダンス
誘発リクエストを送信する MCP サーバーターゲットは、誘発呼び出しを try-catch ブロックにラップし、クライアントが誘発をサポートしていない場合を処理する必要があります。ゲートウェイのクライアントが誘発機能を宣言しなかった場合、ゲートウェイはそれをターゲットに宣言しません。ターゲットが誘発を送信した場合、ゲートウェイはターゲットに -32601 (メソッドが見つかりません) エラーを返します。
誘発が利用できない場合、サーバーはフォールバックパスを実装する必要があります (デフォルト値の使用やオペレーションのスキップなど)。
エラー処理
| シナリオ |
エラー |
説明 |
|
誘発が保留中でない場合、クライアントは誘発レスポンスを送信します
|
JSON-RPC -32600 (無効なリクエスト)
|
このセッションに一致する誘発が見つかりませんでした。
|
|
クライアントが、保留中の誘発とid一致しない で誘発レスポンスを送信する
|
JSON-RPC -32600 (無効なリクエスト)
|
は、elicitation/createリクエストでゲートウェイによって送信されたものと一致するid必要があります。
|
|
ゲートウェイと MCP サーバーターゲット間の接続中断
|
DependencyFailedException による JSON-RPC エラー
|
クライアントは元のツール呼び出しリクエストを再試行する必要があります。
|
|
クライアントとゲートウェイ間の接続中断
|
該当なし
|
保留中の誘発はクリーンアップされます。クライアントはツール呼び出しを再試行する必要があります。
|
|
MCP サーバーが誘発を送信したが、ゲートウェイがサポートを宣言しなかった
|
JSON-RPC -32601 (メソッドが見つかりません)
|
MCP サーバーターゲットに戻ります。トラブルシューティングを参照してください。
|
トラブルシューティング
エラー: "エラー呼び出しツール 'sample_tool': メソッドが見つかりません: 誘発/作成"
このエラーは、MCP サーバーターゲットが誘発リクエストを送信したが、ゲートウェイのクライアントが 中に誘発機能を宣言しなかった場合に発生しますinitialize。ゲートウェイは -32601 (メソッドが見つからない) エラーをターゲットに返し、ターゲットはこれをツール実行エラーとしてクライアントに返す場合があります。
解決するには:
-
MCP サーバー開発者の場合: 誘発呼び出しに関するエラー処理を追加します。誘発がサポートされていない場合は、フォールバックパスを実装します。
try:
result = await context.session.create_elicitation(
message="Confirm this action?",
requested_schema={"type": "object", "properties": {"confirm": {"type": "boolean"}}}
)
except Exception as e:
# Fallback when client doesn't support elicitation
logger.warning(f"Elicitation not supported: {e}")
result = default_action()
-
ゲートウェイクライアント開発者の場合: クライアントが 中に誘発機能を宣言していることを確認しますinitialize。
{
"capabilities": {
"elicitation": {
"form": {},
"url": {}
}
}
}
コードサンプル
フォームモードでは、サーバーはクライアントが入力する構造化スキーマを送信します。レスポンスを待っている間、リクエストは開いたままになります。
例
- Python requests package
-
-
import requests
import json
import sseclient
gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
headers = {
"Content-Type": "application/json",
"Accept": "text/event-stream",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
# Step 1: Initialize with elicitation capability
init_response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "init-request",
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {"elicitation": {"form": {}, "url": {}}},
"clientInfo": {"name": "my-agent", "version": "1.0.0"}
}
})
session_id = init_response.headers["Mcp-Session-Id"]
headers["Mcp-Session-Id"] = session_id
# Step 2: Call tool (streaming response)
response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "tool-call-1",
"method": "tools/call",
"params": {
"name": "use_aws",
"arguments": {"command": "aws s3 rm s3://my-bucket/important-file"}
}
}, stream=True)
# Step 3: Process SSE events
client = sseclient.SSEClient(response)
for event in client.events():
data = json.loads(event.data)
if data.get("method") == "elicitation/create":
elicitation_id = data["id"]
print(f"Form elicitation received: {data['params']['message']}")
# Step 4: Send elicitation response
requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": elicitation_id,
"result": {"action": "accept", "content": {"confirm": True}}
})
elif "result" in data:
print(f"Tool result: {data['result']}")
break
- MCP Client
-
-
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
import asyncio
async def elicitation_handler(request):
"""Handle form elicitation requests from the server."""
print(f"Elicitation: {request.params.message}")
return {"action": "accept", "content": {"confirm": True}}
async def use_elicitation(url, token):
headers = {"Authorization": f"Bearer {token}"}
async with streamablehttp_client(url=url, headers=headers) as (
read_stream, write_stream, _
):
async with ClientSession(
read_stream, write_stream,
elicitation_handler=elicitation_handler
) as session:
await session.initialize()
result = await session.call_tool(
name="use_aws",
arguments={"command": "aws s3 rm s3://my-bucket/important-file"}
)
print(f"Tool result: {result}")
return result
asyncio.run(use_elicitation(
url="https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp",
token="YOUR_ACCESS_TOKEN"
))
- Strands MCP Client
-
-
from mcp.client.streamable_http import streamablehttp_client
from mcp.types import ElicitResult
from strands import Agent
from strands.tools.mcp import MCPClient
mcp_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
access_token = "YOUR_ACCESS_TOKEN"
async def elicitation_callback(context, params):
"""Handle form elicitation requests from the MCP server target."""
print(f"Elicitation: {params.message}")
user_response = get_user_input(params) # Your UI logic
return ElicitResult(action="accept", content=user_response)
mcp_client = MCPClient(
lambda: streamablehttp_client(
mcp_url, headers={"Authorization": f"Bearer {access_token}"}
),
elicitation_callback=elicitation_callback,
)
with mcp_client:
agent = Agent(tools=mcp_client.list_tools_sync())
response = agent("Delete the file s3://my-bucket/important-file using AWS CLI")
print(response)
- LangGraph MCP Client
-
-
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.callbacks import Callbacks, CallbackContext
from langchain.agents import create_agent
from mcp.shared.context import RequestContext
from mcp.types import ElicitRequestParams, ElicitResult
async def on_elicitation(
mcp_context: RequestContext,
params: ElicitRequestParams,
context: CallbackContext,
) -> ElicitResult:
"""Handle elicitation requests from MCP servers."""
print(f"[{context.server_name}] Elicitation: {params.message}")
# Prompt user for input based on params.requestedSchema
return ElicitResult(
action="accept",
content={"confirm": True},
)
client = MultiServerMCPClient(
{
"gateway": {
"url": "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp",
"transport": "http",
"headers": {"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
}
},
callbacks=Callbacks(on_elicitation=on_elicitation),
)
tools = await client.get_tools()
agent = create_agent("claude-sonnet-4-20250514", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Delete s3://my-bucket/important-file"}]}
)
URL モードの例
URL モードでは、サーバーはユーザーが アクション (通常は OAuth 認証) を完了するためにアクセスする必要がある URL を送信します。ユーザーが URL でアクションを完了するのを待っている間、リクエストは開いたままになります。
例
- Python requests package
-
-
import requests
import json
import sseclient
import webbrowser
gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
headers = {
"Content-Type": "application/json",
"Accept": "text/event-stream",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Mcp-Session-Id": "session-abc123def456"
}
# Call tool that triggers URL elicitation
response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "tool-call-2",
"method": "tools/call",
"params": {
"name": "access_github_repo",
"arguments": {"repo": "my-org/my-repo"}
}
}, stream=True)
# Process SSE events
client = sseclient.SSEClient(response)
for event in client.events():
data = json.loads(event.data)
if data.get("method") == "elicitation/create":
elicitation_id = data["id"]
url = data["params"]["url"]
print(f"URL elicitation: {data['params']['message']}")
# Open browser for user to complete authentication
webbrowser.open(url)
input("Press Enter after completing authentication...")
# Send elicitation response
requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": elicitation_id,
"result": {"action": "accept"}
})
elif "result" in data:
print(f"Tool result: {data['result']}")
break
- MCP Client
-
-
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
import asyncio
import webbrowser
async def elicitation_handler(request):
"""Handle URL elicitation by opening the browser."""
if hasattr(request.params, 'url') and request.params.url:
print(f"Opening URL for authentication: {request.params.url}")
webbrowser.open(request.params.url)
input("Press Enter after completing authentication...")
return {"action": "accept"}
# Form mode fallback
return {"action": "accept", "content": {}}
async def use_url_elicitation(url, token):
headers = {"Authorization": f"Bearer {token}"}
async with streamablehttp_client(url=url, headers=headers) as (
read_stream, write_stream, _
):
async with ClientSession(
read_stream, write_stream,
elicitation_handler=elicitation_handler
) as session:
await session.initialize()
result = await session.call_tool(
name="access_github_repo",
arguments={"repo": "my-org/my-repo"}
)
print(f"Tool result: {result}")
return result
asyncio.run(use_url_elicitation(
url="https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp",
token="YOUR_ACCESS_TOKEN"
))
- Strands MCP Client
-
-
from mcp.client.streamable_http import streamablehttp_client
from mcp.types import ElicitResult
from strands import Agent
from strands.tools.mcp import MCPClient
import webbrowser
mcp_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
access_token = "YOUR_ACCESS_TOKEN"
async def elicitation_callback(context, params):
"""Handle URL elicitation by opening the browser."""
if hasattr(params, 'url') and params.url:
print(f"Opening URL: {params.url}")
webbrowser.open(params.url)
input("Press Enter after completing authentication...")
return ElicitResult(action="accept")
return ElicitResult(action="accept", content={})
mcp_client = MCPClient(
lambda: streamablehttp_client(
mcp_url, headers={"Authorization": f"Bearer {access_token}"}
),
elicitation_callback=elicitation_callback,
)
with mcp_client:
agent = Agent(tools=mcp_client.list_tools_sync())
response = agent("Access the my-org/my-repo GitHub repository")
print(response)
- LangGraph MCP Client
-
-
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.callbacks import Callbacks, CallbackContext
from langchain.agents import create_agent
from mcp.shared.context import RequestContext
from mcp.types import ElicitRequestParams, ElicitResult
import webbrowser
async def on_elicitation(
mcp_context: RequestContext,
params: ElicitRequestParams,
context: CallbackContext,
) -> ElicitResult:
"""Handle URL elicitation by opening the browser."""
if params.url:
print(f"[{context.server_name}] Opening URL: {params.url}")
webbrowser.open(params.url)
input("Press Enter after completing authentication...")
return ElicitResult(action="accept")
return ElicitResult(action="accept", content={})
client = MultiServerMCPClient(
{
"gateway": {
"url": "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp",
"transport": "http",
"headers": {"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
}
},
callbacks=Callbacks(on_elicitation=on_elicitation),
)
tools = await client.get_tools()
agent = create_agent("claude-sonnet-4-20250514", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Access the my-org/my-repo GitHub repository"}]}
)