View a markdown version of this page

在网关中使用激励 AgentCore - 亚马逊基岩 AgentCore

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在网关中使用激励 AgentCore

Elicitation 是一项 MCP 功能,它允许 MCP 服务器在工具调用期间向客户端请求其他信息。当工具需要用户确认、身份验证或其他输入才能继续操作时,服务器会向客户端发送激发请求。 AgentCore Gateway 将来自 MCP 服务器目标的诱发请求转发到您的客户端,将请求id替换为网关生成的标识符。

先决条件

要在网关中使用激励,您必须:

  • 启用会话(版本 2025-11-25 及更早版本)— Elicitation 需要会话支持。请参阅在网关上使用 MCP 会话。对于版本2026-07-28及更高版本,您无需sessionConfiguration添加到网关,因为这些版本是无状态的。

  • 启用响应流(2025-11-25 及更早版本)— 在打开的连接期间,激发请求以 Server-Sent 事件 (SSE) 区块的形式发送。streamingConfiguration.enableResponseStreaming在网关true中设置为protocolConfiguration.mcp。对于版本2026-07-28及更高版本,您无需启用响应流。这些版本通过多往返请求 (MRTR) 模式而不是响应流上服务器发起的请求来提供引发。有关更多信息,请参阅 “模型上下文协议” 文档中的多次往返请求。

  • MCP 服务器目标类型 — 只有 MCP 服务器目标支持激发。诱发源自 MCP 服务器,并通过网关转发到客户端。

  • 客户端声明激发能力 -客户端必须声明支持激发,网关才能转发激发请求。对于版本2025-11-25及更早版本,客户端会在initialize请求中声明此支持。对于版本2026-07-28及更高版本,客户端在_meta字段 (io.modelcontextprotocol/clientCapabilities) 中为每个请求声明功能。

支持的激发模式

AgentCore 网关支持 MCP 规范定义的三种激发模式:

Mode 说明

表单模式

服务器发送一个包含字段的结构化表单供客户填写。用于收集用户确认、首选项或输入数据。在等待回复期间,请求保持打开状态。

URL 模式(基于请求)

服务器发送一个 URL,用户必须访问该网址才能完成操作(通常是身份验证)。在等待操作完成期间,请求将保持打开状态。

URL 模式(基于异常)

服务器抛出一个URLElicitationRequiredError包含 URL 的。请求关闭,用户在 URL 处完成操作,然后客户端重试原始工具调用。

能力协商

只有在以下情况下,网关才声明对 MCP 服务器目标的激发支持:

  1. 客户宣布支持招标。对于版本2025-11-25及更早版本,客户端将在此期间声明这一点initialize。对于版本2026-07-28及更高版本,客户端会为中的每个请求声明该版本_meta。

  2. MCP 协议版本支持激发模式。form模式需要版本2025-03-26或更高版本。url模式需要版本2025-11-25或更高版本。

  3. 网关与客户端声明的特定诱发功能(表单、网址或两者兼而有之)相匹配。

表单模式激发流程

注意

此处描述的流程适用于版本2025-11-25及更早版本,其中服务器elicitation/create作为服务器启动的请求在开放的 SSE 流上发送。对于版本2026-07-28及更高版本,引用改为使用多往返请求 (MRTR) 模式。服务器返回临时结果,客户端使用收集的输入重试原始请求。有关更多信息,请参阅 “模型上下文协议” 文档中的多次往返请求。

  1. 客户端发送带有Mcp-Session-Id标头的tools/call请求。

  2. 网关将工具调用转发到 MCP 服务器目标。

  3. 目标打开 SSE 流并作为第一个事件发送elicitation/create请求。

  4. Gateway 通过 SSE 流将elicitation/create请求转发到客户端,取代请求id。

  5. 客户将表单呈现给用户并收集响应。

  6. 客户端使用相同的激发响应(操作:accept或decline)发送新请求。Mcp-Session-Id

  7. 网关将响应转发到 MCP 服务器目标。

  8. 目标使用已接受 HTTP 202 进行确认。

  9. 目标完成工具调用并在原始 SSE 流上发送最终结果。

  10. Gateway 将最终结果转发给客户端并关闭直播。

URL 模式(基于异常)激发流程

  1. 客户端发送带有Mcp-Session-Id标头的tools/call请求。

  2. 网关将工具调用转发到 MCP 服务器目标。

  3. 目标会以 JSON-RPC 错误的URLElicitationRequiredError形式抛出,其中包含 URL 和引发 ID。

  4. 网关将转发URLElicitationRequiredError给客户端,替换请求id。

  5. 客户端将用户重定向到提供的 URL 以完成操作(通常是 OAuth 身份验证)。

  6. 用户完成操作后,客户端会重试原始tools/call请求。

  7. 网关将重试转发给目标。自网址征集完成以来,目标完成了工具调用。

  8. Gateway 将最终的工具结果转发给客户端。

带提示的并行工具调用

客户可以在同一个会话中发起多个tools/call请求,即使请求处于待处理状态。每次诱发都由其独立跟踪. id 发送诱发响应时,客户端必须在请求中id包含网关发送的响应。elicitation/create

MCP 服务器目标开发人员指南

重要

发送激发请求的 MCP 服务器目标应将诱发调用包装在 try-catch 块中,并处理客户端不支持激发的情况。如果网关的客户端没有声明激发能力,则网关不会将其声明给目标。如果目标无论如何都会发送诱发,则网关会向目标返回-32601(未找到方法)错误。

当无法激发时,服务器应实现备用路径(例如使用默认值或跳过操作)。

保护请求状态(版本 2026-07-28 及更高版本)

在版本2026-07-28及更高版本中,Elicitation 使用多往返请求 (MRTR) 模式,该模式在您的客户端和 MCP 服务器目标requestState之间呈不透明状态。保护这一价值是一项共同的责任:网关在不存储的情况下对其进行授权和转发,而您的 MCP 服务器目标必须对其进行验证并防止一个用户重播另一个用户的请求状态。有关完全分担责任模型和您的 MCP 服务器必须遵循的保护指南,请参阅 MCP 服务器目标注意事项中的保护请求状态以进行引用和采样。

错误处理

场景 错误 说明

当没有待处理的请求时,客户端会发送激活响应

JSON-RPC -32600(请求无效)

未找到与该会话匹配的引用。

客户端发送的诱发响应与待处理id的请求不匹配

JSON-RPC -32600(请求无效)

id必须与elicitation/create请求中网关发送的相匹配。

网关和 MCP 服务器目标之间的连接中断

JSON-RPC 出错了 DependencyFailedException

客户端应重试原始工具调用请求。

客户端和网关之间的连接中断

N/A

待处理的招标已清理。客户应重试该工具调用。

MCP 服务器发送邀请,但网关未宣布支持

JSON-RPC -32601(未找到方法)

返回到 MCP 服务器目标。参阅故障排除。

Gateway-authored 激发需要客户未声明的功能(版本2026-07-28及更高版本)

JSON-RPC -32021(缺少所需的客户端功能)、HTTP 400

在版本2026-07-28及更高版本中,网关返回此代码而不是-32601。当客户端未在其请求中声明所需功能时,就会发生这种情况_meta。

问题排查

错误:“调用工具'sample_tool'时出错:未找到方法:” elicitation/create

当 MCP 服务器目标发送激发请求但网关的客户端未声明激发能力时,就会出现此错误。对于版本2025-11-25及更早版本,客户端将在期间声明此功能initialize。对于版本2026-07-28及更高版本,客户端会在_meta字段中为每个请求声明该版本。网关向目标返回-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()
  • 如果您是网关客户端开发者:对于版本2025-11-25及更早版本,请确保您的客户端在以下期间声明激发功能:initialize

    { "capabilities": { "elicitation": { "form": {}, "url": {} } } }

错误:“缺少所需的客户端功能” (-32021)

在版本2026-07-28及更高版本中,当网关创作的激发需要未声明的400功能时,网关会返回-32021错误 (HTTP)。由于这些版本是无状态的,没有initialize握手,因此客户端会在每个请求中声明功能。要纠正此错误,请在每个可能触发激发的请求的请求_meta字段 (io.modelcontextprotocol/clientCapabilities) 中添加激发功能。

代码示例

表单模式示例

在表单模式下,服务器发送结构化架构供客户端填写。在等待回复期间,请求保持打开状态。

例
Python requests package (2025-11-25 and earlier)

在这些版本中,客户端在期间声明了激发能力initialize,并以elicitation/create请求的形式在开放的 SSE 数据流中到达。将标MCP-Protocol-Version头设置为您的网关支持的版本。

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 headers["MCP-Protocol-Version"] = "2025-06-18" # 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
Python requests package (2026-07-28)

在版本上2026-07-28,Elicitation 使用多往返请求模式,而不是服务器在 SSE 流上发起的请求。客户在每个请求中_meta都声明了激发能力。如果该工具需要输入,则响应是包含input_required结果inputRequests且不透明requestState。客户端收集输入并使用新的id、和未修改的重试原始请求。inputResponses requestState不使用会话和initialize握手。您的网关supportedVersions必须包括2026-07-28。

import requests gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp" META = { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientInfo": {"name": "my-agent", "version": "1.0.0"}, "io.modelcontextprotocol/clientCapabilities": {"elicitation": {"form": {}, "url": {}}} } headers = { "Content-Type": "application/json", "Accept": "application/json, text/event-stream", "Authorization": "Bearer YOUR_ACCESS_TOKEN", "MCP-Protocol-Version": "2026-07-28", "Mcp-Method": "tools/call", "Mcp-Name": "use_aws" } arguments = {"command": "aws s3 rm s3://my-bucket/important-file"} # Step 1: Call the tool, declaring the elicitation capability in _meta response = requests.post(gateway_url, headers=headers, json={ "jsonrpc": "2.0", "id": "tool-call-1", "method": "tools/call", "params": {"name": "use_aws", "arguments": arguments, "_meta": META} }).json() result = response["result"] if result.get("resultType") == "input_required": # Step 2: Fulfill each input request (form elicitation) input_responses = {} for key, input_request in result.get("inputRequests", {}).items(): print(f"Form elicitation received: {input_request['params']['message']}") input_responses[key] = {"action": "accept", "content": {"confirm": True}} # Step 3: Retry the tool call with a new id, the input responses, # and the requestState echoed back unmodified retry_params = {"name": "use_aws", "arguments": arguments, "_meta": META, "inputResponses": input_responses} if "requestState" in result: retry_params["requestState"] = result["requestState"] response = requests.post(gateway_url, headers=headers, json={ "jsonrpc": "2.0", "id": "tool-call-2", "method": "tools/call", "params": retry_params }).json() result = response["result"] print(f"Tool result: {result}")
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 模式下,服务器发送一个 URL,用户必须访问该网址才能完成操作(通常是 OAuth 身份验证)。在等待用户在 URL 上完成操作时,请求将保持打开状态。

例
Python requests package (2025-11-25 and earlier)

在这些版本中,URL 引用在 MCP 会话内以开放的 SSE 流中的elicitation/create请求形式到达。将标MCP-Protocol-Version头设置为您的网关支持的版本。

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-Protocol-Version": "2025-11-25", "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
Python requests package (2026-07-28)

在版本上2026-07-28,URL 引用是input_required通过多往返请求模式而不是在 SSE 流中获得的。用户在 URL 上完成操作,然后客户端使用新的id、未requestState修改的inputResponses重试原始请求。不使用会话。您的网关supportedVersions必须包括2026-07-28。

import requests import webbrowser gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp" META = { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientInfo": {"name": "my-agent", "version": "1.0.0"}, "io.modelcontextprotocol/clientCapabilities": {"elicitation": {"form": {}, "url": {}}} } headers = { "Content-Type": "application/json", "Accept": "application/json, text/event-stream", "Authorization": "Bearer YOUR_ACCESS_TOKEN", "MCP-Protocol-Version": "2026-07-28", "Mcp-Method": "tools/call", "Mcp-Name": "access_github_repo" } arguments = {"repo": "my-org/my-repo"} # Step 1: Call the tool, declaring the elicitation capability in _meta response = requests.post(gateway_url, headers=headers, json={ "jsonrpc": "2.0", "id": "tool-call-1", "method": "tools/call", "params": {"name": "access_github_repo", "arguments": arguments, "_meta": META} }).json() result = response["result"] if result.get("resultType") == "input_required": # Step 2: Open the browser for the user to complete each URL elicitation input_responses = {} for key, input_request in result.get("inputRequests", {}).items(): params = input_request["params"] print(f"URL elicitation: {params['message']}") webbrowser.open(params["url"]) input("Press Enter after completing authentication...") input_responses[key] = {"action": "accept"} # Step 3: Retry the tool call with a new id, the input responses, # and the requestState echoed back unmodified retry_params = {"name": "access_github_repo", "arguments": arguments, "_meta": META, "inputResponses": input_responses} if "requestState" in result: retry_params["requestState"] = result["requestState"] response = requests.post(gateway_url, headers=headers, json={ "jsonrpc": "2.0", "id": "tool-call-2", "method": "tools/call", "params": retry_params }).json() result = response["result"] print(f"Tool result: {result}")
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"}]} )