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.
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.
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.
Sentido
Cliente MCP
Servidor MCP
Uso típico
Ollama usa ferramentas
Seu script da ponte, encapsulando um modelo do Ollama
Servidor de arquivos, banco de dados ou pesquisa
Um assistente local que lê suas anotações
Ollama como ferramenta
Claude Desktop, Claude Code, Cursor
Seu script da ponte, encapsulando o Ollama
Delegar 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:
A ponte se conecta a um servidor MCP e pede a lista de ferramentas com tools/list.
Ela reescreve cada esquema de ferramenta no formato que o Ollama espera.
Ela envia a pergunta do usuário e essas definições de ferramentas para um modelo local.
O modelo responde com uma entrada tool_calls em vez de texto.
A ponte executa essa chamada no servidor MCP com tools/call.
O resultado volta para o modelo como uma mensagem tool.
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
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 modelo
Memória para os pesos
Configuração confortável
3B a 4B
2 a 3 GB
Qualquer notebook recente
7B a 8B
5 a 6 GB
GPU de 8 GB ou 16 GB de memória unificada
14B
9 a 10 GB
GPU de 12 GB
20B
13 a 15 GB
GPU de 16 GB ou 24 GB de memória unificada
32B
19 a 21 GB
GPU 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 Ollama
Tamanho em disco
Por que usar
llama3.1:8b
cerca de 4,9 GB
Padrão confiável para os primeiros testes
qwen3:8b
cerca de 5,2 GB
Forte em uso de ferramentas em várias etapas, mais lento com o pensamento ativado
mistral-nemo
cerca de 7,1 GB
Contexto longo, lida com muitas ferramentas
gpt-oss:20b
cerca de 14 GB
O 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:
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
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.
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:
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
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
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:
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?".
Deixe Temperature no padrão de 0,1 para uma saída precisa e repetível. Aumente para fazer brainstorming.
Mantenha Max Tokens em 2048 para respostas longas, ou reduza para respostas curtas.
Ajuste Top P, Presence Penalty e Frequency Penalty apenas se a saída entrar em loop ou parecer repetitiva.
Execute, ajuste e execute de novo. A página do modelo lista gerações ilimitadas, então iterar não custa nada.
💡 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.
Uma rotina simples funciona bem:
Peça ao modelo local três variações de prompt sobre um mesmo assunto.
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
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.