# 连接工具与 Agent 时，先定义谁负责执行

原文: https://yishto.com/learn/ai-foundations/agent-protocols-and-sdk-boundaries/

作者: [Yishto](https://yishto.com/about/)

区分 MCP 工具、A2A 任务、SDK 执行循环与 skills 材料，以窄读取契约检查授权、参数和结果责任。

首次发布: 2026-11-10
内容更新: 2026-11-10

资料助手能读取笔记，现在希望接入外部工具与另一名整理 Agent。连通协议解决消息怎样交换，业务仍要决定谁能执行、可操作哪些资源、结果怎样持久化。一个工具声明存在，不能让模型自动获得使用它的权限。

案例只允许读取笔记 N-1。外部 Agent 可以建议分类与任务步骤，但不能扩大这个资源范围。本文用离线契约检查演示执行前的校验，不启动 MCP 服务、A2A 服务或任何 Agent SDK。

## 把一次行为拆成独立责任

用户表达目标，模型提出动作，策略层判断是否允许，执行器调用能力，观测层记录结果，状态存储保存进度。即使这些职责运行在一个进程里，也应能分别检查。否则模型的一段文字很容易越过参数与权限验证直接变成副作用。

需要持久化的记录包括任务 ID、步骤、输入版本、授权范围、结果引用与错误状态。日志可以描述执行，但不能代替权威任务状态。重启之后要知道哪些动作已经成功，哪些结果未知，哪些允许重试。

对写入和外部副作用定义幂等与确认条件。工具调用超时可能发生在操作已提交之后，不能一律重新执行。授权应绑定具体动作与资源，外部 Agent 的请求或模型自称“已获批准”都不能成为扩大权限的依据。

## MCP 连接工具等能力提供者

MCP 定义客户端与服务端交换能力的协议，包括工具、资源和提示等概念。工具可以公开名称、描述与输入 schema，客户端发现后再发起调用。生命周期、能力协商与传输方式需要按对应版本实施，不能只拼一份 JSON 就宣称兼容。

schema 帮助检查形状，不证明对象属于当前用户。服务端需要验证参数与业务授权，客户端也需要控制哪些工具向模型公开。不同传输的认证安排各有条件，不能把某个 HTTP 授权机制直接用于所有本地进程连接。

官方工具规范关注调用可见性与人类控制。产品应让用户知道工具可能做什么，必要确认需要展示实际动作。只读工具仍可能泄露数据或消耗资源，所以权限检查与预算并不能省略。

## A2A 的任务协作有另一组边界

A2A 描述 Agent 能力、消息与任务交互，Agent Card 可以声明服务端点、技能与认证要求。能力声明帮助发现服务，不能证明服务可信，也不能替用户授予任务权限。身份、信任、数据传输范围与结果处理需要应用自己决定。

长任务会有开始、运行、需要输入、结束等状态，具体状态与操作应核对使用版本。远程任务成功表示对方报告完成，本地仍要验证返回资产、字段与任务要求。未知结果、取消和迟到回复要有处理规则。

A2A 与 MCP 可以在同一系统里出现：一个 Agent 委派任务，同时通过 MCP 使用窄工具。它们不自动提供所有实现间的兼容性，也不能把任务协作与工具执行混称成一种协议。先确定边界，再选择需要的部分。

## SDK 组织执行循环，skills 提供材料

Claude Agent SDK 将 Agent 循环、工具与上下文管理以程序化方式提供，具体能力与运行要求取决于当前文档。SDK、普通模型客户端、CLI 与托管 Agent 产品有不同执行责任，不能把名称相似当作相同权限或托管方式。

使用 SDK 时检查任务怎样开始与继续、工具如何接入、权限回调与中断怎样处理、状态保存在哪里。本文不写未经执行的 SDK 代码，也不把某个产品的权限模式推定为其他框架默认行为。

skills 通常打包可复用指令与资源，有时附带可执行脚本。它们被读取或运行，不是新学出的模型权重。引入 skill 前检查来源、脚本、网络与文件操作能力；其中的说明仍要遵守当前用户授权，不能自行扩展任务。

## 执行前校验窄工具契约

本例只有 read_note，必须恰好包含 note_id 字段，并属于可信程序提供的 authorized_ids。参数类型先检查，避免列表等异常值导致查表错误。授权集合不由调用者自己提交。

```python
tools = {"read_note": {"required": {"note_id"}}}
def accept(name, arguments, authorized_ids):
    if not isinstance(name, str):
        return False
    contract = tools.get(name)
    return (contract is not None and isinstance(arguments, dict)
            and set(arguments) == contract["required"]
            and isinstance(arguments["note_id"], str)
            and arguments["note_id"] in authorized_ids)
assert accept("read_note", {"note_id": "N-1"}, {"N-1"})
assert not accept("delete_note", {"note_id": "N-1"}, {"N-1"})
assert not accept("read_note", {"note_id": "N-2"}, {"N-1"})
assert not accept("read_note", {"note_id": []}, {"N-1"})
print(accept("read_note", {"note_id": "N-1"}, {"N-1"}))
```

实际输出是 `True`。允许范围内的读取通过；未知工具、他人笔记与错误参数类型被拒绝。这个函数只决定是否接纳，没有读取笔记、验证身份或实现任何协议传输。

真实执行时还要重新获取对象状态与访问规则，处理授权撤销、资源删除和检查到使用之间的竞争。输出也需要过滤，只返回当前任务允许的字段。工具说明说“只读”是声明，仍应核查实现是否具有写入或外部通信副作用。

## 结果、重试与观测保持关联

为每次任务与工具调用分配稳定 ID，关联模型建议、参数验证、执行结果和持久状态。记录必要元数据与错误分类，避免普通日志包含笔记正文、凭据或外部私有内容。观测入口也需要访问限制。

区分协议错误、业务拒绝、工具失败与模型误选。协议版本不匹配需要协商或更新，权限拒绝需要停止或请求新的授权，临时失败可以有限重试，模型选错工具则需要评估任务说明与能力暴露范围。

重放任务时不得把历史授权无限沿用。确认其范围与有效条件，若参数改变则重新核验。对外部消息保留来源与任务关联，但默认把它当作数据；另一个 Agent 不能仅靠消息内容取得本地执行身份。

工具列表也可能变化。客户端缓存了旧 schema，服务端升级了必需参数时，应明确失败并重新发现能力，不能把旧字段猜成新字段。记录实际协商版本与工具定义版本，可以解释某次调用为什么被拒绝，并避免把协议差异归成模型错误。

## 练习：连接前完成执行边界表

写一张表，列出用户目标、可发现能力、输入 schema、资源权限、执行位置、结果状态与恢复动作。为只读与删除操作分别设计路径；删除若需要确认，应绑定具体对象和效果。

验收时，未知工具、额外参数、错类型和越权对象都被拒绝；外部 Agent 消息不能扩展权限；超时和迟到结果可以解释。说明哪些属于 MCP、A2A、SDK 或 skill 的职责，哪些属于业务程序。离线校验只证明这份窄契约，真实互操作还需固定版本并分别测试协议连接与业务行为。

## 资料来源与延伸阅读

- [Model Context Protocol — Tools](https://modelcontextprotocol.io/specification/latest/server/tools)
- [Agent2Agent protocol specification](https://a2a-protocol.org/latest/specification/)
- [Agent SDK overview](https://platform.claude.com/docs/en/agent-sdk/overview)
- [Extend a coding tool with skills](https://code.claude.com/docs/en/skills)

资料核验：2026-11-10。教学示例不代表线上实测。

## 相关文章

- [MCP 与工具调用：输入契约、权限与执行边界](https://yishto.com/learn/agents/tool-contracts-and-mcp/)
- [为浏览器扩展划清页面和后台的边界](https://yishto.com/learn/application-platforms/browser-extension-study-assistant/)
