← 所有文章

App Intents 与 MCP:路由问题

两个协议——App Intents 和 MCP——都允许外部代理操作应用的领域。它们并不能合二为一。问题在于哪个用在哪里,以及为什么每个协议都是其自身调用方的正确答案。

Apple 推出 App Intents 是为了给 Apple Intelligence 提供一个类型化的、声明式的接口,以便在不触及第三方应用 UI 的情况下操作它们。1 Anthropic 推出 Model Context Protocol 是为了给任何 LLM 提供一个类型化的、由服务器中介的接口,以便在不触及任何工具 UI 的情况下操作它们。2 形态相似,调用方却不同。把它们当作同一个接口处理,会导致一种两边都不讨好的架构。

本系列前两篇文章分别介绍了每个协议:App Intents 见 App Intents 是 Apple 通往您应用的新 API,MCP 见 两个代理生态,一个购物清单。本文要讨论的是路由问题。某项能力何时应该使用 AppIntent,何时应该使用 MCP 工具,何时应该两者兼用,以及哪些能力应仅在应用内部暴露?

TL;DR

  • App Intents 是通往 Apple Intelligence、Siri、Shortcuts 以及系统建议堆栈的唯一路径。系统会从安装时起以及通过应用更新使其可用,App Shortcuts 的捐赠和索引会将其展现到 Spotlight 和 Siri 建议中。
  • MCP 工具是通往所有非 Apple LLM(Claude、ChatGPT、Gemini、本地模型)的路径。传输方式为 stdio 或 Streamable HTTP,.mcpb 是一种打包格式,通常携带一个本地 stdio 服务器;主机在会话时加载工具。
  • 两种协议都收敛于类型化模式(schema)、entity → action → result 的形态,以及参数解析。它们在身份、持久化、延迟以及渲染表面上有所差异。
  • 路由规则:如果该能力是用户可能向 Siri 询问或从 Spotlight 调用的,就用 App Intents。如果该能力是开发者可能接入 Claude Code 会话或外部代理运行的,就用 MCP。大多数应用对同一领域两者都需要。

两个协议,相同形态

两种协议都定义了外部调用方与应用领域之间的操作契约。该契约由三部分组成:模式(调用方可以请求什么)、解析器(应用如何找到模式所指向的实体)、动作(运行什么以及返回什么)。

App Intents 用 Swift 表达契约。其协议接口为 AppIntentAppEntityAppEnum,由 @Parameter 宏驱动模式定义,func perform() 返回结果。3 模式在编译时生成并随应用安装一起打包。Apple Intelligence、Siri、Shortcuts 和 Spotlight 都读取相同的模式,并通过同一个 perform() 入口路由类型化请求。

MCP 通过 stdio 或 Streamable HTTP 上的 JSON-RPC 表达契约。其协议接口为 tools/listtools/call 方法,每个工具声明一个名称、一个描述和一个 inputSchema(2025-06-18 规范增加了可选的 outputSchema 用于结构化返回)。4 MCP 主机(Claude Desktop、Claude Code、Cursor、ChatGPT 桌面应用)在会话开始时发现工具,并以 JSON 载荷按名称调用它们。主机运行模型,服务器运行工具。

形态是相同的:模式、解析器、动作。不同之处在于谁来运行每个部分以及信任边界在哪里。App Intents 在应用进程内、用户设备上、应用的权限下运行,调用路由由系统中介。MCP 服务器运行在开发者所选的位置(本地 stdio、托管 HTTP、嵌入式包),调用路由由主机 LLM 在无界数量的工具间中介。

两个协议的分歧之处

除了表面形态之外,对路由有影响的运行差异有四个:

身份与持久化。 App Intents 以 AppEntity 类型表达,系统可以存储、呈现并在以后重新解析它们。我今天通过嘿 Siri,在 Water 中记录 250ml保存的喝水记录会在重启后保留下来,跨用户的 iCloud 设备同步,并且可以被后续其他意图引用(显示我昨天的喝水记录)。系统在所有这些调用中跟踪实体 ID。3 MCP 本身是一个具有生命周期管理的有状态协议,Streamable HTTP 也支持用于连接连续性的会话 ID,但持久的领域身份属于服务器自有的关注点;没有协议级的对应物可以让主机模型像依赖 AppEntity 标识符那样跨会话依赖。MCP 支持 resources 用于持久引用数据,但身份仍然是服务器侧的责任,而非一等的协议契约。4

延迟与电池。 App Intent 的 perform() 主体在设备上的应用或应用扩展上下文中执行。任何网络使用都来自应用自身的代码或周围的 Apple Intelligence/Siri 层,而非来自意图契约本身。在常见情况下,类型化的、设备上的动作返回类型化结果是迅速的。MCP 工具,即使是本地的,也要经过 stdio JSON-RPC 帧化处理,并具有独立的进程边界,远程 MCP 工具还要承受 HTTP 往返开销。延迟预算是不同的。一个记录 250ml的 App Intent 可以在 Siri 的会话轮换窗口内完成。一个远程 MCP 工具则可能成为 Claude Code 会话的瓶颈。

渲染表面。 App Intents 返回的结果由 Apple Intelligence 渲染到系统 UI 中:锁屏横幅、Siri 响应、Shortcuts 输出、Spotlight 结果。应用并不控制结果如何呈现。MCP 工具返回内容块(文本、图像、音频、嵌入资源或结构化内容),由主机模型读取并决定如何展现。Claude Code 会话可能将结果引述给开发者、加以总结,或将其输入后续调用。渲染决策位于模型层。

可发现性。 Apple Intelligence 从安装开始就让 App Intents 可用,App Shortcuts 的捐赠与索引会根据用户行为将意图浮现到 Spotlight 搜索和 Siri 建议中;应用更新和动态实体会随时间调整这一表面。用户从不需要键入工具名称。MCP 主机在会话开始时读取工具;用户(或系统提示)决定模型可以看到哪些工具。MCP 端的发现是显式配置,App Intents 端则是隐式的系统推断。

两种协议在身份、延迟、渲染和发现上的分歧——这四种属性都源自一个根本区别。App Intents 服务于用户未配置的系统级代理。MCP 服务于开发者配置的会话级代理。调用方不同,义务也不同。

路由规则

对于一个同时使用两种协议的应用,能力图谱看起来像这样:

                    ┌──────────────────────────────────────────┐
                    │           App's domain capabilities       │
                    │                                            │
                    │  ┌─────────┐  ┌─────────┐  ┌─────────┐    │
                    │  │  CRUD   │  │ Queries │  │ Actions │    │
                    │  └─────────┘  └─────────┘  └─────────┘    │
                    └────┬────────────┬────────────┬────────────┘
                         │            │            │
              ┌──────────┴──────┐    │   ┌────────┴──────────┐
              │                 │    │   │                   │
              ▼                 ▼    ▼   ▼                   ▼
       ┌────────────┐    ┌─────────────────────┐    ┌──────────────┐
       │ App Intents │    │ Both (AppIntent +   │    │  MCP tools   │
       │   only      │    │  MCP tool wrapper)  │    │    only      │
       └────────────┘    └─────────────────────┘    └──────────────┘
            │                       │                       │
       Siri / Spotlight       Cross-protocol           Claude Code,
       Shortcuts              capabilities             external agents,
       Apple Intelligence     where both callers       LLM tooling,
       proactive surfaces     should reach the         dev workflows
                              same domain

路由规则是按顺序提出的三个问题。

该能力是用户会向 Siri 询问或从 Shortcuts 调用的吗?如果是,那么该能力需要 App Intent。记录 250ml 喝水开始一次冥想把香蕉加到我的清单我昨天的体重是多少都是意图,因为用户可能会大声说出来、键入到 Spotlight,或在 Shortcuts 中链式调用。对这些能力而言,App Intent 是非可选的;没有别的途径能让您接入 Apple Intelligence 的第一方代理表面。

该能力是外部代理应该能够驱动的吗?如果是,该能力需要一个 MCP 工具。从 Claude Code 会话向购物清单添加项目将 Get Bananas 状态读入 Cursor 代理上下文从远程使用工具的 LLM 触发工作流都是 MCP 工具,因为调用方不是 Apple Intelligence;调用方是开发者接入的任何 LLM。MCP 工具可以包装 App Intent 调用的同一个领域层 Swift 函数,但其协议接口是开发者所选传输上的 JSON-RPC。

该能力是否需要在单次会话之外存活,并具有稳定的、系统已知的身份?如果是,App Intent 路径是自然的选择,因为系统会免费提供 AppEntity 身份、查询支持和持久化语义。如果不是,MCP 工具可以返回内容块、把持久身份留给服务器自行决定,并省去实体建模成本。

大多数非平凡的应用能力落在两者皆有的列中。Water 中的喝水记录能力既有 AppIntent(让 Siri 可以听写),又有 MCP 工具(让 Claude Code 会话可以从导出日志回填)。两条路径共享一个 Swift 函数;该函数并不知道是哪一个调用方调用了它。5

代码上看,这种形态是一个领域方法和两个适配器包装器,两者都调用它:

// Domain layer (Swift, no protocol assumptions)
func logWater(amount: Measurement<UnitVolume>, at: Date, caller: Caller) throws -> WaterEntry {
    try guards.requireWritePermission(caller)
    let entry = WaterEntry(amount: amount, timestamp: at)
    try store.insert(entry)
    return entry
}

// Adapter 1: App Intent (Apple Intelligence / Siri / Shortcuts)
struct LogWaterIntent: AppIntent {
    static var title: LocalizedStringResource = "Log Water"
    @Parameter(title: "Amount") var amount: Measurement<UnitVolume>

    func perform() async throws -> some IntentResult & ReturnsValue<WaterEntry> {
        let entry = try domain.logWater(amount: amount, at: .now, caller: .siri)
        return .result(value: entry)
    }
}

// Adapter 2: MCP tool (Claude Desktop / Code / external agent)
// Tool name "log_water" with inputSchema {amount_ml: number}
// Handler:
let entry = try domain.logWater(
    amount: .init(value: ml, unit: .milliliters),
    at: .now,
    caller: .mcp(host: hostName)
)
return .text("Logged \(entry.amount) at \(entry.timestamp)")

两个适配器看起来不同,因为它们的调用方不同。但它们调用的函数是相同的。

哪些能力应保留在应用内

有一小部分但很重要的能力应该保持为应用私有。把它们路由到任一协议都是错误的。

UI 状态类能力。“打开第三个标签”、”滚动到底部”、”高亮这一行”不是领域操作。它们是交互原语。App Intents 通过 OpensIntent 和 Shortcuts 在某种程度上支持这类操作,但风格契合度差;用户通常想要的是结果,而不是导航。MCP 对 UI 导航的支持更糟:模型不在驱动屏幕,而是在驱动工具。

需要人体在场的能力。拍照、生物认证、敏感 PII 输入、任何需要用户看屏幕并点击的流程。Apple 的 CameraCaptureIntent 是为相机流程而存在的,但其设计意图是启动前台拍摄活动,而不是授予代理后台相机访问权限。两种协议的诚实规则是:相机、生物识别和敏感输入流程都应作为前台 UI 运行,并附带显式的用户确认,而不是作为静默的意图或工具调用。把这些能力放在应用 UI 后面,让代理把用户引导到屏幕,而不是穿过屏幕

长时间运行的后台工作。 App Intents 包含用于呈现进度的 ProgressReportingIntent,MCP 包含进度通知和任务原语,但两种协议的渲染层都不是为消费者流程上的持续进度而设计的。MCP 会话中的主机模型通常会在多分钟级工具完成之前很久就把推理链超时。对于面向消费者的长时间运行工作,应通过应用自身的 UI 暴露该操作;让协议返回请求已排队并链接到状态屏幕。

任何涉及他人数据的操作。两种协议中的信任边界都是调用方代理。Apple Intelligence 在用户的 iCloud 帐户下运行。MCP 在开发者接入的任何凭据下运行。跨用户的操作(共享、多账户访问、管理员操作)在任一协议下都不安全,因为调用身份就是错误的身份。

我会以何种方式重新构建

了解上述路由规则后,我会以现在为服务边界设计 API 的方式来设计 Swift 应用中的领域层。领域方法接受类型化输入并返回类型化输出,不内置任何协议假设。App Intents 用 @Parameter 模式和 perform() 胶水代码薄薄地包装领域方法。MCP 工具用 JSON 模式和 stdio 帧化薄薄地包装相同的领域方法。两种协议都是薄适配器;工作在领域层。

由此推导出两个结论。

调用方身份是领域问题,而不是协议问题。 App Intent 主体接收系统解析的参数,并在用户已经走完系统意图调用流程的上下文中运行。MCP 工具主体接收主机所安排的任何凭据。两者都通过显式的 caller 参数传递给领域方法。领域方法负责执行授权、确认提示以及任何其他领域不变量。两种协议都不能假装调用方就是用户。

两个适配器暴露相同的功能集合。决定将哪些能力暴露给哪些调用方,是写在两个清单中,而不是散落在协议代码里。新增一项能力是一个领域方法、两个适配器包装、两个清单条目。移除一项能力是对称的。上面的矩阵成为一个真实的文件。

未来几年 Apple 平台的前沿不在于挑选其中一个协议。前沿在于把两者视为正交的契约,在同一领域层组合。Apple Intelligence 代理对用户负有一组义务(设备上运行、说 Siri、通过系统渲染)。外部 LLM 代理对开发者负有另一组义务(任意位置运行、说 JSON-RPC、通过开发者所选模型渲染)。两者都值得拥有进入您应用的类型化接口。两者都不应是唯一的接口。

何时不应两者都构建

这一论点是双向的。某些应用只需要一个协议而不是另一个。

没有开发者接口的纯消费者实用工具。手电筒。鸟鸣识别器。增强现实测距仪。用户可能想通过 Siri 调用它(App Intents 有用),但没有开发者会把它接入 LLM 工作流(MCP 只是装饰)。

没有终端用户接口的纯开发者工具。代码格式化的 MCP 服务器。仓库搜索工具。包版本检查器。用户即开发者,置身 Claude Code 会话;Siri 和 Apple Intelligence 没有用武之地。

对两类代理都服务不佳的应用。高度互动的游戏、实时多人应用、价值在于身处应用内并面对屏幕的应用。两种协议都不合适;正确答案是一个出色的应用,没有代理契约。

决策不是默认就要其一或两者。决策是这个应用是干什么的,还有谁可能想操作它的领域。答案可能是两者都不要、其一,或两者都要。如果领域层结构良好,构建一个的成本是很小的。在该领域层之上同时构建两个的成本,也是很小的。当用例需要时却不构建其中之一的成本,则是该能力在该代理表面上的完全缺席。

这一模式对 iOS 26+ 上的 Apple 技术栈意味着什么

两个要点。

  1. 将 App Intents 与 MCP 视为同一领域上的正交契约,而非相互竞争的协议。 Apple Intelligence、Siri、Shortcuts 和 Spotlight 是一类调用方,承担系统级义务。Claude、Cursor、ChatGPT 等是第二类调用方,承担会话级义务。两者都应得到类型化访问。它们之下的领域层并不会改变。

  2. 路由规则是谁来调用,而不是运行什么 App Intent 与 MCP 工具可以调用同一个 Swift 函数。它们的差异在于调用方所承担的义务、它们获得的渲染、以及所期望的持久化。把函数写对;让协议层保持轻薄。

完整的 Apple 生态集群:用于 Apple Intelligence 的类型化 App Intents,用于跨 LLM 代理的 MCP 服务器,用于锁屏状态机的 Live Activities,用于视觉层的 Liquid Glass 模式,以及用于跨设备触达的 多平台发布。中心枢纽位于 Apple 生态系列。关于更广泛的 iOS 与 AI 代理上下文,请参阅 iOS 代理开发指南

常见问题

对于同一项能力,我应该构建 App Intent 还是 MCP 工具?

当能力应该到达 Apple Intelligence、Siri、Shortcuts 或 Spotlight 时,构建 App Intent。当能力应该到达外部 LLM(Claude、ChatGPT、Claude Code 或 Cursor 中的代理)时,构建 MCP 工具。对于应同时服务两类调用方的领域能力,两者都构建——作为共享 Swift 领域方法之上的轻薄适配器。

App Intents 和 MCP 服务器是否相互竞争?

不竞争。App Intents 是通往 Apple 第一方代理堆栈的路径;MCP 是通往所有其他 LLM 的路径。Apple Intelligence 不会调用 MCP 工具,外部 LLM 代理也无法直接调用 App Intents(它们要经过系统)。两种协议服务于不同的调用方类别,具有不同的信任模型、不同的延迟预算和不同的渲染表面。

单个应用能否通过两种协议同时暴露其领域?

可以,而且大多数希望获得完整代理触达的非平凡应用都应该这样做。Get Bananas(在 MCP 服务器文章 中介绍)和 Water(在 App Intents 文章 中介绍)就是早期范例。模式是底下一个领域层,上方是 App Intent 适配器和 MCP 工具适配器。两个适配器调用同样的 Swift 函数。

Apple Intelligence 跟踪哪些 MCP 不跟踪的状态?

Apple Intelligence 跨调用、会话和重启跟踪 AppEntity 身份。实体模型为系统提供了用户可以跨意图链接的持久引用。MCP 本身是一个有状态协议,具有生命周期管理和 Streamable HTTP 中的会话 ID,但持久的领域身份是服务器侧的责任,而非一等的协议契约;主机模型不会从协议表面获得 AppEntity 等价的标识符。MCP 的 resources 概念支持持久引用数据,但运作于同一服务器自有的层级。

是否有些能力不应通过任一协议暴露?

是的。UI 状态类能力(打开此标签、滚动到此处)、需要人体在场的能力(拍照、生物认证、敏感输入)、长时间运行的后台工作,以及跨多用户数据的操作,都应保留在应用 UI 后面。两种协议对此类能力的原语都很弱,都不携带跨用户安全运行所需的信任信号。

参考文献


  1. Apple Developer,“App Intents framework”。用于声明意图、实体、参数和查询的接口,可被 Apple Intelligence、Siri、Shortcuts 和 Spotlight 路由。 

  2. Anthropic,“Model Context Protocol”。用于跨 LLM 主机进行类型化工具暴露的开放协议。传输方式为 stdio 或 Streamable HTTP;.mcpb 是一种打包格式,通常携带本地 stdio 服务器。规范涵盖 tools/listtools/callresources 与提示。 

  3. Apple Developer,“Creating your first app intent”“AppEntity”AppIntent 协议、@Parameter 宏、func perform() 入口,以及用于持久身份的 AppEntity。 

  4. Anthropic,“MCP Specification: Tools (2025-06-18)”“MCP Architecture”,以及 “Transports (2025-06-18)”tools/listtools/call 的 JSON-RPC 方法定义、inputSchema 与可选 outputSchema、主机职责、生命周期管理,以及 stdio / Streamable HTTP 传输。 

  5. 作者在 App Intents 是 Apple 通往您应用的新 API两个代理生态,一个购物清单 中的分析。双适配器模式(一个 Swift 领域方法,两个协议包装器)在两篇文章中分别针对 Water 和 Get Bananas 在实现层级有所描述。 

相关文章

三个界面:人类、Apple Intelligence、智能体

每个iOS应用的能力都面向三个界面:人类、Apple Intelligence、智能体。每个界面都有不同的义务、渲染、延迟和信任态势。

2 分钟阅读

单一可信源:SwiftData、MCP、iCloud

三个调用方可以写入同一份购物清单:人类、Apple Intelligence 和外部代理。真相必须存放在某处。请选择基础载体。

3 分钟阅读

你的Agent中间商你从未审查过

研究人员测试了28个LLM API路由器。17个接触了AWS金丝雀凭证。一个从私钥中抽走了ETH。路由器层是新的攻击面。

1 分钟阅读