Servidor MCP do Ollama: como conectar modelos locais com uma ponte

Crie uma ponte de servidor MCP do Ollama nos dois sentidos: um cliente Python que permite a modelos locais chamar ferramentas MCP e um servidor que expõe o Ollama ao Claude Desktop e ao Claude Code. Inclui dimensionamento de hardware, código funcional, arquivos de configuração e correções para os três bugs que quebram a maioria das primeiras tentativas.

Servidor MCP do Ollama: como conectar modelos locais com uma ponte
Cristian Da Conceicao
Fundador do Picasso IA

Seu notebook já consegue rodar um modelo de linguagem capaz, mas a maioria das suas ferramentas nem sabe que ele existe. Uma configuração de servidor MCP do Ollama resolve isso. Uma pequena ponte fica entre o Ollama, que serve os modelos em localhost:11434, e o Model Context Protocol (MCP), o padrão que os aplicativos de IA usam para encontrar e chamar ferramentas. Você constrói isso uma vez e um modelo local consegue ler seus arquivos, consultar um banco de dados ou pesquisar suas anotações. Inverta o sentido e o Claude Desktop ou o Claude Code podem passar tarefas baratas e privadas para a GPU que está embaixo da sua mesa.

Este artigo constrói os dois sentidos com código Python funcional: um cliente da ponte que permite que os modelos do Ollama usem qualquer servidor MCP, e um servidor da ponte que expõe o Ollama como um conjunto de ferramentas para qualquer cliente MCP. Você também recebe números de memória, arquivos de configuração e os três bugs que consomem a maior parte do tempo de depuração.

O que faz uma ponte MCP para o Ollama

O Ollama e o MCP resolvem metades diferentes de um mesmo problema. O Ollama baixa modelos de pesos abertos e os serve por uma API HTTP simples. O MCP, que a Anthropic publicou no fim de 2024, padroniza como um aplicativo de IA conversa com ferramentas, arquivos e dados por meio de pequenos programas chamados servidores. A API do Ollama fala mensagens de chat e definições de ferramentas. Ela não fala MCP, e os clientes MCP não fazem ideia de onde seus modelos estão. A ponte faz a tradução entre os dois.

Vista em contra-plongée de uma ponte de arco de pedra coberta de musgo cruzando um rio enevoado ao amanhecer

Dois jeitos de construir uma ponte

"Ponte" significa dois programas diferentes dependendo de quem precisa do quê, então escolha o sentido antes de escrever qualquer código.

SentidoCliente MCPServidor MCPUso típico
Ollama usa ferramentasSeu script da ponte, encapsulando um modelo do OllamaServidor de arquivos, banco de dados ou pesquisaUm assistente local que lê suas anotações
Ollama como ferramentaClaude Desktop, Claude Code, CursorSeu script da ponte, encapsulando o OllamaDelegar tarefas privadas ou baratas a um modelo local

O primeiro sentido dá mãos a um modelo local. O segundo dá a um assistente na nuvem um colega local. A maioria das pessoas acaba construindo os dois, porque o segundo leva cerca de 30 linhas.

Uma observação rápida sobre o transporte. Os exemplos aqui usam stdio, em que o cliente inicia o servidor como um processo filho e conversa com ele pela entrada e saída padrão. É a opção mais simples para uma máquina pessoal. Se você quiser uma ponte compartilhada por vários aplicativos ou por vários computadores da sua rede, execute-a com o transporte Streamable HTTP e mantenha-a atrás do seu próprio firewall. O código das ferramentas continua o mesmo, e só a última linha do servidor muda.

Como uma chamada de ferramenta percorre o caminho

Seja qual for o sentido escolhido, uma chamada de ferramenta segue o mesmo ciclo:

  1. A ponte se conecta a um servidor MCP e pede a lista de ferramentas com tools/list.
  2. Ela reescreve cada esquema de ferramenta no formato que o Ollama espera.
  3. Ela envia a pergunta do usuário e essas definições de ferramentas para um modelo local.
  4. O modelo responde com uma entrada tool_calls em vez de texto.
  5. A ponte executa essa chamada no servidor MCP com tools/call.
  6. O resultado volta para o modelo como uma mensagem tool.
  7. As etapas de 3 a 6 se repetem até o modelo responder com texto simples.

💡 O modelo nunca toca no seu disco. Ele apenas pede uma ação. Sua ponte decide se executa, e é por isso que ela é o lugar certo para listas de permissão, confirmações e registros de log.

O que você precisa primeiro

Hardware que funciona

Close-up extremo de uma placa de vídeo com dois ventiladores pretos instalada dentro de um gabinete de PC aberto

Os pesos do modelo precisam caber na memória da GPU (ou na memória unificada, em um Mac) com espaço sobrando para o contexto. Estes números são aproximados, para versões quantizadas em 4 bits:

Tamanho do modeloMemória para os pesosConfiguração confortável
3B a 4B2 a 3 GBQualquer notebook recente
7B a 8B5 a 6 GBGPU de 8 GB ou 16 GB de memória unificada
14B9 a 10 GBGPU de 12 GB
20B13 a 15 GBGPU de 16 GB ou 24 GB de memória unificada
32B19 a 21 GBGPU de 24 GB

Modelos que transbordam para a RAM do sistema ainda rodam, mas a velocidade de tokens cai muito. Uma ponte faz várias chamadas ao modelo por pergunta, então a velocidade importa mais que o tamanho. Um modelo de 8B que cabe inteiro na GPU geralmente supera um modelo de 32B que não cabe.

Modelos que suportam chamadas de ferramenta

Nem todo modelo consegue pedir uma ferramenta. O Ollama verifica o template de chat do modelo, e um modelo sem suporte a ferramentas retorna um erro quando você passa tools. Filtre a biblioteca do Ollama pela tag tools ou comece por esta lista curta:

Tag no OllamaTamanho em discoPor que usar
llama3.1:8bcerca de 4,9 GBPadrão confiável para os primeiros testes
qwen3:8bcerca de 5,2 GBForte em uso de ferramentas em várias etapas, mais lento com o pensamento ativado
mistral-nemocerca de 7,1 GBContexto longo, lida com muitas ferramentas
gpt-oss:20bcerca de 14 GBO GPT OSS 20B de pesos abertos, criado pensando em uso de ferramentas

Instale as peças

Ative primeiro um ambiente virtual (source .venv/bin/activate no macOS e no Linux, .venv\Scripts\activate no Windows) e depois execute:

# 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

Se curl retornar uma lista JSON com seus modelos, o Ollama está pronto. Se a conexão for recusada, inicie-o com ollama serve.

Construa o cliente da ponte em Python

O cliente é um único arquivo. Ele inicia um servidor MCP como processo filho pelo transporte stdio, lê as ferramentas dele e executa o ciclo da seção anterior. O servidor de exemplo é o servidor oficial de arquivos, apontado para uma pasta de anotações.

Converta as ferramentas MCP para o formato do Ollama

Uma ferramenta MCP traz um name, uma description e um inputSchema escritos em JSON Schema. O formato de function calling do Ollama pede as mesmas três partes, envolvidas em um objeto function. A conversão é, em grande parte, uma simples renomeação:

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

A maioria dos esquemas passa sem alterações. Se um servidor trouxer construções incomuns, como anyOf ou $ref, achate-as antes de enviar. Modelos pequenos lidam muito melhor com esquemas planos.

Escreva o loop de chamada de ferramentas

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

Quatro detalhes merecem atenção:

  • MAX_TURNS é uma trava de segurança. Um modelo confuso pode chamar a mesma ferramenta para sempre, e um contador transforma isso em uma falha clara.
  • dict(call.function.arguments) importa porque o Ollama devolve os argumentos como um mapeamento, que a sessão MCP espera como um dicionário simples.
  • Somente blocos de texto. Resultados MCP podem incluir imagens e recursos incorporados. Esta versão mantém o texto e ignora o resto.
  • tool_name na mensagem da ferramenta informa ao modelo a qual chamada o resultado pertence, o que evita que chamadas paralelas se misturem.

Execute com arquivos reais

Vista por cima do ombro de um desenvolvedor digitando em um notebook numa mesa de café ensolarada

Salve o arquivo como bridge_client.py, troque NOTES_DIR por uma pasta real e execute python bridge_client.py. Uma execução saudável faz primeiro uma chamada de listagem de diretório ou de busca, depois uma ou duas leituras de arquivo e, por fim, responde em texto simples. Para acompanhar o modelo escolhendo ferramentas, adicione print(call.function.name, call.function.arguments) no topo do loop interno.

💡 Dica para Windows: se o Python não conseguir iniciar npx, use npx.cmd como comando. A flag -y faz com que npx instale o servidor de arquivos na primeira execução, sem perguntar.

Antes de apontar a ponte para algo sensível, decida o que o modelo pode fazer. O servidor de arquivos só acessa as pastas que você passa na linha de comando, então dê a ele uma pasta de anotações em vez do seu diretório pessoal. Para ferramentas que escrevem, apagam ou enviam dados, adicione uma etapa de confirmação dentro do loop: mostre a chamada e peça um sim antes de session.call_tool ser executado. Trinta segundos de atrito valem mais do que um modelo de 8B decidindo que uma faxina é uma boa ideia.

Exponha o Ollama como servidor MCP

Agora inverta o sentido. Em vez de um modelo local usar ferramentas de outras pessoas, você publica o modelo local como uma ferramenta. Qualquer cliente MCP pode então chamá-lo para redigir, resumir ou classificar textos que nunca deveriam sair da sua máquina.

Vista de cima de um pequeno mini PC prateado, um roteador e esboços em um caderno sobre uma mesa de carvalho

Um servidor pequeno em Python

O SDK oficial de Python inclui o FastMCP, que monta o esquema da ferramenta a partir das suas type hints e a descrição a partir da sua 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")

Escreva a docstring para quem chama a ferramenta, não para você. O modelo cliente a lê para decidir quando sua ferramenta vale a pena ser chamada, então "use para texto privado" faz diferença de verdade.

Conecte ao Claude Desktop

Abra claude_desktop_config.json. No Windows ele fica em %APPDATA%\Claude, e no macOS em ~/Library/Application Support/Claude. Adicione o servidor em 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" }
    }
  }
}

Aponte command para o Python do ambiente virtual, não para o do sistema. O Claude Desktop não ativa o seu ambiente, e um interpretador do sistema sem o pacote mcp falha em silêncio. Feche e reabra o aplicativo, e as duas ferramentas aparecerão no menu de ferramentas.

Conecte ao Claude Code

O Claude Code registra servidores pelo terminal:

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

Tudo depois do duplo hífen é o comando de inicialização. Quando claude mcp list mostrar o servidor como conectado, peça ao Claude Code para "resumir este log com o modelo local" e observe-o chamar ask_local_model.

Corrija os problemas que você vai encontrar

Close-up de uma mão de técnico encaixando um conector em um patch panel de rede cheio de cabos coloridos

Três problemas explicam a maioria das primeiras tentativas que falham. Todos os três têm correções curtas.

A saída padrão quebra servidores stdio

Um servidor MCP stdio envia mensagens JSON-RPC pela stdout. Um único print() perdido injeta texto nesse fluxo, e o cliente derruba a conexão ou relata um erro de parsing. O sintoma é um servidor que conecta e desconecta em menos de um segundo.

A correção é um hábito: registre logs no stderr (print(..., file=sys.stderr)) ou num arquivo, e nunca escreva mais nada na stdout. Isso inclui barras de progresso e avisos impressos por bibliotecas importadas.

Modelos pequenos ignoram as ferramentas

Um modelo de 8B que recebe 25 ferramentas costuma responder de memória ou chamar a errada. Quatro mudanças ajudam, em ordem aproximada de impacto:

  • Envie menos ferramentas. Filtre a lista para as três a seis que se encaixam na pergunta.
  • Reescreva as descrições. "Leia o conteúdo de um arquivo pelo caminho absoluto" é melhor que "Leitor de arquivos".
  • Reduza a temperatura para 0,1 ou 0,2 na seleção de ferramentas.
  • Suba um tamanho. Passar de 3B para 8B corrige mais falhas de chamada de ferramenta do que qualquer truque de prompt.

As janelas de contexto enchem rápido

As definições de ferramentas e os resultados delas consomem contexto, e uma única leitura grande de arquivo pode empurrar a pergunta para fora da janela. O contexto padrão do Ollama é pequeno, então aumente-o explicitamente e corte os resultados antes que cheguem ao 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

Valores mais altos de num_ctx usam mais memória para o cache de atenção, então aumente aos poucos. Defina também OLLAMA_KEEP_ALIVE para um valor maior, como 30m. O Ollama descarrega modelos ociosos após cinco minutos por padrão, e cada recarga acrescenta segundos à primeira resposta.

Modelos locais ou modelos hospedados

Vista ampla em contra-plongée de um longo corredor de racks de servidores pretos em um data center

Uma ponte não obriga a fazer uma escolha. Ela permite direcionar cada tarefa para o lugar mais barato que consiga executá-la bem.

Modelos locais vencem quando:

  • o texto é privado, como contratos, anotações de saúde ou código-fonte sob NDA
  • a tarefa se repete milhares de vezes, então o preço por token se acumula
  • você trabalha offline ou numa rede que não controla

Modelos hospedados vencem quando:

  • sua GPU tem menos de 8 GB de memória
  • a tarefa exige um modelo acima de 30 bilhões de parâmetros
  • você precisa de uma resposta em segundos numa inicialização a frio

Na prática, um modelo híbrido funciona melhor. Deixe o modelo local cuidar dos primeiros rascunhos, da classificação e de tudo o que toca arquivos privados, e então envie os 10% difíceis para um modelo hospedado maior. Como os dois ficam atrás da mesma interface MCP, seu assistente pode escolher entre ask_local_model e uma alternativa hospedada apenas com uma descrição de ferramenta mais clara.

As opções hospedadas no PicassoIA são boas referências. Rode o mesmo prompt em um modelo local de 8B e em um destes, e você verá exatamente o que o tamanho extra oferece:

ModeloIdeal para
Llama 4 Scout InstructRascunhos rápidos e resumos
DeepSeek R1Raciocínio passo a passo em perguntas difíceis
Qwen3.7-PlusGeração de texto com entrada de imagem
Granite 4.1 8BChat e código em tamanho de modelo pequeno

Use o GPT OSS 20B no PicassoIA

Se você quiser testar gpt-oss:20b antes de baixar 14 GB, rode o mesmo modelo de pesos abertos no navegador:

  1. Abra a página do GPT OSS 20B na coleção de Large Language Models.
  2. Digite seu prompt no campo Prompt. Um bom teste é a docstring que você pretende dar para ask_local_model, com a pergunta "Você saberia quando chamar esta ferramenta?".
  3. Deixe Temperature no padrão de 0,1 para uma saída precisa e repetível. Aumente para fazer brainstorming.
  4. Mantenha Max Tokens em 2048 para respostas longas, ou reduza para respostas curtas.
  5. Ajuste Top P, Presence Penalty e Frequency Penalty apenas se a saída entrar em loop ou parecer repetitiva.
  6. Execute, ajuste e execute de novo. A página do modelo lista gerações ilimitadas, então iterar não custa nada.

Close-up das mãos de uma mulher digitando em um notebook fino em uma mesa branca e luminosa

💡 Compare a resposta hospedada com a sua execução local. Se forem muito parecidas, a configuração local está fazendo seu trabalho e você pode parar de pagar pela chamada hospedada.

Combine a ponte com a geração de imagens

Depois que ask_local_model existir, ele pode fazer mais do que resumir logs. Um modelo local é uma forma barata e privada de redigir prompts de imagem, e é aí que a ponte encontra o trabalho visual.

Adicione uma terceira ferramenta que recebe um tema e devolve um prompt fotográfico de 60 palavras: assunto, cenário, direção da luz, lente e aspecto de filme. Seu assistente chama a ferramenta e você cola o resultado num modelo de texto para imagem. O P-Image é uma opção rápida para rascunhos. O FLUX 2 Pro serve para uma segunda passada, quando um prompt precisa de mais detalhes.

Um designer em pé diante de uma parede de cópias fotográficas fixadas em um estúdio iluminado

Uma rotina simples funciona bem:

  1. Peça ao modelo local três variações de prompt sobre um mesmo assunto.
  2. Gere as três imagens e guarde o melhor quadro.
  3. Anime o vencedor com um modelo de imagem para vídeo do catálogo de modelos do PicassoIA.

O mesmo padrão funciona para miniaturas, fotos de produtos e cabeçalhos de blog. A ponte mantém a etapa de redação gratuita e privada, e os modelos hospedados cuidam da renderização pesada.

Crie suas próprias imagens no PicassoIA

Um jovem sorridente recostado com um notebook em um estúdio caseiro iluminado pela luz dourada

Agora você tem uma ponte funcionando nos dois sentidos: um modelo local que pode usar ferramentas, e um modelo local que outros aplicativos podem chamar. O próximo passo é colocá-la para trabalhar em algo que você consegue ver.

Pegue a ideia de redigir prompts e experimente hoje. Peça ao seu modelo local um prompt fotográfico, abra o Picasso IA e gere sua primeira imagem com o P-Image ou o FLUX 2 Pro. Troque a lente, a direção da luz ou o cenário e rode de novo. Quando um quadro funcionar, transforme-o em um vídeo curto. Explore todos os modelos disponíveis no catálogo completo do PicassoIA e comece a experimentar com o Picasso IA.

Compartilhe este artigo

Escolha seu idioma