Vous pouvez associer des outils à une session Realtime pour permettre au modèle de consulter des données, d’effectuer des actions ou d’appeler des services pendant une conversation en direct. La configuration des outils repose sur la même interface événementielle, que votre client utilise un canal de données WebRTC ou une connexion WebSocket.
Utilisez des outils de type fonction lorsque votre application doit exécuter l’outil et renvoyer le résultat. Utilisez des outils MCP lorsque Realtime API doit se connecter à un serveur d’outils distant pour vous.
Choisissez un type d’outil
| Type d’outil | Cas d’utilisation | Qui l’exécute |
|---|---|---|
function | Votre application gère la logique métier, les vérifications d’approbation ou l’accès aux systèmes privés. | Votre client ou serveur reçoit un appel de fonction et renvoie function_call_output. |
mcp avec server_url | Vous souhaitez que le modèle appelle des outils exposés par un serveur MCP distant. | Realtime API appelle le serveur MCP distant. |
mcp avec connector_id | Vous utilisez un ancien connecteur intégré avec un modèle existant. | Realtime API appelle le connecteur avec l’autorisation que vous fournissez. |
Ajoutez des outils à l’un des deux niveaux suivants :
- Au niveau de la session , avec
session.toolsdanssession.update, si vous souhaitez que l’outil soit disponible pendant toute la session. - Au niveau de la réponse , avec
response.toolsdansresponse.create, si vous n’avez besoin de l’outil que pour un seul tour.
Configurez un outil de type fonction
Les outils de type fonction sont le choix à privilégier lorsque l’outil doit s’exécuter dans votre application. Le modèle émet les arguments de l’appel de fonction, votre code exécute l’action, puis renvoie le résultat dans un élément function_call_output.
const event = {
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1",
tools: [
{
type: "function",
name: "lookup_order",
description: "Look up an order by its order number.",
parameters: {
type: "object",
properties: {
order_number: {
type: "string",
description: "The customer-facing order number.",
},
},
required: ["order_number"],
},
},
],
tool_choice: "auto",
},
};
ws.send(JSON.stringify(event));Lorsque le modèle appelle la fonction, écoutez l’arrivée de l’élément d’appel de fonction, exécutez la logique de votre application, puis renvoyez le résultat :
const event = {
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: functionCall.call_id,
output: JSON.stringify({
status: "shipped",
delivery_date: "2026-05-09",
}),
},
};
ws.send(JSON.stringify(event));
ws.send(JSON.stringify({ type: "response.create" }));Pour une présentation complète de l’appel de fonction, événement par événement, consultez Gestion des conversations.
Configurez un outil MCP
Les outils MCP sont utiles lorsque l’outil est déjà accessible via un serveur MCP distant, ou lorsqu’un modèle existant utilise un ancien connecteur intégré. Contrairement aux outils de type fonction, les outils MCP sont exécutés par Realtime API elle-même.
Dans Realtime, un outil MCP a la structure suivante :
type: "mcp"server_label- L’un des deux champs :
server_urlouconnector_id authorizationetheadersfacultatifsallowed_toolsfacultatifrequire_approvalfacultatifserver_descriptionfacultatif
Cet exemple rend un serveur MCP de documentation disponible pendant toute la session :
const event = {
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1",
output_modalities: ["text"],
tools: [
{
type: "mcp",
server_label: "openai_docs",
server_url: "https://developers.openai.com/mcp",
allowed_tools: ["search_openai_docs", "fetch_openai_doc"],
require_approval: "never",
},
],
},
};
ws.send(JSON.stringify(event));Anciens connecteurs
connector_id est déprécié pour les modèles publiés après le 1er septembre
2026. Utilisez server_url pour vous connecter à un serveur MCP distant, ou
tunnel_id pour vous connecter à un serveur MCP local via le
Tunnel MCP sécurisé. Les modèles
existants continuent de prendre en charge les connecteurs. L’exemple ci-dessous utilise
gpt-realtime-1.5, publié avant cette date limite.
Les connecteurs intégrés utilisent la même structure d’outil MCP, mais transmettent connector_id
à la place de server_url. Par exemple, Google Calendar utilise
connector_googlecalendar. Dans Realtime, utilisez ces connecteurs intégrés pour des opérations
de lecture, telles que la recherche ou la lecture d’événements ou d’e-mails. Transmettez le token d’accès OAuth de l’utilisateur
dans authorization et limitez les outils accessibles avec
allowed_tools lorsque c’est possible :
const event = {
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-1.5",
output_modalities: ["text"],
tools: [
{
type: "mcp",
server_label: "google_calendar",
connector_id: "connector_googlecalendar",
authorization: "<google-oauth-access-token>",
allowed_tools: ["search_events", "read_event"],
require_approval: "never",
},
],
},
};
ws.send(JSON.stringify(event));Les serveurs MCP distants
ne reçoivent pas automatiquement tout le contexte de la conversation,
mais ils peuvent voir toutes les données que le modèle transmet dans un appel d’outil.
Limitez les outils accessibles avec allowed_tools,
et exigez une approbation pour toute action que vous n’exécuteriez pas automatiquement.
Déroulement des appels MCP dans Realtime
Contrairement aux outils function de Realtime, les outils MCP distants sont exécutés directement par Realtime API. Votre client n’exécute pas l’outil distant et ne renvoie pas de function_call_output. Il configure l’accès, écoute les événements du cycle de vie MCP et envoie, le cas échéant, une réponse d’approbation si le serveur en demande une.
Voici un déroulement typique :
- Vous envoyez
session.updateouresponse.createavec une entrée danstoolsdont le champtypevautmcp. - Le serveur commence à importer les outils et émet
mcp_list_tools.in_progress. - Tant que la récupération de la liste est en cours, le modèle ne peut pas appeler un outil qui n’a pas encore été chargé. Si vous souhaitez attendre avant de démarrer un tour qui dépend de ces outils, écoutez l’événement
mcp_list_tools.completed. L’événementconversation.item.donedont le champitem.typevautmcp_list_toolsindique les noms des outils effectivement importés. Si l’importation échoue, vous recevezmcp_list_tools.failed. - L’utilisateur parle ou envoie du texte, et une réponse est créée, soit par votre client, soit automatiquement selon la configuration de la session.
- Si le modèle choisit un outil MCP, vous recevez
response.mcp_call_arguments.deltaetresponse.mcp_call_arguments.done. - Si une approbation est requise, le serveur ajoute un élément à la conversation dont le champ
item.typevautmcp_approval_request. Votre client doit y répondre avec un élémentmcp_approval_response. - Lorsque l’outil s’exécute, vous recevez
response.mcp_call.in_progress. En cas de réussite, vous recevez ensuite un événementresponse.output_item.donedont le champitem.typevautmcp_call; en cas d’échec, vous recevezresponse.mcp_call.failed. - L’événement
response.doned’une réponse peut arriver avant la fin de ses appels MCP. Une fois la réponse terminée et tous ses appels MCP achevés, envoyez un nouvel événementresponse.createpour permettre au modèle d’utiliser les résultats et de poursuivre la conversation. Répétez cette étape si le modèle effectue d’autres appels MCP. Realtime API ne crée pas automatiquement ces réponses de suivi.
Ce gestionnaire d’événements journalise les principaux événements du cycle de vie MCP ; il ne gère pas les réponses de suivi :
function parseRealtimeEvent(rawMessage) {
if (typeof rawMessage === "string") {
return JSON.parse(rawMessage);
}
if (typeof rawMessage?.data === "string") {
return JSON.parse(rawMessage.data);
}
return JSON.parse(rawMessage.toString());
}
function getOutputText(item) {
if (item.type !== "message") return "";
return (item.content ?? [])
.filter((part) => part.type === "output_text")
.map((part) => part.text)
.join("");
}
ws.on("message", (rawMessage) => {
const event = parseRealtimeEvent(rawMessage);
switch (event.type) {
case "mcp_list_tools.in_progress":
console.log("Listing MCP tools for item:", event.item_id);
break;
case "mcp_list_tools.completed":
console.log("MCP tool listing complete for item:", event.item_id);
break;
case "mcp_list_tools.failed":
console.error("MCP tool listing failed for item:", event.item_id);
break;
case "conversation.item.done":
if (event.item.type === "mcp_list_tools") {
const names = event.item.tools.map((tool) => tool.name).join(", ");
console.log(`MCP tools ready on ${event.item.server_label}: ${names}`);
}
if (event.item.type === "mcp_approval_request") {
console.log(
"Approval required for:",
event.item.name,
event.item.arguments
);
}
break;
case "response.mcp_call_arguments.done":
console.log("Final MCP call arguments:", event.arguments);
break;
case "response.mcp_call.in_progress":
console.log("Running MCP tool for item:", event.item_id);
break;
case "response.mcp_call.failed":
console.error("MCP tool call failed for item:", event.item_id);
break;
case "response.output_item.done":
if (event.item.type === "mcp_call") {
console.log(
`MCP output from ${event.item.server_label}.${event.item.name}:`,
event.item.output
);
}
if (event.item.type === "message") {
console.log("Assistant:", getOutputText(event.item));
}
break;
case "response.done":
console.log("Realtime turn complete.");
break;
}
});Échecs courants
mcp_list_tools.failed: Realtime API n’a pas pu importer les outils du serveur distant ou du connecteur. Vérifiezserver_urlouconnector_id, l’authentification, la connectivité du serveur et les noms éventuellement spécifiés dansallowed_tools.response.mcp_call.failed: le modèle a sélectionné un outil, mais l’appel à cet outil n’a pas abouti. Examinez les données de l’événement et l’élémentmcp_callreçu ensuite pour détecter d’éventuelles erreurs de protocole MCP, d’exécution ou de transport.mcp_approval_requestsansmcp_approval_responsecorrespondant : l’appel à l’outil ne peut pas se poursuivre tant que votre client ne l’a pas explicitement approuvé ou rejeté.- Un tour commence alors que
mcp_list_tools.in_progressest encore actif : seuls les outils dont le chargement est déjà terminé peuvent être utilisés pendant ce tour. - Une réponse utilise
tool_choice: "required", mais aucun outil n’est disponible pour le moment : le modèle n’a aucun outil à appeler. Attendezmcp_list_tools.completed, vérifiez qu’au moins un outil a été importé ou utilisez une autre valeur detool_choicepour les tours qui ne nécessitent pas d’outil. - La validation de la définition d’un outil MCP échoue avant le début de l’importation. Les causes fréquentes sont les suivantes : un
server_labelen double dans le même tableautools, la présence simultanée deserver_urlet deconnector_id, l’absence de ces deux paramètres dans la requête initiale de création de session, une valeurconnector_idnon valide ou l’envoi simultané deauthorizationet deheaders.Authorization. Pour les connecteurs, n’envoyez jamaisheaders.Authorization.
Approuvez ou rejetez les appels aux outils MCP
Si un outil nécessite une approbation, la Realtime API insère un élément mcp_approval_request dans la conversation. Pour continuer, envoyez un nouvel événement conversation.item.create dont le champ item.type vaut mcp_approval_response.
function approveMcpRequest(approvalRequestId) {
const event = {
type: "conversation.item.create",
item: {
id: `mcp_approval_${approvalRequestId}`,
type: "mcp_approval_response",
approval_request_id: approvalRequestId,
approve: true,
},
};
ws.send(JSON.stringify(event));
}Si vous rejetez la demande, définissez approve sur false et, si vous le souhaitez, indiquez un motif dans reason.
Utilisez MCP pour une seule réponse
Si MCP doit être disponible pour un seul tour, ajoutez le même objet d’outil MCP à response.tools au lieu de session.tools :
const event = {
type: "response.create",
response: {
output_modalities: ["text"],
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Which transport should I use for browser clients in the Realtime API?",
},
],
},
],
tools: [
{
type: "mcp",
server_label: "openai_docs",
server_url: "https://developers.openai.com/mcp",
allowed_tools: ["search_openai_docs", "fetch_openai_doc"],
require_approval: "never",
},
],
},
};
ws.send(JSON.stringify(event));Cette approche est utile lorsqu’une seule réponse nécessite un contexte externe ou lorsque différents tours doivent utiliser différents serveurs MCP.
Réutilisez un libellé de serveur déjà défini
server_label est l’identifiant stable d’une définition d’outil dans la session
Realtime en cours. Une fois que vous avez défini un serveur ou un connecteur avec
server_label et server_url ou connector_id, les événements session.update ou
response.create suivants peuvent simplement faire référence à ce même server_label. La
Realtime API réutilise alors la définition précédente, sans que vous ayez à renvoyer
l’objet d’outil complet.
const event = {
type: "response.create",
response: {
output_modalities: ["text"],
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Check my schedule for this afternoon.",
},
],
},
],
// Reuses the google_calendar connector defined earlier in this session.
tools: [
{
type: "mcp",
server_label: "google_calendar",
},
],
},
};
ws.send(JSON.stringify(event));Cette réutilisation se limite à la session en cours. Si vous démarrez une nouvelle session Realtime, renvoyez la définition MCP complète afin que le serveur puisse importer sa liste d’outils.