O Model Context Protocol (MCP) está a fazer pela integração entre IAs e ferramentas externas o que o HTTP fez pela web: estabelecer um padrão universal. Se trabalhas com IA agentica, este artigo vai mudar a forma como pensas integrações.

Imagina que tens um assistente de IA que precisa de ler ficheiros do teu projeto, consultar a base de dados, criar PRs no GitHub e ver erros no Sentry: tudo na mesma conversa. Até há bem pouco tempo, cada uma destas integrações era feita de forma ad-hoc, com código específico para cada combinação de modelo e ferramenta.

Foi para resolver este caos que a Anthropic criou o Model Context Protocol (MCP): um protocolo aberto que standardiza a comunicação entre modelos de linguagem (LLMs) e sistemas externos. Desde o seu lançamento em Novembro de 2024, o MCP tornou-se o standard de facto para integração de IAs com ferramentas, com mais de 86.000 estrelas no GitHub e centenas de servidores disponíveis.

Vou mostrar-te:

  • O que é o MCP e como funciona a sua arquitetura
  • Vantagens e desvantagens em relação a integrações tradicionais
  • Os 10 servidores MCP essenciais para o teu setup
  • Como criar o teu próprio servidor MCP em TypeScript
  • Diferenças de configuração entre OpenCode e Claude Desktop
  • Boas práticas para usares MCP em produção

Arquitetura MCP

⬆ Arquitetura MCP: Host, Clients e Servers num ecossistema padronizado


O que é o mcp?

O Model Context Protocol (MCP) é um protocolo aberto, desenvolvido pela Anthropic, que standardiza a forma como aplicações de IA se conectam a fontes de dados e ferramentas externas. Pensa nele como um LSP (Language Server Protocol): mas para IAs em vez de editores de código.

O MCP define uma camada de comunicação baseada em JSON-RPC 2.0, onde aplicações de IA (os hosts) podem descobrir e invocar dinamicamente as capacidades expostas por servidores MCP. Isto inclui:

  • Tools: funções que o LLM pode executar (ex: ler um ficheiro, fazer uma query à BD)
  • Resources: dados e contexto que o LLM pode consultar (ex: schema da BD, documentação)
  • Prompts: templates de mensagens para workflows reutilizáveis

O protocolo funciona sobre dois transportes principais: stdio para servidores locais (o servidor corre como processo filho) e SSE (Server-Sent Events) para servidores remotos. Desde a versão mais recente, também suporta Streamable HTTP para maior flexibilidade.

Nota: O MCP é completamente open-source (Apache 2.0 / MIT) e independente de qualquer modelo ou fornecedor. Isto significa que podes usar o mesmo servidor MCP com Claude, GPT, Gemini, ou qualquer outro modelo compatível.


Arquitetura

A arquitetura do MCP segue um modelo cliente-servidor com três papéis distintos, inspirado no LSP. Cada componente tem responsabilidades bem definidas:

Componentes principais

Host: é a aplicação que contém o ecossistema. Pode ser o Claude Desktop, o OpenCode, um IDE como o VS Code, ou qualquer app que queira usar MCP. O Host gere os clients, aplica políticas de segurança e coordena o ciclo de vida.

Client: cada client mantém uma sessão 1:1 com um servidor MCP específico. É responsável por negociar capacidades, fazer o handshake JSON-RPC, e encaminhar mensagens bidirecionais. Um Host pode ter múltiplos clients ativos.

Server: é onde a mágica acontece. Cada servidor expõe tools, resources e prompts através do protocolo MCP. Pode ser um processo local (stdio) ou um serviço remoto (SSE). Os servidores são altamente especializados: um para ficheiros, outro para base de dados, outro para GitHub, etc.

A comunicação é feita exclusivamente por JSON-RPC 2.0, com mensagens request/response. O cliente descobre as capacidades do servidor na inicialização (negociação de capacidades) e depois pode invocar tools ou aceder a resources dinamicamente.

Negociação de capacidades

Quando um cliente se conecta a um servidor MCP, ocorre um processo de handshake onde ambas as partes declaram o que suportam:

  • O servidor declara: resources.subscribe, tools, prompts
  • O cliente declara: sampling, roots, elicitation
  • Ambos respeitam os limites declarados durante toda a sessão

Isto permite que servidores e clientes evoluam independentemente, mantendo compatibilidade para trás. Um servidor antigo funciona com um cliente novo, e vice-versa.

Fluxo de chamada MCP

⬆ Fluxo de uma chamada MCP: do utilizador ao servidor e de volta ao LLM


Porquê mcp?

Antes do MCP, cada integração de IA com ferramentas externas era um caso único. Querias que o Claude lesse ficheiros? Escrevias código específico para o Claude. Querias que o GPT pesquisasse na base de dados? Outra integração. Cada modelo, cada ferramenta, cada cenário: tudo código diferente.

Dimensão Antes do MCP Com MCP
IntegraçõesAd-hoc, específicas de cada modeloProtocolo universal
DescobertaTools definidas no código do clienteDinâmica (tools/list)
ReutilizaçãoNula: cada integração serve um modeloUm servidor serve qualquer cliente
SegurançaCada tool com o seu sistemaSandboxing por processo
ManutençãoN integrações × M modelosN servidores, qualquer cliente
EcosistemaFragmentado1000+ servidores disponíveis

O MCP é, essencialmente, um padrão de integração. Tal como o LSP unificou o suporte a linguagens de programação em todos os IDEs, o MCP unifica o acesso a ferramentas e dados por parte de todas as IAs.

MCP vs Tradicional

⬆ Comparação visual: antes (integracões manuais e fragmentadas) vs depois (MCP unifica tudo)


Vantagens do MCP

1. Padronização

O MCP define um contrato claro entre clientes e servidores. Isto significa que qualquer servidor MCP funciona com qualquer cliente MCP: seja o Claude Desktop, OpenCode, VS Code, Cline, ou qualquer outra ferramenta. Um protocolo para todas as integrações.

2. Descoberta Dinâmica

O cliente não precisa de saber à partida o que cada servidor oferece. Na inicialização, faz tools/list e o servidor responde com as tools disponíveis e os seus schemas de input. O LLM descobre as ferramentas em runtime e decide quais usar com base na descrição.

3. Segurança

Cada servidor MCP corre no seu próprio processo, com o seu próprio sandboxing. Isto significa que um servidor de ficheiros não tem acesso à rede, e um servidor de GitHub não tem acesso ao sistema de ficheiros local (a menos que configures). O Host aplica políticas de consentimento e autorização.

4. Extensibilidade

Qualquer pessoa pode criar um servidor MCP. Tens SDKs oficiais em TypeScript, Python, Go, Java, Rust, C#, Kotlin, Swift, PHP e Ruby. Basta implementares o protocolo JSON-RPC e expores as tuas tools.

5. Composabilidade

Podes ter múltiplos servidores no mesmo Host: um para filesystem, outro para base de dados, outro para GitHub. Cada um faz o seu trabalho, isolado dos outros, e o Host coordena tudo. Adicionar um servidor novo não afecta os existentes.


Desvantagens e limitações

Nem tudo são rosas. O MCP tem limitações que deves conhecer antes de o adoptares:

1. Latência

Cada chamada a uma tool MCP passa por serialização JSON-RPC, transporte (stdio ou HTTP), deserialização, execução, e resposta. Isto tem mais overhead do que uma chamada direta a uma API. Para operações simples que precisas de rapidez, pode ser perceptível.

2. Complexidade

Para cenários simples: como executar um comando ou ler um ficheiro: configurar um servidor MCP é mais trabalho do que fazer a chamada diretamente. O MCP brilha em ecossistemas complexos com múltiplas integrações, não em casos isolados.

3. Ecossistema Jovem

Apesar de já existirem mais de 1000 servidores no MCP Registry, o ecossistema ainda é recente (lançado em Novembro de 2024). Muitos servidores são experimentais, e a qualidade varia. REST APIs, por comparação, têm décadas de maturidade.

4. Debugging

Quando algo corre mal, tens de debuggar o fluxo completo: Cliente → JSON-RPC → stderr/stdout do servidor → ferramenta → resposta. O stack trace raramente é claro. Ferramentas como opencode mcp debug ajudam, mas ainda há caminho a percorrer.

5. Dependência do Runtime

Para correr servidores MCP locais, precisas de ter Node.js, Python, Go, ou o runtime apropriado instalado. Isto adiciona complexidade à configuração, especialmente em equipas ou ambientes CI/CD.


MCPs must have em todo o setup

Aqui estão os servidores MCP que considero essenciais para qualquer developer que use IAs agenticas no seu dia-a-dia.

Servidor Função Transporte Essencial
filesystemAcesso a ficheiros locaisstdio MUST
githubPRs, issues, repositóriosstdio/SSE MUST
puppeteerAutomação de browserstdio MUST
sqlite/postgresAcesso a bases de dadosstdio MUST
memoryPersistência de contextostdio Recomendado
fetch/webRequisições HTTPstdio MUST
terminalComandos no sistemastdio Cuidado
dockerGestão de containersstdio Recomendado
sentryError trackingSSE (remoto) Recomendado
jira/linearGestão de tarefasSSE (remoto) Recomendado

Filesystem

O servidor de filesystem é a base de tudo. Permite ao LLM ler, escrever, pesquisar e listar ficheiros no sistema local. É essencial para qualquer interação com o projeto: sem ele, o modelo não consegue ver o teu código.

// opencode.json / claude_desktop_config.json
"mcp": {
  "filesystem": {
    "type": "local",
    "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/caminho/do/projeto"]
  }
}
Copy

GitHub

Gerir repositórios, criar e rever PRs, listar issues, fazer code review: tudo diretamente pelo teu assistente de IA. O servidor GitHub integration permite controlo quase total sobre o teu workflow de desenvolvimento.

"mcp": {
  "github": {
    "type": "local",
    "command": ["npx", "-y", "@modelcontextprotocol/server-github"],
    "environment": {
      "GITHUB_PERSONAL_ACCESS_TOKEN": "{env:GITHUB_TOKEN}"
    }
  }
}
Copy

Puppeteer / Playwright

Browser automation: navegar em páginas web, tirar screenshots, extrair dados, preencher formulários, testar aplicações. É o teu "olhos" para o mundo web.

"mcp": {
  "puppeteer": {
    "type": "local",
    "command": ["npx", "-y", "@modelcontextprotocol/server-puppeteer"]
  }
}
Copy

SQLite / PostgreSQL

Acesso a bases de dados: executar queries, inspecionar schemas, fazer migrações. O servidor PostgreSQL é read-only por segurança, o que permite consultar dados sem risco de alterações acidentais.

// SQLite
"mcp": {
  "sqlite": {
    "type": "local",
    "command": ["uvx", "mcp-server-sqlite", "--db-path", "./data.db"]
  }
}

// PostgreSQL
"mcp": {
  "postgres": {
    "type": "local",
    "command": ["npx", "-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
  }
}
Copy

Memory

O servidor Memory mantém um grafo de conhecimento persistente entre sessões. Isto significa que o modelo "lembra-se" de preferências, decisões de arquitetura, e contexto entre conversas. É um game changer para projetos de longo prazo.

"mcp": {
  "memory": {
    "type": "local",
    "command": ["npx", "-y", "@modelcontextprotocol/server-memory"]
  }
}
Copy

Fetch / Web

Fazer requisições HTTP a APIs externas, buscar documentação, consultar endpoints REST. Essencial para integração com serviços web: é a "porta de saída" do teu LLM para a internet.

"mcp": {
  "fetch": {
    "type": "local",
    "command": ["npx", "-y", "@modelcontextprotocol/server-fetch"]
  }
}
Copy

Terminal / Shell

Executar comandos no sistema. É a tool mais poderosa (e mais perigosa). Permite correr scripts, compilar código, fazer deploy, etc. Requer cuidado: configura permissões adequadas.

"mcp": {
  "terminal": {
    "type": "local",
    "command": ["npx", "-y", "@anthropic/mcp-terminal"],
    "enabled": true
  }
}
Copy

Docker

Gerir containers Docker: listar, iniciar, parar, inspecionar imagens, gerir docker-compose. Indispensável para quem trabalha com containers no dia-a-dia.

"mcp": {
  "docker": {
    "type": "local",
    "command": ["npx", "-y", "mcp-docker"]
  }
}
Copy

Sentry

Debug de erros em produção: listar issues, ver stack traces, analisar logs. O Sentry MCP é remoto e usa OAuth, o que o torna seguro e fácil de configurar.

"mcp": {
  "sentry": {
    "type": "remote",
    "url": "https://mcp.sentry.dev/mcp",
    "oauth": {}
  }
}
Copy

Jira / Linear

Gestão de tarefas integrada no teu assistente de IA: criar issues, atualizar sprints, comentar em tarefas, consultar o backlog. Menos contexto switching entre o código e o project management.

"mcp": {
  "linear": {
    "type": "remote",
    "url": "https://mcp.linear.app/mcp",
    "oauth": {}
  }
}
Copy

Ecossistema MCP

⬆ Ecossistema MCP: servidores populares organizados por categoria


Como criar um servidor MCP personalizado

Vamos criar um servidor MCP em TypeScript que expõe tools para calcular métricas de código: contagem de linhas, complexidade ciclomática, etc. Este exemplo serve de template para qualquer servidor personalizado.

1. Setup do Projeto

mkdir mcp-code-metrics && cd mcp-code-metrics
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
npx tsc --init --outDir dist --rootDir src
Copy

2. Servidor MCP com Tools

// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { readFileSync, statSync } from "fs";
import { glob } from "glob";

// --- Schemas de input com Zod ---
const CountLinesSchema = z.object({
  path: z.string().describe("Caminho do ficheiro a analisar"),
});

const CountFilesSchema = z.object({
  pattern: z.string().describe("Glob pattern (ex: src/**/*.ts)"),
});

// --- Server MCP ---
const server = new Server(
  { name: "code-metrics", version: "1.0.0" },
  { capabilities: { tools: {}, resources: {} } }
);

// --- List Tools Handler ---
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "count_lines",
      description: "Conta linhas de código num ficheiro",
      inputSchema: {
        type: "object",
        properties: {
          path: { type: "string", description: "Caminho do ficheiro" },
        },
        required: ["path"],
      },
    },
    {
      name: "count_files",
      description: "Conta ficheiros que correspondem a um padrão glob",
      inputSchema: {
        type: "object",
        properties: {
          pattern: { type: "string", description: "Glob pattern" },
        },
        required: ["pattern"],
      },
    },
    {
      name: "health_check",
      description: "Verifica se o servidor está operacional",
      inputSchema: {
        type: "object",
        properties: {},
      },
    },
  ],
}));

// --- Call Tool Handler ---
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case "count_lines": {
      const { path } = CountLinesSchema.parse(args);
      const content = readFileSync(path, "utf-8");
      const lines = content.split("
").length;
      return {
        content: [{ type: "text", text: `O ficheiro ${path} tem ${lines} linhas.` }],
      };
    }

    case "count_files": {
      const { pattern } = CountFilesSchema.parse(args);
      const files = await glob(pattern, { nodir: true });
      return {
        content: [{ type: "text", text: `Encontrei ${files.length} ficheiros para o padrão "${pattern}".` }],
      };
    }

    case "health_check": {
      return {
        content: [{ type: "text", text: "✅ Servidor code-metrics operacional." }],
        isError: false,
      };
    }

    default:
      throw new Error(`Tool desconhecida: ${name}`);
  }
});

// --- Health Check Resource ---
server.setRequestHandler("resources/list", async () => ({
  resources: [
    {
      uri: "metrics://health",
      name: "Health Status",
      description: "Estado atual do servidor",
      mimeType: "application/json",
    },
  ],
}));

// --- Resource Reader ---
server.setRequestHandler("resources/read", async (request) => {
  if (request.params.uri === "metrics://health") {
    return {
      contents: [
        {
          uri: "metrics://health",
          mimeType: "application/json",
          text: JSON.stringify({
            status: "healthy",
            uptime: process.uptime(),
            version: "1.0.0",
            memoryUsage: process.memoryUsage().heapUsed,
          }),
        },
      ],
    };
  }
  throw new Error("Resource não encontrado");
});

// --- Startup ---
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("🚀 Servidor MCP code-metrics pronto (stdio)");
}

main().catch((error) => {
  console.error("Erro fatal:", error);
  process.exit(1);
});
Copy

3. Compilar e Correr

npx tsc
node dist/index.js
Copy

4. Adicionar ao OpenCode ou Claude Desktop

"mcp": {
  "code-metrics": {
    "type": "local",
    "command": ["node", "/caminho/absoluto/mcp-code-metrics/dist/index.js"]
  }
}
Copy

E pronto! Tens um servidor MCP funcional. O teu LLM pode agora contar linhas e ficheiros do projeto: e com algumas linhas extras, podias adicionar suporte para ESLint, Prettier, ou qualquer outra ferramenta.

Dica: Para servidores Python, usa o SDK oficial mcp (pip install mcp). A estrutura é semelhante: decoradores para tools/resources, e um transport (stdio ou SSE).


MCP no OpenCode vs claude desktop

O OpenCode e o Claude Desktop são dois dos clientes MCP mais usados. Embora ambos suportem o mesmo protocolo, a abordagem de configuração é diferente.

Característica OpenCode Claude Desktop
Ficheiro configopencode.json (projeto)
ou ~/.config/opencode/opencode.json
claude_desktop_config.json
em ~/Library/Application Support/Claude/
Chave no JSON"mcp": { ... }"mcpServers": { ... }
Servidores locaistype: "local" com command: [ ... ]"command": "npx" com "args": [ ... ]
Servidores remotostype: "remote" com url e headersSuporte limitado (principalmente stdio)
OAuthAutomático + opencode mcp authManual
Glob patterns "tools": { "mcp*": false } Apenas disable individual
Per agent Ativar/desativar MCP por agente Global apenas
Variáveis de ambiente"environment": { "KEY": "{env:VAR}" }"env": { "KEY": "value" }

A principal diferença está na filosofia: o OpenCode foi desenhado para ser um cliente MCP de primeira classe, com suporte nativo a servidores remotos, OAuth, e controlo granular por agente. O Claude Desktop é mais simples, focado em servidores locais com stdio.

Exemplo de configuração para OpenCode:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "filesystem": {
      "type": "local",
      "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."],
      "enabled": true
    },
    "github": {
      "type": "local",
      "command": ["npx", "-y", "@modelcontextprotocol/server-github"],
      "environment": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "{env:GITHUB_TOKEN}"
      },
      "enabled": true
    },
    "sentry": {
      "type": "remote",
      "url": "https://mcp.sentry.dev/mcp",
      "oauth": {}
    }
  },
  "tools": {
    "filesystem": true,
    "github*": true
  }
}
Copy

Exemplo de configuração para Claude Desktop:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."
      }
    }
  }
}
Copy

Boas práticas

Depois de meses a usar MCP no dia-a-dia, aqui estão as práticas que mais impacto tiveram na minha produtividade:

1. Um Servidor MCP por Responsabilidade

Cada servidor deve fazer uma coisa e fazê-la bem. Não cries um servidor monolítico que faz tudo: cria servidores especializados (filesystem, DB, GitHub, etc.) e combina-os no Host. Isto segue o princípio da single responsibility e facilita a manutenção.

2. stdio para Local, SSE para Remoto

Para servidores que correm na mesma máquina (filesystem, terminal, DB local), usa stdio transport: é mais rápido, mais seguro, e não precisas de gerir portas. Para servidores externos (GitHub, Sentry, Jira), usa SSE ou Streamable HTTP.

3. Schemas de Input Bem Tipados

Usa Zod (TypeScript) ou Pydantic (Python) para validar os parâmetros das tools. Um schema bem definido ajuda o LLM a perceber o que precisa de passar e evita erros de runtime. Inclui descrições claras em cada campo.

4. Timeout Razoável

Nunca defines timeouts superiores a 60 segundos para ferramentas síncronas. O LLM está à espera de uma resposta: se a ferramenta demora muito, a conversa fica bloqueada. Para operações longas, usa um padrão assíncrono com polling ou callbacks.

// Exemplo de timeout no OpenCode
"mcp": {
  "meu-servidor": {
    "type": "local",
    "command": ["...", "..."],
    "timeout": 30000  // 30 segundos
  }
}
Copy

5. Logging Adequado

Os servidores MCP usam stderr para logging (o stdout é reservado para o protocolo JSON-RPC). Usa console.error() para logs de debug, e configura níveis de log para não poluíres a saída em produção.

6. Tratar Erros Gracefully

Todas as tools devem devolver respostas estruturadas mesmo em caso de erro. Isto permite ao LLM perceber o que correu mal e, potencialmente, corrigir e tentar de novo.

// Sempre devolver uma resposta estruturada
try {
  const result = await operacaoRiscada();
  return { content: [{ type: "text", text: result }] };
} catch (error) {
  return {
    content: [{ type: "text", text: `Erro: ${error.message}` }],
    isError: true,
  };
}
Copy

7. Tool Annotations

Desde a especificação mais recente, podes anotar as tuas tools com metadados que ajudam o LLM a decidir quando usá-las: readOnlyHint, idempotentHint, destructiveHint, openWorldHint. Isto melhora significativamente a qualidade das decisões do modelo.


Conclusão

O Model Context Protocol é, neste momento, a aposta mais sólida para o futuro da integração entre IAs e ferramentas externas. Tal como o HTTP standardizou a comunicação na web e o LSP unificou o suporte a linguagens nos IDEs, o MCP está a fazer o mesmo para o ecossistema de IA.

As vantagens são claras: padronização, descoberta dinâmica, segurança por isolamento, extensibilidade e composabilidade. O ecossistema já conta com mais de 1000 servidores, e o número cresce todas as semanas. Desde servidores essenciais como filesystem e GitHub, a integrações especializadas como Sentry e Jira, há um MCP para praticamente tudo.

Claro que não é perfeito. A latência do JSON-RPC, a complexidade inicial, e a maturidade ainda em desenvolvimento são fatores a considerar. Mas para qualquer pessoa que trabalhe seriamente com IA agentica, o MCP já não é uma opção: é uma necessidade.

O que fazer agora?

  • Se usas Claude Desktop, começa por adicionar os servidores Filesystem e GitHub
  • Se usas OpenCode, explora a configuração de MCPs remotos com OAuth
  • Se tens uma ferramenta interna, cria o teu próprio servidor MCP: o SDK TypeScript é simples e bem documentado
  • Partilha os teus servidores no MCP Registry e contribui para o ecossistema

O futuro da IA não é sobre modelos maiores: é sobre modelos melhor conectados. E o MCP é o protocolo que está a construir essas pontes.


Recursos

Comentários (0)

Nenhum comentário ainda. Seja o primeiro!

Deixar comentário