Servidor MCP de Ollama: cómo conectar modelos locales con un puente

Construye un puente de servidor MCP para Ollama en ambas direcciones: un cliente en Python que permite a los modelos locales llamar a herramientas MCP, y un servidor que expone Ollama a Claude Desktop y Claude Code. Incluye dimensionamiento de hardware, código funcional, archivos de configuración y soluciones a los tres errores que rompen la mayoría de los primeros intentos.

Servidor MCP de Ollama: cómo conectar modelos locales con un puente
Cristian Da Conceicao
Fundador de Picasso IA

Tu equipo portátil ya puede ejecutar un modelo de lenguaje capaz, pero la mayoría de tus herramientas no sabe que existe. Una configuración de servidor MCP de Ollama soluciona eso. Un pequeño puente se sitúa entre Ollama, que sirve los modelos en localhost:11434, y el Model Context Protocol (MCP), el estándar que usan las aplicaciones de IA para encontrar y llamar herramientas. Lo construyes una vez y un modelo local puede leer tus archivos, consultar una base de datos o buscar en tus notas. Si cambias la dirección, Claude Desktop o Claude Code pueden delegar tareas baratas y privadas en la GPU que tienes debajo de la mesa.

Este artículo construye las dos direcciones con código Python funcional: un cliente puente que permite a los modelos de Ollama usar cualquier servidor MCP, y un servidor puente que expone Ollama como un conjunto de herramientas para cualquier cliente MCP. También incluye cifras de memoria, archivos de configuración y los tres errores que consumen la mayor parte del tiempo de depuración.

Qué hace un puente de Ollama MCP

Ollama y MCP resuelven mitades distintas de un mismo problema. Ollama descarga modelos de pesos abiertos y los sirve a través de una API HTTP sencilla. MCP, que Anthropic publicó a finales de 2024, estandariza la forma en que una aplicación de IA se comunica con herramientas, archivos y datos a través de pequeños programas llamados servidores. La API de Ollama habla con mensajes de chat y definiciones de herramientas. No habla MCP, y los clientes MCP no saben dónde viven tus modelos. El puente traduce entre ambos.

Vista desde abajo de un puente de piedra cubierto de musgo que cruza un río neblinoso al amanecer

Dos formas de construir un puente

"Puente" significa dos programas distintos según quién necesite qué, así que elige la dirección antes de escribir cualquier código.

DirecciónCliente MCPServidor MCPUso típico
Ollama usa herramientasTu script puente, que envuelve un modelo de OllamaServidor de archivos, base de datos o búsquedaUn asistente local que lee tus notas
Ollama como herramientaClaude Desktop, Claude Code, CursorTu script puente, que envuelve OllamaDelegar tareas privadas o baratas en un modelo local

La primera dirección da a un modelo local la capacidad de actuar. La segunda le da a un asistente en la nube un colega local. La mayoría termina construyendo ambas, porque la segunda solo lleva unas 30 líneas.

Una nota rápida sobre el transporte. Los ejemplos usan stdio, donde el cliente inicia el servidor como proceso hijo y se comunica con él por la entrada y salida estándar. Es la opción más sencilla para un equipo personal. Si quieres un único puente compartido por varias aplicaciones o por varios equipos de tu red, ejecútalo con el transporte Streamable HTTP y mantenlo detrás de tu propio cortafuegos. El código de las herramientas sigue siendo el mismo, y solo cambia la última línea del servidor.

Cómo viaja una llamada a una herramienta

Sea cual sea la dirección que elijas, una llamada a una herramienta sigue el mismo ciclo:

  1. El puente se conecta a un servidor MCP y pide la lista de herramientas con tools/list.
  2. Reescribe el esquema de cada herramienta al formato que espera Ollama.
  3. Envía la pregunta del usuario y esas definiciones de herramientas a un modelo local.
  4. El modelo responde con una entrada tool_calls en lugar de texto.
  5. El puente ejecuta esa llamada en el servidor MCP con tools/call.
  6. El resultado vuelve al modelo como un mensaje tool.
  7. Los pasos del 3 al 6 se repiten hasta que el modelo responde con texto plano.

💡 El modelo nunca toca tu disco. Solo solicita una acción. Tu puente decide si la ejecuta, y por eso es el lugar adecuado para las listas de permitidos, las confirmaciones y el registro de actividad.

Lo que necesitas antes

Hardware que funciona

Primer plano extremo de una tarjeta gráfica con dos ventiladores negros instalada dentro de una caja de PC abierta

Los pesos del modelo tienen que caber en la memoria de la GPU (o en la memoria unificada de un Mac) con espacio libre para el contexto. Estas cifras son aproximadas y corresponden a versiones cuantizadas a 4 bits:

Tamaño del modeloMemoria para los pesosConfiguración cómoda
3B a 4B2 a 3 GBCualquier equipo portátil reciente
7B a 8B5 a 6 GBGPU de 8 GB o 16 GB de memoria unificada
14B9 a 10 GBGPU de 12 GB
20B13 a 15 GBGPU de 16 GB o 24 GB de memoria unificada
32B19 a 21 GBGPU de 24 GB

Los modelos que se desbordan hacia la RAM del sistema siguen funcionando, pero la velocidad de tokens cae en picado. Un puente hace varias llamadas al modelo por pregunta, así que la velocidad importa más que el tamaño. Un modelo de 8B que cabe por completo en la GPU suele superar a un modelo de 32B que no cabe.

Modelos que admiten llamadas a herramientas

No todos los modelos pueden pedir una herramienta. Ollama revisa la plantilla de chat del modelo, y un modelo sin soporte para herramientas devuelve un error cuando le pasas tools. Filtra la biblioteca de Ollama por la etiqueta tools o empieza con esta lista corta:

Etiqueta de OllamaTamaño en discoPor qué usarlo
llama3.1:8bunos 4,9 GBOpción predeterminada fiable para las primeras pruebas
qwen3:8bunos 5,2 GBSólido en uso de herramientas de varios pasos, más lento con el pensamiento activado
mistral-nemounos 7,1 GBContexto largo, maneja muchas herramientas
gpt-oss:20bunos 14 GBEl GPT OSS 20B de pesos abiertos, diseñado pensando en el uso de herramientas

Instala las piezas

Activa primero un entorno virtual (source .venv/bin/activate en macOS y Linux, .venv\Scripts\activate en Windows) y luego ejecuta:

# 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 devuelve una lista JSON con tus modelos, Ollama está listo. Si la conexión es rechazada, inícialo con ollama serve.

Construye el cliente puente en Python

El cliente es un solo archivo. Lanza un servidor MCP como proceso hijo mediante el transporte stdio, lee sus herramientas y ejecuta el ciclo de la sección anterior. El servidor del ejemplo es el servidor oficial de archivos, apuntado a una carpeta de notas.

Convierte las herramientas MCP al formato de Ollama

Una herramienta MCP tiene un name, una description y un inputSchema escritos en JSON Schema. El formato de llamadas a funciones de Ollama necesita esas mismas tres piezas, envueltas en un objeto function. La conversión es casi solo un cambio de nombre:

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

La mayoría de los esquemas pasan sin cambios. Si un servidor incluye construcciones poco comunes como anyOf o $ref, aplánalas antes de enviarlas. Los modelos pequeños manejan los esquemas planos mucho mejor.

Escribe el ciclo de llamadas a herramientas

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?")))

Cuatro detalles merecen atención:

  • MAX_TURNS es una barrera de seguridad. Un modelo confundido puede llamar a la misma herramienta sin parar, y un contador convierte eso en un fallo claro.
  • dict(call.function.arguments) importa porque Ollama devuelve los argumentos como un mapeo que la sesión MCP espera como diccionario simple.
  • Solo bloques de texto. Los resultados de MCP pueden incluir imágenes y recursos incrustados. Esta versión conserva el texto e ignora el resto.
  • tool_name en el mensaje de la herramienta indica al modelo a qué llamada pertenece el resultado, lo que evita que se mezclen las llamadas paralelas.

Ejecútalo con archivos reales

Vista por encima del hombro de un desarrollador escribiendo en un equipo portátil en una mesa de cafetería iluminada por el sol

Guarda el archivo como bridge_client.py, cambia NOTES_DIR por una carpeta real y ejecuta python bridge_client.py. Una ejecución correcta primero hace una llamada para listar directorios o buscar, luego una o dos lecturas de archivos, y después responde en texto plano. Para ver cómo el modelo elige las herramientas, añade print(call.function.name, call.function.arguments) al inicio del bucle interno.

💡 Consejo para Windows: si Python no puede lanzar npx, usa npx.cmd como comando. La marca -y hace que npx instale el servidor de archivos la primera vez sin pedir confirmación.

Antes de apuntar el puente a algo sensible, decide qué puede hacer el modelo. El servidor de archivos solo accede a las carpetas que le pasas en la línea de comandos, así que dale una carpeta de notas en lugar de tu directorio personal. Para las herramientas que escriben, borran o envían datos, añade un paso de confirmación dentro del bucle: muestra la llamada y pide un sí antes de que se ejecute session.call_tool. Treinta segundos de fricción valen más que un modelo de 8B decidiendo que una limpieza es buena idea.

Expón Ollama como servidor MCP

Ahora cambia la dirección. En lugar de que un modelo local use herramientas ajenas, publicas el modelo local como una herramienta. Cualquier cliente MCP puede entonces llamarlo para redactar, resumir o clasificar texto que nunca debería salir de tu equipo.

Vista cenital de un pequeño mini PC plateado, un router y bocetos de cuadernos sobre un escritorio de roble

Un servidor pequeño en Python

El SDK oficial de Python incluye FastMCP, que construye el esquema de la herramienta a partir de tus anotaciones de tipo y la descripción a partir de tu 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")

Escribe el docstring para quien llama, no para ti. El modelo cliente lo lee para decidir cuándo merece la pena llamar a tu herramienta, así que "úsala para texto privado" hace un trabajo real.

Conéctalo a Claude Desktop

Abre claude_desktop_config.json. En Windows está en %APPDATA%\Claude, y en macOS en ~/Library/Application Support/Claude. Añade el servidor bajo 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" }
    }
  }
}

Apunta command al Python del entorno virtual, no al del sistema. Claude Desktop no activa tu entorno, y un intérprete del sistema sin el paquete mcp falla sin avisar. Cierra la aplicación y vuelve a abrirla, y las dos herramientas aparecerán en el menú de herramientas.

Conéctalo a Claude Code

Claude Code registra los servidores desde la terminal:

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

Todo lo que va después de los dos guiones es el comando de lanzamiento. Cuando claude mcp list muestre el servidor como conectado, pide a Claude Code que "resuma este log con el modelo local" y observa cómo llama a ask_local_model.

Soluciona los problemas que te vas a encontrar

Primer plano de la mano de un técnico conectando un conector en un panel de parcheo de red lleno de cables de colores

Tres problemas explican la mayoría de los primeros intentos fallidos. Los tres tienen soluciones breves.

La salida estándar rompe los servidores stdio

Un servidor MCP stdio envía mensajes JSON-RPC por stdout. Un print() perdido inyecta texto en ese flujo, y el cliente cierra la conexión o informa de un error de análisis. El síntoma es un servidor que se conecta y, en menos de un segundo, se desconecta.

La solución es un hábito: registra en stderr (print(..., file=sys.stderr)) o en un archivo, y nunca escribas nada más en stdout. Eso incluye las barras de progreso y las advertencias que imprimen las bibliotecas importadas.

Los modelos pequeños ignoran las herramientas

Un modelo de 8B al que le das 25 herramientas a menudo responde de memoria o llama a la equivocada. Cuatro cambios ayudan, más o menos por orden de impacto:

  • Envía menos herramientas. Filtra la lista hasta dejar entre tres y seis herramientas que encajen con la pregunta.
  • Reescribe las descripciones. "Lee el contenido de un archivo por su ruta absoluta" es mejor que "Lector de archivos".
  • Baja la temperatura a 0,1 o 0,2 para la selección de herramientas.
  • Sube un tamaño. Pasar de 3B a 8B corrige más fallos de llamadas a herramientas que cualquier truco de prompt.

Las ventanas de contexto se llenan rápido

Las definiciones de herramientas y los resultados de las herramientas consumen contexto, y una sola lectura de un archivo grande puede empujar la pregunta fuera de la ventana. El contexto predeterminado de Ollama es pequeño, así que auméntalo de forma explícita y recorta los resultados antes de que lleguen al modelo:

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

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

Los valores más altos de num_ctx usan más memoria para la caché de atención, así que auméntalos por pasos. Además, define OLLAMA_KEEP_ALIVE con un valor más largo, como 30m. Ollama descarga los modelos inactivos después de cinco minutos por defecto, y cada recarga añade segundos a la primera respuesta.

Modelos locales o modelos alojados

Vista amplia desde abajo de un largo pasillo de racks de servidores negros en un centro de datos

Un puente no te obliga a elegir. Te permite enviar cada tarea al lugar más barato que puede hacerla bien.

Los modelos locales ganan cuando:

  • el texto es privado, como contratos, notas de salud o código fuente bajo acuerdo de confidencialidad
  • la tarea se repite miles de veces, así que el precio por token se acumula
  • trabajas sin conexión o en una red que no controlas

Los modelos alojados ganan cuando:

  • tu GPU tiene menos de 8 GB de memoria
  • la tarea necesita un modelo de más de 30B parámetros
  • necesitas una respuesta en segundos desde un arranque en frío

En la práctica, lo que mejor funciona es un enfoque híbrido. Deja que el modelo local se encargue de los primeros borradores, la clasificación y todo lo que toque archivos privados, y envía el 10 % más difícil a un modelo alojado más grande. Como ambos están detrás de la misma interfaz MCP, tu asistente puede elegir entre ask_local_model y una alternativa alojada con solo una descripción de herramienta más clara.

Los modelos alojados en PicassoIA sirven como referencias útiles. Ejecuta el mismo prompt en un modelo local de 8B y en uno de estos, y verás exactamente lo que aporta el tamaño extra:

ModeloIdeal para
Llama 4 Scout InstructBorradores rápidos y resúmenes
DeepSeek R1Razonamiento paso a paso en preguntas difíciles
Qwen3.7-PlusGeneración de texto más entrada de imágenes
Granite 4.1 8BChat y código a tamaño de modelo pequeño

Usa GPT OSS 20B en PicassoIA

Si quieres probar gpt-oss:20b antes de descargar 14 GB, ejecuta el mismo modelo de pesos abiertos en el navegador:

  1. Abre la página de GPT OSS 20B en la colección de Large Language Models.
  2. Escribe tu prompt en el campo Prompt. Una buena prueba es el docstring que piensas dar a ask_local_model, con la pregunta "¿Sabrías cuándo llamar a esta herramienta?".
  3. Deja Temperature en su valor predeterminado de 0,1 para obtener resultados precisos y repetibles. Súbelo para lluvia de ideas.
  4. Mantén Max Tokens en 2048 para respuestas largas, o bájalo para respuestas cortas.
  5. Ajusta Top P, Presence Penalty y Frequency Penalty solo si la salida se repite en bucle o resulta repetitiva.
  6. Ejecútalo, ajusta y vuelve a ejecutarlo. La página del modelo indica generaciones ilimitadas, así que iterar no cuesta nada.

Primer plano de las manos de una mujer escribiendo en un equipo portátil delgado sobre un escritorio blanco y luminoso

💡 Compara la respuesta alojada con tu ejecución local. Si coinciden en gran medida, la configuración local está cumpliendo su función y puedes dejar de pagar la llamada alojada.

Combina el puente con la generación de imágenes

Una vez que ask_local_model existe, puede hacer más que resumir logs. Un modelo local es una forma barata y privada de redactar prompts para imágenes, y ahí es donde el puente se encuentra con el trabajo visual.

Añade una tercera herramienta que reciba un tema y devuelva un prompt fotográfico de 60 palabras: sujeto, escenario, dirección de la luz, objetivo y estilo de película. Tu asistente la llama, y pegas el resultado en un modelo de texto a imagen. P-Image es una opción rápida para borradores. FLUX 2 Pro sirve para una segunda pasada cuando un prompt necesita más detalle.

Un diseñador de pie frente a una pared con copias fotográficas clavadas en un estudio luminoso

Una rutina sencilla funciona muy bien:

  1. Pide al modelo local tres variantes de prompt sobre un mismo tema.
  2. Genera las tres y conserva la mejor imagen.
  3. Anima el ganador con un modelo de imagen a video del catálogo de modelos de PicassoIA.

El mismo patrón sirve para miniaturas, fotos de producto y cabeceras de blog. El puente mantiene gratuita y privada la fase de redacción, y los modelos alojados se encargan del render pesado.

Crea tus propias imágenes en PicassoIA

Un joven sonriente recostado con un equipo portátil en un estudio doméstico bañado por la luz dorada

Ya tienes un puente funcionando en ambas direcciones: un modelo local que puede usar herramientas y un modelo local al que otras aplicaciones pueden llamar. El siguiente paso es ponerlo a trabajar en algo que puedas ver.

Lleva la idea de redactar prompts a la práctica hoy mismo. Pide a tu modelo local un prompt fotográfico, abre Picasso IA y genera tu primera imagen con P-Image o FLUX 2 Pro. Cambia el objetivo, la dirección de la luz o el escenario, y vuelve a ejecutarlo. Cuando un fotograma funcione, conviértelo en un video corto. Explora todos los modelos disponibles en el catálogo completo de PicassoIA y empieza a experimentar con Picasso IA.

Compartir este artículo

Elige tu idioma