App Intents vs MCP : la question du routage
Genre : frontier-essay. Cet article énonce une règle de routage pour le développement Apple agentique. Deux protocoles (App Intents et MCP) permettent à un agent extérieur d’opérer le domaine d’une application. Ils ne se confondent pas. La question est de savoir lequel va où, et pourquoi chaque protocole est la bonne réponse pour son propre appelant.
Apple a livré App Intents pour donner à Apple Intelligence une surface typée et déclarative permettant d’opérer des applications tierces sans toucher à leur UI.1 Anthropic a livré le Model Context Protocol pour donner à n’importe quel LLM une surface typée et médiée par un serveur permettant d’opérer n’importe quel outil sans toucher à son UI.2 Les formes sont similaires. Les appelants ne le sont pas. Les traiter comme une seule surface produit une architecture qui ne satisfait ni l’un ni l’autre.
Les deux articles précédents de ce cluster couvraient chaque protocole isolément : App Intents dans App Intents Are Apple’s New API to Your App, MCP dans Two Agent Ecosystems, One Shopping List. Le présent article est la question du routage. Quand une capacité reçoit-elle un AppIntent, quand reçoit-elle un outil MCP, quand reçoit-elle les deux, et qu’est-ce qui reste exposé uniquement à l’intérieur de l’application ?
TL;DR
- Les App Intents sont la seule voie vers Apple Intelligence, Siri, Shortcuts et la pile de suggestions du système. Le système les rend disponibles dès l’installation et au fil des mises à jour de l’application, la donation et l’indexation des App Shortcuts les faisant remonter dans Spotlight et les suggestions Siri.
- Les outils MCP sont la voie vers tous les LLM non-Apple (Claude, ChatGPT, Gemini, modèles locaux). Le transport est stdio ou Streamable HTTP, avec
.mcpbcomme format d’empaquetage qui livre couramment un serveur stdio local ; l’hôte charge les outils au moment de la session. - Les deux protocoles convergent sur un schéma typé, une forme
entity → action → resultet la résolution de paramètres. Ils divergent sur l’identité, la persistance, la latence et la surface de rendu. - La règle de routage : si la capacité est quelque chose qu’un utilisateur pourrait demander à Siri ou invoquer depuis Spotlight, App Intents. Si la capacité est quelque chose qu’un développeur pourrait câbler dans une session Claude Code ou un run d’agent externe, MCP. La plupart des applications ont besoin des deux pour le même domaine.
Deux protocoles, une même forme
Les deux protocoles définissent un contrat d’opération entre un appelant extérieur et le domaine d’une application. Le contrat comporte trois parties : le schéma (ce que l’appelant peut demander), le résolveur (comment l’application trouve les entités que le schéma nomme) et l’action (ce qui s’exécute et ce qui est retourné).
Les App Intents expriment le contrat en Swift. La surface du protocole est AppIntent, AppEntity, AppEnum, avec les macros @Parameter qui pilotent le schéma et func perform() qui retourne le résultat.3 Le schéma est généré à la compilation et embarqué dans l’application à l’installation. Apple Intelligence, Siri, Shortcuts et Spotlight lisent tous le même schéma et acheminent une requête typée à travers le même point d’entrée perform().
MCP exprime le contrat en JSON-RPC sur stdio ou Streamable HTTP. La surface du protocole est constituée des méthodes tools/list et tools/call, chaque outil déclarant un nom, une description et un inputSchema (la spécification 2025-06-18 ajoutant un outputSchema optionnel pour les retours structurés).4 Un hôte MCP (Claude Desktop, Claude Code, Cursor, l’application desktop ChatGPT) découvre les outils au début de la session et les appelle par leur nom avec une charge utile JSON. L’hôte exécute le modèle ; le serveur exécute l’outil.
La forme est la même : schéma, résolveur, action. La différence porte sur qui exécute chaque pièce et sur l’endroit où réside la frontière de confiance. Les App Intents s’exécutent à l’intérieur du processus de l’application, sur l’appareil de l’utilisateur, sous les entitlements de l’application, le système assurant la médiation du routage des appels. Les serveurs MCP s’exécutent là où le développeur a choisi de les exécuter (stdio local, HTTP hébergé, bundle embarqué), l’hôte LLM assurant la médiation du routage des appels sur un ensemble non borné d’outils.
Là où les deux protocoles divergent
Au-delà de la forme de surface, quatre différences opérationnelles comptent pour le routage :
Identité et persistance. Les App Intents s’expriment en types AppEntity que le système peut stocker, présenter et re-résoudre plus tard. L’entrée d’eau que j’enregistre aujourd’hui via Hey Siri, log 250ml in Water survit aux redémarrages, se synchronise via NSUbiquitousKeyValueStore et peut être référencée par d’autres intents par la suite (Show me yesterday’s water entries). Le système suit l’identifiant de l’entité à travers tous ces appels.3 MCP est lui-même un protocole avec état doté d’une gestion du cycle de vie, et Streamable HTTP prend en charge des identifiants de session pour la continuité de connexion, mais l’identité durable du domaine est une affaire qui appartient au serveur ; il n’existe pas d’analogue au niveau protocole aux identifiants AppEntity sur lesquels un modèle hôte pourrait s’appuyer entre les sessions. MCP prend en charge les resources pour les données de référence persistantes, mais l’identité demeure une responsabilité côté serveur plutôt qu’un contrat de protocole de premier rang.4
Latence et batterie. Le corps perform() de l’App Intent s’exécute dans le contexte de l’application ou de l’extension d’application, sur l’appareil. Tout usage du réseau provient du code propre de l’application ou de la couche Apple Intelligence/Siri qui l’entoure, et non du contrat d’intent lui-même. Une action typée, sur l’appareil, retournant un résultat typé est rapide dans le cas commun. Les outils MCP, même locaux, passent par un cadrage JSON-RPC sur stdio avec une frontière de processus séparée, et les outils MCP distants encourent des allers-retours HTTP. Le budget de latence est différent. Un App Intent log 250ml peut s’achever à l’intérieur d’une fenêtre de prise de parole Siri. Un outil MCP distant pourrait être le goulot d’étranglement d’une session Claude Code.
Surface de rendu. Les App Intents retournent des résultats qu’Apple Intelligence rend dans l’UI du système : une bannière d’écran verrouillé, une réponse Siri, une sortie Shortcuts, un résultat Spotlight. L’application ne contrôle pas la manière dont le résultat se présente. Les outils MCP retournent des blocs de contenu (texte, images, audio, ressources embarquées ou contenu structuré) que le modèle hôte lit et dont il décide la mise en avant. Une session Claude Code pourrait citer le résultat au développeur, le résumer ou l’injecter dans un appel suivant. La décision de rendu réside au niveau du modèle.
Découvrabilité. Apple Intelligence rend les App Intents disponibles dès l’installation, la donation et l’indexation des App Shortcuts les faisant remonter dans les recherches Spotlight et les suggestions Siri en fonction du comportement de l’utilisateur ; les mises à jour de l’application et les entités dynamiques ajustent la surface au fil du temps. L’utilisateur ne tape jamais le nom d’un outil. Les hôtes MCP lisent les outils au début de la session ; l’utilisateur (ou le prompt système) décide quels outils le modèle peut voir. La découverte est une configuration explicite du côté MCP et une inférence implicite du système du côté App Intents.
Les deux protocoles divergent sur l’identité, la latence, le rendu et la découverte : quatre propriétés qui découlent d’une distinction racine. Les App Intents servent un agent au niveau système que l’utilisateur n’a pas configuré. MCP sert un agent au niveau session que le développeur a configuré. Appelants différents, obligations différentes.
La règle de routage
La carte des capacités d’une application disposant des deux protocoles ressemble à ceci :
┌──────────────────────────────────────────┐
│ 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
La règle de routage tient en trois questions, dans l’ordre.
La capacité est-elle quelque chose que l’utilisateur demanderait à Siri ou invoquerait depuis Shortcuts ? Si oui, la capacité a besoin d’un App Intent. Log 250ml of water, Start a meditation, Add bananas to my list, What did I weigh yesterday sont des intents parce que l’utilisateur pourrait les énoncer à voix haute, les taper dans Spotlight ou les enchaîner dans Shortcuts. L’App Intent n’est pas optionnel pour ces capacités ; rien d’autre ne vous mène à la surface d’agent first-party d’Apple Intelligence.
La capacité est-elle quelque chose qu’un agent externe devrait pouvoir piloter ? Si oui, la capacité a besoin d’un outil MCP. Add an item to the shopping list from a Claude Code session, Read Get Bananas state into a Cursor agent context, Trigger a workflow from a remote tool-using LLM sont des outils MCP parce que l’appelant n’est pas Apple Intelligence ; l’appelant est le LLM que le développeur a câblé. L’outil MCP peut envelopper la même fonction Swift de la couche domaine que l’App Intent appelle, mais la surface du protocole est JSON-RPC sur le transport choisi par le développeur.
La capacité doit-elle survivre à une session unique avec une identité stable et connue du système ? Si oui, la voie App Intent est l’ajustement naturel, parce que le système vous fournit gratuitement l’identité AppEntity, la prise en charge des requêtes et la sémantique de persistance. Sinon, l’outil MCP peut retourner un bloc de contenu, laisser l’identité durable à la discrétion du serveur et éviter le coût de la modélisation d’entité.
La plupart des capacités d’application non triviales tombent dans la colonne les deux. Une capacité d’enregistrement d’eau dans Water dispose d’un AppIntent (pour que Siri puisse prendre la dictée) et d’un outil MCP (pour qu’une session Claude Code puisse remplir rétroactivement à partir d’un journal exporté). Les deux voies partagent une fonction Swift ; la fonction ne sait pas quel appelant l’a invoquée.5
La forme, en code, ressemble à une méthode de domaine et deux enveloppes adaptateur qui l’appellent toutes les deux :
// 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)")
Les deux adaptateurs paraissent différents parce que leurs appelants le sont. La fonction qu’ils appellent est la même.
Ce qui reste dans l’application
Un ensemble réduit mais important de capacités devrait rester privé à l’application. Les acheminer vers l’un ou l’autre protocole est une erreur.
Capacités d’état d’UI. « Open the third tab », « scroll to the bottom », « highlight this row » ne sont pas des opérations de domaine. Ce sont des primitives d’interaction. Les App Intents en prennent en charge une partie via OpensIntent et Shortcuts, mais l’ajustement de genre est médiocre ; l’utilisateur veut généralement un résultat, pas une navigation. La prise en charge de la navigation d’UI par MCP est encore pire : le modèle ne pilote pas un écran, il pilote un outil.
Capacités qui exigent le corps d’une personne dans la boucle. Capture photo, authentification biométrique, saisie de PII sensibles, tout flux qui exige que l’utilisateur regarde l’écran et tape. Le CameraCaptureIntent d’Apple existe pour les flux de caméra, mais l’intention de conception est de lancer une activité de capture en avant-plan, et non d’accorder un accès caméra en arrière-plan à un agent. La règle honnête pour les deux protocoles : les flux caméra, biométriques et de saisie sensible devraient s’exécuter en tant qu’UI au premier plan avec une confirmation utilisateur explicite, et non en tant qu’appels d’intent ou d’outils silencieux. Gardez ces capacités derrière l’UI de l’application et laissez l’agent acheminer l’utilisateur vers l’écran, pas à travers lui.
Travail en arrière-plan de longue durée. Les App Intents incluent ProgressReportingIntent pour faire remonter la progression, et MCP inclut des notifications de progression et des primitives de tâche, mais la couche de rendu d’aucun des deux protocoles n’est conçue pour une progression soutenue sur des flux grand public. Le modèle hôte dans une session MCP expire généralement les chaînes de raisonnement bien avant qu’un outil de plusieurs minutes ne se termine. Pour le travail de longue durée tourné vers le grand public, exposez l’opération via l’UI propre de l’application ; laissez les protocoles retourner the request was queued et établir un lien vers un écran de statut.
Tout ce qui touche aux données d’un autre utilisateur. La frontière de confiance dans les deux protocoles est l’agent appelant. Apple Intelligence s’exécute sous le compte iCloud de l’utilisateur. MCP s’exécute sous les identifiants que le développeur a câblés. Les opérations qui s’étendent à plusieurs utilisateurs (partage, accès multi-comptes, actions d’administration) ne sont pas sûres via l’un ou l’autre protocole, parce que l’identité appelante est la mauvaise identité.
Ce que je construirais différemment
Connaissant la règle de routage ci-dessus, je concevrais la couche de domaine dans une application Swift de la manière dont je conçois désormais les APIs à la frontière d’un service. Les méthodes de domaine prennent des entrées typées et retournent des sorties typées, sans hypothèses de protocole intégrées. Les App Intents enveloppent finement les méthodes de domaine avec un schéma @Parameter et de la glu perform(). Les outils MCP enveloppent finement les mêmes méthodes de domaine avec un schéma JSON et un cadrage stdio. Les deux protocoles sont des adaptateurs fins ; le travail réside dans le domaine.
Deux conséquences en découlent.
L’identité de l’appelant est une affaire de domaine, pas une affaire de protocole. Le corps de l’App Intent reçoit des paramètres résolus par le système et s’exécute dans un contexte où l’utilisateur est passé par le flux d’invocation d’intent du système. Le corps de l’outil MCP reçoit les identifiants que l’hôte a arrangés. Les deux passent à la méthode de domaine sous la forme d’un argument explicite caller. La méthode de domaine impose l’autorisation, les invites de confirmation et toute autre invariante de domaine. Aucun des deux protocoles ne peut prétendre que l’appelant est l’utilisateur.
Les deux adaptateurs font remonter le même ensemble d’affordances. La décision de quelles capacités exposer à quel appelant est consignée dans deux manifestes, et non dans du code de protocole éparpillé. Ajouter une nouvelle capacité, c’est une méthode de domaine, deux enveloppes adaptateur, deux entrées de manifeste. Retirer une capacité est symétrique. La matrice ci-dessus devient un véritable fichier.
La frontière de la plateforme Apple pour les prochaines années n’est pas le choix d’un protocole. La frontière est de traiter les deux comme des contrats orthogonaux qui se composent à la même couche de domaine. Les agents Apple Intelligence ont un ensemble d’obligations envers l’utilisateur (ils s’exécutent sur l’appareil, ils parlent Siri, ils rendent à travers le système). Les agents LLM externes ont un ensemble d’obligations différent envers le développeur (ils s’exécutent où ils veulent, ils parlent JSON-RPC, ils rendent à travers le modèle que le développeur a choisi). Tous deux méritent une surface typée vers votre application. Aucun ne mérite d’être la seule surface.
Quand ne pas construire les deux
L’argument coupe dans les deux sens. Certaines applications ont besoin d’un protocole et pas de l’autre.
Pures utilités grand public sans surface développeur. Une lampe torche. Un identificateur de chant d’oiseau. Un mètre ruban en réalité augmentée. L’utilisateur pourrait vouloir l’invoquer via Siri (les App Intents sont utiles), mais aucun développeur ne le câble dans un workflow LLM (MCP serait cosmétique).
Purs outils développeur sans surface utilisateur final. Un serveur MCP de formatage de code. Un outil de recherche dans un dépôt. Un inspecteur de version de paquet. L’utilisateur est le développeur dans une session Claude Code ; Siri et Apple Intelligence n’ont aucun rôle.
Applications qui ne servent bien aucune des deux classes d’agent. Jeux hautement interactifs, applications multijoueur en temps réel, applications dont la valeur consiste à être dans l’application et à l’écran. Aucun des deux protocoles n’est un bon ajustement ; la bonne réponse est une excellente application et aucun contrat d’agent.
La décision n’est pas l’un ou les deux par défaut. La décision est à quoi sert cette application et qui d’autre pourrait vouloir opérer son domaine. La réponse pourrait être aucun, l’un ou les deux. Le coût de construire l’un est faible si la couche de domaine est bien formée. Le coût de construire les deux, par-dessus cette couche de domaine, est également faible. Le coût de ne pas construire l’un quand le cas d’usage l’exige est l’absence complète de la capacité de cette surface d’agent.
Ce que ce pattern signifie pour la pile Apple sur iOS 26+
Deux enseignements.
-
Traitez App Intents et MCP comme des contrats orthogonaux sur le même domaine, pas comme des protocoles concurrents. Apple Intelligence, Siri, Shortcuts et Spotlight forment une classe d’appelants avec des obligations au niveau système. Claude, Cursor, ChatGPT et les autres forment une seconde classe d’appelants avec des obligations au niveau session. Tous deux méritent un accès typé. La couche de domaine en dessous ne change pas.
-
La règle de routage porte sur qui appelle, pas sur ce qui s’exécute. L’App Intent et l’outil MCP peuvent appeler la même fonction Swift. Ils diffèrent sur les obligations que porte l’appelant, le rendu qu’ils reçoivent en retour et la persistance qu’ils attendent. Faites en sorte que la fonction soit juste ; laissez les couches de protocole être fines.
Le cluster Apple Ecosystem complet : App Intents typés pour Apple Intelligence, serveurs MCP pour les agents inter-LLM, Live Activities pour la machine à états de l’écran verrouillé, patterns Liquid Glass pour la couche visuelle et livraison multi-plateforme pour la portée multi-appareil. Le hub se trouve à la Apple Ecosystem Series. Pour le contexte plus large iOS-avec-agents-IA, consultez le iOS Agent Development guide.
FAQ
Quand faut-il construire un App Intent plutôt qu’un outil MCP pour la même capacité ?
Construisez un App Intent quand la capacité doit atteindre Apple Intelligence, Siri, Shortcuts ou Spotlight. Construisez un outil MCP quand la capacité doit atteindre des LLMs externes (Claude, ChatGPT, des agents dans Claude Code ou Cursor). Pour les capacités de domaine qui doivent servir les deux classes d’appelants, construisez les deux comme adaptateurs fins par-dessus une méthode de domaine Swift partagée.
Les App Intents et les serveurs MCP sont-ils en concurrence ?
Non. Les App Intents sont la voie vers la pile d’agent first-party d’Apple ; MCP est la voie vers tous les autres LLM. Apple Intelligence n’appelle pas les outils MCP, et les agents LLM externes ne peuvent pas invoquer directement les App Intents (ils passent par le système). Les deux protocoles servent des classes d’appelants différentes avec des modèles de confiance différents, des budgets de latence différents et des surfaces de rendu différentes.
Une seule application peut-elle exposer son domaine via les deux protocoles ?
Oui, et la plupart des applications non triviales qui veulent une portée d’agent complète devraient le faire. Get Bananas (couvert dans l’article sur le serveur MCP) et Water (couvert dans l’article sur App Intents) sont des exemples précoces. Le pattern est une couche de domaine en dessous, avec des adaptateurs App Intent et des adaptateurs d’outil MCP au-dessus. Les deux adaptateurs appellent les mêmes fonctions Swift.
Quel état Apple Intelligence suit-il qu’MCP ne suit pas ?
Apple Intelligence suit l’identité AppEntity à travers les appels, les sessions et les redémarrages. Le modèle d’entité fournit au système des références persistantes que l’utilisateur peut enchaîner à travers les intents. MCP est lui-même un protocole avec état doté d’une gestion du cycle de vie et d’identifiants de session dans Streamable HTTP, mais l’identité durable du domaine est une responsabilité côté serveur plutôt qu’un contrat de protocole de premier rang ; le modèle hôte n’obtient pas un identifiant équivalent à AppEntity depuis la surface du protocole. Le concept de resources d’MCP prend en charge les données de référence persistantes mais opère à la même couche détenue par le serveur.
Y a-t-il des capacités que je ne devrais exposer via aucun des deux protocoles ?
Oui. Les capacités d’état d’UI (ouvrir cet onglet, scroller jusqu’ici), les capacités qui exigent le corps d’une personne dans la boucle (capture caméra, auth biométrique, saisie sensible), le travail en arrière-plan de longue durée et les opérations qui s’étendent aux données de plusieurs utilisateurs devraient toutes rester derrière l’UI de l’application. Les deux protocoles disposent de primitives faibles pour cela, et aucun ne porte les signaux de confiance requis pour opérer en toute sécurité entre utilisateurs.
Références
-
Apple Developer, « App Intents framework ». Surface pour déclarer intents, entités, paramètres et requêtes qu’Apple Intelligence, Siri, Shortcuts et Spotlight peuvent acheminer. ↩
-
Anthropic, « Model Context Protocol ». Protocole ouvert pour l’exposition typée d’outils à travers les hôtes LLM. Le transport est stdio ou Streamable HTTP ;
.mcpbest un format d’empaquetage qui livre couramment un serveur stdio local. La spécification couvretools/list,tools/call,resourceset les prompts. ↩ -
Apple Developer, « Creating your first app intent » et « AppEntity ». Protocole
AppIntent, macro@Parameter, point d’entréefunc perform()etAppEntitypour l’identité persistante. ↩↩ -
Anthropic, « MCP Specification: Tools (2025-06-18) », « MCP Architecture » et « Transports (2025-06-18) ». Définitions de méthodes JSON-RPC pour
tools/listettools/call,inputSchemaetoutputSchemaoptionnel, responsabilités de l’hôte, gestion du cycle de vie et transports stdio / Streamable HTTP. ↩↩ -
Analyse de l’auteur dans App Intents Are Apple’s New API to Your App et Two Agent Ecosystems, One Shopping List. Le pattern à double adaptateur (une méthode de domaine Swift, deux enveloppes de protocole) est décrit dans les deux articles au niveau de l’implémentation pour Water et Get Bananas respectivement. ↩