Introdução MCP

MCP O que é? O MCP é um protocolo de comunicação open-source que padroniza a forma pela qual aplicações provém contexto e disponibilizam ferramentas as LLMs. As aplicações por sua vez podem se conectar a N servidores, permitindo uma maior variedade de contexto e de capacidades. Sua arquitetura segue o modelo client-server, sendo seus principais componentes: MCP Hosts -> Aplicações que irão consumir o conteúdo e utilizar as ferramentas disponbilizadas via MCP (Ex: Claude Desktop, IDEs ou AI Tools); MCP Clients -> Protocolo responsável pela manutenção e conexão 1:1 com o servidor (1 aplicação = N clients:N servers); MCP Servers -> Programa leve que irá expor os recursos e capacidades do MCP previamente configurados; Porque usar? De acordo com a própria documentação: "O MCP ajuda a construir agentes e worflows complexos integrados com IA, uma vez que LLMs frequentemente precisam de uma forma de se conectar a diferentes fontes de dados para contexto e ferramentas para executar ações. E o que o MCP prove?" Uma crescente lista de integrações "pré-construídas" que podem ser ligadas diretamente a sua aplicação; Flexibilidade para alterar entre diferentes provedores de LLMs; As melhores práticas para proteger seus dados, dentro da sua infraestrutura; Como usar? É possível construir clients e servers a partir de SDKs disponíveis para diferentes linguagens. Python TypeScript Java Kotlin Comunicação Interna Como explicado anteriormente, o MCP é constituído de 3 partes principais Hosts, Clients e Servers. Essas partes se comunicam através de diferentes tipos de mensagens, que por sua vez são enviadas e recebidas através do Protocol Layer e do Transport Layer. Protocol layer Camada responsável pelo recebimento e tratamento das mensagens trocadas entre client e server. Funciona de forma similar ao modelo request/response do HTTP. Transport layer Camada responsável pela real comunicação entre o client e o server. Utiliza JSON-RPC 2.0 para comunicação e segue seguinte especificação. O MCP suporta 2 formas de comunicação nativamente, stdio que consiste em termos simples na leitura e execução do arquivo contendo a configuração do server pelo próprio client, útil para processamento local e para operações que exijam leitura e escrita. E também suporta nativamente a comunicação via HTTP/SSE para os casos onde o server ficará disponível de forma remota. Além disso o MCP também permite a implementação de transports customizados. Message types O MCP possui 4 tipos de mensagens: Request - Mensagem que espera uma resposta; interface Request { method: string; params?: { ... }; } Result - Mensagem de resposta a solicitação de Request; interface Result { [key: string]: unknown; } Error - Indica que algo falhou; interface Error { code: number; message: string; data?: unknown; } Notification - Mensagens de sentido único, não esperam resposta; interface Notification { method: string; params?: { ... }; } Resources Os resources são um componente primitivo no MCP, sendo responsáveis pela exposição de dados ao client. Dados esses que podem ser textos, ou binários (que possam ser convertidos em base64) e serão lidos pelo usuário e/ou usados de contexto para LLMs. Os resources foram criados para serem controlados pela aplicação (host), dessa forma diferentes aplicações lidam com os dados de formas diferentes, sendo assim é essencial que o server esteja apito a fornecer acesso a recursos de diferentes maneiras. Por exemplo (com a própria documentação): O Claude Desktop exige que o usuário selecione explicitamente os recursos que serão consumidos pela LLM; Outras aplicaçãoes podem escolher de forma pré-definida alguns recursos; E por fim, pode ser que a própria LLM escolha quais recursos irá usar; Entre as maneiras de acesso estão a forma direta, acessando um resource através de sua URI, e a forma dinâmica através de templates de URI. A URI por sua vez é a forma de identificação de um recurso, sendo estruturada da seguinte forma [protocol]://[host]/[path]. Exemplo (da própria documentação) const server = new Server({ name: "example-server", version: "1.0.0" }, { capabilities: { resources: {} } }); // List available resources server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { uri: "file:///logs/app.log", name: "Application Logs", mimeType: "text/plain" } ] }; }); // Read resource contents server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const uri = request.params.uri; if (uri === "file:///logs/app.log") { const logContents = await readLogFile(); return { contents: [ { uri, mimeType: "text/plain", text: logContents } ] }; } throw new Error("Resource no

Mar 27, 2025 - 21:22
 0
Introdução MCP

MCP

O que é?

O MCP é um protocolo de comunicação open-source que padroniza a forma pela qual aplicações provém contexto e disponibilizam ferramentas as LLMs. As aplicações por sua vez podem se conectar a N servidores, permitindo uma maior variedade de contexto e de capacidades.

Sua arquitetura segue o modelo client-server, sendo seus principais componentes:

  • MCP Hosts -> Aplicações que irão consumir o conteúdo e utilizar as ferramentas disponbilizadas via MCP (Ex: Claude Desktop, IDEs ou AI Tools);
  • MCP Clients -> Protocolo responsável pela manutenção e conexão 1:1 com o servidor (1 aplicação = N clients:N servers);
  • MCP Servers -> Programa leve que irá expor os recursos e capacidades do MCP previamente configurados;

Porque usar?

De acordo com a própria documentação: "O MCP ajuda a construir agentes e worflows complexos integrados com IA, uma vez que LLMs frequentemente precisam de uma forma de se conectar a diferentes fontes de dados para contexto e ferramentas para executar ações. E o que o MCP prove?"

  • Uma crescente lista de integrações "pré-construídas" que podem ser ligadas diretamente a sua aplicação;
  • Flexibilidade para alterar entre diferentes provedores de LLMs;
  • As melhores práticas para proteger seus dados, dentro da sua infraestrutura;

Como usar?

É possível construir clients e servers a partir de SDKs disponíveis para diferentes linguagens.

Comunicação Interna

Como explicado anteriormente, o MCP é constituído de 3 partes principais Hosts, Clients e Servers. Essas partes se comunicam através de diferentes tipos de mensagens, que por sua vez são enviadas e recebidas através do Protocol Layer e do Transport Layer.

Protocol layer

Camada responsável pelo recebimento e tratamento das mensagens trocadas entre client e server. Funciona de forma similar ao modelo request/response do HTTP.

Transport layer

Camada responsável pela real comunicação entre o client e o server. Utiliza JSON-RPC 2.0 para comunicação e segue seguinte especificação.

O MCP suporta 2 formas de comunicação nativamente, stdio que consiste em termos simples na leitura e execução do arquivo contendo a configuração do server pelo próprio client, útil para processamento local e para operações que exijam leitura e escrita. E também suporta nativamente a comunicação via HTTP/SSE para os casos onde o server ficará disponível de forma remota.

Além disso o MCP também permite a implementação de transports customizados.

Message types

O MCP possui 4 tipos de mensagens:

Request - Mensagem que espera uma resposta;

interface Request {
  method: string;
  params?: { ... };
}

Result - Mensagem de resposta a solicitação de Request;

interface Result {
  [key: string]: unknown;
}

Error - Indica que algo falhou;

interface Error {
  code: number;
  message: string;
  data?: unknown;
}

Notification - Mensagens de sentido único, não esperam resposta;

interface Notification {
  method: string;
  params?: { ... };
}

Resources

Os resources são um componente primitivo no MCP, sendo responsáveis pela exposição de dados ao client. Dados esses que podem ser textos, ou binários (que possam ser convertidos em base64) e serão lidos pelo usuário e/ou usados de contexto para LLMs.

Os resources foram criados para serem controlados pela aplicação (host), dessa forma diferentes aplicações lidam com os dados de formas diferentes, sendo assim é essencial que o server esteja apito a fornecer acesso a recursos de diferentes maneiras. Por exemplo (com a própria documentação):

  • O Claude Desktop exige que o usuário selecione explicitamente os recursos que serão consumidos pela LLM;
  • Outras aplicaçãoes podem escolher de forma pré-definida alguns recursos;
  • E por fim, pode ser que a própria LLM escolha quais recursos irá usar;

Entre as maneiras de acesso estão a forma direta, acessando um resource através de sua URI, e a forma dinâmica através de templates de URI. A URI por sua vez é a forma de identificação de um recurso, sendo estruturada da seguinte forma [protocol]://[host]/[path].

Exemplo (da própria documentação)

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

// List available resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: [
      {
        uri: "file:///logs/app.log",
        name: "Application Logs",
        mimeType: "text/plain"
      }
    ]
  };
});

// Read resource contents
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const uri = request.params.uri;

  if (uri === "file:///logs/app.log") {
    const logContents = await readLogFile();
    return {
      contents: [
        {
          uri,
          mimeType: "text/plain",
          text: logContents
        }
      ]
    };
  }

  throw new Error("Resource not found");
});

Prompts

Os prompts permitem definir no server templates de prompts reutilizáveis, bem como workflows que podem ser acionados pelo usuário, ou pela LLM, através do client. Um prompt pode aceitar argumentos dinâmicos, incluir contexto de resources, encadear múltiplas interações e guiar o usuário/LLM através de workflows.

Exemplo (da própria documentação)

import { Server } from "@modelcontextprotocol/sdk/server";
import {
  ListPromptsRequestSchema,
  GetPromptRequestSchema
} from "@modelcontextprotocol/sdk/types";

const PROMPTS = {
  "git-commit": {
    name: "git-commit",
    description: "Generate a Git commit message",
    arguments: [
      {
        name: "changes",
        description: "Git diff or description of changes",
        required: true
      }
    ]
  },
  "explain-code": {
    name: "explain-code",
    description: "Explain how code works",
    arguments: [
      {
        name: "code",
        description: "Code to explain",
        required: true
      },
      {
        name: "language",
        description: "Programming language",
        required: false
      }
    ]
  }
};

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

// List available prompts
server.setRequestHandler(ListPromptsRequestSchema, async () => {
  return {
    prompts: Object.values(PROMPTS)
  };
});

// Get specific prompt
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
  const prompt = PROMPTS[request.params.name];
  if (!prompt) {
    throw new Error(`Prompt not found: ${request.params.name}`);
  }

  if (request.params.name === "git-commit") {
    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `Generate a concise but descriptive commit message for these changes:\n\n${request.params.arguments?.changes}`
          }
        }
      ]
    };
  }

  if (request.params.name === "explain-code") {
    const language = request.params.arguments?.language || "Unknown";
    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `Explain how this ${language} code works:\n\n${request.params.arguments?.code}`
          }
        }
      ]
    };
  }

  throw new Error("Prompt implementation not found");
});

Tools

As tools permitem que as LLMs executem ações de forma quase 100% autonoma, apenas com a necessidade de um humano no fluxo por questão de design. Através das tools é possível realizar qualquer ação desde que ela retorne uma resposta.

Exemplo (da própria documentação)

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

// Define available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [{
      name: "calculate_sum",
      description: "Add two numbers together",
      inputSchema: {
        type: "object",
        properties: {
          a: { type: "number" },
          b: { type: "number" }
        },
        required: ["a", "b"]
      }
    }]
  };
});

// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "calculate_sum") {
    const { a, b } = request.params.arguments;
    return {
      content: [
        {
          type: "text",
          text: String(a + b)
        }
      ]
    };
  }
  throw new Error("Tool not found");
});