App Intents vs MCP:ルーティングの問題
ジャンル: frontier-essay。本稿ではエージェント型 Apple 開発のためのルーティングルールを定義します。2つのプロトコル(App Intents と MCP)はどちらも、外部のエージェントがアプリのドメインを操作することを可能にします。これらは1つに統合されるものではありません。問題は、どちらをどこに配置するか、そしてなぜ各プロトコルがそれぞれの呼び出し元にとって正しい答えなのか、ということです。
Apple は、Apple Intelligence がサードパーティ製アプリの UI に触れることなく操作できるよう、型付きで宣言的なサーフェスを提供する目的で App Intents を出荷しました。1 Anthropic は、あらゆる LLM がツールの UI に触れることなく操作できるよう、型付きでサーバー仲介型のサーフェスを提供する目的で Model Context Protocol を出荷しました。2 形は似ています。呼び出し元は違います。これらを1つのサーフェスとして扱うと、どちらにも適合しないアーキテクチャが生まれます。
このクラスタの過去2記事では、各プロトコルを単独で扱いました。App Intents については App Intents Are Apple’s New API to Your App、MCP については Two Agent Ecosystems, One Shopping List です。本稿はルーティングの問題を扱います。ある機能には AppIntent を与えるべきか、それとも MCP ツールを与えるべきか、両方を与えるべきか、それともアプリ内部にのみ公開すべきか、というものです。
TL;DR
- App Intents は、Apple Intelligence、Siri、ショートカット、システムのサジェストスタックへの唯一の経路です。システムはインストール時およびアプリのアップデートを通じてこれらを利用可能にし、App Shortcuts のドネーションとインデックス化により、Spotlight および Siri のサジェストへ表出させます。
- MCP ツールは、Apple 以外のあらゆる LLM(Claude、ChatGPT、Gemini、ローカルモデル)への経路です。トランスポートは stdio または Streamable HTTP であり、
.mcpbはパッケージ化フォーマットで、一般的にはローカルの stdio サーバーを同梱します。ホストはセッション時にツールをロードします。 - 両プロトコルは、型付きスキーマ、
entity → action → resultという形、パラメータ解決という点で収束します。一方で、アイデンティティ、永続性、レイテンシー、レンダリングサーフェスという点では異なります。 - ルーティングルール:その機能をユーザーが Siri に頼んだり Spotlight から呼び出したりしそうなものなら、App Intents です。その機能を開発者が Claude Code セッションや外部エージェントの実行に組み込みそうなものなら、MCP です。ほとんどのアプリは同じドメインに対して両方を必要とします。
2つのプロトコル、同じ形
両プロトコルは、外部の呼び出し元とアプリのドメインとの間の操作契約を定義します。契約は3つの部分から成ります。スキーマ(呼び出し元が何を要求できるか)、リゾルバ(アプリがスキーマで指定されたエンティティをどう見つけるか)、そしてアクション(何が実行され何が返ってくるか)です。
App Intents はこの契約を Swift で表現します。プロトコルのサーフェスは AppIntent、AppEntity、AppEnum であり、@Parameter マクロがスキーマを駆動し、func perform() が結果を返します。3 スキーマはコンパイル時に生成され、インストール時にアプリにバンドルされます。Apple Intelligence、Siri、ショートカット、Spotlight はすべて同じスキーマを読み、同じ perform() のエントリポイントを通じて型付きリクエストをルーティングします。
MCP はこの契約を、stdio または Streamable HTTP 上の JSON-RPC で表現します。プロトコルのサーフェスは tools/list および tools/call メソッドであり、各ツールは名前、説明、inputSchema を宣言します(2025-06-18 の仕様では、構造化された返り値のためのオプションの outputSchema が追加されました)。4 MCP ホスト(Claude Desktop、Claude Code、Cursor、ChatGPT デスクトップアプリ)は、セッション開始時にツールを発見し、JSON ペイロードで名前を指定して呼び出します。ホストはモデルを実行し、サーバーはツールを実行します。
形は同じです。スキーマ、リゾルバ、アクション。違いは、誰が各部分を実行し、信頼境界がどこにあるかです。App Intents はアプリプロセス内、ユーザーのデバイス上、アプリのエンタイトルメントの下で実行され、システムが呼び出しのルーティングを仲介します。MCP サーバーは、開発者が選択した場所(ローカルの stdio、ホスト型の HTTP、組み込みバンドル)で実行され、ホストの LLM が無制限のツールセットにわたる呼び出しのルーティングを仲介します。
2つのプロトコルが食い違う部分
サーフェスの形を超えて、ルーティング上重要な4つの運用上の違いがあります。
アイデンティティと永続性。 App Intents は、システムが保存・提示・後で再解決できる AppEntity 型で語ります。今日 Hey Siri, log 250ml in Water で保存した水分エントリーは、再起動をまたいで存続し、NSUbiquitousKeyValueStore で同期され、後で他のインテントから参照できます(Show me yesterday’s water entries)。システムはこれらすべての呼び出しにわたってエンティティ ID を追跡します。3 MCP 自体はライフサイクル管理を持つステートフルなプロトコルであり、Streamable HTTP は接続継続のためのセッション ID をサポートしますが、永続的なドメインアイデンティティはサーバー所有の関心事です。ホストモデルがセッションをまたいで信頼できる、AppEntity 識別子に相当するプロトコルレベルのものは存在しません。MCP は永続的な参照データのために resources をサポートしますが、アイデンティティは第一級のプロトコル契約ではなく、サーバー側の責任のままです。4
レイテンシーとバッテリー。 App Intent の perform() 本体は、デバイス上のアプリまたはアプリ拡張のコンテキストで実行されます。ネットワーク利用は、アプリ自身のコードか、その周囲の Apple Intelligence/Siri レイヤーから行われ、インテント契約自体からは行われません。型付きでオンデバイスのアクションが型付きの結果を返すのは、一般的なケースで高速です。MCP ツールは、ローカルなものであっても、別個のプロセス境界を持つ stdio JSON-RPC のフレーミングを経由しますし、リモートの MCP ツールは HTTP のラウンドトリップが発生します。レイテンシー予算は異なります。log 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 側では暗黙的なシステムの推論です。
2つのプロトコルは、アイデンティティ、レイテンシー、レンダリング、発見の4点で食い違います。これらは1つの根本的な区別から導かれる4つの性質です。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
ルーティングルールは、順番に3つの問いです。
その機能は、ユーザーが Siri に尋ねたり、ショートカットから呼び出したりするものか? イエスならば、その機能には App Intent が必要です。Log 250ml of water、Start a meditation、Add bananas to my list、What did I weigh yesterday がインテントになるのは、ユーザーが声に出したり、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 セッションがエクスポートされたログから補填できるように)の両方を持ちます。2つの経路は1つの Swift 関数を共有しており、その関数はどの呼び出し元が呼び出したかを知りません。5
コードでの形は、1つのドメインメソッドと、それを呼び出す2つのアダプタラッパーになります。
// 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)")
2つのアダプタが異なって見えるのは、呼び出し元が違うからです。彼らが呼び出す関数は同じものです。
アプリ内に留めるもの
少数ながら重要な機能群は、アプリのプライベートに留めておくべきです。これらをいずれかのプロトコルにルーティングするのは間違いです。
UI 状態の機能。 “Open the third tab”、”scroll to the bottom”、”highlight this row” などはドメイン操作ではありません。これらはインタラクションのプリミティブです。App Intents は OpensIntent とショートカットを通じてその一部をサポートしますが、ジャンル的には合いません。ユーザーは通常、ナビゲーションではなく結果を求めています。MCP の UI ナビゲーションへのサポートはさらに不適切です。モデルは画面を駆動しているのではなく、ツールを駆動しているのです。
人の身体をループ内に必要とする機能。 写真の撮影、生体認証、機微な PII の入力、ユーザーが画面を見てタップする必要のあるあらゆるフロー。Apple の CameraCaptureIntent はカメラフローのために存在しますが、設計意図はフォアグラウンドのキャプチャアクティビティを起動することであり、エージェントにバックグラウンドのカメラアクセスを付与することではありません。両プロトコルに対する誠実なルール:カメラ、生体認証、機微な入力フローは、サイレントなインテントやツール呼び出しではなく、明示的なユーザー確認を伴うフォアグラウンド UI として実行されるべきです。これらの機能はアプリの UI の背後に留め、エージェントには画面を通してではなく画面へユーザーをルーティングさせましょう。
長時間のバックグラウンド作業。 App Intents には進捗表示のための ProgressReportingIntent が含まれ、MCP には進捗通知やタスクのプリミティブが含まれていますが、どちらのプロトコルのレンダリング層も、消費者向けフローでの持続的な進捗表示のために作られていません。MCP セッションのホストモデルは、数分かかるツールが終わるはるか前に推論チェーンをタイムアウトさせるのが普通です。消費者向けの長時間作業については、操作をアプリ自身の UI で公開し、プロトコルにはリクエストはキューに入れられましたと返させ、ステータス画面へリンクさせましょう。
他のユーザーのデータに触れるもの。 両プロトコルにおける信頼境界は、呼び出し元のエージェントです。Apple Intelligence はユーザーの iCloud アカウントの下で実行されます。MCP は開発者が組み込んだクレデンシャルの下で実行されます。ユーザーをまたぐ操作(共有、複数アカウントアクセス、管理者アクション)は、呼び出し元のアイデンティティが間違ったアイデンティティであるため、どちらのプロトコルを通しても安全ではありません。
私なら何を変えて作るか
上記のルーティングルールを知った上で、Swift アプリのドメイン層は、私が今サービスの境界で API を設計するのと同じように設計するでしょう。ドメインメソッドは型付きの入力を受け取り、型付きの出力を返し、プロトコルの仮定を焼き付けません。App Intents は @Parameter スキーマと perform() のグルーで、ドメインメソッドを薄くラップします。MCP ツールは JSON スキーマと stdio フレーミングで、同じドメインメソッドを薄くラップします。両プロトコルは薄いアダプタです。仕事はドメインの中にあります。
2つの帰結が続きます。
呼び出し元のアイデンティティはドメインの関心事であり、プロトコルの関心事ではありません。 App Intent の本体はシステムが解決したパラメータを受け取り、ユーザーがシステムのインテント呼び出しフローを通過したコンテキストで実行されます。MCP ツールの本体は、ホストが用意したクレデンシャルを受け取ります。両者は、明示的な caller 引数としてドメインメソッドにそのまま渡されます。ドメインメソッドが認可、確認プロンプト、その他のドメイン不変条件を強制します。どちらのプロトコルも、呼び出し元がユーザーであるかのように振る舞うことは許されません。
両アダプタは同じアフォーダンス集合を表出させます。 どの機能をどの呼び出し元に公開するかという決定は、散在するプロトコルコードではなく、2つのマニフェストに記録されます。新しい機能の追加は、1つのドメインメソッド、2つのアダプタラッパー、2つのマニフェストエントリです。機能の削除は対称的です。上記のマトリクスは実際のファイルになります。
今後数年にわたる Apple プラットフォームのフロンティアは、1つのプロトコルを選ぶことではありません。フロンティアは、両者を同じドメイン層で構成される直交する契約として扱うことです。Apple Intelligence のエージェントには、ユーザーに対する一連の義務があります(オンデバイスで実行され、Siri を話し、システムを通じてレンダリングします)。外部の LLM エージェントには、開発者に対する別の一連の義務があります(どこでも実行され、JSON-RPC を話し、開発者が選択したモデルを通じてレンダリングします)。両者ともあなたのアプリへの型付きサーフェスに値します。どちらも唯一のサーフェスである資格はありません。
両方を作らない場合
議論は両方向に切れます。あるアプリは一方のプロトコルを必要とし、他方は必要としません。
開発者向けサーフェスのない純粋な消費者向けユーティリティ。 懐中電灯。鳥の鳴き声識別アプリ。AR 巻尺。ユーザーは Siri 経由で呼び出したいかもしれません(App Intents は有用です)が、開発者がそれを LLM ワークフローに組み込むことはありません(MCP は装飾的です)。
エンドユーザー向けサーフェスのない純粋な開発者向けツール。 コードフォーマッターの MCP サーバー。リポジトリ検索ツール。パッケージバージョンインスペクター。ユーザーは Claude Code セッションの開発者であり、Siri と Apple Intelligence には役割がありません。
どちらのエージェントクラスにもうまく仕えないアプリ。 高度にインタラクティブなゲーム、リアルタイムマルチプレイヤーアプリ、価値がアプリ内かつ画面上にあることにあるアプリ。どちらのプロトコルもうまく合いません。正解は、優れたアプリとエージェント契約なしです。
決定はデフォルトで一方または両方ではありません。決定はこのアプリは何のためにあり、誰がそのドメインを操作したいかもしれないかです。答えはどちらでもない、片方、両方のいずれかでありえます。ドメイン層がうまく形作られていれば、片方を作るコストは小さいです。そのドメイン層の上に両方を作るコストも小さいです。ユースケースが要求するときに片方を作らないコストは、そのエージェントサーフェスからの機能の完全な不在です。
このパターンが iOS 26+ における Apple スタックに意味すること
2つの要点。
-
App Intents と MCP を、競合するプロトコルとしてではなく、同じドメイン上の直交する契約として扱いましょう。 Apple Intelligence、Siri、ショートカット、Spotlight は、システムレベルの義務を持つ1つの呼び出し元クラスです。Claude、Cursor、ChatGPT、その他は、セッションレベルの義務を持つ第2の呼び出し元クラスです。両者とも型付きアクセスに値します。その下のドメイン層は変わりません。
-
ルーティングルールは誰が呼び出すかであり、何が実行されるかではありません。 App Intent と MCP ツールは、同じ Swift 関数を呼び出すことができます。違うのは、呼び出し元が背負う義務、返されるレンダリング、期待される永続性です。関数を正しく作り、プロトコル層は薄くしておきましょう。
Apple Ecosystem クラスタの全体:Apple Intelligence のための型付き App Intents、クロス-LLM エージェントのための MCP サーバー、ロック画面状態マシンのための Live Activities、ビジュアル層のための Liquid Glass パターン、デバイスをまたぐリーチのための マルチプラットフォーム出荷。ハブは Apple Ecosystem シリーズ にあります。AI エージェントを伴う iOS のより広いコンテキストについては、iOS Agent Development guide を参照してください。
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 を直接呼び出すことはできません(システムを通じます)。2つのプロトコルは、異なる信頼モデル、異なるレイテンシー予算、異なるレンダリングサーフェスを持つ、異なる呼び出し元クラスに仕えます。
1つのアプリが両方のプロトコルを通じてドメインを公開できますか?
はい。フルなエージェント・リーチを望む、自明でないほとんどのアプリはそうすべきです。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 の背後に留めるべきです。両プロトコルともこれらに対しては弱いプリミティブしか持たず、ユーザーをまたいで安全に操作するために必要な信頼シグナルを運びません。
References
-
Apple Developer, “App Intents framework”. Apple Intelligence、Siri、ショートカット、Spotlight がルーティングできる、インテント、エンティティ、パラメータ、クエリを宣言するためのサーフェス。 ↩
-
Anthropic, “Model Context Protocol”. LLM ホストをまたいだ型付きツール公開のためのオープンプロトコル。トランスポートは stdio または Streamable HTTP。
.mcpbはパッケージ化フォーマットで、一般的にはローカルの stdio サーバーを同梱します。仕様はtools/list、tools/call、resources、プロンプトをカバーします。 ↩ -
Apple Developer, “Creating your first app intent” and “AppEntity”.
AppIntentプロトコル、@Parameterマクロ、func perform()エントリポイント、永続的なアイデンティティのためのAppEntity。 ↩↩ -
Anthropic, “MCP Specification: Tools (2025-06-18)”, “MCP Architecture”, and “Transports (2025-06-18)”.
tools/listおよびtools/callのための JSON-RPC メソッド定義、inputSchemaとオプションのoutputSchema、ホストの責務、ライフサイクル管理、stdio / Streamable HTTP のトランスポート。 ↩↩ -
著者の分析、App Intents Are Apple’s New API to Your App および Two Agent Ecosystems, One Shopping List。デュアルアダプタパターン(1つの Swift ドメインメソッド、2つのプロトコルラッパー)は、Water と Get Bananas のそれぞれについて、両記事で実装レベルで説明されています。 ↩