Como construir o nosso próprio servidor MCP e melhorar o nosso LLM local?

Olá a todos!

Hoje vou voltar falar-vos de algo fundamental para os vossos LLMs locais: o Model Context Protocol (MCP). Já abordamos isto no passado, mas iremos aprofundar hoje.
Mas porque a importância? Porque para qualquer AI/LLM contexto e informação é tudo. Quanto melhor a informação que dispõe melhor será a resposta e a eficiência.
Neste post iremos ver como implementar um ou mais MCP’s “nosso” para alimentar o nosso LLM.

O Que É o Model Context Protocol (MCP)?

Imaginem o seguinte cenário: têm um LLM local a correr no vosso servidor através do Ollama ou outro motor, mas ele está completamente isolado do mundo. Não consegue aceder aos vossos ficheiros, às vossas bases de dados, nem sequer sabe que horas são. É como ter um assistente genial trancado numa sala vazia.
O MCP é um standard open-source que permite conectar aplicações de AI a sistemas externos. Pensem nele como um porto USB-C para as vossas aplicações de AI. Da mesma forma que o USB-C padronizou as ligações entre dispositivos eletrónicos, o MCP padroniza a forma como os LLMs se ligam a fontes de dados externas, APIs e ferramentas.
Foi lançado pela Anthropic em novembro de 2024 e rapidamente ganhou adoção por gigantes como OpenAI, Google DeepMind e Microsoft. Em dezembro de 2025, foi doado à Agentic AI Foundation sob a Linux Foundation, garantindo o seu futuro como standard verdadeiramente aberto.

Porque É Que Isto Interessa Para Quem Faz Self-Hosting?

Se fazem self-hosting dos vossos LLMs, provavelmente já se depararam com esta limitação: o modelo é poderoso, mas vive numa bolha. Quer aceder à vossa documentação interna? Tens de fazer copy-paste manual. Quer que ele interaja com a vossa API? Boa sorte a programar isso do zero.
O MCP resolve isto de forma elegante. Em vez de criarem integrações custom para cada ferramenta ou fonte de dados, implementam um servidor MCP que expõe essas capacidades de forma padronizada. E aqui está a melhor parte: um servidor MCP que criem pode ser reutilizado em qualquer aplicação que suporte o protocolo.

A Arquitetura: Três Componentes Essenciais

A arquitetura do MCP é surpreendentemente simples e segue um modelo cliente-servidor tradicional:

MCP Host: É a aplicação onde o LLM vive. Pode ser o Claude Desktop, o Cursor IDE, ou no nosso caso, o OpenWebUI a correr no nosso homelab.
MCP Client: O componente que faz a ponte entre o host e o servidor. Gere as ligações, mantém o estado da sessão e garante comunicação segura.
MCP Server: O programa que vocês desenvolvem e que expõe as capacidades reais – acesso a ficheiros, queries a bases de dados, chamadas a APIs, ações no GitHub, e tudo o que conseguirem imaginar.

Os servidores MCP expõem dados e ferramentas através de um protocolo padronizado, mantendo ligações seguras 1:1 com clientes dentro das aplicações host.

Tipos de Capacidades que Um Servidor MCP Pode Oferecer

Um servidor MCP pode expor três tipos principais de capacidades:

Tools (Ferramentas): São funções que o modelo pode chamar. Por exemplo, “consultar a meteorologia”, “executar um script Python”, ou “criar um issue no GitHub”. O modelo decide quando usar estas ferramentas com base nas descrições que fornecemos.
Resources (Recursos): São dados que podem ser lidos, como conteúdos de ficheiros, respostas de APIs, ou registos de bases de dados. Podem ser estáticos (um ficheiro específico) ou dinâmicos (resultados de queries).
Prompts: Templates pré-escritos que ajudam os utilizadores a realizar tarefas específicas. É como ter snippets prontos a usar que o modelo conhece.

A Biblioteca de Servidores MCP: Um Ecossistema em Crescimento

Uma das grandes vantagens do MCP é o ecossistema vibrante que se está a formar à sua volta. Existem já centenas de servidores prontos a usar que podemos adaptar às nossas necessidades.

Servidores Oficiais da Anthropic

A Anthropic disponibiliza implementações de referência para sistemas empresariais populares:

  • Google Drive: Acesso completo aos vossos documentos
  • Slack: Integração com canais e mensagens
  • GitHub: Gestão completa de repositórios, issues e pull requests
  • PostgreSQL: Queries e manipulação de bases de dados
  • Puppeteer: Automação de browser para scraping e testes

O Directório da Comunidade

Sabiam que isto vinha aí. É na comunidade que a coisa fica mesmo interessante. Sites como claudedirectory.co, glama.ai e mcp.so agregam milhares de servidores MCP criados pela comunidade. Vamos ver alguns exemplos fascinantes:

Firecrawl MCP Server: Permite fazer web scraping avançado, processamento em batch, extração de dados estruturados e análise de conteúdo com LLMs. Suporta tanto a cloud como instâncias self-hosted.

Blender MCP: Liga o Blender diretamente ao Claude através do MCP, permitindo modelação 3D assistida por prompts. Imaginem dizer “cria-me uma esfera com textura metálica” e ver isso acontecer no Blender.

Postgres MCP Pro: Oferece tuning de índices, explain plans, health checks e execução segura de SQL para PostgreSQL. É open source e perfeito para DBAs que querem assistência de AI.

Qdrant MCP: Integração com o motor de pesquisa vectorial Qdrant, ideal para quem trabalha com embeddings e RAG.

Memory MCP (mem0.ai): Permite ao LLM armazenar, recuperar e pesquisar preferências de programação para práticas mais consistentes. É como dar memória de longo prazo ao modelo.

Time & Timezone MCP: Capacidades de conversão de tempo e timezone com deteção automática do timezone do sistema. Parece simples, mas é surpreendentemente útil.

Sentry MCP: Integração com o Sentry para inspecionar error reports, stacktraces e informação de debugging. Perfeito para troubleshooting assistido por AI.

A facilidade com que estes servidores podem ser adaptados é impressionante. Como os servidores MCP podem ser expostos através de um protocolo universal, os developers podem construir contra um standard único em vez de manterem conectores separados para cada fonte de dados.

Construir o Vosso Próprio Servidor MCP

Agora vem a parte divertida: construir o nosso próprio servidor. Vou mostrar-vos como é simples criar um servidor básico em Python. A Anthropic fornece SDKs oficiais em Python, TypeScript, C#, Java, PHP, Ruby e Go.

Configuração Inicial em Python

Primeiro, vamos configurar o ambiente. Vou usar o uv, uma ferramenta moderna de gestão de pacotes Python que é extremamente rápida:

# Instalar o uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Criar o projeto
uv init meu-mcp-server
cd meu-mcp-server

# Criar ambiente virtual e instalar dependências
uv venv
source .venv/bin/activate  # No Windows: .venv\Scripts\activate
uv add "mcp[cli]" httpx

Estrutura Básica de Um Servidor MCP

Em seguida, iremos  criar um servidor simples que fornece informações sobre o sistema. Criem um ficheiro server.py:

from typing import Any
import platform
import psutil
from mcp.server.fastmcp import FastMCP

# Inicializar o servidor FastMCP
mcp = FastMCP("system-info")

@mcp.tool()
def get_system_info() -> dict[str, Any]:
    """
    Obtém informações sobre o sistema operativo e hardware.
    
    Returns:
        Dicionário com informações do sistema
    """
    return {
        "os": platform.system(),
        "os_version": platform.version(),
        "architecture": platform.machine(),
        "cpu_count": psutil.cpu_count(),
        "memory_total_gb": round(psutil.virtual_memory().total / (1024**3), 2),
        "memory_available_gb": round(psutil.virtual_memory().available / (1024**3), 2)
    }

@mcp.tool()
def get_disk_usage(path: str = "/") -> dict[str, Any]:
    """
    Obtém informações sobre o uso de disco.
    
    Args:
        path: Caminho para verificar (default: raiz)
        
    Returns:
        Informações sobre o uso de disco
    """
    usage = psutil.disk_usage(path)
    return {
        "path": path,
        "total_gb": round(usage.total / (1024**3), 2),
        "used_gb": round(usage.used / (1024**3), 2),
        "free_gb": round(usage.free / (1024**3), 2),
        "percent_used": usage.percent
    }

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

Nota importante sobre logging: Quando implementarem servidores MCP baseados em STDIO, nunca escrevam para stdout. Usem sempre stderr ou ficheiros de log. Em Python, evitem print() – usem o módulo logging em vez disso. Escrever para stdout corrompe as mensagens JSON-RPC e aterra com o servidor.

Exemplo Mais Avançado: Servidor de API REST

Vamos criar algo mais útil – um servidor que consulta uma API externa:

from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("weather-api")

@mcp.tool()
async def get_weather(city: str, country_code: str = "PT") -> dict[str, Any]:
    """
    Obtém informações meteorológicas de uma cidade.
    
    Args:
        city: Nome da cidade
        country_code: Código do país (default: PT)
        
    Returns:
        Dados meteorológicos da cidade
    """
    async with httpx.AsyncClient() as client:
        # Geocoding para obter coordenadas
        geocode_url = f"https://geocoding-api.open-meteo.com/v1/search"
        params = {"name": city, "count": 1, "language": "pt"}
        
        response = await client.get(geocode_url, params=params)
        data = response.json()
        
        if not data.get("results"):
            return {"error": f"Cidade {city} não encontrada"}
            
        location = data["results"][0]
        lat, lon = location["latitude"], location["longitude"]
        
        # Obter dados meteorológicos
        weather_url = "https://api.open-meteo.com/v1/forecast"
        weather_params = {
            "latitude": lat,
            "longitude": lon,
            "current": "temperature_2m,relative_humidity_2m,wind_speed_10m"
        }
        
        weather_response = await client.get(weather_url, params=weather_params)
        weather_data = weather_response.json()
        
        return {
            "city": location["name"],
            "country": location["country"],
            "temperature": weather_data["current"]["temperature_2m"],
            "humidity": weather_data["current"]["relative_humidity_2m"],
            "wind_speed": weather_data["current"]["wind_speed_10m"]
        }

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

Integração com OpenWebUI: A Ponte Para o Vosso LLM Local

Aqui é onde a coisa fica interessante para quem faz self-hosting. O OpenWebUI suporta nativamente MCP desde a versão 0.6.31, mas há um detalhe importante: o suporte nativo do OpenWebUI para MCP é apenas para Streamable HTTP.
A maioria dos servidores MCP usa STDIO (standard input/output) para comunicação, o que funciona perfeitamente para aplicações desktop mas não para interfaces web. É aqui que entra o mcpo (MCP to OpenAPI Proxy).

O Que É o MCPO?

O mcpo é um proxy simples e seguro que transforma qualquer servidor MCP em API compatível com OpenAPI. Basicamente, pega no vosso servidor MCP que fala STDIO e expõe-no como uma REST API que o OpenWebUI consegue consumir.

Instalar e Configurar o MCPO

A forma mais simples é usando o uvx:

# Executar o servidor weather que criámos antes através do mcpo
uvx mcpo --port 8000 --api-key "minha-chave-secreta" -- uv run server.py

Isto faz três coisas:

  1. Inicia o vosso servidor MCP
  2. Cria um proxy HTTP na porta 8000
  3. Gera automaticamente uma API OpenAPI com documentação em /docs

Podem visitar http://localhost:8000/docs e vão ver uma interface Swagger completa com todos os tools do vosso servidor documentados automaticamente.

Configurar o OpenWebUI

No OpenWebUI, naveguem para Settings → Tools e adicionem um novo Tool Server:

{
  "name": "Weather MCP Server",
  "url": "http://localhost:8000",
  "api_key": "minha-chave-secreta"
}

Nota importante: Se usarem API Key ou Auth Token, devem definir WEBUI_SECRET_KEY na configuração Docker do OpenWebUI. Se esta chave mudar, o OpenWebUI não conseguirá desencriptar as credenciais armazenadas.

Múltiplos Servidores MCP

Para gerir múltiplos servidores, basta adicionarem ao vosso OpenWebui a configuração, portos e credenciais para aceder aos mesmos.

Adaptar Servidores MCP de Terceiros

Uma das grandes vantagens do MCP é que os servidores são completamente reutilizáveis. Podem pegar em servidores feitos para o Claude Desktop e usá-los com o vosso setup de OpenWebUI através do mcpo.

Exemplo: Usar o Brave Search MCP

Muitos servidores estão disponíveis através do npm. Por exemplo, para usar o Brave Search:

# Instalar o servidor
npm install -g @modelcontextprotocol/server-brave-search

# Executar através do mcpo
uvx mcpo --port 8001 --api-key "key123" -- npx -y @modelcontextprotocol/server-brave-search

Configurem depois no OpenWebUI apontando para http://localhost:8001.

Exemplo: Servidor de Filesystem

Para dar acesso a ficheiros locais:

# Instalar
npm install -g @modelcontextprotocol/server-filesystem

# Executar (substituir /path/to/allowed/directory pelo vosso caminho)
uvx mcpo --port 8002 --api-key "key456" -- npx -y @modelcontextprotocol/server-filesystem /path/to/allowed/directory

Agora o vosso LLM pode ler e analisar ficheiros nesse diretório!

Exemplo: GitHub MCP

Para integração completa com GitHub (criar repos, issues, PRs):

# Instalar
npm install -g @modelcontextprotocol/server-github

# Executar (precisam de um Personal Access Token do GitHub)
GITHUB_PERSONAL_ACCESS_TOKEN="ghp_your_token_here" \
uvx mcpo --port 8003 --api-key "key789" -- npx -y @modelcontextprotocol/server-github

Servidor MCP em TypeScript

Para quem prefere TypeScript, aqui está um exemplo rápido:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
  {
    name: "calculator-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// Listar ferramentas disponíveis
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "add",
        description: "Soma dois números",
        inputSchema: {
          type: "object",
          properties: {
            a: { type: "number" },
            b: { type: "number" },
          },
          required: ["a", "b"],
        },
      },
    ],
  };
});

// Executar ferramentas
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "add") {
    const { a, b } = request.params.arguments as { a: number; b: number };
    return {
      content: [
        {
          type: "text",
          text: `Resultado: ${a + b}`,
        },
      ],
    };
  }
  throw new Error("Ferramenta não encontrada");
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Servidor MCP iniciado"); // stderr é seguro!
}

main().catch(console.error);

Compilem e executem através do mcpo da mesma forma que em Python.

Boas Práticas e Segurança

Ao criar servidores MCP para produção, há algumas considerações importantes:

Segurança: Os servidores MCP podem aceder a dados sensíveis e executar código. Implementem sempre autenticação robusta, validação de inputs e controlos de acesso. O mcpo suporta API keys, mas para produção considerem OAuth 2.1.
Rate Limiting: Se o vosso servidor faz chamadas a APIs externas, implementem rate limiting para evitar abusos.
Logging: Usem sempre stderr para logs em servidores STDIO. Em HTTP podem usar stdout normalmente.
Error Handling: Devolvam erros claros e informativos. O modelo precisa de entender o que correu mal.
Documentação: As descrições das vossas ferramentas devem ser claras e detalhadas. O modelo usa-as para decidir quando chamar cada ferramenta.

Debugging e Testes

A Anthropic fornece uma ferramenta chamada MCP Inspector que é invaluável para debugging:

npx @modelcontextprotocol/inspector node /path/to/your/build/index.js

Isto abre uma interface web onde podem:

  • Listar todas as ferramentas disponíveis
  • Testar cada ferramenta com inputs específicos
  • Ver os resultados em tempo real
  • Inspecionar erros e logs

Deploy em Produção

Para produção, há várias opções:

Docker: A minha favorita eCriem uma imagem Docker com o vosso servidor e o mcpo:

FROM python:3.11-slim
WORKDIR /app
RUN pip install mcpo uv
COPY server.py .
CMD ["uvx", "mcpo", "--host", "0.0.0.0", "--port", "8000", "--", "uv", "run", "server.py"]
  • Cloudflare Workers: Para servidores HTTP, os Workers são uma excelente opção de deploy serverless.
  • Kubernetes: Para ambientes enterprise, podem orquestrar múltiplos servidores MCP como microserviços.
  • Reverse Proxy: Coloquem um reverse proxy (Nginx, Traefik, Caddy) à frente do mcpo para HTTPS, load balancing e WAF.

O Futuro do MCP

O MCP está a crescer rapidamente, com suporte de grandes players como AWS, Cloudflare, Bloomberg, e Microsoft. A doação à Linux Foundation garante que se manterá aberto e neutro.
Além disso, surgem protocolos complementares como o A2A (Agent-to-Agent) para comunicação entre múltiplos agentes de AI. Juntos, estes standards estão a criar um ecossistema onde diferentes sistemas de AI podem colaborar de forma padronizada.

O Model Context Protocol representa uma mudança fundamental na forma como construímos aplicações de AI. Para quem faz self-hosting, é especialmente valioso porque:

  1. Controlo Total: Vocês controlam completamente os dados e ferramentas que expõem
  2. Reutilização: Um servidor que desenvolvem pode ser usado em múltiplas aplicações
  3. Ecossistema: Acedem a centenas de servidores já desenvolvidos pela comunidade
  4. Standard Aberto: Não estão presos a um vendor específico

Com ferramentas como o mcpo, integrar servidores MCP no vosso stack local de AI tornou-se trivial. Podem começar com servidores simples e ir adicionando complexidade à medida que as vossas necessidades crescem.
O melhor de tudo? Como isto é open source e baseado em standards, o investimento que fazem hoje em criar servidores MCP continuará válido no futuro, independentemente de qual LLM ou plataforma usarem.
Se têm um homelab, se fazem self-hosting dos vossos LLMs, ou se simplesmente querem ter controlo total sobre como a AI interage com os vossos dados, o MCP é uma ferramenta essencial no vosso arsenal.Recursos Úteis:

  • Documentação oficial MCP: https://modelcontextprotocol.io
  • Claude Directory (servidores MCP): https://www.claudedirectory.co/mcps
  • Glama MCP Servers: https://glama.ai/mcp/servers
  • MCP.so (marketplace): https://mcp.so
  • MCPO GitHub: https://github.com/open-webui/mcpo
  • OpenWebUI MCP Docs: https://docs.openwebui.com/features/mcp/

Até à próxima, e bons deploys!
Abraço
Nuno