Notes · Article
Chaque écran de cette appli SaaS est une MCP App
Mathew Goldsborough a affiché une appli de tâches à l’écran : une liste de choses à faire, une barre latérale, un panneau de chat calé à droite. On aurait dit n’importe quel tableau de bord SaaS. Puis il a annoncé à la salle que tout ce qu’on voyait était un serveur MCP ou une MCP App, assemblés à l’exécution. Son entreprise, NimbleBrain, construit l’hôte open source qui tient ces pièces ensemble, et son talk portait sur cet hôte : comment une appli trouve sa place à l’écran, affiche un compteur sans appel au modèle, apprend qu’elle vient d’être installée, et finit par ressembler à un seul produit.
C’était le dernier talk de la première journée d’AGNTCon + MCPCon North America, à San José, le 22 octobre. Regardez-le sur le livestream à partir de 7:12:34. Goldsborough est le fondateur et CEO de NimbleBrain, et ambassadeur de l’AAIF, le seul basé à Hawaï, ce qui lui permet d’ouvrir par un aloha. Ma note sur le talk de Liad Yosef couvrait les MCP Apps côté client : un plan de salle qui revient dans votre assistant. Voici l’autre moitié, et je l’ai lue à côté du code et de la doc de NimbleBrain, qui sont publics.
- Espace
- Conversations
- Fichiers
- Tâches
- Applis
- À faire
- Contacts
- Mémoire
Vues de l’hôte, puis emplacements des applis
À faire
- Relire les brouillons sortants
- Renouveler le domaine d’envoi
- Synchroniser le CRM
+ Ajouter une tâche
ui://todos dans une iframe. Les boutons sont des appels d’outils
Chat
Qu’est-ce qui vient ensuite sur ma liste ?
Relire les brouillons sortants.
La boucle de l’agent, skills via MCP
MCP est devenu un format de paquet
Son cadrage : chaque plateforme a eu son format de paquet, et une couche de composition autour. Les exécutables sur le bureau. Les fichiers WAR pour les applis web Java, « si vous avez eu la chance ou la malchance d’en faire ». Les paquets Debian pour Linux. Aujourd’hui MCP, qui selon lui n’a mûri que récemment assez pour porter tout ce dont un vrai produit a besoin.
Il compte trois pièces dans le paquet, et les appelle la triforce, pour les fans de Zelda. Les outils, les capacités qu’un serveur donne au modèle. Les MCP Apps, des interfaces riches et interactives livrées via MCP. Et les skills via MCP, le savoir-faire qui se charge avec les outils ; NimbleBrain avait bricolé sa propre version rudimentaire avant que l’extension existe. Ajoutez un server.json et deux ou trois extensions, et vous avez quelque chose qu’on peut livrer et composer.
La petite démo montre pourquoi ça compte. Demandez à un serveur de tâches « qu’est-ce qui vient ensuite sur ma liste ? » et un widget HTML s’affiche dans une iframe, pas un paragraphe de texte. Les skills arrivent avec. Chaque bouton sur lequel vous cliquez est un appel d’outil.
- .exeLe bureau
- .warApplis web Java
- .debLinux
- MCPLes agents, et désormais des applis entières
1Outils
Ce que le serveur permet au modèle
2Applis
Une interface dans une iframe ; chaque bouton est un appel d’outil
3Skills
Le savoir-faire, chargé via MCP
Le paquetUn server.json et deux ou trois extensions tiennent les trois.
Le chat, c’est le bac à sable de quelqu’un d’autre
Le hic, c’est que tout ça vit dans un chat. Le paquet est à vous, le serveur est à vous, mais le runtime ne vous appartient pas. Son image : vous entrez dans un bac à sable avec vos jouets, et quelqu’un vous dit comment jouer, où jouer, quelle hauteur font les murs et combien de sable vous avez.
Construire son propre hôte règle ça, et NimbleBrain l’a fait. Mais alors on réécrit la même plomberie à chaque fois. Et la spec elle-même est pensée pour un hôte qui parle à un serveur. Il n’y a pas grand-chose dedans pour un serveur MCP qui parle à un autre.
Il y a aussi un problème de public. Tout le monde fait du vibe coding dans Claude Code et construit son propre harness, a-t-il dit, mais les utilisateurs métier veulent toujours un tableau de bord, un bouton, un rapport, un graphique. Alors NimbleBrain a construit l’autre moitié.
Dans un hôte de chat
Leur bac à sable
Votre paquet, votre serveur
Leurs murs : où elle s’affiche, sa taille, ce qu’elle atteint
Un hôte vers un serveur, rien de serveur à serveur
ou
Dans votre propre hôte
La même plomberie, encore
Le runtime est à vous
Identité, fichiers, conversations, routage : refaits par produit
Les utilisateurs métier ont toujours une boîte de chat
NimbleBrainConstruire l’hôte une fois, en open source, et laisser chaque serveur s’en servir.
L’autre moitié, c’est un hôte
NimbleBrain démarre sur un shell vide avec des points d’extension : des endroits de l’interface web où une MCP App peut s’afficher. Les applis intégrées viennent d’abord (conversations, fichiers, tâches planifiées), et les applis installées s’affichent à côté. Une appli ou deux cents. Cliquez sur l’une d’elles et sa MCP App s’affiche dans la zone principale. Vous n’êtes plus dans un chat, c’est un écran SaaS complet, et les boutons ne font pas d’appels REST. Ce sont des appels d’outils MCP. Sa thèse, dite avec un sourire : REST est mort, on peut tout faire via MCP.
Faites glisser le chat et la même appli tourne avec un agent. Vous voyez les appels d’outils et les skills qui se chargent, et l’agent peut agir. Ou laissez tomber l’interface web et branchez votre propre client MCP, parce que le runtime est aussi un serveur MCP.
Sous le shell se trouve ce qu’il appelle les primitives de l’hôte, ce dont chaque serveur a besoin et qu’il ne devrait pas construire lui-même : fichiers, conversations, routage des outils, identité. Tout se découpe en espaces de travail. La finance a Sage et Stripe, l’ingénierie a GitHub et Linear, et vous gardez le vôtre, privé. Les pièces s’échangent. Un client qui avait sa propre mémoire dans une base vectorielle l’a branchée, des gens de son équipe qui aiment Obsidian ont branché Obsidian, et Salesforce ou HubSpot, c’est un choix de connecteur.
Ça tourne partout : sur site, dans un cloud privé, sur leur service managé. Ça le place à côté des API internes et du Postgres que personne n’a touché depuis vingt ans. Ils mettent un petit broker MCP devant, et un seul runtime atteint à la fois le cloud public et le système historique.
Le dépôt confirme tout ça. Il est sous Apache 2.0, tourne sur Bun, est livré en deux images de conteneur, et docker compose up vous donne l’interface web sur le port 27246. La boucle de l’agent tourne jusqu’à ce que le modèle arrête d’appeler des outils, plafonnée à 10 itérations par défaut et 25 au maximum.
Portes d’entrée
Le shell webVotre client MCPAgents de code, harness
Primitives de l’hôte
FichiersConversationsRoutage des outilsIdentitéEspaces de travail
La spec MCP
OutilsRessourcesApplisSkills
Serveurs
Les leurs : recherche, mémoire, CRM, prospectionLes vôtresN’importe quel serveur publicUn broker vers un Postgres de 20 ans
- FinanceSage · Stripe
- IngénierieGitHub · Linear
- Le mienGitHub
TourneSur site, dans un cloud privé ou sur leur service managé, avec n’importe quel modèle compatible OpenAI.
Placements : l’appli choisit sa place
Alors comment une appli se retrouve-t-elle dans la barre latérale ? Elle le demande. NimbleBrain a défini une extension d’hôte sous son domaine inversé, ai.nimblebrain/host, et le manifeste d’une appli liste des placements : un slot, un libellé, une route, et la ressource ui:// à afficher là.
"ai.nimblebrain/host": {
"placements": [
{ "slot": "sidebar.apps", "resourceUri": "ui://dashboard",
"label": "Tasks", "route": "tasks" },
{ "slot": "settings", "resourceUri": "ui://settings" }
]
}
L’hôte lit ça au démarrage. Il ne sait rien du serveur, seulement l’interface. Quand vous cliquez sur Tasks, il charge cette ressource dans une iframe de la zone principale, à côté du chat ancré, à une URL comme /w/ops/app/tasks. La doc liste les slots : une entrée sous Applis dans la barre latérale, une page entière sans entrée de navigation, une section sur la page de réglages du connecteur, et un élément épinglé en bas du tiroir mobile. La barre latérale montre les quatre premières applis, puis un lien Tout voir. Si deux connecteurs réclament la même route, le premier la garde, et l’hôte journalise qui la détient.
Une entreprise qui veut une autre disposition peut changer le gabarit autour des slots et garder les mêmes applis.
/w/ops/app/tasks
- Conversations
- Fichiers
- Applis
- Tasks
Facets : un compteur sans demander au modèle
C’est la partie que je volerais en premier. Un tableau de bord a besoin de chiffres : tâches bloquées, brouillons qui attendent une relecture. Vous pourriez demander au modèle. « Chaque fois que vous demandez au LLM, vous dépensez de plus en plus de tokens », a-t-il dit, alors les facets s’en passent.
Une facet est une ressource MCP ordinaire avec un marqueur dans son _meta. L’hôte liste les ressources du serveur, repère le marqueur, lit cette ressource, et récupère un seul nombre :
{ "uri": "acme://facets/drafts-awaiting-review",
"title": "Drafts awaiting review",
"_meta": { "ai.nimblebrain/facets": { "level": "warning" } } }
→ resources/read → { "count": 3 }
L’hôte l’affiche en une ligne, « 3 Drafts awaiting review », dans un panneau Needs attention sur la vue d’ensemble de l’espace, et un clic ouvre l’appli. La doc précise le reste. Le niveau (critical, warning ou info) fixe la couleur et l’ordre. Un zéro n’affiche rien. Une lecture plus lente que cinq secondes affiche la ligne comme indisponible sans casser les autres. Les compteurs sont mis en cache 60 secondes. Et le titre et le compteur sont traités comme des données non fiables qui n’atteignent jamais un modèle.
- Hôte → serveur
resources/list - Une ressource porte
"ai.nimblebrain/facets": { "level": "warning" } - Hôte → serveur
resources/read → { "count": 3 } - Vue d’ensemble3 Drafts awaiting review
Le modèlePas sur ce chemin. Aucun token dépensé.
- 2Tasks blockedcritical
- 3Drafts awaiting reviewwarning
- 1Reply receivedinfo
Lifecycle : l’installer achète un domaine
Certains serveurs doivent faire quelque chose ailleurs quand on les installe. L’appli de go-to-market de NimbleBrain achète des domaines et provisionne des boîtes mail dès que vous l’ajoutez à un espace de travail. C’est à deux ou trois couches du fournisseur, et aucun message MCP ne dit « tu viens d’être installé ».
L’extension lifecycle ne fait pas l’achat. C’est le crochet. Un serveur marque un outil pour chaque événement, ready et removing, et l’hôte l’appelle par un appel d’outil ordinaire. Installez-le, et le serveur entend « espace prêt », puis va acheter. Désinstallez-le, et removing arrive pendant que le serveur est encore joignable, pour qu’il libère ce qu’il a acheté.
C’est dans la doc que ça devient intéressant, parce qu’elle est honnête sur la livraison :
readyarrive au moins une fois, et deux fois sur une installation neuve, dans un ordre incertain : une fois avec la raisoninstall, une fois avecresumequand la connexion s’établit. Un redémarrage de l’hôte, c’est aussiresume, donc un redémarrage ne ressemble jamais à un nouveau client.- Le handler doit donc être idempotent : « fais que ce soit vrai », un upsert, jamais un insert.
removingest livré au mieux. Si l’hôte était éteint au moment de la désinstallation, il n’arrive jamais, donc un serveur qui laisse traîner un domaine sans lui compte sur un appel que rien ne garantit. Ajoutez votre propre balayage.- Le handler doit seulement enregistrer l’intention et rendre la main. Un processus séparé, qui détient l’identifiant du fournisseur, fait l’achat lui-même, pour qu’un bug ou un appel d’outil injecté par prompt ne puisse pas atteindre cet identifiant.
- L’hôte cache les outils marqués à tous les autres, modèle compris. Un autre hôte pourrait ne pas le faire, donc la doc demande d’écrire chaque handler comme si n’importe quel appelant pouvait l’atteindre.
- Installation
ready · reason: "install"Enregistrer « veut un domaine et des boîtes mail ». Un processus séparé les achète. - Redémarrage
ready · reason: "resume"Le même upsert. Rien de neuf à acheter. - Désinstallation
removingEnregistrer la libération. Livré au mieux, donc un balayage rattrape le reste.
Hôte seulementLe modèle ne voit jamais ces outils. L’hôte les cache à tous les autres appelants.
Dix applis devraient n’en faire qu’une
Il a montré deux applis faites par deux développeurs. L’un avait choisi le violet, l’autre le vert. Côte à côte, on aurait dit un patchwork.
La spec MCP Apps permet déjà à un hôte d’envoyer des variables de style à l’iframe. NimbleBrain les envoie, ajoute les tokens pour lesquels la spec n’a pas de clé, comme une couleur d’accent, et son SDK d’applis sous licence MIT, Synapse, les applique. Passez le shell en mode sombre et toutes les applis passent en sombre. « Combien de fois quelqu’un a essayé d’afficher une iframe dans un truc en mode sombre et a eu le mode clair ? » La même astuce donne des shells en marque blanche : les couleurs et les polices d’un client, c’est un kit de style, pas un rechargement d’appli.
Les toasts ont eu droit au même traitement. Le message de notification de la spec finit surtout en ligne de log, alors le bridge a une méthode notify avec un niveau et un titre, et le shell l’affiche comme ses propres toasts. Dans la doc, un succès reste cinq secondes, une info six, et les avertissements et les erreurs jusqu’à ce qu’on les ferme.
Basique, a-t-il reconnu. Mais c’est ce qui fait que dix ou douze serveurs donnent l’impression d’une seule appli plutôt que d’un assemblage cousu main.
À faire
Relire les brouillons sortants
Renouveler le domaine
Ajouter une tâche
Prospection
3 brouillons à relire
Boîte en préchauffe
Envoyer le lot
successRapport exportéEnregistré dans Fichiers.
Ce que ça change pour mes cinquante applis
Je fais tourner une cinquantaine d’applis sur un Mac mini, chacune derrière son propre port HTTPS Tailscale, chacune avec son front-end et son thème. Dix serveurs MCP vivent dans leurs propres dépôts à côté, la plupart de simples clients HTTP de l’API d’une appli, pour que mes agents puissent aussi utiliser les applis. Ce site en a un aussi : mon portfolio derrière un serveur MCP.
Donc chaque appli que touchent mes agents a deux portes d’entrée, construites deux fois : une interface pour moi et un serveur MCP pour eux. Le paquet de Goldsborough, c’est une seule porte. Outils, interface et skills sont livrés ensemble, le shell ancre un chat à côté de chaque écran, et les boutons comme l’agent appellent les mêmes outils.
Hier, j’ai construit une page qui liste chaque appli par port et vérifie lesquelles répondent. C’est son catalogue sans la composition. Les facets s’y glisseraient parfaitement : un compteur de ce qui attend dans chaque appli, sur une seule page, sans modèle dans la boucle.
Deux réserves honnêtes. Je n’ai pas encore fait tourner NimbleBrain ; tout ce qui précède vient du talk, du dépôt et de la doc. Et les extensions sont celles de NimbleBrain, sous son propre préfixe. Un autre hôte les ignore, ce que la doc rend sûr par conception, mais alors on perd la fonctionnalité. Goldsborough a dit qu’ils voulaient contribuer là où le travail sur la spec se recoupe déjà.
Une réponse du Q&A mérite d’être gardée. À la question « pourquoi les MCP Apps et pas A2UI ? », il a répondu qu’ils avaient adopté les MCP Apps à leur lancement et n’avaient pas encore vu l’intérêt d’A2UI. Et ce n’est pas de l’UI générative. Vous concevez et construisez toujours l’appli. Ça ressemble à une appli CRUD, avec une couche d’agent fournie d’office.
Mon installation aujourd’hui
Deux portes par appli
Un front-end par appli, son thème et son port
Un serveur MCP dans un autre dépôt, même API
Une cinquantaine d’applis, dix serveurs MCP
vs
Un paquet par appli
Une seule porte
Outils, interface et skills livrés ensemble
Les boutons et l’agent appellent les mêmes outils
Un shell, un chat, un look
Pas encore essayéJe n’ai pas fait tourner NimbleBrain. C’est le talk, le dépôt et la doc.
Essayez
- Regardez le talk : le livestream d’AGNTCon + MCPCon à partir de 7:12:34, environ 25 minutes avec le Q&A.
- Faites tourner l’hôte : NimbleBrainInc/nimblebrain, sous Apache 2.0.
docker compose upavec une clé d’API Anthropic et uninstance.jsond’une ligne. - Construisez une appli pour lui, ou pour n’importe quel hôte MCP Apps : Synapse, sous MIT.
- Lisez les extensions : placements, facets, lifecycle et le bridge des applis.
- La spec en dessous : MCP Apps.
Si vous avez livré une MCP App hors d’une fenêtre de chat, je veux voir l’hôte. Et si vous essayez les facets avant moi, dites-moi ce que vous avez compté.
Texte brut: every-screen-is-an-mcp-app.md · Flux Atom · Toutes les notes