云端AgentCore通过WebSocket隧道+浏览器扩展实现远程调用本地MCP服务器,无需开放端口或VPN。
我们的智能体运行在云端,但用户的电子表格却保存在他们的笔记本电脑上。如何弥合这道鸿沟?
Model Context Protocol(MCP)是由 Anthropic 于 2024 年 11 月发布的开源标准,旨在标准化 AI 模型如何连接外部数据和工具。MCP 采用客户端-服务器架构,其中 MCP 主机(如 Amazon Quick 或 Claude Code 之类的 AI 应用)建立与一个或多个 MCP 服务器的连接。MCP 协议支持两种传输机制:stdio(同一机器上本地进程间通信的标准 I/O)和 streamable HTTP 传输(远程服务器与客户端之间的 HTTP 通信)。但有一种场景尚未覆盖:当 MCP 服务器位于本地而 MCP 客户端位于远程时。
这种模式对主要使用 Excel 和本地文件的财务人员和分析人员非常重要。他们可以使用集中部署的 AI 智能体来对这些文件执行操作,同时从浏览器中获取上下文。这与 Claude Cowork 等产品的底层模式相同——云端智能体通过 MCP 调用本地工具——但它完全自托管在 AWS 上,使用自己的模型和自定义工具服务器。我们在内部构建了一个生产级别的金融 AI 助手,自上线以来一年内的对话数已超过 41,000 次。
在本文中,我们以简化形式重现了内部构建的内容。我们的智能体部署在 Amazon Bedrock AgentCore 上,使用在用户本地机器上运行的 MCP 服务器。我们通过 WebSocket 和原生消息传递隧道传输 MCP 消息,来桥接远程 MCP 客户端与本地 MCP 服务器之间的通信。关于更多生产级加固措施,我们将在"What's Next"部分讨论。完整的源代码可在 GitHub 上获取。

架构概览
AgentCore 运行时(Amazon Bedrock AgentCore 的一项能力)将架构锚定在四个组件上:
下图展示了端到端的消息流。用户通过扩展发送消息,扩展通过预签名 WebSocket 连接到 AgentCore 运行时。当 Strands 智能体需要调用工具时,它发送一个封装在 JSON 信封中的 MCP JSON-RPC 请求,通过 WebSocket 返回给扩展。扩展通过原生消息传递将消息原样中继给桥接器。桥接器解开信封,提取 JSON-RPC 内容,并通过 stdio 将其转发给 MCP 服务器。响应沿相反路径返回。桥接器将未修改的 MCP 服务器响应重新封装到信封中,并通过扩展中继给 AgentCore 运行时,智能体消费工具结果并继续生成。

下表展示了一次工具调用从智能体到 MCP 服务器的完整旅程,每个跳点剥去一层封装:
| Hop | 协议 | 封装 |
|---|---|---|
| 1 | Strands Agent → WebSocket | JSON 信封 + JSON-RPC |
| 2 | WebSocket → 扩展 | JSON 信封 + JSON-RPC |
| 3 | 扩展 → Bridge(原生消息) | 4 字节长度 + JSON 信封 |
| 4 | Bridge → MCP Server(stdio) | 原始 JSON-RPC |
Strands 智能体在 AgentCore 运行时中如何工作
WebSocket 连接:浏览器扩展通过预签名 WebSocket URL 连接到 AgentCore 运行时。启动时,侧边栏通过后台脚本向原生桥接器发送预签名请求,原生桥接器使用用户的本地 AWS 凭证和 bedrock-agentcore 软件开发工具包(SDK)生成一个作用域为已部署运行时 ARN 的 SigV4 签名 wss:// URL(有效期 5 分钟)。侧边栏打开到该 URL 的 WebSocket。凭证永不离开用户机器,也不进入浏览器。如果因 URL 过期或网络中断导致连接断开,侧边栏会在 2 秒后自动请求新的预签名 URL 并重新连接,使过期窗口在正常使用中对用户不可见。
MCP 初始化:在发现工具之前,智能体会执行标准的 MCP 初始化握手。它发送带有协议版本的 initialize 请求,等待服务器的能力响应,然后发送 notifications/initialized 通知。只有在握手完成后,服务器才会接受 tools/list 和 tools/call 请求。
工具发现:对于每条用户消息,智能体调用 tools/list 并接收一个工具架构数组。它将每个架构封装到一个 Strands AgentTool 中,其 stream() 方法通过桥接器发送 tools/call 请求。添加到 MCP 服务器的工具会在下次请求时自动可用,无需修改智能体代码。
请求-响应关联:来自智能体的每个出站 JSON-RPC 请求都会被分配一个唯一 ID,并注册到一个以 (session_id, jsonrpc_id) 为键的 asyncio.Future 上。当响应通过 WebSocket 返回时,它与等待中的 Future 匹配并解析。这允许多个工具调用并发进行而不会产生歧义。
原生消息传递如何工作
我们需要扩展能够与长期运行的本地进程通信,但不能使用网络权限或每条消息都需用户确认。原生消息传递正是为此而设计。Chrome 和 Firefox 都支持其扩展的原生消息传递。浏览器在用户机器上的已知位置查找一个清单文件,该文件指定要启动的可执行文件。macOS 上 Chrome 的原生消息传递清单文件如下:
# Stored at ~/Library/Application\ Support/Google/Chrome/NativeMessagingHosts/com.example.mcp_bridge.json
{
"name": "com.example.mcp_bridge",
"description": "MCP Bridge - Routes MCP messages to local servers",
"path": "/path/to/mcp-bridge-demo/bridge/run_bridge.sh",
"type": "stdio",
"allowed_origins": [
"chrome-extension://<extension_id>/"
]
}
扩展启动时,后台脚本调用 chrome.runtime.connectNative("com.example.mcp_bridge") 在本地启动原生应用。清单文件中引用的 run_bridge.sh 脚本激活 Python 环境并启动桥接器:
#!/bin/bash
cd "/path/to/mcp-bridge-demo/bridge"
source .venv/bin/activate
exec python3 bridge.py
原生消息传递主机进程在连接的生命周期内保持运行。每条消息序列化为 JSON、UTF-8 编码,并在前面加上 32 位小端字节序的消息长度。原生消息传递主机发送的单个消息最大为 1 MB(以保护浏览器免受行为不当的原生应用程序影响)。发送到原生消息传递主机的消息最大为 64 MiB。
MCP Bridge 如何工作
MCP Bridge 在两个世界之间充当协议转换器:一侧是 Chrome 的原生消息传递协议,另一侧是 MCP 标准(基于 stdio 的 JSON-RPC 2.0)。在入站路径上,它从 stdin 剥离 4 字节长度头,解析 JSON 正文,解开信封提取原始 JSON-RPC 消息。在出站路径上,它做相反的事情:将 JSON-RPC 响应封装到信封中并加上长度头写回。JSON-RPC 内容本身保持不变地通过。
在内部,桥接器通过 FastMCP 代理运行两个并发循环连接的。主循环从浏览器读取消息,解开消息,并将 JSON-RPC 内容放入输入队列。FastMCP 代理在桥接器启动时启动一次,并在桥接器的整个生命周期内保持运行,它从队列中取出消息,通过其 stdin 将其转发给 MCP 服务器子进程,并将来自服务器 stdout 的响应放到输出队列中。第二个后台循环从输出队列中读取,将每个响应重新封装到信封中,并将其写入 stdout 以供浏览器接收。这种双循环设计将浏览器的请求时序与 MCP 服务器的处理速度解耦,使桥接器在等待慢速工具完成之前不必阻塞即可接受下一个请求。
MCP 服务器本身是由桥接器在启动时通过 mcp.json 文件配置生成的子进程。它在桥接器的整个生命周期内保持运行,没有每个请求的进程开销。添加新的 MCP 服务器只需修改一行配置。桥接器处理管道连接。
MCP Bridge 将浏览器扩展发出的消息转换为 MCP 协议,与 MCP 服务器通信。I/O 队列与 FastMCP 代理服务器协作,将消息转发至本地运行的 MCP 服务器,并将响应中继回浏览器扩展。
部署和测试 MCP Bridge 方案需要满足以下前提条件,涵盖浏览器扩展、部署在 AgentCore 上的智能体、MCP Bridge 以及一个示例 Excel MCP 服务器。
AWS 账户及权限
aws sts get-caller-identity 验证)。cdk bootstrap)。软件环境
npm install -g @aws/agentcore。npm install -g aws-cdk。预估时间及费用
克隆代码仓库
git clone https://github.com/aws-samples/sample-mcp-bridge-agentcore.git
cd mcp-bridge-demo
安装 Python 依赖
chmod +x scripts/setup.sh manifests/install.sh
./scripts/setup.sh
创建并部署智能体至 AgentCore
npm install -g @aws/agentcore
cd agent
agentcore create --name McpBridgeAgent --defaults
cd McpBridgeAgent
cp ../agent.py app/McpBridgeAgent/main.py
cp ../mcp_bridge_transport.py app/McpBridgeAgent/
agentcore deploy
注意输出中的运行时 Amazon Resource Name (ARN)(或运行 agentcore status)。
配置 Bridge
编辑 bridge/bridge_config.json,填入你的运行时 ARN:
{
"runtime_arn": "arn:aws:bedrock-agentcore:<region>:<account-id>:runtime/<your-runtime>",
"region": "us-east-1",
"presign_expires": 300
}
Bridge 使用本地 AWS 凭证自动生成预签名 WebSocket URL,无需手动管理令牌。
加载 Chrome 扩展
chrome://extensions。extension/ 目录。注册原生消息桥接
./manifests/install.sh <your-extension-id>
此脚本会创建一个启动器脚本并向 Chrome 注册,使浏览器能够启动 Bridge 进程。
启动并验证
重启浏览器,点击扩展图标打开侧边栏。扩展程序会自动向 Bridge 请求预签名 URL,连接至 AgentCore 并发现可用的 MCP 工具。
浏览器扩展通过原生消息与 MCP Bridge 通信,并在 AgentCore 托管的智能体与侧边栏之间中继 MCP 消息(如图为扩展 DevTools 控制台中的显示)。
可进一步实验的查询语句:
"Create a workbook called budget.xlsx with sheets Q1 and Q2"
"Write 'Revenue' in cell A1 of the Q1 sheet in budget.xlsx"
"Read the data from budget.xlsx"
本文优先演示 MCP Bridge 功能,因此安全措施限于以下几项:
allowed_origins 列表中,拒绝未明确列入的扩展连接。本架构特有的主要暴露面是 Bridge 本身。它接受云端托管智能体的指令,并以用户的文件系统权限在本地执行。核心原则是智能体不应获得超出用户明确授权范围的访问权限,且用户始终可以查看调用的工具及其参数。
对于生产系统,除了实现 Amazon Bedrock Guardrails 进行内容过滤外,我们还建议采取以下额外安全措施:
实验完成后,删除已部署的资源以避免持续产生费用。
移除 AgentCore 部署
cd agent/McpBridgeAgent
agentcore remove all
agentcore deploy
注销原生消息桥接
rm ~/Library/Application\ Support/Google/Chrome/NativeMessagingHosts/com.example.mcp_bridge.json
移除 Chrome 扩展
chrome://extensions。删除本地文件(可选)
rm -rf mcp-bridge-demo/
我们内部的生产方案包含以下能力。MCP Bridge 作为 AgentCore 托管智能体访问用户本地系统的窗口。结合浏览器扩展,当前架构可以扩展支持更多使用场景。
浏览器工具自动化
浏览器扩展可以基于 Playwright MCP 的工具定义实现自己的浏览器工具,并将其暴露给智能体,以执行点击元素、填写表单、导航页面和截图等操作。由于扩展充当 AgentCore 智能体与 MCP Bridge 之间的消息中继,它可以拦截 tools/list 和 tools/call MCP 消息,将浏览器工具注入工具列表,并在本地处理其执行。
本地工具自动化
Bridge 通过 stdio 传输标准 MCP JSON-RPC 通信,因此使用 stdio 传输的 MCP 服务器无需修改即可兼容。只需在 mcp.json 中添加一条配置即可。示例用途:沙盒化文件读写、Git 仓库操作、持久化本地知识图谱等。详见 awesome-mcp-servers 获取可用服务器目录。
将 Bridge 打包为独立二进制文件
生产分发时,我们使用 PyInstaller 将 Bridge 打包为独立二进制文件,将 Python 运行时、依赖项和配置捆绑为单一可执行文件。原生消息清单直接指向该二进制文件,因此用户无需安装 Python 或管理虚拟环境。Bridge 在首次启动扩展时即可正常工作,无需额外设置。
本文构建了一个 MCP Bridge,将 Amazon Bedrock AgentCore 上托管的云端 Strands 智能体连接到用户机器上本地运行的 MCP 工具服务器。借助浏览器扩展作为中继层,并使用 Chrome 的原生消息作为本地传输方式,我们在云端与用户文件系统之间建立了标准 MCP JSON-RPC 消息隧道,全程未向浏览器暴露凭证,也未修改 MCP 协议本身。
通过这种模式,你可以将智能体集中部署和管理,同时让它访问必须本地运行的工具,如 Excel 文件、Git 仓库或其他本地运行的 MCP 服务器。该架构具有良好的扩展性,只需修改一行配置即可添加新工具,通过扩展程序叠加浏览器操作,或将桥接程序打包为独立二进制文件以便无摩擦分发。
要开始使用,请部署示例仓库并尝试接入你自己的 MCP 服务器。有关本文使用的服务的更多信息,请探索 Amazon Bedrock AgentCore 文档、Strands Agents SDK 和 Model Context Protocol 规范。
感谢 Daniel Sheng Sun、Markus Hueck、Nishant Bisen、Shraddha Kabade 和 Stacy Kim 对内部生产系统的贡献,正是这一系统启发了本文。