MCP ou function calling : différences avec les exemples OpenAI et Claude
MCP et function calling résolvent des problèmes différents. Le function calling permet à un modèle de demander une action, tandis que MCP donne aux applications un protocole commun pour trouver des outils. Cet article compare les deux avec des exemples de code OpenAI et Claude, une liste de contrôle de sécurité et une règle simple pour choisir.
Choisir la mauvaise couche vous obligera à reconstruire la même intégration deux fois. MCP vs function calling ressemble à un choix entre deux chemins, mais les deux se situent à des niveaux différents de la même pile. Le function calling est la manière dont un modèle demande une action. Le Model Context Protocol (MCP) est la manière dont une application trouve les outils sur lesquels cette action s’exécute, et les atteint.
La réponse courte, avant tout code : le function calling est une fonctionnalité du modèle, MCP est un protocole de communication, et la plupart des configurations MCP utilisent le function calling en coulisses. Avec deux ou trois outils dans une même application, le function calling classique est plus simple. Quand plusieurs applications ont besoin des mêmes outils, MCP se rentabilise rapidement. Les sections suivantes montrent côte à côte des exemples OpenAI et Claude pour les deux approches.
Ce que fait réellement le function calling
Un modèle de langage ne produit que du texte. Le function calling donne à ce texte une forme sur laquelle votre code peut compter. À chaque requête, vous envoyez une liste de définitions d’outils : un nom, une description en langage courant et un JSON Schema pour les arguments. Quand le modèle juge qu’un outil est nécessaire, il n’exécute rien. Il renvoie un appel structuré avec le nom de l’outil et ses arguments, et c’est votre code qui fait le travail.
La boucle requête-réponse
Votre application envoie le message de l’utilisateur accompagné des définitions d’outils.
Le modèle répond par un appel d’outil au lieu d’un texte final.
Votre code exécute la fonction et récupère le résultat.
Vous renvoyez le résultat sous la forme d’un nouveau message.
Le modèle rédige la réponse finale, ou demande un autre outil.
💡 Astuce : le modèle n’exécute jamais de code. Il propose un appel, et votre application décide de l’exécuter ou non. C’est précisément à cet endroit que doivent se placer les contrôles d’autorisation et la journalisation.
Où vit le schéma
Les définitions se trouvent dans votre propre base de code, en général à côté de la fonction qu’elles décrivent. OpenAI appelle le champ du schéma parameters. Claude l’appelle input_schema. L’enveloppe varie un peu d’un fournisseur à l’autre, donc un outil écrit pour l’un a besoin d’un petit adaptateur pour l’autre.
C’est là le vrai coût du function calling classique : chaque application conserve sa propre copie de chaque définition, et chaque fournisseur réclame sa propre variante. Si vous construisez la même recherche de commande pour une application de chat, un plugin d’IDE et un bot de support, vous maintenez trois copies.
Ce que MCP ajoute par-dessus
Anthropic a publié MCP en novembre 2024 en tant que protocole ouvert, et OpenAI l’a adopté en mars 2025. MCP standardise la manière dont les outils sont décrits, listés et appelés : un outil écrit une seule fois sous forme de serveur MCP fonctionne dans chaque client qui parle ce protocole. C’est le port standard de la photo ci-dessus : une seule forme de connecteur, de nombreux appareils. Au lieu de N applications multipliées par M outils de code d’intégration sur mesure, vous construisez N clients et M serveurs.
Hôtes, clients et serveurs
MCP repose sur trois rôles :
Hôte : l’application que voit l’utilisateur, comme une application de chat, un IDE ou votre propre agent.
Client : un connecteur à l’intérieur de l’hôte qui maintient une session avec un serveur.
Serveur : un petit programme qui expose des outils, des données et des prompts.
Les messages utilisent JSON-RPC 2.0. Les serveurs locaux communiquent via stdio, et les serveurs distants via Streamable HTTP. Le client ouvre une session, demande au serveur ce qu’il propose et appelle les éléments par leur nom.
Outils, ressources et prompts
Un serveur peut exposer trois types de capacités :
Primitive
Ce que c’est
Qui la contrôle
Outils
Actions ou calculs que le modèle peut appeler
Le modèle
Ressources
Données lisibles identifiées par une URI, comme un fichier ou un enregistrement
L’application
Prompts
Modèles de messages réutilisables
L’utilisateur
Seuls les outils se recoupent avec le function calling. Les ressources et les prompts n’ont pas de réponse standard dans le function calling classique, ce qui explique en partie pourquoi on se tourne vers MCP.
Voici le trafic réseau pour un seul outil. Le client demande au serveur ses outils :
Le serveur répond avec des définitions semblables à celles que vous écririez à la main, à ceci près que le champ du schéma s’appelle inputSchema en camelCase :
{"jsonrpc": "2.0", "id": 1, "result": {"tools": [{
"name": "get_order_status",
"description": "Look up the shipping status of an order by its ID.",
"inputSchema": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"]
}
}]}}
Plus tard, lorsque le modèle demande cet outil, le client envoie :
Un protocole ouvert entre applications et serveurs d’outils
Où vivent les définitions ?
Dans le code de votre application, envoyées à chaque requête
Sur le serveur, listées à la demande avec tools/list
Qui exécute l’outil ?
Le processus de votre application
Le serveur MCP, local ou distant
Réutilisation entre applications
Copier et adapter pour chaque application
Écrire une fois, connecter depuis n’importe quel client
A besoin de l’autre ?
Non
Oui, le modèle appelle toujours les outils via le function calling
Effort de mise en place
Quelques minutes
Quelques heures pour un premier serveur, quelques minutes pour un serveur existant
Idéal pour
Peu d’outils, logique propre à l’application
Outils partagés et intégrations tierces
Comment les appels MCP deviennent des appels de function calling
Les deux ne sont pas rivaux, car MCP alimente le function calling. Voici le parcours complet d’une requête dans une configuration MCP :
Le client MCP liste les outils de chaque serveur connecté.
Il les convertit au format d’outil propre au fournisseur et les envoie avec la requête.
Le modèle renvoie un appel de fonction ordinaire.
Le client MCP le transmet au bon serveur sous la forme tools/call.
Le résultat du serveur retourne au modèle comme un résultat d’outil classique.
Du point de vue du modèle, rien n’a changé. Il a vu des définitions d’outils et a émis un appel. Ce qui a changé, c’est qui a écrit les définitions et qui exécute la fonction.
💡 Règle empirique : si vous pouvez montrer la ligne de votre propre code qui exécute la fonction, vous faites du function calling classique. Si un serveur séparé l’exécute, vous faites du MCP, le function calling restant utilisé entre le modèle et le client.
Exemples de code OpenAI et Claude
Le même outil, quatre façons : une recherche de statut de commande. Les exemples utilisent Python, et l’URL du serveur MCP est un espace réservé que vous remplacerez par la vôtre.
Function calling OpenAI
Cette version utilise l’API Responses avec GPT 5. Vous définissez l’outil, exécutez vous-même la fonction et renvoyez un élément function_call_output.
import json
from openai import OpenAI
client = OpenAI()
def get_order_status(order_id: str) -> dict:
return {"order_id": order_id, "status": "shipped", "eta": "2026-10-09"}
tools = [{
"type": "function",
"name": "get_order_status",
"description": "Look up the shipping status of an order by its ID.",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
"additionalProperties": False,
},
"strict": True,
}]
input_items = [{"role": "user", "content": "Where is order 8841?"}]
response = client.responses.create(model="gpt-5", tools=tools, input=input_items)
input_items += response.output
for item in response.output:
if item.type == "function_call":
result = get_order_status(**json.loads(item.arguments))
input_items.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result),
})
final = client.responses.create(model="gpt-5", tools=tools, input=input_items)
print(final.output_text)
MCP distant avec OpenAI
Même question, sans schéma et sans boucle dans votre code. L’API se connecte au serveur, liste ses outils et les appelle à votre place.
response = client.responses.create(
model="gpt-5",
tools=[{
"type": "mcp",
"server_label": "orders",
"server_url": "https://mcp.example.com/mcp",
"require_approval": "always",
}],
input="Where is order 8841?",
)
print(response.output_text)
Avec require_approval défini sur "always", la réponse contient une demande d’approbation pour chaque appel, et votre code décide de l’autoriser ou non. Utilisez "never" uniquement pour les serveurs auxquels vous faites entièrement confiance.
Tool use avec Claude
L’API Messages suit la même boucle avec d’autres noms de champs. Le schéma va dans input_schema, le modèle signale un appel avec stop_reason == "tool_use", et vous répondez avec un bloc tool_result.
import json
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "get_order_status",
"description": "Look up the shipping status of an order by its ID.",
"input_schema": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
}]
messages = [{"role": "user", "content": "Where is order 8841?"}]
response = client.messages.create(
model="claude-sonnet-5-5", max_tokens=1024, tools=tools, messages=messages
)
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
results = []
for block in response.content:
if block.type == "tool_use":
output = get_order_status(**block.input)
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(output),
})
messages.append({"role": "user", "content": results})
response = client.messages.create(
model="claude-sonnet-5-5", max_tokens=1024, tools=tools, messages=messages
)
print(response.content[-1].text)
Envoyez tous les tool_result d’un même tour dans un seul message utilisateur. Les répartir sur plusieurs messages apprend au modèle à cesser d’appeler les outils en parallèle.
Connecteur MCP de Claude
Le connecteur MCP repose sur deux éléments : le serveur dans mcp_servers, et une entrée mcp_toolset correspondante dans tools. Il est aussi derrière un en-tête bêta, et il atteint les serveurs distants via HTTP, et non les serveurs locaux en stdio.
Comparez les quatre. Les versions MCP sont plus courtes, car le schéma et la boucle ont quitté votre code. Le compromis porte sur le contrôle : vous confiez la boucle à l’API et vous faites confiance à tout ce que le serveur affirme sur lui-même.
Pièges de sécurité et de coût à surveiller
Descriptions d’outils non fiables
Les noms, descriptions et résultats des outils alimentent tous le contexte du modèle. Un serveur négligent ou malveillant peut y cacher des instructions, ce qui ouvre une voie d’injection de prompt. Le function calling classique présente le même risque avec les résultats des outils, mais MCP l’élargit, car ce sont des tiers qui rédigent les descriptions.
Ne connectez que les serveurs de confiance, et figez les versions lorsque c’est possible.
Gardez une approbation humaine sur toute action qui écrit, envoie ou supprime.
Donnez à chaque serveur les identifiants les plus restreints qui fonctionnent encore.
Journalisez chaque appel avec ses arguments.
Coût en tokens des longues listes d’outils
Chaque définition est envoyée comme tokens d’entrée à chaque requête. Quarante outils aux descriptions longues peuvent ajouter des milliers de tokens avant que l’utilisateur n’ait écrit un mot. MCP rend cela facile à faire par inadvertance, car rattacher un serveur importe d’un coup tous ses outils.
Trois solutions fonctionnent bien :
Ne rattachez que les serveurs dont une tâche donnée a besoin.
Raccourcissez les descriptions à ce que le modèle doit savoir pour choisir l’outil.
Chargez les définitions à la demande, par exemple avec l’outil de recherche d’outils de Claude, et gardez la partie stable de la liste dans le cache.
💡 Erreurs courantes : rattacher chaque serveur à chaque requête, approuver automatiquement les actions d’écriture et négliger les journaux d’appels. Chacune coûte peu à éviter dès le premier jour, et cher à corriger après un incident.
Quand choisir l’un ou l’autre
Choisissez le function calling quand
Vous avez une poignée d’outils utilisés par une seule application.
Les outils ont besoin d’un accès en processus à votre propre état, comme une session de base de données ou l’utilisateur connecté.
Vous voulez un contrôle total sur la latence, les nouvelles tentatives et les écrans d’approbation.
Vous prototypez et voulez le moins de pièces mobiles possible.
Choisissez MCP quand
Plusieurs clients ont besoin des mêmes outils : une application de chat, un IDE et un agent.
Un tiers fournit déjà un serveur MCP pour le service dont vous avez besoin.
Des équipes différentes gèrent les outils et les applications, et elles ne doivent pas se bloquer mutuellement.
Vous voulez changer de fournisseur de modèle sans réécrire le code d’intégration des outils.
La plupart des piles en production finissent par être mixtes. La logique privée reste sous forme d’outils de function calling en processus, et les capacités partagées ou tierces arrivent par des serveurs MCP. Les deux atteignent le modèle via la même interface de function calling, donc les combiner ne coûte presque rien.
Un vrai serveur MCP : PicassoIA
PicassoIA expose sa génération d’images et de vidéos via un connecteur MCP, ce qui en fait un exemple pratique des choix de conception évoqués plus haut. La génération prend du temps, donc les outils se répartissent entre ceux qui lancent une tâche et une vérification de statut. C’est la même structure que vous construiriez à la main avec deux définitions de fonctions.
Ce que le connecteur expose
Outil
Ce qu’il fait
generate_image
Lance une tâche de génération d’image et renvoie un ID de prédiction
edit_image
Lance une modification d’une image existante
generate_video_picassoia
Lance une tâche vidéo avec le modèle vidéo de PicassoIA
generate_video_seedance
Lance une tâche vidéo avec Seedance
get_generation
Interroge une prédiction jusqu’à ce qu’elle réussisse ou échoue
list_generations
Liste les générations passées
cancel_generation
Annule une tâche encore en file d’attente ou en cours
list_models
Affiche les modèles auxquels votre compte peut accéder
get_account
Affiche votre forfait et vos limites de traitements parallèles
Cette approche vaut la peine d’être reprise dans vos propres serveurs : renvoyer un ID rapidement, interroger le statut avec un outil séparé, et donner au modèle un outil d’annulation pour qu’il puisse interrompre une mauvaise exécution. La documentation pour développeurs indique 5 prédictions simultanées par compte, partagées entre les identifiants d’API et les connexions MCP. Un client bien conçu interroge donc le statut au lieu de tout lancer d’un coup. Les mêmes tâches sont aussi accessibles via une API REST de type Replicate à https://api.picassoia.com/v1. Consultez la page des tarifs pour savoir quels forfaits incluent l’accès à l’API et à MCP.
Comment utiliser Claude Sonnet 5 sur PicassoIA
Avant de brancher le code, vous pouvez rédiger des schémas d’outils et tester des prompts sur la page Claude Sonnet 5. La page du modèle expose ces champs :
Prompt : saisissez la demande, par exemple : « Écrivez un JSON Schema pour un outil nommé get_order_status qui prend un ID de commande et renvoie le statut de livraison. »
Prompt système (facultatif) : définissez un rôle une fois, comme « Vous êtes un concepteur d’API. Répondez uniquement en JSON. »
Effort : la valeur par défaut est low, ce qui désactive la réflexion pour des réponses plus rapides et moins chères. Passez à high ou max pour un bug complexe réparti sur plusieurs fichiers ou une conception avec de nombreux outils. Les niveaux sont low, medium, high, xhigh et max.
Tokens maximum : la valeur par défaut est 8192, suffisante pour un schéma complet accompagné d’une explication.
Image (facultatif) : joignez une capture d’écran d’erreur ou une maquette comme contexte supplémentaire.
Exécuter et comparer : envoyez le même prompt à GPT 5 et voyez quel schéma est le plus propre.
💡 Astuce : demandez d’abord le schéma, puis demandez au modèle de critiquer sa propre description. Des descriptions courtes et précises facilitent un choix correct de l’outil.
Créez vos propres images avec Picasso IA
Chaque photo de cet article est née d’un prompt textuel : un panneau perforé, un standard téléphonique, un meuble de fiches, un embranchement de sentier. Chacune transforme une idée abstraite en quelque chose que vous pouvez voir, et la même recette fonctionne pour vos propres publications, documentations et présentations.
Utilisez cette structure : sujet et action, environnement, éclairage, caméra et objectif, détails de texture. Par exemple : « Gros plan d’une main branchant un câble sur un ordinateur portable posé sur un bureau en chêne, lumière douce de fenêtre venant de la droite, objectif macro 100 mm, faible profondeur de champ, texture d’aluminium brossé. »
Ouvrez Picasso IA, choisissez un modèle texte vers image dans la liste complète des modèles, collez un prompt de cette forme et lancez-le. Modifiez un seul détail à la fois, comme l’objectif ou la direction de la lumière, et observez comment le résultat change. Si vous travaillez déjà avec Claude, connectez le connecteur MCP de PicassoIA depuis votre compte et demandez des images directement depuis le chat. Essayez trois variations d’une même idée aujourd’hui et gardez la meilleure.