Ollama MCP Server : comment connecter des modèles locaux grâce à un pont

Construisez un pont Ollama MCP Server dans les deux sens : un client Python qui permet aux modèles locaux d’appeler des outils MCP, et un serveur qui expose Ollama à Claude Desktop et Claude Code. Dimensionnement matériel, code fonctionnel, fichiers de configuration et correctifs des trois bugs qui font échouer la plupart des premiers essais.

Ollama MCP Server : comment connecter des modèles locaux grâce à un pont
Cristian Da Conceicao
Fondateur de Picasso IA

Votre ordinateur portable peut déjà faire tourner un modèle de langage performant, mais la plupart de vos outils ignorent qu’il existe. Une configuration Ollama MCP Server règle ce problème. Un petit pont se place entre Ollama, qui sert les modèles à localhost:11434, et le Model Context Protocol (MCP), le standard que les applications d’IA utilisent pour trouver et appeler des outils. Une fois en place, un modèle local peut lire vos fichiers, interroger une base de données ou rechercher dans vos notes. Dans l’autre sens, Claude Desktop ou Claude Code peuvent confier des tâches peu coûteuses et privées au GPU posé sous votre bureau.

Cet article construit les deux sens avec du code Python fonctionnel : un client de pont qui permet aux modèles Ollama d’utiliser n’importe quel serveur MCP, et un serveur de pont qui expose Ollama comme un ensemble d’outils à n’importe quel client MCP. Vous trouverez aussi des chiffres de mémoire, des fichiers de configuration et les trois bugs qui vous font perdre le plus de temps au débogage.

Ce que fait un pont Ollama MCP

Ollama et MCP résolvent deux moitiés différentes d’un même problème. Ollama télécharge des modèles à poids ouverts et les sert via une API HTTP simple. MCP, publié fin 2024 par Anthropic, standardise la manière dont une application d’IA communique avec des outils, des fichiers et des données, par l’intermédiaire de petits programmes appelés serveurs. L’API d’Ollama parle en messages de chat et en définitions d’outils. Elle ne parle pas MCP, et les clients MCP ignorent où vivent vos modèles. Le pont fait la traduction entre les deux.

Vue en contre-plongée d’un pont en pierre recouvert de mousse traversant une rivière brumeuse à l’aube

Deux façons de construire un pont

« Pont » désigne deux programmes différents selon ce dont on a besoin, donc choisissez le sens avant d’écrire le moindre code.

DirectionClient MCPServeur MCPUsage typique
Ollama utilise des outilsVotre script de pont, qui encapsule un modèle OllamaServeur de fichiers, de base de données ou de rechercheUn assistant local qui lit vos notes
Ollama comme outilClaude Desktop, Claude Code, CursorVotre script de pont, qui encapsule OllamaConfier des tâches privées ou peu coûteuses à un modèle local

Le premier sens donne des mains à un modèle local. Le second donne à un assistant cloud un collègue local. La plupart des gens finissent par construire les deux, car le second ne demande qu’environ 30 lignes.

Une remarque rapide sur le transport. Les exemples utilisent stdio, où le client lance le serveur comme processus enfant et communique avec lui via l’entrée et la sortie standard. C’est l’option la plus simple pour une machine personnelle. Si vous voulez un seul pont partagé par plusieurs applications ou plusieurs ordinateurs de votre réseau, lancez-le plutôt avec le transport Streamable HTTP et gardez-le derrière votre propre pare-feu. Le code des outils reste le même, seule la dernière ligne du serveur change.

Le trajet d’un appel d’outil

Quelle que soit la direction choisie, un appel d’outil suit toujours la même boucle :

  1. Le pont se connecte à un serveur MCP et demande la liste de ses outils avec tools/list.
  2. Il réécrit chaque schéma d’outil au format attendu par Ollama.
  3. Il envoie la question de l’utilisateur et ces définitions d’outils à un modèle local.
  4. Le modèle répond par une entrée tool_calls au lieu d’un texte.
  5. Le pont exécute cet appel sur le serveur MCP avec tools/call.
  6. Le résultat est renvoyé au modèle sous forme de message tool.
  7. Les étapes 3 à 6 se répètent jusqu’à ce que le modèle réponde par un texte simple.

💡 Le modèle ne touche jamais à votre disque. Il se contente de demander une action. Votre pont décide de l’exécuter ou non, ce qui en fait l’endroit idéal pour les listes d’autorisation, les demandes de confirmation et la journalisation.

Ce qu’il vous faut d’abord

Un matériel adapté

Gros plan extrême d’une carte graphique équipée de deux ventilateurs noirs, installée dans un boîtier d’ordinateur ouvert

Les poids du modèle doivent tenir dans la mémoire du GPU (ou la mémoire unifiée d’un Mac), avec de la marge pour le contexte. Ces valeurs sont approximatives, pour des versions quantifiées sur 4 bits :

Taille du modèleMémoire pour les poidsConfiguration confortable
3B à 4B2 à 3 GoN’importe quel ordinateur portable récent
7B à 8B5 à 6 GoGPU de 8 Go ou 16 Go de mémoire unifiée
14B9 à 10 GoGPU de 12 Go
20B13 à 15 GoGPU de 16 Go ou 24 Go de mémoire unifiée
32B19 à 21 GoGPU de 24 Go

Les modèles qui débordent dans la RAM système fonctionnent toujours, mais la vitesse en tokens chute fortement. Un pont fait plusieurs appels au modèle par question, donc la vitesse compte plus que la taille. Un modèle 8B qui tient entièrement sur le GPU bat généralement un modèle 32B qui n’y tient pas.

Les modèles qui prennent en charge les appels d’outils

Tous les modèles ne peuvent pas demander un outil. Ollama vérifie le template de chat du modèle, et un modèle sans prise en charge des outils renvoie une erreur lorsque vous transmettez tools. Filtrez la bibliothèque Ollama par le tag tools, ou partez de cette liste restreinte :

Tag OllamaTaille sur le disquePourquoi l’utiliser
llama3.1:8benviron 4,9 GoChoix par défaut fiable pour les premiers tests
qwen3:8benviron 5,2 GoSolide pour l’usage d’outils en plusieurs étapes, plus lent quand la réflexion est activée
mistral-nemoenviron 7,1 GoLong contexte, gère de nombreux outils
gpt-oss:20benviron 14 GoLe GPT OSS 20B à poids ouverts, pensé pour l’usage d’outils

Installer les éléments

Activez d’abord un environnement virtuel (source .venv/bin/activate sur macOS et Linux, .venv\Scripts\activate sous Windows), puis lancez :

# 1. Pull a tool-capable model and confirm Ollama is serving
ollama pull llama3.1:8b
curl http://localhost:11434/api/tags

# 2. Install the two Python packages the bridge needs
pip install ollama mcp

# 3. Check Node, because the example MCP server runs through npx
node --version

Si curl renvoie une liste JSON de vos modèles, Ollama est prêt. Si la connexion est refusée, démarrez-le avec ollama serve.

Construire le client de pont en Python

Le client tient dans un seul fichier. Il lance un serveur MCP comme processus enfant via le transport stdio, lit ses outils et exécute la boucle de la section précédente. Le serveur d’exemple est le serveur de fichiers officiel, pointé vers un dossier de notes.

Convertir les outils MCP au format Ollama

Un outil MCP porte un name, une description et un inputSchema écrits en JSON Schema. Le format d’appel de fonctions d’Ollama attend les mêmes trois éléments, enveloppés dans un objet function. La conversion consiste surtout en un renommage :

def to_ollama_tool(tool):
    return {
        "type": "function",
        "function": {
            "name": tool.name,
            "description": tool.description or "",
            "parameters": tool.inputSchema,
        },
    }

La plupart des schémas passent sans modification. Si un serveur livre des constructions inhabituelles comme anyOf ou $ref, aplatissez-les avant l’envoi. Les petits modèles gèrent bien mieux les schémas plats.

Écrire la boucle d’appel d’outils

import asyncio

import ollama
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

MODEL = "llama3.1:8b"
NOTES_DIR = "/home/me/notes"
MAX_TURNS = 8

server_params = StdioServerParameters(
    command="npx",
    args=["-y", "@modelcontextprotocol/server-filesystem", NOTES_DIR],
)


def to_ollama_tool(tool):
    return {
        "type": "function",
        "function": {
            "name": tool.name,
            "description": tool.description or "",
            "parameters": tool.inputSchema,
        },
    }


async def ask(question: str) -> str:
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            listed = await session.list_tools()
            tools = [to_ollama_tool(t) for t in listed.tools]

            client = ollama.AsyncClient()
            messages = [{"role": "user", "content": question}]

            for _ in range(MAX_TURNS):
                response = await client.chat(model=MODEL, messages=messages, tools=tools)
                message = response.message
                messages.append(message)

                if not message.tool_calls:
                    return message.content

                for call in message.tool_calls:
                    result = await session.call_tool(
                        call.function.name, dict(call.function.arguments)
                    )
                    text = "\n".join(
                        block.text for block in result.content if block.type == "text"
                    )
                    messages.append(
                        {"role": "tool", "tool_name": call.function.name, "content": text}
                    )

            return "Stopped: the model kept calling tools."


if __name__ == "__main__":
    print(asyncio.run(ask("Which markdown files in my notes folder mention invoices?")))

Quatre points méritent attention :

  • MAX_TURNS est un garde-fou. Un modèle confus peut appeler le même outil indéfiniment, et un compteur transforme cela en échec clair.
  • dict(call.function.arguments) est important, car Ollama renvoie les arguments sous forme de mapping, alors que la session MCP attend un dictionnaire simple.
  • Blocs de texte uniquement. Les résultats MCP peuvent inclure des images et des ressources intégrées. Cette version conserve le texte et ignore le reste.
  • tool_name sur le message d’outil indique au modèle à quel appel le résultat appartient, ce qui évite de mélanger les appels parallèles.

Exécuter le tout sur de vrais fichiers

Vue par-dessus l’épaule d’un développeur tapant sur un ordinateur portable à une table de café ensoleillée

Enregistrez le fichier sous bridge_client.py, remplacez NOTES_DIR par un vrai dossier, puis lancez python bridge_client.py. Une exécution réussie fait d’abord un appel de listage de répertoire ou de recherche, puis une ou deux lectures de fichiers, et enfin répond en texte simple. Pour observer le modèle choisir ses outils, ajoutez print(call.function.name, call.function.arguments) en haut de la boucle interne.

💡 Astuce Windows : si Python ne parvient pas à lancer npx, utilisez npx.cmd comme commande. L’option -y permet à npx d’installer le serveur de fichiers au premier lancement, sans demander de confirmation.

Avant de pointer le pont vers quoi que ce soit de sensible, décidez de ce que le modèle peut faire. Le serveur de fichiers n’atteint que les dossiers passés sur sa ligne de commande, donc donnez-lui un dossier de notes plutôt que votre répertoire personnel. Pour les outils qui écrivent, suppriment ou envoient des données, ajoutez une étape de confirmation dans la boucle : affichez l’appel et demandez un oui avant que session.call_tool ne s’exécute. Trente secondes de friction valent mieux qu’un modèle 8B qui juge qu’un nettoyage est une bonne idée.

Exposer Ollama comme serveur MCP

Inversons maintenant le sens. Au lieu qu’un modèle local utilise les outils d’autres personnes, vous publiez le modèle local comme un outil. Tout client MCP peut alors l’appeler pour rédiger, résumer ou classer des textes qui ne doivent jamais quitter votre machine.

Vue de dessus d’un petit mini-PC argenté, d’un routeur et de croquis dans un carnet posés sur un bureau en chêne

Un petit serveur en Python

Le SDK Python officiel inclut FastMCP, qui construit le schéma de l’outil à partir de vos annotations de type et la description à partir de votre docstring :

import sys

import ollama
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("ollama-bridge")
client = ollama.AsyncClient()
DEFAULT_MODEL = "llama3.1:8b"


@mcp.tool()
async def list_local_models() -> list[str]:
    """List the models installed in the local Ollama instance."""
    listed = await client.list()
    return [m.model for m in listed.models]


@mcp.tool()
async def ask_local_model(
    prompt: str, model: str = DEFAULT_MODEL, temperature: float = 0.2
) -> str:
    """Send a prompt to a local Ollama model and return its reply.
    Use it for private text or cheap drafts that should stay on this machine."""
    print(f"ask_local_model: {model}", file=sys.stderr)
    response = await client.chat(
        model=model,
        messages=[{"role": "user", "content": prompt}],
        options={"temperature": temperature},
    )
    return response.message.content


if __name__ == "__main__":
    mcp.run(transport="stdio")

Rédigez la docstring pour l’appelant, et non pour vous-même. Le modèle client la lit pour décider quand votre outil vaut la peine d’être appelé, donc « à utiliser pour du texte privé » fait un vrai travail.

Connecter le serveur à Claude Desktop

Ouvrez claude_desktop_config.json. Sous Windows, il se trouve dans %APPDATA%\Claude, et sous macOS dans ~/Library/Application Support/Claude. Ajoutez le serveur sous mcpServers :

{
  "mcpServers": {
    "ollama-bridge": {
      "command": "C:\\tools\\ollama-bridge\\.venv\\Scripts\\python.exe",
      "args": ["C:\\tools\\ollama-bridge\\ollama_bridge.py"],
      "env": { "OLLAMA_HOST": "http://127.0.0.1:11434" }
    }
  }
}

Faites pointer command vers le Python de l’environnement virtuel, et non vers celui du système. Claude Desktop n’active pas votre environnement, et un interpréteur système sans le paquet mcp échoue silencieusement. Quittez puis rouvrez l’application : les deux outils apparaissent dans le menu des outils.

Connecter le serveur à Claude Code

Claude Code enregistre les serveurs depuis le terminal :

claude mcp add ollama-bridge -- /path/to/.venv/bin/python /path/to/ollama_bridge.py
claude mcp list

Tout ce qui suit le double tiret est la commande de lancement. Une fois que claude mcp list affiche le serveur comme connecté, demandez à Claude Code de « résumer ce journal avec le modèle local » et observez-le appeler ask_local_model.

Corriger les problèmes que vous rencontrerez

Gros plan de la main d’un technicien branchant un connecteur dans un panneau de brassage réseau rempli de câbles colorés

Trois problèmes expliquent la plupart des premiers essais ratés. Chacun a une solution rapide.

Stdout casse les serveurs stdio

Un serveur MCP stdio envoie ses messages JSON-RPC via stdout. Un print() égaré injecte du texte dans ce flux, et le client coupe la connexion ou signale une erreur d’analyse. Le symptôme : un serveur qui se connecte puis se déconnecte en moins d’une seconde.

La solution tient en une habitude : écrivez les journaux sur stderr (print(..., file=sys.stderr)) ou dans un fichier, et n’écrivez jamais rien d’autre sur stdout. Cela inclut les barres de progression et les avertissements affichés par les bibliothèques importées.

Les petits modèles ignorent les outils

Un modèle 8B à qui l’on donne 25 outils répond souvent à partir de sa mémoire ou appelle le mauvais. Quatre changements aident, à peu près par ordre d’impact :

  • Envoyez moins d’outils. Filtrez la liste pour ne garder que les trois à six qui correspondent à la question.
  • Réécrivez les descriptions. « Lire le contenu d’un fichier à partir de son chemin absolu » vaut mieux que « Lecteur de fichiers ».
  • Baissez la température à 0,1 ou 0,2 pour la sélection d’outils.
  • Passez à une taille supérieure. Passer de 3B à 8B corrige plus d’échecs d’appel d’outils que n’importe quelle astuce de prompt.

Les fenêtres de contexte se remplissent vite

Les définitions d’outils et les résultats consomment tous deux du contexte, et une seule lecture de gros fichier peut repousser la question hors de la fenêtre. Le contexte par défaut d’Ollama est petit, donc augmentez-le explicitement et réduisez les résultats avant qu’ils n’atteignent le modèle :

response = await client.chat(
    model=MODEL,
    messages=messages,
    tools=tools,
    options={"num_ctx": 8192},
)

text = text[:4000]  # trim large tool results before appending them

Des valeurs plus élevées de num_ctx consomment davantage de mémoire pour le cache d’attention, augmentez-les donc par paliers. Réglez aussi OLLAMA_KEEP_ALIVE sur une valeur plus longue, comme 30m. Par défaut, Ollama décharge les modèles inactifs après cinq minutes, et chaque rechargement ajoute quelques secondes à la première réponse.

Modèles locaux ou modèles hébergés

Vue en contre-plongée large d’un long couloir bordé de baies de serveurs noires dans un centre de données

Un pont n’impose pas de choix. Il vous permet d’envoyer chaque tâche vers l’endroit le moins coûteux capable de la faire correctement.

Les modèles locaux l’emportent quand :

  • le texte est privé, comme des contrats, des notes de santé ou du code source sous accord de confidentialité (NDA)
  • la tâche se répète des milliers de fois, si bien que la tarification au token s’additionne
  • vous travaillez hors ligne ou sur un réseau que vous ne contrôlez pas

Les modèles hébergés l’emportent quand :

  • votre GPU dispose de moins de 8 Go de mémoire
  • la tâche nécessite un modèle au-delà de 30 milliards de paramètres
  • vous avez besoin d’une réponse en quelques secondes lors d’un démarrage à froid

En pratique, un système hybride fonctionne le mieux. Confiez au modèle local les premiers jets, la classification et tout ce qui touche aux fichiers privés, puis transmettez les 10 % de cas difficiles à un grand modèle hébergé. Comme les deux sont derrière la même interface MCP, votre assistant peut choisir entre ask_local_model et une alternative hébergée avec rien de plus qu’une description d’outil plus claire.

Les options hébergées sur PicassoIA sont de bons étalons de comparaison. Lancez le même prompt sur un modèle 8B local et sur l’un de ceux-ci, et vous verrez exactement ce que la taille supplémentaire apporte :

ModèleIdéal pour
Llama 4 Scout InstructBrouillons et résumés rapides
DeepSeek R1Raisonnement pas à pas sur les questions difficiles
Qwen3.7-PlusGénération de texte et entrée d’images
Granite 4.1 8BChat et code à la taille d’un petit modèle

Utiliser GPT OSS 20B sur PicassoIA

Si vous voulez tester gpt-oss:20b avant de télécharger 14 Go, lancez le même modèle à poids ouverts dans le navigateur :

  1. Ouvrez la page GPT OSS 20B dans la collection Large Language Models.
  2. Saisissez votre prompt dans le champ Prompt. Un bon test consiste à reprendre la docstring que vous prévoyez de donner à ask_local_model, avec la question « Sauriez-vous quand appeler cet outil ? »
  3. Laissez Temperature à sa valeur par défaut de 0,1 pour une sortie précise et reproductible. Augmentez-la pour le brainstorming.
  4. Gardez Max Tokens à 2048 pour les réponses longues, ou réduisez-le pour les réponses courtes.
  5. Ajustez Top P, Presence Penalty et Frequency Penalty uniquement si la sortie tourne en boucle ou paraît répétitive.
  6. Lancez, ajustez, puis relancez. La page du modèle indique des générations illimitées, donc itérer ne coûte rien.

Gros plan des mains d’une femme tapant sur un fin ordinateur portable à un bureau blanc et lumineux

💡 Comparez la réponse hébergée avec votre exécution locale. Si elles correspondent de près, la configuration locale fait son travail et vous pouvez arrêter de payer l’appel hébergé.

Associer le pont à la génération d’images

Une fois ask_local_model en place, il peut faire plus que résumer des journaux. Un modèle local est un moyen peu coûteux et privé de rédiger des prompts d’image, et c’est là que le pont rencontre le travail visuel.

Ajoutez un troisième outil qui prend un sujet et renvoie un prompt photographique de 60 mots : sujet, décor, direction de la lumière, objectif et rendu du film. Votre assistant l’appelle, puis vous collez le résultat dans un modèle de texte vers image. P-Image est une option rapide pour les brouillons. FLUX 2 Pro convient à une seconde passe lorsqu’un prompt demande plus de détails.

Un designer debout devant un mur de tirages photographiques épinglés dans un studio lumineux

Une routine simple fonctionne bien :

  1. Demandez au modèle local trois variantes de prompt sur un même sujet.
  2. Générez les trois et gardez la meilleure image.
  3. Animez la gagnante avec un modèle d’image vers vidéo du catalogue de modèles PicassoIA.

Le même schéma fonctionne pour les miniatures, les photos de produits et les en-têtes de blog. Le pont rend l’étape de rédaction gratuite et privée, et les modèles hébergés se chargent du rendu lourd.

Créer vos propres images sur PicassoIA

Un jeune homme souriant, appuyé en arrière avec un ordinateur portable dans un studio domestique baigné de lumière dorée

Vous disposez maintenant d’un pont fonctionnel dans les deux sens : un modèle local capable d’utiliser des outils, et un modèle local que d’autres applications peuvent appeler. L’étape suivante consiste à le mettre au travail sur quelque chose que vous pouvez voir.

Testez dès aujourd’hui l’idée de rédaction de prompts. Demandez à votre modèle local un prompt photographique, ouvrez PicassoIA et générez votre première image avec P-Image ou FLUX 2 Pro. Changez l’objectif, la direction de la lumière ou le décor, puis relancez. Quand une image fonctionne, transformez-la en courte vidéo. Parcourez tous les modèles disponibles dans le catalogue complet de PicassoIA et commencez à expérimenter avec PicassoIA.

Partager cet article

Choisissez votre langue