python-sdk/i18n/fr/pages/servers/handling-errors.md

139 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
translation:
sections: [e33d441f12d50535, 7099694c603e0f5f, c1df4cf9673433e6, c9cd294541422e6e, 6cec073617bfd037, efa92b8f99e908c8, 6a22a29e27fb4601]
tool: 1
---
# Gérer les erreurs {#handling-errors}
Un outil (tool) peut échouer de deux manières, et le SDK les traite très différemment.
Levez une exception ordinaire et c’est le **modèle** qui la voit. Levez `MCPError` et c’est le **protocole** qui la voit.
Cette page vous aide à choisir.
## Une erreur que le modèle peut corriger {#an-error-the-model-can-fix}
Prenez un outil qui effectue une recherche, et laissez cette recherche échouer :
```python title="server.py" hl_lines="11-12"
--8<-- "docs_src/handling_errors/tutorial001.py"
```
Ces deux lignes n’ont rien de spécifique à MCP. `get_author` lève une simple `ValueError`, comme le ferait n’importe quelle fonction Python.
Appelez-le avec un titre absent du catalogue et regardez le résultat :
```python
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author: No book titled 'Nothing' in the catalog.")]
result.structured_content # None
```
* La requête a **réussi**. Il y a un résultat ; rien n’a été levé côté appelant.
* `is_error` vaut `True`, et le message de votre exception (préfixé du nom de l’outil) se trouve dans `content`, exactement là où le modèle lit.
* `structured_content` vaut `None`. Un appel en échec n’a aucune valeur de retour à structurer.
C’est une **erreur d’outil** (tool error), et c’est le comportement par défaut pour *toute* exception que lève votre outil. C’est aussi presque toujours ce que vous voulez.
C’est le modèle qui appelle votre outil. C’est lui qui a choisi les arguments. Une erreur d’outil est donc un tour de conversation : le modèle lit *« No book titled 'Nothing' in the catalog. »*, comprend qu’il s’est trompé de titre et rappelle l’outil avec un meilleur. Vous avez écrit un seul `raise` et obtenu un agent qui se corrige tout seul.
!!! tip
N’utilisez jamais `return` pour renvoyer un message d’erreur depuis un outil. Une chaîne renvoyée a
`is_error=False` : pour le modèle (et pour toute interface cliente), l’outil semble avoir
fonctionné et cette chaîne semble être la réponse. Utilisez `raise`. C’est le drapeau qui fait signal.
## Une erreur que le modèle ne peut pas corriger {#an-error-the-model-cannot-fix}
Remplacez maintenant `ValueError` par `MCPError`.
```python title="server.py" hl_lines="1 3 14"
--8<-- "docs_src/handling_errors/tutorial002.py"
```
`MCPError` est l’**erreur de protocole** du SDK. C’est la seule exception que l’enveloppe de l’outil n’intercepte *pas* : elle se propage, et toute la requête `tools/call` échoue avec une erreur JSON-RPC au lieu d’un résultat.
```json
{
"code": -32602,
"message": "No book titled 'Nothing' in the catalog."
}
```
* Il n’y a **aucun résultat**. Pas de `content`, pas de `is_error` : rien à lire pour le modèle.
* C’est l’application **hôte** qui reçoit l’erreur, exactement comme si l’outil n’existait pas du tout.
* `code`, `message` et `data` arrivent intacts. `INVALID_PARAMS` vaut `-32602` ; `mcp.types` l’exporte, avec les autres codes d’erreur JSON-RPC (`INVALID_REQUEST`, `INTERNAL_ERROR`, …), sous forme de constantes pour que vous n’ayez jamais à saisir de nombre magique.
!!! check
Même recherche, même échec, mais cette fois l’appel *lève une exception* côté client au lieu de renvoyer un résultat :
```text
mcp.shared.exceptions.MCPError: No book titled 'Nothing' in the catalog.
```
La première version donnait au modèle une phrase à laquelle réagir. Celle-ci ne lui donne rien.
Pour `get_author`, c’est strictement pire, et c’est tout l’objet de la section suivante.
## Laquelle lever {#which-one-to-raise}
Les deux voies répondent à deux questions différentes.
* **Levez n’importe quelle exception** pour un échec d’*exécution* : ce que votre outil a tenté de faire n’a pas fonctionné. Le modèle a choisi l’appel, il devrait donc en voir la conséquence et avoir une chance de se rattraper. Un titre mal orthographié, une API amont qui a expiré, une ligne qui n’existe pas : autant d’erreurs d’outil.
* **Levez `MCPError`** quand c’est la *requête elle-même* qui doit être rejetée : il manque au client une capacité dont dépend votre outil, le serveur n’est pas en état de servir qui que ce soit, l’appelant a sauté une étape obligatoire. Aucune nouvelle tentative du modèle ne corrige cela, il n’y a donc rien à gagner à lui transmettre le message.
Une seule question tranche : **un modèle plus malin aurait-il pu éviter cela ?** Oui -> exception ordinaire. Non -> `MCPError`.
Selon ce critère, la seconde version de `get_author` a fait le mauvais choix : un meilleur titre règle le problème, le modèle méritait donc de voir le message. Elle est là pour vous montrer le mécanisme, pas pour le recommander.
!!! info
`MCPError` s’importe avec `from mcp import MCPError` et prend `code`, `message` et une charge
utile `data` facultative. Ce que vous y mettez est ce que le client reçoit : le SDK transmet telle
quelle une `MCPError` levée au lieu de l’assainir.
## Une ressource qui n’existe pas {#a-resource-that-doesnt-exist}
Les ressources tracent la même frontière, et fournissent une exception dédiée pour le cas courant.
```python title="server.py" hl_lines="2 13"
--8<-- "docs_src/handling_errors/tutorial003.py"
```
`books://{title}` est un **modèle** (template). Il correspond à *n’importe quel* titre, donc « l’URI est bien formé » et « le livre existe » sont deux questions différentes, et seule votre fonction peut répondre à la seconde.
Quand elle ne le peut pas, levez `ResourceNotFoundError`. Le SDK la transforme en l’erreur de protocole que la spécification attribue à une ressource manquante : `-32602` avec l’URI demandé dans `data`, pour que le client sache *quelle* lecture a échoué.
```json
{
"code": -32602,
"message": "No book titled 'Nothing' in the catalog.",
"data": {"uri": "books://Nothing"}
}
```
Remarquez qu’il n’y a pas ici de demi-résultat `is_error=True`. La lecture d’une ressource renvoie un contenu ou échoue : les ressources n’ont que la voie du protocole. Les modèles et tout ce qui concerne les ressources se trouvent dans **[Ressources](resources.md)**.
## Les erreurs que vous ne levez jamais {#errors-you-never-raise}
Un mauvais argument n’atteint jamais votre fonction.
Envoyez à `get_author` un `title` qui n’est pas une chaîne et le SDK le rejette d’après le schéma d’entrée **avant** de vous appeler, sous la forme du même genre d’erreur d’outil `is_error=True` que le modèle peut lire et corriger. **[Outils](tools.md)** montre le même rejet avec une contrainte `Field(le=50)`.
Cela représente toute une catégorie d’instructions `raise` que vous n’écrivez pas : ne revalidez pas vos propres annotations de type.
!!! info
Tout ce que décrit cette page est ce qu’un **client** voit, et le `Client` en mémoire avec lequel
vous écrirez vos tests voit exactement la même chose. Même `raise_exceptions=True` ne retransforme
pas une erreur d’outil en traceback : au moment où ce drapeau pourrait agir, votre exception est déjà
devenue le résultat `is_error=True`. Faites vos assertions sur le résultat. **[Tests](../get-started/testing.md)** présente ce schéma.
## Récapitulatif {#recap}
* Levez **n’importe quelle exception** dans un outil -> l’appel renvoie `is_error=True` avec votre message dans `content`. Le modèle le lit et peut réessayer. C’est le comportement par défaut.
* Levez **`MCPError`** -> l’appel lui-même échoue avec une erreur JSON-RPC. Le modèle ne voit rien ; c’est l’hôte qui s’en occupe. `code`, `message` et `data` arrivent intacts.
* La question qui tranche : *un modèle plus malin aurait-il pu éviter cela ?* Oui -> exception. Non -> `MCPError`.
* `ResourceNotFoundError` depuis un gestionnaire (handler) de ressource -> le `-32602` du protocole, avec l’URI dans `data`.
* Les mauvais arguments sont rejetés d’après le schéma avant que votre fonction ne s’exécute ; vous n’avez pas de `raise` à écrire pour eux.
* `from mcp import MCPError` ; les constantes de codes d’erreur viennent de `mcp.types`.
Les erreurs sont gérées. C’est tout ce qu’un serveur *expose*. Ce que chaque gestionnaire peut lire, et faire en retour auprès du client pendant qu’il s’exécute, fait l’objet de la section suivante : **[Dans votre gestionnaire](../handlers/index.md)**.
Le texte exact des erreurs du SDK que vous avez le plus de chances de rencontrer, ce que chacune signifie et le correctif en un geste pour chacune se trouvent dans **[Dépannage](../troubleshooting.md)**.