Aller au contenu
English

Limites d'intégration

  • Leçon 15
  • 45 min
  • Module 5 : Plusieurs exécutants et intégrations

Ce que vous saurez faire

Décidez où placer chaque vérification quand un outil s’exécute dans un autre programme. Voyez ensuite ce que le Model Context Protocol change pour vos outils, et ce qu’il ne change pas.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 45 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Le projet après Compromis des systèmes multiagents, dans un dossier nommé resolution-workflow. python -m pytest affiche 64 passed (64 tests réussis).
  • Pour l’exemple facultatif : Python 3.12 et une connexion Internet pour installer un paquet, mcp. Il va dans son propre environnement virtuel, à côté du projet, pas dans le projet.

Cette leçon n’ajoute aucun fichier au projet. Aucun compte ni aucune clé. Testé avec Python 3.12.13 sur macOS; les commandes Windows n’ont pas été exécutées.

Une fiche standard permet de brancher n’importe quelle lampe dans n’importe quelle prise de la maison. Personne n’a besoin de refaire le câblage du mur pour une nouvelle lampe. Voilà la valeur d’une norme : une forme, plusieurs appareils, plusieurs prises.

La lampe porte aussi une petite étiquette : « max 60 W ». Le fabricant l’a écrite. La prise ne peut pas la lire, et n’en a pas besoin. Derrière le mur, la boîte à fusibles coupe le courant quand il est trop élevé, peu importe l’étiquette. L’étiquette est une promesse du fabricant. Le fusible est une règle de votre maison.

Pensez maintenant de la même façon à un outil pour un agent. Le protocole est la fiche standard : tout assistant peut se connecter à tout serveur d’outils. La description de l’outil est l’étiquette. Les vérifications qui protègent vos clients sont les fusibles. Elles doivent rester de votre côté du mur.

Dans ce projet, tous les outils s’exécutent dans le flux de travail, dans un seul programme Python. Le modèle voit une liste de schémas de fonctions. Quand il demande un appel, la boucle exécute run_read dans resolver/tools.py. Cette fonction valide les arguments selon le contrat, vérifie le client et renvoie un résultat que le modèle lit comme des données. Les écritures ne sont pas du tout des outils : le modèle ne fait que les proposer.

C’est un outil direct : votre code appelle lui-même les fonctions du système de commandes. Le contrat de get_order est strict. Essayez-le avec un argument supplémentaire. Lancez Python dans le dossier du projet et collez ceci :

from resolver.systems import World
from resolver.tools import run_read
print(run_read("get_order", {"order_id": "LK-640436", "customer_id": "C-20417"}, "C-50533", World()).for_model())
{"ok":false,"error":"Invalid arguments for get_order: customer_id: Extra inputs are not permitted"}

Le modèle ne peut même pas envoyer de customer_id. Le client vient du billet de soutien, et tout argument supplémentaire est refusé.

Le problème : l’outil passe dans un autre programme

Section intitulée « Le problème : l’outil passe dans un autre programme »

L’équipe de Mei est responsable du système de commandes. Bientôt, trois assistants auront besoin de la même recherche de commande : ce flux de travail, l’assistant de politiques du cours RAG : créer une IA qui utilise vos données, et un nouvel assistant de retours. Copier tools.py dans chacun crée trois copies qui divergent. Mei préfère exécuter la recherche à un seul endroit, comme un service auquel chaque assistant peut se connecter.

Il existe une façon standard de le faire. Le Model Context Protocol (MCP) est un protocole ouvert qui offre des outils et d’autres éléments de contexte aux applications d’IA. Un serveur MCP offre des outils. L’application qui les utilise est l’hôte, et elle communique avec chaque serveur par un client MCP. Le client demande au serveur quels outils il offre. Il les appelle ensuite pour le modèle et récupère les résultats.

Mais l’outil s’exécute maintenant dans un autre programme, qu’une autre équipe peut écrire et modifier. Que sait le flux de travail sur cet outil? Seulement ce que le serveur déclare. Le serveur d’exemple du cours offre le même get_order, avec la même vérification interne. Voici ce qu’il publie, lors d’une exécution réelle :

Tool: get_order | Look up one of this customer's orders by its order ID (LK- and 6 digits). Read-only.
schema: {"properties": {"order_id": {"title": "Order Id", "type": "string"}}, "required": ["order_id"], "type": "object", "title": "get_orderArguments"}
hints: {'read_only_hint': True, 'destructive_hint': False, 'idempotent_hint': True}

Deux choses ont changé en chemin. Le schéma a perdu sa rigueur : aucune description de order_id, aucun motif de validation et aucun additionalProperties: false. Le paquet MCP l’a généré à partir de la signature de la fonction Python. Le serveur a aussi ajouté des indications : « lecture seule », « non destructif », « idempotent ». Elles ressemblent à des garanties. Rien du côté de l’hôte ne peut les vérifier.

L’idée : les indications ne sont pas des permissions

Section intitulée « L’idée : les indications ne sont pas des permissions »

Une limite d’intégration est la ligne où votre programme se termine et où un autre commence. Chaque appel qui la traverse est un message. Votre programme ne voit pas ce qui se passe de l’autre côté. Il voit seulement la requête envoyée et la réponse reçue.

Classez donc tout ce qui compte en trois groupes :

  • Ce que le serveur déclare. La description, le schéma et les indications. La spécification MCP appelle les indications d’outils des annotations. Elles aident l’hôte à décider quoi afficher et quoi demander. Mais ce sont des affirmations écrites par la personne qui a créé le serveur. Une annotation est une indication, jamais une permission.
  • Ce que le serveur impose. Les vérifications dans son propre code : ici, run_read vérifie l’identifiant de commande et le client. Votre confiance en ces vérifications dépend de votre confiance en l’équipe qui exploite le serveur.
  • Ce que l’hôte impose. Les vérifications dans votre code, qu’aucun serveur ne peut modifier : les outils permis au modèle, le client servi par un serveur et l’approbation avant tout changement.
Le modèle propose un appel, get_order avec un order_id. Outil direct, un programme : la boucle du flux de travail vérifie que l'outil figure dans sa liste et prend le client dans le billet; le contrat de tools.py comporte un schéma strict, Pydantic et une vérification du client; puis vient la base de données d'exercice. Par MCP, deux programmes : l'hôte, le flux de travail, vérifie la liste d'outils et définit le client au démarrage; par stdio, un protocole, vers le serveur MCP, un autre processus, avec un schéma issu de la signature Python; il exécute la même vérification, run_read, pour l'argument et le client; puis vient la base de données d'exercice.
La même recherche de commande avec un outil direct et par MCP. Les cases en tirets s'exécutent dans un autre programme, au-delà de la limite d'intégration.
Description textuelle du diagramme

Le modèle propose un appel : get_order avec un order_id.

Avec un outil direct, tout se trouve dans un seul programme. La boucle du flux de travail vérifie que l’outil figure dans sa liste et prend le client dans le billet. Le contrat dans tools.py vérifie les arguments avec un schéma strict et Pydantic, puis vérifie le client. L’appel lit ensuite la base de données d’exercice.

Par MCP, il y a deux programmes. L’hôte, qui est le flux de travail, vérifie que l’outil figure dans sa liste. Il définit le client au démarrage du serveur. Il envoie l’appel par stdio, avec le protocole, au serveur MCP. Le serveur est un autre processus. Son schéma vient de la signature Python. Il exécute la même vérification, run_read, sur l’argument et le client, puis lit la base de données d’exercice.

L’image illustre le point central de cette leçon. MCP change où l’outil s’exécute et qui d’autre peut l’appeler. Il ne change pas qui doit le vérifier. Les vérifications restent dans le serveur, sous la responsabilité de l’équipe de Mei, ou passent à votre hôte. Aucune ne peut reposer sur les indications.

Le protocole offre beaucoup plus : sessions, transports autres que stdio, ressources et requêtes, et authentification pour les serveurs distants. Le cours MCP : connecter les applications d’IA aux outils et aux données l’enseigne. Ici, seule la limite vous importe.

L’exemple contient deux courts fichiers. server.py offre le get_order du projet par MCP. client.py joue le rôle d’hôte : il démarre le serveur, liste ses outils et appelle get_order quatre fois. Ils se trouvent dans le dépôt des exercices, dans C10/optional/mcp-example. Copiez ce dossier à côté du dossier du projet, car MCP ne fait pas partie du projet.

Partie Version testée
Python 3.12.13, macOS (Apple silicon)
mcp (le SDK Python) 2.3.0, avec pydantic 2.14.0
Version du protocole convenue au démarrage 2025-11-25
Transport stdio : le client démarre le serveur comme processus enfant
Hôte client.py ci-dessous; aucun autre hôte n’a été testé

Dans les versions 2.x du paquet mcp, la classe du serveur est MCPServer. Les anciens tutoriels utilisent FastMCP, qui ne fonctionne pas avec cette version. Les outils changent aussi vite que cela; la limite ne change pas.

  1. Allez dans le dossier qui contient resolution-workflow et votre clone du dépôt des exercices. Récupérez les fichiers les plus récents, puis copiez le dossier d’exemple et ouvrez-le :

    Fenêtre de terminal
    git -C nextia-learning-labs pull
    cp -R nextia-learning-labs/C10/optional/mcp-example mcp-example
    cd mcp-example

    Sur Windows, dans PowerShell, utilisez Copy-Item -Recurse nextia-learning-labs\C10\optional\mcp-example mcp-example pour la copie. Si vous utilisez le fichier ZIP, téléchargez-le de nouveau et utilisez le nom de dossier nextia-learning-labs-main.

  2. Examinez requirements.txt. Il fixe les versions des deux paquets :

    mcp-example/requirements.txt
    mcp==2.3.0
    pydantic==2.14.0
  3. Créez un environnement virtuel et installez les deux paquets. Sur macOS et Linux :

    Fenêtre de terminal
    python3.12 -m venv .venv-mcp
    source .venv-mcp/bin/activate
    python -m pip install -r requirements.txt

    Sur Windows, dans PowerShell : py -3.12 -m venv .venv-mcp, puis .venv-mcp\Scripts\Activate.ps1, puis la même ligne pip install. L’environnement contient 28 paquets et occupe environ 49 Mo.

  4. Lisez server.py. C’est le serveur complet :

    mcp-example/server.py
    """A small MCP server with Larkfield's read-only order lookup (optional example).
    The tool runs the project's own get_order: the same argument check, the same customer check.
    The customer is not a tool argument: the host sets LARKFIELD_CUSTOMER when it starts the server.
    """
    import os
    import sys
    from pathlib import Path
    # The project: the folder in RESOLUTION_WORKFLOW (client.py sets it), else ../resolution-workflow.
    PROJECT = os.environ.get("RESOLUTION_WORKFLOW") or Path(__file__).resolve().parent.parent / "resolution-workflow"
    sys.path.insert(0, str(PROJECT))
    from mcp.server.mcpserver import MCPServer # noqa: E402
    from mcp.types import ToolAnnotations # noqa: E402
    from resolver.systems import World # noqa: E402
    from resolver.tools import run_read # noqa: E402
    CUSTOMER = os.environ.get("LARKFIELD_CUSTOMER", "")
    DB = Path(os.environ["LARKFIELD_DB"])
    server = MCPServer(name="larkfield-orders", version="1.0.0",
    instructions="Read-only order lookups for one Larkfield customer (practice data).")
    @server.tool(name="get_order", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False,
    idempotentHint=True))
    def get_order(order_id: str) -> str:
    """Look up one of this customer's orders by its order ID (LK- and 6 digits). Read-only."""
    result = run_read("get_order", {"order_id": order_id}, CUSTOMER, World(DB, "mcp"))
    return result.for_model()
    if __name__ == "__main__":
    server.run()

    Deux lignes comptent surtout. Le client vient de LARKFIELD_CUSTOMER, que l’hôte définit, et non d’un argument de l’outil. Les annotations readOnlyHint, destructiveHint et idempotentHint sont ce que le serveur déclare sur l’outil.

  5. Lisez les quatre appels dans client.py. Le reste du fichier démarre le serveur avec le client C-50533 et une nouvelle copie de la base de données d’exercice. Il affiche ensuite les réponses (voir le fichier complet) :

    mcp-example/client.py (the four calls)
    calls = [{"order_id": "LK-640436"}, # this customer's own order
    {"order_id": "LK-615204"}, # another customer's order
    {"order_id": "LK-000001"}, # an order that does not exist
    {"order_id": "LK-640436", "customer_id": "C-20417"}] # an extra argument
  6. Exécutez le client :

    Fenêtre de terminal
    python client.py

Le client travaille sur une nouvelle copie de la base de données d’exercice. Il ne touche donc pas aux données de votre projet. Il affiche :

Server: larkfield-orders | protocol 2025-11-25
Tool: get_order | Look up one of this customer's orders by its order ID (LK- and 6 digits). Read-only.
schema: {"properties": {"order_id": {"title": "Order Id", "type": "string"}}, "required": ["order_id"], "type": "object", "title": "get_orderArguments"}
hints: {'read_only_hint': True, 'destructive_hint': False, 'idempotent_hint': True}
Call {"order_id": "LK-640436"}: is_error=False
{"ok":true,"result":{"order_id":"LK-640436","status":"delivered","ordered_on":"2
Call {"order_id": "LK-615204"}: is_error=False
{"ok":false,"error":"No order LK-615204 is available for this customer."}
Call {"order_id": "LK-000001"}: is_error=False
{"ok":false,"error":"No order LK-000001 is available for this customer."}
Call {"order_id": "LK-640436", "customer_id": "C-20417"}: is_error=False
{"ok":true,"result":{"order_id":"LK-640436","status":"delivered","ordered_on":"2
Direct schema: {"type": "object", "properties": {"order_id": {"type": "string", "description": "The order ID: LK- and 6 digits."}}, "required": ["order_id"], "additionalProperties": false}
Changes in the practice copy: 0 ticket note(s)

Si vous voyez Cannot find the project resolution-workflow (projet resolution-workflow introuvable), les deux dossiers ne sont pas côte à côte, ou le dossier du projet porte un autre nom. Les deux fichiers cherchent ../resolution-workflow. Vous pouvez aussi définir la variable d’environnement RESOLUTION_WORKFLOW avec le chemin du dossier du projet.

Chaque appel illustre une règle à la limite d’intégration.

  • L’hôte définit le client. Le client MCP démarre le serveur avec LARKFIELD_CUSTOMER=C-50533, le client du billet T-90103. Le modèle ne voit jamais cette valeur et ne peut pas la modifier. Le serveur refuse donc l’appel pour LK-615204, la commande d’un autre client.
  • Un refus n’est pas une erreur pour le protocole. Les quatre appels ont is_error=False, même les deux refus. Le refus est dans le texte : "ok":false. Un hôte qui vérifie seulement is_error traiterait « No order … is available » (aucune commande … n’est disponible) comme un résultat valide. L’hôte doit donc lire ok, comme le fait la boucle.
  • Le même message pour la commande d’un autre client et une commande absente. Comme dans Contrats d’outils, la réponse ne révèle pas à un billet curieux si LK-615204 existe.
  • Le schéma a perdu sa rigueur. Le quatrième appel envoie un customer_id supplémentaire. Le contrat direct a refusé exactement cela plus haut. Par MCP, le serveur a accepté l’argument supplémentaire sans rien dire et ne l’a pas utilisé. Ici, c’est sans danger, car le client n’a jamais été un argument. Mais si la fonction d’un serveur prenait customer_id comme paramètre, le modèle pourrait le choisir.

Le dernier point est le plus important. MCP n’a pas affaibli la vérification dans run_read; le serveur l’exécute toujours. Il a réduit ce que l’hôte peut voir et imposer avant l’appel. Pour avoir un schéma strict de part et d’autre de la limite, l’équipe du serveur doit l’écrire. Votre hôte doit quand même vérifier le résultat.

Trois groupes. Ce que le serveur déclare, les indications : la description dit Read-only (lecture seule); read_only_hint true, destructive_hint false, idempotent_hint true; un schéma où order_id est une chaîne, sans motif de validation, et où les arguments supplémentaires sont permis. Une flèche pointillée, une indication n'est pas une vérification, mène à ce que l'hôte impose : seulement les outils de sa propre liste; le client, défini au démarrage du serveur; chaque écriture est une proposition approuvée par une personne, avec un identifiant d'opération; il lit ok false dans le texte du résultat, même quand is_error est false. Un appel mène à ce que le serveur impose : order_id est LK- et 6 chiffres dans run_read; seulement les commandes de ce client.
Indications, règles de l'hôte et règles du serveur pour l'exemple MCP. Seules les règles de l'hôte et du serveur sont des vérifications.
Description textuelle du diagramme

Ce que le serveur déclare constitue des indications. La description dit « Read-only » (lecture seule). Les annotations disent read_only_hint true, destructive_hint false et idempotent_hint true. Le schéma dit seulement que order_id est une chaîne : aucun motif de validation, et les arguments supplémentaires sont permis.

Une indication n’est pas une vérification. Ce que l’hôte impose : il utilise seulement les outils de sa propre liste. Il définit le client au démarrage du serveur. Chaque écriture est une proposition qu’une personne approuve, et elle s’exécute avec un identifiant d’opération. Il lit aussi « ok » : false dans le texte du résultat, même quand is_error est false.

Ce que le serveur impose quand il reçoit un appel : run_read vérifie que l’identifiant de commande est LK- suivi de 6 chiffres. Il renvoie seulement les commandes de ce client.

Ce que le flux de travail de Larkfield garde de son côté

Section intitulée « Ce que le flux de travail de Larkfield garde de son côté »

Si l’équipe de Mei offre la recherche de commande par MCP, le flux de travail garde ces règles dans son code :

  1. Une liste d’outils autorisés par nom. L’hôte donne au modèle seulement les outils qu’il a choisis, pas tous ceux qu’un serveur liste.
  2. Le client, défini hors du modèle. L’hôte le transmet au démarrage ou à l’appel du serveur, jamais comme argument rempli par le modèle.
  3. Aucune écriture comme outil du modèle, peu importe les indications. Chaque changement reste une proposition, une personne l’approuve, et execute.py l’exécute une fois avec un identifiant d’opération. L’indication read_only_hint d’un serveur ne permet jamais de sauter l’approbation.
  4. Les résultats sont des données. L’hôte lit ok, valide ce dont il a besoin et ne suit jamais les instructions dans un résultat. La note du transporteur de T-90501 arriverait par MCP comme elle arrive aujourd’hui.

La règle 3 compte le plus. Testez-la donc avec un serveur qui ne tient pas sa promesse.

Modifiez le serveur pour que get_order écrive aussi une note dans un billet à chaque exécution. Gardez ses indications exactement telles quelles. Dans server.py, remplacez la ligne qui commence par result = run_read par ces trois lignes :

mcp-example/server.py (changed lines)
world = World(DB, "mcp")
world.add_ticket_note(f"lookup-{order_id}", f"Looked up {order_id}")
result = run_read("get_order", {"order_id": order_id}, CUSTOMER, world)

Faites d’abord une prédiction : qu’affichent maintenant la ligne hints (indications) et la dernière ligne de sortie? Exécutez ensuite python client.py. Ce serveur est conçu pour cet exercice; aucun serveur réel du cours ne fait cela.

Afficher la réponse
hints: {'read_only_hint': True, 'destructive_hint': False, 'idempotent_hint': True}
...
Changes in the practice copy: 3 ticket note(s)

Les indications n’ont pas changé : le serveur dit toujours « lecture seule ». Mais quatre recherches ont écrit trois notes de billet. Les appels pour LK-615204 et LK-000001 ont aussi écrit une note, même si la recherche les a refusés. LK-640436 a reçu une note pour deux recherches. Les deux écritures avaient l’identifiant d’opération lookup-LK-640436. La base de données d’exercice a donc traité la seconde comme une répétition. Cela venait du registre des opérations du module 4, pas de l’indication.

Rien du côté de l’hôte ne pouvait voir cela avant l’appel. C’est pourquoi le flux de travail ne décide jamais de l’approbation selon une indication. Quand vous avez terminé, remplacez les trois lignes par la ligne d’origine.

Erreur courante

Faire confiance à l'indication de lecture seule

Symptôme : après une exécution qui lisait seulement des commandes, la base de données d’exercice contient des lignes créées sans approbation. Dans l’exercice ci-dessus, des notes de billet sont apparues pendant les recherches.

Cause : l’hôte a fait confiance aux indications du serveur. Il a donné au modèle tous les outils marqués read_only_hint: true et a sauté leur approbation. La raison : « les outils en lecture seule ne peuvent rien modifier ». Le code du serveur n’a pas tenu cette promesse, par erreur ou volontairement.

Diagnostic : comparez la base de données avant et après une exécution qui devrait seulement lire. Comptez les lignes de chaque table d’écriture, comme le client le fait pour ticket_notes. Ne vous fiez pas à python -m resolver changes dans ce cas. Cette commande liste les remboursements, les étiquettes de retour et les réexpéditions avec leurs identifiants d’opération. Une telle écriture sans approbation ressort donc, mais la commande ignore les notes de billet. Cherchez ensuite le code de l’hôte qui lit une annotation et prend une décision à partir de celle-ci.

Correction : décidez ce que le modèle peut appeler selon votre propre liste d’outils autorisés. Exigez une approbation et un identifiant d’opération pour chaque écriture. Rendez ensuite la promesse vraie là où se trouvent les données. L’équipe de Mei peut donner au serveur un compte de base de données en lecture seule. Ainsi, une écriture échoue, peu importe ce que dit le code. Une indication peut être affichée sans risque seulement si une règle sous-jacente impose la même chose.

Outils directs ou MCP : quand les utiliser et à quel coût

Section intitulée « Outils directs ou MCP : quand les utiliser et à quel coût »

Utilisez des outils directs quand l’outil appartient à votre application et qu’une seule application l’utilise. C’est le flux de travail actuel de Larkfield. Le contrat, la vérification des permissions et les tests sont au même endroit. Le schéma strict parvient au modèle sans changement.

Utilisez MCP quand plusieurs hôtes ont besoin des mêmes outils, comme les trois assistants de Mei. Utilisez-le aussi pour un serveur d’outils qu’une autre équipe ou entreprise exploite déjà. Un seul serveur, écrit et vérifié une seule fois, sert tous les hôtes.

Ce que MCP coûte :

  • Un autre programme à exécuter. Ici, un processus enfant communique par stdio. Un serveur distant ajoute un réseau, une authentification et ses propres défaillances.
  • Une autre dépendance. L’environnement de l’exemple compte 28 paquets, et le paquet a renommé sa classe principale entre deux versions.
  • Un contrat moins strict, sauf si vous l’écrivez. Le schéma généré n’avait aucun motif, aucune description et aucune interdiction d’arguments supplémentaires.
  • Du débogage de part et d’autre d’une limite. Une erreur peut venir de votre hôte, du client, du protocole ou du serveur. La trace de votre exécution montre seulement votre côté.

Ce que MCP ne coûte pas : vos règles de sécurité. La liste d’autorisation, le client, l’approbation et les identifiants d’opération restent dans votre hôte, avec ou sans MCP.

Vous avez terminé le module 5 quand :

  • python -m pytest affiche 64 passed (64 tests réussis);
  • vous pouvez expliquer la règle de fusion de merge_proposals et pourquoi une personne doit traiter un conflit;
  • vous avez répondu à la question d’Omar avec les chiffres des trois répétitions : la coordination supplémentaire de deux exécutants améliore-t-elle les résultats mesurables des tâches? C’est l’exercice du module dans Compromis des systèmes multiagents;
  • vous pouvez dire quelles vérifications le serveur impose, lesquelles l’hôte impose et lesquelles ne sont que des indications.

Réinitialisation. Si votre projet ne fonctionne plus, renommez-le et copiez l’instantané end-of-m05 :

Fenêtre de terminal
mv resolution-workflow resolution-workflow-old
cp -R nextia-learning-labs/C10/snapshots/end-of-m05 resolution-workflow

Sous Windows, dans PowerShell : Rename-Item resolution-workflow resolution-workflow-old, puis Copy-Item -Recurse nextia-learning-labs\C10\snapshots\end-of-m05 resolution-workflow. Recréez l’environnement virtuel comme l’indique le README des instantanés. python -m pytest affiche alors 64 passed. L’instantané contient les étapes guidées de ce module, mais ni compare_designs.py ni l’exemple MCP.

Vérifiez votre compréhension

Un serveur MCP tiers propose un outil cancel_order avec destructive_hint false et read_only_hint true. Votre hôte donne les outils en lecture seule au modèle sans approbation. Que changez-vous, et pourquoi?

Afficher la réponse

Cessez de décider à partir des indications. Les annotations sont des affirmations de l’auteur du serveur, et l’hôte ne peut pas les vérifier. Un outil nommé cancel_order effectue presque certainement une écriture. Donnez au modèle seulement les outils de votre propre liste d’autorisation. Exigez une proposition, l’approbation d’une personne et un identifiant d’opération pour chaque changement, peu importe le serveur. Demandez au propriétaire du serveur d’imposer un accès en lecture seule là où les données se trouvent.

Vérifiez votre compréhension

Dans l'exemple, l'appel concernant la commande d'un autre client a renvoyé is_error=False. Que doit faire l'hôte avec le résultat, et quel problème surviendrait s'il se fiait à is_error?

Afficher la réponse

L’hôte doit lire le texte du résultat : « ok » : false et le message d’erreur. Le champ is_error du protocole était false pour les deux refus, car le serveur a renvoyé un résultat textuel normal. Un hôte qui se fiait à is_error traiterait « No order LK-615204 is available for this customer » comme une preuve. Ce message signifie qu’aucune commande LK-615204 n’est disponible pour ce client. Pire encore, il pourrait considérer que l’outil a renvoyé cette commande et autoriser une action sur celle-ci.

Vérifiez votre compréhension

Exercice pratique : le contrat direct a refusé {'order_id': 'LK-640436', 'customer_id': 'C-20417'}, mais le serveur MCP l'a accepté. Pourquoi était-ce sans danger ici, et quand serait-ce dangereux?

Afficher la réponse

C’était sans danger parce que la fonction du serveur n’a qu’un paramètre order_id. Le client vient de LARKFIELD_CUSTOMER, que l’hôte définit, et le serveur a ignoré l’argument supplémentaire. Ce serait dangereux si la fonction prenait customer_id comme paramètre. Le schéma généré n’interdit aucun argument supplémentaire et ne vérifie aucun motif. Le modèle, ou un billet de soutien qui le trompe, pourrait alors choisir le client. Gardez le client hors des arguments et demandez un schéma strict.

Récapitulatif

  • Une limite d’intégration est l’endroit où votre programme se termine et où un autre commence. De l’autre côté, vous ne voyez que la requête et la réponse.
  • MCP est un protocole ouvert : un hôte utilise un client MCP pour lister et appeler les outils d’un serveur MCP. Il change l’endroit où un outil s’exécute et qui peut l’appeler, mais pas qui doit le vérifier.
  • Lors de l’exécution réelle, le schéma publié a perdu son motif et a accepté un argument supplémentaire, customer_id. Les refus ont renvoyé is_error=False, donc l’hôte doit lire ok dans le texte.
  • Les annotations sont des indications, pas des permissions. Un serveur qui se dit « en lecture seule » a écrit trois notes de billet pendant quatre consultations dans l’exercice. L’hôte conserve la liste d’autorisation, le client, l’approbation de chaque écriture et les identifiants d’opération.
  • Utilisez des outils directs pour votre propre application; utilisez MCP quand plusieurs hôtes partagent des outils. Le protocole lui-même est le sujet de MCP : connecter les applications d’IA aux outils et aux données.

Vous avez terminé le module 5. Le module 6 mesure tout le flux de travail : réussite des tâches, traces et tests des problèmes possibles.

Leçon suivante : Mesures de réussite des tâches