Gunakan elicitation dengan gateway Anda AgentCore
Elicitation adalah fitur MCP yang memungkinkan server MCP untuk meminta informasi tambahan dari klien selama panggilan alat. Ketika alat membutuhkan konfirmasi pengguna, otentikasi, atau input tambahan untuk melanjutkan, server mengirimkan permintaan elisitasi kembali ke klien. AgentCore Gateway meneruskan permintaan dari target server MCP ke klien Anda, menggantikan permintaan id dengan pengenal yang dihasilkan gateway.
Prasyarat
Untuk menggunakan elicitation dengan gateway Anda, Anda harus memiliki:
-
Sesi diaktifkan - Elicitation membutuhkan dukungan sesi. Lihat Menggunakan sesi MCP dengan gateway Anda.
-
Streaming respons diaktifkan - Permintaan elicitation dikirim sebagai potongan Server-Sent Acara (SSE) selama koneksi terbuka. Setel streamingConfiguration.enableResponseStreaming ke true dalam gateway AndaprotocolConfiguration.mcp.
-
Jenis target server MCP - Elicitation hanya didukung untuk target server MCP. Elisitasi berasal dari server MCP dan diteruskan melalui gateway ke klien.
-
Klien mendeklarasikan kemampuan elisitasi — Klien harus menyatakan dukungan untuk elisitasi selama permintaan gateway untuk meneruskan initialize permintaan elisitasi.
Mode elisitasi yang didukung
AgentCore Gateway mendukung tiga mode elisitasi yang ditentukan oleh spesifikasi MCP:
| Modus |
Deskripsi |
|
Mode formulir
|
Server mengirimkan formulir terstruktur dengan bidang untuk diisi klien. Digunakan untuk mengumpulkan konfirmasi pengguna, preferensi, atau data input. Permintaan tetap terbuka sambil menunggu tanggapan.
|
|
Mode URL (berbasis permintaan)
|
Server mengirimkan URL yang harus dikunjungi pengguna untuk menyelesaikan suatu tindakan (biasanya otentikasi). Permintaan tetap terbuka sambil menunggu tindakan selesai.
|
|
Mode URL (berbasis pengecualian)
|
Server melempar URLElicitationRequiredError berisi URL. Permintaan ditutup, pengguna menyelesaikan tindakan di URL, dan klien mencoba ulang panggilan alat asli.
|
Negosiasi kemampuan
Gateway hanya mendeklarasikan dukungan elisitasi ke target server MCP jika:
-
Klien menyatakan dukungan elisitasi selama. initialize
-
Versi protokol MCP mendukung mode elicitation — mode memerlukan versi atau yang lebih baru, form url mode memerlukan versi 2025-03-26 2025-11-25 atau yang lebih baru.
-
Gateway cocok dengan kemampuan elisitasi spesifik yang dideklarasikan oleh klien (formulir, url, atau keduanya).
-
Klien mengirimkan tools/call permintaan dengan Mcp-Session-Id header.
-
Gateway meneruskan panggilan alat ke target server MCP.
-
Target membuka aliran SSE dan mengirimkan elicitation/create permintaan sebagai acara pertama.
-
Gateway meneruskan elicitation/create permintaan ke klien pada aliran SSE, menggantikan permintaan. id
-
Klien menyajikan formulir kepada pengguna dan mengumpulkan respons.
-
Klien mengirimkan permintaan baru dengan respons elisitasi (tindakan: accept ataudecline) menggunakan yang sama. Mcp-Session-Id
-
Gateway meneruskan respons ke target server MCP.
-
Target mengakui dengan HTTP 202 Diterima.
-
Target menyelesaikan panggilan alat dan mengirimkan hasil akhir pada aliran SSE asli.
-
Gateway meneruskan hasil akhir ke klien dan menutup aliran.
Aliran elisitasi mode URL (berbasis pengecualian)
-
Klien mengirimkan tools/call permintaan dengan Mcp-Session-Id header.
-
Gateway meneruskan panggilan alat ke target server MCP.
-
Target melempar URLElicitationRequiredError sebagai JSON-RPC kesalahan, berisi URL dan ID elisitasi.
-
Gateway meneruskan URLElicitationRequiredError ke klien, menggantikan permintaanid.
-
Klien mengarahkan pengguna ke URL yang disediakan untuk menyelesaikan tindakan (biasanya otentikasi OAuth).
-
Setelah pengguna menyelesaikan tindakan, klien mencoba ulang permintaan aslitools/call.
-
Gateway meneruskan percobaan lagi ke target. Target menyelesaikan panggilan alat sejak elisitasi URL terpenuhi.
-
Gateway meneruskan hasil alat akhir ke klien.
Panggilan alat paralel dengan elisitasi
Klien dapat memulai beberapa tools/call permintaan dalam sesi yang sama, bahkan saat elisitasi tertunda. Setiap elisitasi dilacak secara independen olehnya. id Saat mengirim respons elisitasi, klien harus menyertakan hal yang sama id yang dikirim oleh gateway dalam permintaan. elicitation/create
Panduan untuk pengembang target server MCP
Target server MCP yang mengirim permintaan elisitasi harus membungkus panggilan elicitation dalam blok try-catch dan menangani kasus di mana klien tidak mendukung elisitasi. Jika klien gateway tidak mendeklarasikan kemampuan elisitasi, gateway tidak mendeklarasikannya ke target. Jika target tetap mengirimkan elisitasi, gateway mengembalikan kesalahan -32601 (Metode tidak ditemukan) ke target.
Server harus mengimplementasikan jalur fallback (seperti menggunakan nilai default atau melewatkan operasi) saat elicitation tidak tersedia.
Penanganan kesalahan
| Skenario |
Kesalahan |
Deskripsi |
|
Klien mengirimkan respons elisitasi ketika tidak ada elisitasi yang tertunda
|
JSON-RPC -32600(Permintaan Tidak Valid)
|
Tidak ada elisitasi yang cocok ditemukan untuk sesi ini.
|
|
Klien mengirimkan respons elisitasi dengan yang tidak cocok dengan elisitasi id yang tertunda
|
JSON-RPC -32600(Permintaan Tidak Valid)
|
idHarus cocok dengan yang dikirim oleh gateway dalam elicitation/create permintaan.
|
|
Koneksi terputus antara gateway dan target server MCP
|
JSON-RPC kesalahan dengan DependencyFailedException
|
Klien harus mencoba lagi permintaan panggilan alat asli.
|
|
Koneksi terputus antara klien dan gateway
|
N/A
|
Elisitasi yang tertunda dibersihkan. Klien harus mencoba lagi panggilan alat.
|
|
Server MCP mengirimkan elisitasi tetapi gateway tidak menyatakan dukungan
|
JSON-RPC -32601(Metode tidak ditemukan)
|
Kembali ke target server MCP. Lihat Pemecahan Masalah.
|
Pemecahan masalah
Kesalahan: “Kesalahan memanggil alat 'sample_tool': Metode tidak ditemukan:" elicitation/create
Kesalahan ini terjadi ketika target server MCP mengirimkan permintaan elisitasi tetapi klien gateway tidak mendeklarasikan kemampuan elisitasi selama. initialize Gateway mengembalikan kesalahan -32601 (Metode tidak ditemukan) ke target, dan target dapat mengembalikan ini sebagai kesalahan eksekusi alat ke klien.
Untuk menyelesaikan:
-
Jika Anda adalah pengembang server MCP: Tambahkan penanganan kesalahan di sekitar panggilan elisitasi Anda. Menerapkan jalur fallback saat elicitation tidak didukung:
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()
-
Jika Anda adalah pengembang klien gateway: Pastikan klien Anda mendeklarasikan kemampuan elisitasi selama: initialize
{
"capabilities": {
"elicitation": {
"form": {},
"url": {}
}
}
}
Sampel Kode
Dalam mode formulir, server mengirimkan skema terstruktur untuk diisi klien. Permintaan tetap terbuka sambil menunggu tanggapan.
contoh
- 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"}]}
)
Contoh mode URL
Dalam mode URL, server mengirimkan URL yang harus dikunjungi pengguna untuk menyelesaikan tindakan (biasanya otentikasi OAuth). Permintaan tetap terbuka sambil menunggu pengguna menyelesaikan tindakan di URL.
contoh
- 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"}]}
)