Documentação

Construa sobre o MCPEmails

Tudo o que um cliente MCP faz, um script pode fazer com HTTPS comum. Um endpoint, uma chave de API, JSON na entrada e JSON na saída. Este guia cobre autenticação, as três chamadas de que você precisa, erros, novas tentativas, limites e webhooks para e-mails novos.

O endpoint

Toda requisição é um POST JSON-RPC 2.0 para https://mcpemails.com/api/mcp. É o mesmo endpoint que o claude.ai, o ChatGPT e outros clientes MCP usam, com as mesmas ferramentas e as mesmas permissões, então um script e um assistente de chat enxergam um único produto.

  • Envie Content-Type: application/json e Accept: application/json. A resposta é um único objeto JSON.
  • O servidor não mantém sessão. Não há nada para abrir ou fechar, e cada requisição leva seu próprio cabeçalho Authorization.
  • Os resultados bem-sucedidos das ferramentas trazem um objeto tipado structuredContent, então você nunca precisa interpretar texto corrido. Os mesmos dados estão em content[0].text como uma string JSON.

Autenticação

Chaves de API

  • Crie uma chave no painel em Chaves de API → Nova chave. Dê a ela o nome do script ou fluxo de trabalho que vai usá-la.
  • Uma chave é mcpe_ seguido de 64 caracteres hexadecimais. Ela aparece uma única vez, quando você a cria, e só um hash fica armazenado. Copie-a nesse momento; uma chave perdida não pode ser recuperada, só substituída.
  • Envie-a em toda requisição como Authorization: Bearer mcpe_.... Nunca coloque uma chave em uma URL ou em uma query string.
  • Todos os planos podem criar quantas chaves precisarem. Use uma chave por script ou fluxo de trabalho, para poder revogar uma sem mexer nas outras.
  • Revogar uma chave na página Chaves de API encerra o acesso na hora.

Escopos

Cada chave tem só as permissões que você marca ao criá-la. Você pode alterá-las depois em Editar acesso, e a mudança vale a partir da próxima chamada, sem reconectar.

EscopoPermite
read:emailListar, ler e pesquisar mensagens, baixar anexos, listar caixas de entrada e pastas.
search:emailMantido para chaves antigas. A pesquisa já está coberta por read:email.
send:emailEnviar, responder e encaminhar.
manage:draftsCriar, atualizar e excluir rascunhos. Enviar um rascunho também exige send:email.
manage:foldersMover, copiar, sinalizar e arquivar mensagens; criar, renomear e excluir pastas.
delete:emailExcluir mensagens, uma a uma ou em massa.
manage:contactsPesquisar contatos nos seus e-mails recentes.
schedule:emailAgendar envios e gerenciar e-mails agendados.
manage:automationsCriar regras que rodam em um horário programado sem ninguém acompanhando.

Comece com read:email e adicione um escopo de escrita só quando o fluxo de trabalho precisar. Uma chamada fora dos escopos da chave é recusada antes de entrarmos em contato com o seu servidor de e-mail. Visualizadores de um espaço de trabalho só podem ter escopos de leitura.

Acesso às caixas de entrada

Por padrão, uma chave alcança todas as caixas de entrada do espaço de trabalho. Para restringi-la a algumas delas, abra Editar acesso na chave e escolha as caixas em Acesso às caixas de entrada. O limite é verificado em toda chamada, então uma chave restrita à caixa de suporte não consegue ler a do financeiro, diga o que disser a requisição.

OAuth para apps de conector

Apps que as próprias pessoas conectam, como o claude.ai, o ChatGPT e outros clientes MCP, entram com OAuth em vez de uma chave: registro dinâmico de cliente, código de autorização com PKCE e uma tela de consentimento onde o usuário escolhe os escopos e as caixas de entrada. Veja Conexão OAuth. Para os seus próprios scripts, servidores e fluxos de trabalho, uma chave de API é mais simples.

As três chamadas

1. initialize (opcional)

Clientes MCP começam com initialize. Um script pode pular essa etapa, porque o servidor não mantém sessão, mas ela é uma forma barata de conferir se a chave funciona e de ler as instruções do servidor.

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "clientInfo": { "name": "my-agent", "version": "1.0" },
      "capabilities": {}
    }
  }'

2. tools/list

tools/list retorna todas as ferramentas que essa chave pode chamar, com a descrição, o schema de entrada e o schema de saída de cada uma. Leia a lista na inicialização em vez de fixar nomes de ferramentas ou argumentos no código: ela é filtrada pelos escopos da chave, e as ferramentas ganham argumentos com o tempo.

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'

3. tools/call

Chame uma ferramenta pelo nome com seus argumentos. A maioria das ferramentas recebe uma action que define o que ela faz, como list, read ou search em email_read. Indique a caixa de correio com inbox (o endereço) ou inbox_id; inbox_list retorna os dois.

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "email_read",
      "arguments": { "action": "list", "inbox": "you@example.com", "unread": true, "limit": 20 }
    }
  }'

Um resultado bem-sucedido:

JSON
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{ "type": "text", "text": "{\"messages\":[...],\"total\":42, ...}" }],
    "structuredContent": {
      "messages": [{ "id": "...", "subject": "...", "from": { "name": "...", "email": "..." } }],
      "total": 42,
      "total_is_estimate": false,
      "has_more": true,
      "next_offset": 20
    }
  }
}

A referência de ferramentas descreve cada ferramenta, e o guia de curl tem mais exemplos.

Erros

Há dois tipos. Uma requisição que nem chegou a rodar volta como um error JSON-RPC com um status HTTP. Uma requisição que chegou a uma ferramenta e foi recusada por ela volta como um result normal com isError: true, para que um modelo de IA leia o motivo. Tome decisões com base em data.error_code ou no código em _meta, não no texto da mensagem.

RespostaQuandoO que fazer
HTTP 401, -32001Chave ausente, malformada, revogada ou expirada.Corrija o cabeçalho Authorization ou crie uma chave nova. Tentar de novo não resolve.
HTTP 403, -32004, insufficient_scopeFalta à chave um escopo de que essa ação da ferramenta precisa. data.required_scopes lista o que a permitiria.Adicione o escopo em Editar acesso ou use outra chave.
HTTP 429, -32003, rate_limit_exceededRequisições demais. data.window diz qual janela encheu.Espere os segundos de Retry-After (também em data.retry_after) e repita a mesma requisição.
-32602Nome de ferramenta desconhecido. data.available_tools lista os nomes que essa chave pode chamar.Use um nome de tools/list.
isError: true, invalid_argumentsOs argumentos não passaram no schema da ferramenta. Nada foi executado. O texto aponta cada argumento inválido e, quando o nome de um argumento foi chutado, indica o que existe.Corrija os argumentos. Os mesmos argumentos são rejeitados do mesmo jeito.
isError: true, usage_limit_reachedUm espaço de trabalho Free usou suas ações de e-mail do mês.Espere a data de renovação em _meta ou faça upgrade. Os planos pagos têm ações de e-mail ilimitadas.
isError: true, outroA ferramenta rodou e falhou: mensagem não encontrada, provedor recusou, destinatário inválido e assim por diante.Leia content[0].text. Ele diz o que aconteceu e se algo foi enviado.
HTTP
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", ...

{
  "jsonrpc": "2.0",
  "id": 4,
  "error": {
    "code": -32004,
    "message": "Insufficient scope: the 'send:email' scope is required to call email_compose.",
    "data": { "error_code": "insufficient_scope", "required_scopes": ["send:email"], ... }
  }
}
HTTP
HTTP/1.1 429 Too Many Requests
Retry-After: 12

{
  "jsonrpc": "2.0",
  "id": 5,
  "error": {
    "code": -32003,
    "message": "Rate limit exceeded",
    "data": { "error_code": "rate_limit_exceeded", "window": "per_minute", "retry_after": 12, ... }
  }
}
JSON
{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "isError": true,
    "content": [{ "type": "text", "text": "Invalid arguments for email_read. The call was rejected before it ran, ..." }],
    "_meta": {
      "com.mcpemails/invalid_arguments": {
        "error_code": "invalid_arguments",
        "retryable": false,
        "errors": [{ "path": "arguments.since", "message": "..." }]
      }
    }
  }
}

Paginação

Todo resultado de listagem e de pesquisa termina com os mesmos quatro campos:

  • has_more: true quando existe outra página. Só has_more: false significa que você viu tudo.
  • next_offset: devolva-o como offset, com todos os outros argumentos iguais, para obter a próxima página. É null quando has_more é false.
  • total: o número de resultados, ou null quando o provedor não consegue contá-los. Nunca contradiz a página que você tem em mãos.
  • total_is_estimate: true quando total é uma estimativa ou um valor mínimo, e não uma contagem exata.

Corpos de mensagem longos são divididos em janelas da mesma forma: quando body_truncated é true, leia de novo passando body_next_offset como body_offset.

Novas tentativas e chaves de idempotência

Uma conexão que cai depois de um envio deixa você sem saber se o e-mail saiu. Passe uma idempotency_key e tente de novo com a mesma chave: o trabalho é executado uma única vez.

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 7,
    "method": "tools/call",
    "params": {
      "name": "email_compose",
      "arguments": {
        "action": "send",
        "inbox": "you@example.com",
        "to": ["customer@example.com"],
        "subject": "Your order has shipped",
        "body": "Hi, your order is on its way.",
        "idempotency_key": "order-1042-shipped"
      }
    }
  }'
  • Aceita em envios, respostas, encaminhamentos, envios agendados, gravação de rascunhos e alterações na caixa de correio, como mover, sinalizar e excluir. tools/list mostra idempotency_key no schema de entrada de toda ferramenta que a aceita.
  • Até 200 caracteres. Use algo do seu próprio sistema, como um número de pedido e um nome de evento.
  • As chaves valem só para a chave de API que as enviou e ficam guardadas por 24 horas.
  • Uma nova tentativa com a mesma chave e os mesmos argumentos não é executada de novo. Ela retorna idempotent_replay: true, o status original e o resultado original em result, incluindo o message_id que você pode ter perdido.
  • A mesma chave com argumentos diferentes é recusada com idempotency_key_conflict. Use uma chave nova para uma operação nova.
  • Uma nova tentativa enquanto a primeira chamada ainda está rodando retorna status: "processing". Tente de novo em instantes.
  • Quando o provedor de e-mail recusou um envio antes de aceitá-lo, nada foi enviado e a chave é liberada, então a nova tentativa idêntica envia de fato.
  • Quando o resultado é incerto, a resposta repetida diz status: "unknown". Confira os Enviados antes de enviar de novo com uma chave nova.
JSON
{
  "idempotency_key": "order-1042-shipped",
  "idempotent_replay": true,
  "status": "succeeded",
  "result": { "message_id": "...", "inbox_id": "...", "status": "sent" },
  "message": "This logical request was already processed. ..."
}

Aprovação de envios

Qualquer caixa de entrada pode segurar todos os envios até que uma pessoa os aprove. Um envio do seu script passa então a retornar um approval_id com status: "pending_approval" em vez de sair, e ele sai quando alguém o aprova no painel. Isso funciona em todos os planos e é um bom padrão enquanto uma automação nova ainda está provando seu valor. Uma nova tentativa com a mesma idempotency_key informa a aprovação existente em vez de criar uma segunda.

Limites de taxa

Cada plano tem um teto por minuto para o espaço de trabalho inteiro. Uma única chave pode usar todo o limite por minuto do plano; várias chaves o compartilham.

PlanoRequisições por minutoWebhooks
Free60Não
Personal120Não
Pro300Sim
Business1.000Sim
  • As respostas de tools/call trazem RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset (em segundos) para a janela que estiver mais perto de encher, para que o cliente possa regular o ritmo antes de atingir o limite.
  • Cada chave também tem janelas por hora e por dia. Um 429 indica em data.window a janela que encheu.
  • Um 429 traz Retry-After em segundos. Espere esse tempo e repita a mesma requisição.
  • O Free inclui uma cota mensal de ações de e-mail. Os planos pagos têm ações de e-mail ilimitadas e nenhuma cobrança por chamada.

Webhooks para e-mails novos

No Pro e no Business, o MCPEmails pode fazer um POST na sua URL quando chega e-mail em uma caixa de entrada, para que um fluxo de trabalho comece com o e-mail novo em vez de fazer polling. Crie um endpoint no painel, escolha as caixas de entrada dele e copie o segredo de assinatura, que aparece uma única vez. A URL precisa ser HTTPS, na porta 443 ou 8443. Use o botão de teste para enviar um evento ping assinado.

O evento

HTTP
POST /your/webhook HTTP/1.1
Content-Type: application/json
MCPEmails-Event-Id: evt_...
MCPEmails-Event-Type: message.received
MCPEmails-Signature: t=1792843200,v1=5f2b...

{
  "id": "evt_...",
  "type": "message.received",
  "created_at": "2026-10-24T09:20:00.000Z",
  "workspace_id": "...",
  "inbox_id": "...",
  "folder": "INBOX",
  "count": 1,
  "message_ids": ["..."]
}
  • type é message.received. message_ids lista as mensagens novas na pasta INBOX daquela caixa de entrada, até 10 por evento; count é quantas chegaram, o que pode ser mais.
  • Por padrão, o payload traz só ids, sem conteúdo. Um endpoint configurado para incluir cabeçalhos também recebe uma lista messages com o id, o from e o subject de cada mensagem.
  • Busque a mensagem com email_read (action: "read", o inbox_id e um message_id) usando uma chave de API. Os escopos e o acesso às caixas de entrada dessa chave valem normalmente.
  • A entrega costuma acontecer em cerca de dois minutos depois que a mensagem chega. As caixas de entrada são verificadas em intervalos programados, então não é instantâneo.

Verifique a assinatura

Cada entrega traz MCPEmails-Signature: t=<unix seconds>,v1=<hex>, em que v1 é o HMAC-SHA256 do timestamp, um ponto e o corpo bruto da requisição, com o segredo do endpoint como chave. A chave é o segredo inteiro como aparece, prefixo whsec_ incluído. Recalcule a assinatura sobre o corpo bruto, compare em tempo constante e rejeite um timestamp com mais de cinco minutos.

JavaScript
import crypto from 'node:crypto';

// rawBody: the request body exactly as received, before JSON.parse.
export function verifyMcpemailsSignature(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    String(header ?? '').split(',').map((part) => part.trim().split('=')),
  );
  const timestamp = Number(parts.t);
  if (!Number.isFinite(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest();
  const received = Buffer.from(parts.v1 ?? '', 'hex');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

Novas tentativas

  • Responda com qualquer status 2xx em até 10 segundos. Qualquer outra coisa conta como falha, inclusive um redirecionamento, que não é seguido.
  • Uma entrega que falhou é reenviada depois de 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas e 24 horas. Cada nova tentativa é assinada de novo com um timestamp novo.
  • Um endpoint que falhou por 24 horas, ou 50 vezes seguidas, é desativado e o dono do espaço de trabalho é avisado por e-mail. Você pode reativá-lo pelo painel.
  • Use MCPEmails-Event-Id para ignorar uma entrega que você já processou. Uma nova tentativa traz o mesmo id de evento.

Receitas

n8n: rode um fluxo de trabalho quando chegar e-mail novo

  • Adicione um nó de gatilho Webhook com o método HTTP POST e registre a URL de produção dele como endpoint de webhook no painel do MCPEmails.
  • Adicione um nó HTTP Request: método POST, URL https://mcpemails.com/api/mcp, autenticação Generic Credential Type → Header Auth com nome Authorization e valor Bearer mcpe_....
  • Ative Send Body, escolha JSON e use o corpo abaixo para ler a mensagem nova. Os nós seguintes recebem a mensagem em result.structuredContent.
  • Para verificar a assinatura no n8n, ative Raw Body no nó Webhook e rode a verificação acima em um nó Code. No n8n auto-hospedado, libere o módulo crypto com NODE_FUNCTION_ALLOW_BUILTIN=crypto.
JSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "email_read",
    "arguments": {
      "action": "read",
      "inbox_id": "{{ $json.body.inbox_id }}",
      "message_id": "{{ $json.body.message_ids[0] }}"
    }
  }
}

Para um nó AI Agent que lê e envia e-mails por conta própria, veja o guia do n8n.

Claude Code

Adicione o servidor com uma chave em um cabeçalho. Isso serve para máquinas sem interface e para CI, onde não há navegador para o login OAuth:

bash
claude mcp add --transport http mcpemails https://mcpemails.com/api/mcp \
  --header "Authorization: Bearer $MCPEMAILS_KEY"

O guia do Claude Code cobre o login OAuth e a escolha de escopos.

Um script curto em Node

Lista todas as mensagens não lidas de uma caixa de entrada, página por página, e espera passar um 429:

JavaScript
// node agent.mjs  (Node 18 or later, MCPEMAILS_KEY in the environment)
const ENDPOINT = 'https://mcpemails.com/api/mcp';
let nextId = 1;

async function callTool(name, args) {
  const res = await fetch(ENDPOINT, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.MCPEMAILS_KEY}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({ jsonrpc: '2.0', id: nextId++, method: 'tools/call', params: { name, arguments: args } }),
  });
  if (res.status === 429) {
    const wait = Number(res.headers.get('Retry-After') ?? 1);
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
    return callTool(name, args);
  }
  const reply = await res.json();
  if (reply.error) throw new Error(`${reply.error.code}: ${reply.error.message}`);
  if (reply.result.isError) throw new Error(reply.result.content[0].text);
  return reply.result.structuredContent;
}

const inbox = 'you@example.com';
let offset = 0;
do {
  const page = await callTool('email_read', { action: 'list', inbox, unread: true, limit: 50, offset });
  for (const m of page.messages) console.log(m.id, m.from?.email, m.subject);
  offset = page.has_more ? page.next_offset : null;
} while (offset !== null);

OpenClaw

O OpenClaw entra com OAuth por padrão; o guia do OpenClaw mostra o passo a passo. Para usar uma chave com escopos, coloque-a no mapa headers da entrada do servidor e deixe auth sem valor, porque o OpenClaw ignora um cabeçalho Authorization estático em uma entrada configurada para OAuth.

JSON
{
  "mcp": {
    "servers": {
      "mcpemails": {
        "url": "https://mcpemails.com/api/mcp",
        "transport": "streamable-http",
        "headers": { "Authorization": "Bearer mcpe_YOUR_KEY_HERE" }
      }
    }
  }
}

Comece com uma caixa de entrada, grátis

Crie uma chave, chame tools/list e veja seus próprios e-mails voltarem como JSON.