← 所有文章

App Intents 与 MCP:路由问题

类型: 前沿随笔。本文为 Apple 智能化开发命名了一条路由规则。两种协议(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、快捷指令以及系统建议栈的唯一路径。系统会从应用安装起以及通过应用更新让它们可用,App Shortcuts 的捐献和索引会将它们呈现到 Spotlight 与 Siri 建议中。
  • MCP 工具是通往所有非 Apple LLM(Claude、ChatGPT、Gemini、本地模型)的路径。传输层为 stdio 或 Streamable HTTP,.mcpb 是一种打包格式,通常会附带一个本地 stdio 服务器;宿主在会话开始时加载工具。
  • 两种协议都收敛于一个类型化模式、实体 → 动作 → 结果的形态以及参数解析。它们在身份、持久化、延迟和渲染面这几方面有所分歧。
  • 路由规则:如果某项能力是用户可能让 Siri 执行或从 Spotlight 唤起的,那就用 App Intents。如果某项能力是开发者可能接入 Claude Code 会话或外部代理流程的,那就用 MCP。大多数应用对同一领域两者都需要。

两种协议,相同形态

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

App Intents 用 Swift 表达该契约。协议接口为 AppIntentAppEntityAppEnum,由 @Parameter 宏驱动模式,func perform() 返回结果。3 模式在编译期生成,并在安装时打包进应用。Apple Intelligence、Siri、快捷指令和 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保存的饮水记录,可以跨重启留存,通过 NSUbiquitousKeyValueStore 同步,并在之后被其他意图引用(显示昨天的饮水记录)。系统会跨这些调用追踪实体 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 回复、快捷指令输出、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 执行或从快捷指令调用的? 如果是,那它就需要一个 App Intent。记录 250ml 饮水开始一次冥想把香蕉加入清单我昨天体重是多少都属于意图,因为用户可能把它们说出口、键入 Spotlight,或在快捷指令中链式调用。对这些能力而言,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 和快捷指令在某种程度上支持这类操作,但类型契合度很差;用户通常想要的是结果,而不是导航。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、快捷指令和 Spotlight 是一类带有系统级义务的调用方。Claude、Cursor、ChatGPT 等是第二类带有会话级义务的调用方。两类都应当获得类型化访问。其下的领域层并不改变。

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

完整的 Apple 生态系统系列:用于 Apple Intelligence 的类型化 App Intents、用于跨 LLM 代理的 MCP 服务器、用于锁屏状态机的 Live Activities、用于视觉层的 Liquid Glass 模式,以及用于跨设备触达的 多平台发布。专题入口在 Apple 生态系统系列。关于 iOS 与 AI 代理的更宏观背景,请参阅 iOS 代理开发指南

FAQ

同一项能力,何时该构建 App Intent,何时该构建 MCP 工具?

当能力需要触达 Apple Intelligence、Siri、快捷指令或 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 概念支持持久化引用数据,但运作于同样属于服务器自有的层级上。

是否存在哪些能力既不应通过 App Intents 也不应通过 MCP 暴露?

是的。UI 状态类能力(打开这个标签页、滚动到这里)、需要人在回路中亲身参与的能力(拍照、生物识别认证、敏感录入)、长时间运行的后台工作,以及跨多用户数据的操作,都应当留在应用的 UI 之后。两种协议针对它们都只有薄弱的原语,且都不携带跨用户安全运行所需的信任信号。

参考资料


  1. Apple Developer,《App Intents framework》。用于声明意图、实体、参数和查询的接口,Apple Intelligence、Siri、快捷指令和 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 在实现层面进行了描述。 

相关文章

Two Agent Ecosystems, One Shopping List: An MCP Server Living Alongside an iOS App

Get Bananas runs on iOS, macOS, watchOS, visionOS. It also lives inside Claude Desktop as an MCP server. The bridge is i…

19 分钟阅读

Foundation Models On-Device LLM: The Tool Protocol

iOS 26's Foundation Models framework puts a 3B-parameter LLM on every Apple Intelligence device. The Tool protocol is th…

15 分钟阅读

Your Agent Has a Middleman You Didn't Vet

Researchers tested 28 LLM API routers. 17 touched AWS canary credentials. One drained ETH from a private key. The router…

15 分钟阅读