Prompts
Traduction automatique
Cette page a été traduite automatiquement à partir de la documentation en anglais, et la page en anglais fait foi. Si quelque chose vous semble incorrect, la page Traductions explique comment le signaler.
Un prompt est un modèle de message que l’utilisateur choisit.
Les outils sont destinés au modèle. Un prompt, c’est l’inverse : l’utilisateur en choisit un dans un menu de son client (une commande slash, un bouton), renseigne ses arguments, et les messages rendus entrent dans la conversation comme s’il les avait saisis lui-même.
Vous en déclarez un en plaçant @mcp.prompt() sur une fonction qui renvoie le texte.
Votre premier prompt
from mcp.server import MCPServer
mcp = MCPServer("Code Helper")
@mcp.prompt()
def review_code(code: str) -> str:
"""Review a piece of code."""
return f"Please review this code:\n\n{code}"
Le SDK lit les trois mêmes éléments qu’il lit sur un outil :
- Le nom est le nom de la fonction :
review_code. - La description que le client affiche est la docstring :
Review a piece of code. - Les arguments proviennent des paramètres.
coden’a pas de valeur par défaut, il est donc obligatoire.
Voici ce qu’un client obtient en retour de prompts/list :
{
"name": "review_code",
"description": "Review a piece of code.",
"arguments": [
{"name": "code", "required": true}
]
}
Il n’y a pas de JSON Schema ici. Les arguments d’un prompt forment une liste plate de valeurs chaînes nommées : un formulaire qu’une personne remplit, pas une charge utile qu’un modèle construit.
Le rendre
Le client rend le modèle avec prompts/get, en passant les arguments. Votre fonction s’exécute et la str que vous renvoyez devient un seul message utilisateur :
{
"description": "Review a piece of code.",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Please review this code:\n\ndef add(a, b): return a + b"
}
}
],
"resultType": "complete"
}
C’est toute la vie d’un prompt : listé par son nom, rendu à la demande, déposé dans la conversation.
Check
required est vérifié avant l’exécution de votre fonction. Rendez review_code sans code et la
requête elle-même échoue avec une erreur JSON-RPC (code -32603) :
mcp.shared.exceptions.MCPError: Internal server error
Il n’y a pas de résultat d’erreur à la manière des outils à remettre à un modèle, car aucun modèle n’est dans la boucle :
l’appel lève une exception. La raison (Missing required arguments: {'code'}) arrive dans le journal de votre serveur.
Essayer
Lancez le serveur avec le MCP Inspector :
uv run mcp dev server.py
Ouvrez l’onglet Prompts et sélectionnez review_code. L’Inspector dessine un formulaire avec un seul champ obligatoire code. Renseignez-le, lancez le rendu, et vous obtenez en retour exactement le message utilisateur ci-dessus.
Plus d’un message
Une revue de code, c’est un message. Une session de débogage, c’est une conversation, et un prompt peut l’amorcer tout entière.
Renvoyez une liste de messages au lieu d’une str :
from mcp.server import MCPServer
from mcp.server.mcpserver.prompts.base import AssistantMessage, Message, UserMessage
mcp = MCPServer("Code Helper")
@mcp.prompt()
def review_code(code: str) -> str:
"""Review a piece of code."""
return f"Please review this code:\n\n{code}"
@mcp.prompt()
def debug_error(error: str) -> list[Message]:
"""Start a debugging conversation."""
return [
UserMessage("I'm seeing this error:"),
UserMessage(error),
AssistantMessage("I'll help debug that. What have you tried so far?"),
]
UserMessageetAssistantMessageviennent demcp.server.mcpserver.prompts.base. Passez-leur unestret ils l’enveloppent dans unTextContentpour vous. Le rôle est le nom de la classe.Messageest leur classe de base commune. Utilisez-la comme annotation de retour.
Le rendu de debug_error produit désormais trois messages, dans l’ordre :
{
"description": "Start a debugging conversation.",
"messages": [
{"role": "user", "content": {"type": "text", "text": "I'm seeing this error:"}},
{"role": "user", "content": {"type": "text", "text": "TypeError: 'int' object is not iterable"}},
{
"role": "assistant",
"content": {"type": "text", "text": "I'll help debug that. What have you tried so far?"}
}
],
"resultType": "complete"
}
Remarquez le dernier. Préremplir un tour assistant, c’est la façon d’orienter la prochaine réponse du modèle sans obliger l’utilisateur à saisir lui-même cette orientation.
Titres et descriptions d’arguments
review_code est un nom de fonction, pas un libellé. Donnez au client quelque chose de mieux à afficher sur le bouton, et décrivez chaque argument pour que le formulaire s’explique de lui-même :
from typing import Annotated
from pydantic import Field
from mcp.server import MCPServer
mcp = MCPServer("Code Helper")
@mcp.prompt(title="Code review")
def review_code(
code: Annotated[str, Field(description="The code to review.")],
language: Annotated[str, Field(description="The language the code is written in.")] = "python",
) -> str:
"""Review a piece of code."""
return f"Please review this {language} code:\n\n{code}"
title="Code review"est le nom lisible par un humain, exactement comme letitled’un outil.Annotated[str, Field(description=...)]est le même motif que celui que Outils utilise pour décrire les paramètres d’un outil. Ici, la description se retrouve sur l’argument plutôt que dans un schéma.languagea une valeur par défaut, il cesse donc d’être obligatoire.
L’entrée prompts/list contient désormais tout ce dont un client a besoin pour dessiner un bon formulaire :
{
"name": "review_code",
"title": "Code review",
"description": "Review a piece of code.",
"arguments": [
{"name": "code", "description": "The code to review.", "required": true},
{"name": "language", "description": "The language the code is written in.", "required": false}
]
}
Info
Si vous avez lu Outils, vous connaissez déjà tout jusqu’ici. Même décorateur, même
docstring servant de description, mêmes Annotated/Field. Seuls changent qui
le déclenche (l’utilisateur) et où va le résultat (dans la conversation).
Au-delà du texte
UserMessage et AssistantMessage acceptent aussi un bloc de contenu, ou un utilitaire Image / Audio, partout où ils acceptent une str. Deux cas se présentent dans les prompts : joindre un document et joindre une image.
Incorporer un fichier
from pathlib import Path
from mcp.server import MCPServer
from mcp.server.mcpserver import Message, UserMessage
from mcp.types import EmbeddedResource, TextResourceContents
mcp = MCPServer("Code Helper")
STYLE_GUIDE_FILE = Path(__file__).parent / "style-guide.md" # or the path to your file on disk
@mcp.resource("style://python", mime_type="text/markdown")
def style_guide() -> str:
"""The team's Python style guide."""
return STYLE_GUIDE_FILE.read_text(encoding="utf-8")
@mcp.prompt()
def review_code(code: str) -> list[Message]:
"""Review a piece of code against the team style guide."""
guide = TextResourceContents(uri="style://python", mime_type="text/markdown", text=style_guide())
return [
UserMessage(EmbeddedResource(resource=guide)),
UserMessage(f"Review this code against the style guide above:\n\n{code}"),
]
- Le guide de style est une ressource à l’adresse
style://python(Ressources traite de celles-ci), lue depuis un fichierstyle-guide.mdplacé à côté deserver.py. Mettez-y n’importe quel fichier Markdown. EmbeddedResource(resource=TextResourceContents(...)), tous deux issus demcp.types, transporte le fichier avec son URI et son type MIME comme premier message ; la demande qui y fait référence suit sous forme de texte brut.- Incorporer le guide, plutôt que de le coller dans la f-string, permet au client de l’afficher comme pièce jointe et de rouvrir
style://pythonplus tard, et le modèle reçoit le fichier tel quel. Pour un fichier binaire, utilisezBlobResourceContentsavec unbloben base64.
Une fois rendu, le content du premier message est un bloc resource :
{"type": "resource", "resource": {"uri": "style://python", "mimeType": "text/markdown", "text": "* Prefer early returns.\n..."}}
Joindre une image
from pathlib import Path
from mcp.server import MCPServer
from mcp.server.mcpserver import Image, Message, UserMessage
mcp = MCPServer("Code Helper")
DIAGRAM_FILE = Path(__file__).parent / "architecture.png" # or the path to your file on disk
@mcp.prompt()
def explain_component(component: str) -> list[Message]:
"""Explain one component using the architecture diagram."""
return [
UserMessage(Image(path=DIAGRAM_FILE)),
UserMessage(f"Where does {component} sit in this architecture, and what does it talk to?"),
]
Imageest l’utilitaire de Images, audio et icônes.UserMessagele convertit en blocImageContent(le fichier encodé en base64, le type MIME deviné d’après.png) au moment du rendu du prompt ;Audiodevient unAudioContentde la même façon.- Placez n’importe quel PNG nommé
architecture.pngà côté deserver.py. Les arguments d’un prompt sont des chaînes, l’image vient donc toujours du serveur ;componentne fournit que les mots.
{"type": "image", "data": "iVBORw0KGgoAAAANSUhEUg...", "mimeType": "image/png"}
Modifier la liste à l’exécution
Des prompts peuvent être ajoutés pendant que des clients sont connectés, par exemple pour permettre à un utilisateur d’enregistrer une instruction comme entrée de menu bien à lui. Enregistrez le prompt, puis notifiez :
from contextlib import suppress
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
from mcp.server.mcpserver.prompts import Prompt
mcp = MCPServer("Code Helper")
@mcp.prompt()
def review_code(code: str) -> str:
"""Review a piece of code."""
return f"Please review this code:\n\n{code}"
@mcp.tool()
async def save_template(name: str, instruction: str, ctx: Context) -> str:
"""Save an instruction as a prompt the user can pick from the menu."""
def template(code: str) -> str:
return f"{instruction}\n\n{code}"
with suppress(ValueError): # replace an existing entry of the same name
mcp.remove_prompt(name)
mcp.add_prompt(Prompt.from_function(template, name=name, description=instruction))
await ctx.notify_prompts_changed()
await ctx.session.send_prompt_list_changed()
return f"Saved '{name}' to the prompt menu."
mcp.add_prompt(Prompt.from_function(fn, name=..., description=...))enregistre une fonction exactement comme le ferait@mcp.prompt(), etmcp.remove_prompt(name)fait l’inverse.add_promptconserve une entrée existante du même nom au lieu de l’écraser ; l’outil supprime donc d’abord toute ancienne entrée pour que l’enregistrement soit un remplacement.prompts/listreflète le changement immédiatement.await ctx.notify_prompts_changed()envoienotifications/prompts/list_changedà chaque client2026-07-28à l’écoute sur un fluxsubscriptions/listen(Abonnements).await ctx.session.send_prompt_list_changed()l’envoie au client appelant lorsque celui-ci est antérieur à 2026 (Prendre en charge les clients historiques). Appelez les deux ; chacun ne fait rien quand il n’y a personne à prévenir.- Un client qui reçoit la notification appelle de nouveau
prompts/list. Dans leClientPython, c’estasync with client.listen(prompts_list_changed=True) as sub:, qui produit un événementPromptsListChanged.
Récapitulatif
@mcp.prompt()sur une fonction en fait un prompt. Le nom vient de la fonction, la description de la docstring.- Les prompts sont contrôlés par l’utilisateur : le client les liste, l’utilisateur en choisit un et renseigne les arguments.
- Les arguments forment une liste plate de chaînes nommées (pas de schéma). Un paramètre avec une valeur par défaut est facultatif.
- Renvoyez une
stret elle devient un seul message utilisateur. Renvoyez une liste deUserMessage/AssistantMessagepour amorcer une conversation à plusieurs tours. title=etField(description=...)sont ce qu’un client affiche dans son interface.- Un argument obligatoire manquant fait échouer toute la requête. Il n’y a pas de résultat d’erreur par prompt.
- Enveloppez un
EmbeddedResourceou uneImagedans unUserMessagepour joindre un document ou une image. - Ajoutez ou supprimez des prompts à l’exécution avec
mcp.add_prompt(...)/mcp.remove_prompt(...), puisawait ctx.notify_prompts_changed()etawait ctx.session.send_prompt_list_changed().
L’autocomplétion côté serveur des arguments d’un prompt (ou d’un modèle de ressource), c’est Complétions.