Amazon Quick + MCP 远程服务实战:让 AI 助手直接操作飞书,从设计到落地

Amazon Quick + MCP 远程服务实战:让 AI 助手直接操作飞书,从设计到落地

"帮我在飞书上建一个项目群,把这 5 个人拉进去,然后发一条启动通知。"

这种话以前只能对人说。现在可以对 Amazon Quick 说了——它真的能帮你执行。

但实现起来没那么简单。飞书有 200+ 开放 API,全塞给 AI 作为工具上下文?token 直接爆炸。多步操作的准确率怎么保证?token 泄露了怎么办?

亚马逊云科技官博最近发了一篇实践文章,讲了怎么用 Bedrock AgentCore 构建远程 MCP 服务来解决这些问题。我看完之后照着搭了一套,记录一下关键设计决策和踩的坑。

问题:200+ 工具的上下文膨胀

飞书开放平台的 API 覆盖了消息、群组、文档、日历、审批、多维表格等十几个模块。如果把所有工具描述一股脑塞进 system prompt:

  • 200+ 工具 × 平均 300 token/工具描述 ≈ 60,000 token 上下文
  • Claude 每次请求都要"读"这些描述来决策用哪个
  • 绝大多数工具在当前对话中完全用不上
  • 成本和延迟都往上飙

方案:Meta Tool + 按需加载

核心思路是分层注册。不把 200+ 工具全给 AI,而是给它一个"工具索引"(Meta Tool),让它先查询有哪些能力,再按需加载具体工具。

用户请求
    ↓
AI 调用 Meta Tool → "飞书消息相关能力有哪些?"
    ↓
返回 5 个具体工具描述
    ↓
AI 选择具体工具执行 → send_message / create_group

这样每次对话只加载用得上的工具,上下文从 60K token 降到 3-5K token。

架构设计

整体架构分三层:

Amazon Quick (AI 助手)
    ↓ MCP 协议
Bedrock AgentCore (远程 MCP 服务)
    ↓ REST API
飞书开放平台

Bedrock AgentCore 做了什么

AgentCore 在这里的角色是远程 MCP 服务器。它负责:

  1. 工具注册和发现 — 管理所有飞书 API 的工具描述
  2. 认证和鉴权 — OAuth PKCE + HMAC 签名
  3. 执行代理 — 接收 AI 的工具调用请求,转发到飞书 API
  4. 结果格式化 — 把飞书 API 的原始响应转成 AI 能理解的格式

为什么用远程 MCP 不用本地

本地 MCP(每个用户电脑跑一个 MCP server)有几个问题:

  • 需要用户本地安装和配置
  • 飞书 token 存在用户电脑上,安全风险大
  • 不同用户的权限难以统一管理
  • 无法集中监控和审计

远程 MCP 服务部署在 AWS 上,统一管理认证和权限。Amazon Quick 通过 MCP 协议与之通信。

关键设计:token 安全

飞书 API 调用需要 access_token。这个 token 怎么管理,直接影响系统安全。

方案:OAuth PKCE + HMAC 域分离签名

import hashlib
import hmac
import time
import secrets

class TokenManager:
    """飞书 token 安全管理"""
    
    def __init__(self, app_id: str, app_secret: str, signing_key: bytes):
        self.app_id = app_id
        self.app_secret = app_secret
        self.signing_key = signing_key
    
    def get_tenant_token(self) -> str:
        """获取租户级别的 access_token"""
        import requests
        resp = requests.post(
            "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
            json={"app_id": self.app_id, "app_secret": self.app_secret}
        )
        return resp.json()["tenant_access_token"]
    
    def sign_request(self, user_id: str, action: str, timestamp: int) -> str:
        """HMAC 域分离签名 — 防止跨用户/跨操作伪造"""
        message = f"{user_id}|{action}|{timestamp}"
        return hmac.new(
            self.signing_key,
            message.encode(),
            hashlib.sha256
        ).hexdigest()
    
    def verify_request(self, user_id: str, action: str, 
                       timestamp: int, signature: str) -> bool:
        """验证请求签名,防止重放攻击"""
        # 检查时间戳(5分钟有效)
        if abs(time.time() - timestamp) > 300:
            return False
        expected = self.sign_request(user_id, action, timestamp)
        return hmac.compare_digest(expected, signature)

关键点:

  • 域分离 — 签名里包含 user_id 和 action,防止 A 用户的签名被 B 用户复用
  • 时间戳 — 5 分钟有效期,防重放
  • HMAC-SHA256 — 签名密钥存在服务端,客户端拿不到

Meta Tool 实现

Meta Tool 本质上是一个"工具目录"服务:

from typing import Dict, List

# 工具分类注册表
TOOL_REGISTRY: Dict[str, List[dict]] = {
    "messaging": [
        {"name": "send_message", "description": "发送消息到指定会话"},
        {"name": "reply_message", "description": "回复指定消息"},
        {"name": "recall_message", "description": "撤回已发送的消息"},
    ],
    "group": [
        {"name": "create_group", "description": "创建群组"},
        {"name": "add_members", "description": "添加群成员"},
        {"name": "set_group_name", "description": "修改群名称"},
    ],
    "calendar": [
        {"name": "create_event", "description": "创建日历事件"},
        {"name": "list_events", "description": "查询日历事件列表"},
        {"name": "update_event", "description": "更新日历事件"},
    ],
    "docs": [
        {"name": "create_doc", "description": "创建云文档"},
        {"name": "update_doc", "description": "更新文档内容"},
        {"name": "share_doc", "description": "分享文档给指定用户"},
    ]
}

def meta_tool_query(category: str = None, keyword: str = None) -> List[dict]:
    """Meta Tool: AI 调用此函数发现可用工具
    
    Args:
        category: 按分类筛选 (messaging/group/calendar/docs)
        keyword: 按关键词搜索工具描述
    
    Returns:
        匹配的工具列表(含完整参数定义)
    """
    results = []
    for cat, tools in TOOL_REGISTRY.items():
        if category and cat != category:
            continue
        for tool in tools:
            if keyword and keyword not in tool["description"]:
                continue
            results.append({"category": cat, **tool})
    return results

AI 的调用流程变成:

  1. 用户说"帮我建个群" → AI 调用 meta_tool_query(category="group")
  2. 拿到 create_groupadd_members 等工具描述
  3. AI 选择 create_group 并填入参数执行

多步编排的准确性

实际任务往往需要多步操作。比如"建群+拉人+发消息":

async def execute_multi_step(steps: List[dict], context: dict):
    """多步操作编排器"""
    results = {}
    
    for step in steps:
        tool_name = step["tool"]
        params = step["params"]
        
        # 支持步骤间参数传递
        # 比如 create_group 返回 group_id,add_members 需要用它
        for key, value in params.items():
            if isinstance(value, str) and value.startswith("$"):
                ref = value[1:]  # "$create_group.group_id" → "create_group.group_id"
                ref_step, ref_field = ref.split(".")
                params[key] = results[ref_step][ref_field]
        
        # 执行当前步骤
        result = await call_feishu_api(tool_name, params, context)
        results[step["id"]] = result
        
        # 失败则中断(不做半截操作)
        if not result.get("success"):
            return {"status": "failed", "failed_step": step["id"], 
                    "error": result.get("error"), "completed": results}
    
    return {"status": "success", "results": results}

部署到 AgentCore

把整套 MCP 服务部署为 AgentCore 托管的远程服务:

# 打包部署
aws bedrock-agentcore create-mcp-service \
  --service-name "feishu-mcp" \
  --description "飞书操作 MCP 服务" \
  --runtime "python3.12" \
  --handler "main.handler" \
  --source-code-path "./feishu_mcp/" \
  --environment-variables '{
    "FEISHU_APP_ID": "cli_xxxx",
    "SIGNING_KEY_ARN": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:feishu-signing-key"
  }' \
  --region ap-northeast-1

敏感配置(app_secret、signing_key)存在 Secrets Manager 里,运行时通过 IAM Role 获取。

踩坑记录

  1. 飞书 token 有效期 2 小时 — 必须做自动刷新。我用了一个后台 timer 每 90 分钟刷新一次。

  2. 消息格式兼容 — 飞书消息支持富文本、卡片、Markdown 等多种格式。AI 生成的纯文本消息需要包装成飞书消息格式。

  3. 权限粒度 — 不是所有用户都能操作所有群。Meta Tool 返回工具列表时要根据当前用户的权限过滤。

参考链接

posted @ 2026-06-09 20:00  亚马逊云开发者  阅读(12)  评论(0)    收藏  举报