Skip to main content
Glama
ronnyarruda20

mcp-email-instagram

mcp-email-instagram

mcp-email-instagram: servidor MCP em Python para e-mail e Instagram

CI Python 3.11+ MCP Licença MIT

Servidor MCP (Model Context Protocol) em Python que dá a assistentes de IA acesso a caixas de e-mail (qualquer provedor IMAP/SMTP, uma ou várias) e a uma conta profissional do Instagram, pela API oficial da Meta.

Com ele conectado, você pede ao Claude (ou a qualquer cliente MCP) coisas como:

"Tem e-mail de cliente sem resposta desde segunda? Rascunha uma resposta para cada um."

"Quantas pessoas visitaram o perfil do Instagram esta semana? E qual post teve mais alcance?"

"Responde o comentário do último post agradecendo, e oculta o que é spam."

e o modelo chama as ferramentas certas em vez de pedir para você copiar e colar.

Em resumo:

  • 20 ferramentas: 9 de e-mail e 11 de Instagram.

  • Travas no servidor, não no prompt: a DM só sai dentro de 24h, o token nunca aparece em URL e toda escrita fica registrada.

  • Segredos só na sua máquina: o modelo nunca vê senha nem token.

  • 27 testes sem rede, rodando no CI em Python 3.11, 3.12 e 3.13.

Como funciona

Como funciona: o assistente pede pelo MCP, o servidor confere as travas e só então age no e-mail e no Instagram; os segredos ficam num .env local que o modelo nunca vê

Related MCP server: gigamail

Na prática

Um pedido vira uma sequência de chamadas. As de leitura correm soltas, as de escrita ficam registradas, e o que a regra não permite é recusado antes de chegar à API:

Exemplo de conversa: o assistente busca e lê dois e-mails, grava dois rascunhos no mesmo fio, responde uma DM e tem a segunda recusada por estar fora da janela de 24h

As duas imagens são geradas de HTML: docs/como-funciona.html e docs/exemplo-conversa.html.

Ferramentas

Ferramenta

O que faz

Tipo

email_pastas

Lista as pastas, com os marcadores especiais (Enviados, Lixeira, Rascunhos)

leitura

email_buscar

Busca por remetente, assunto, texto, período, não lidas; no Gmail, aceita a sintaxe de busca dele

leitura

email_ler

Cabeçalhos, corpo em texto (HTML convertido) e lista de anexos, sem marcar como lido

leitura

email_baixar_anexo

Salva um anexo localmente

escrita

email_enviar

Envia, inclusive respondendo no mesmo fio (In-Reply-To/References), com anexos

escrita

email_rascunho

Grava rascunho sem enviar

escrita

email_mover · email_marcar

Move entre pastas; marca lida/não lida, sinalizada

escrita

email_apagar

Manda para a Lixeira; apaga em definitivo só se pedido

destrutiva

ig_perfil · ig_posts

Perfil, seguidores e posts com curtidas e comentários

leitura

ig_metricas_conta · ig_metricas_post

Alcance, visualizações, visitas ao perfil, interações

leitura

ig_comentarios · ig_conversas · ig_mensagens

Comentários de um post e o Direct

leitura

ig_responder_comentario · ig_ocultar_comentario

Responde ou oculta comentário

escrita

ig_enviar_dm

Responde no Direct, só dentro da janela de 24h

escrita

ig_publicar

Publica imagem, carrossel (2 a 10) ou Reels

escrita

Cada ferramenta declara ao cliente se é somente leitura, destrutiva ou idempotente (ToolAnnotations). O cliente usa isso para decidir quando pedir confirmação.

Decisões de implementação

  • Token no cabeçalho, nunca na URL. O httpx registra a URL completa em nível INFO, e servidores MCP costumam ligar o log nesse nível. Com o token na query string, ele vai parar no log do cliente. Descobri isso num teste real. Agora o token vai em Authorization: Bearer, os loggers httpx/httpcore ficam em WARNING, e há teste para as duas coisas. Veja instagram.graph.

  • Instagram sem Facebook. O caminho padrão é a API do Instagram com login do Instagram (graph.instagram.com), que não exige conta no Facebook nem Página vinculada. O token vale 60 dias, e o servidor renova sozinho depois de 20 (a Meta só renova token com mais de 24h), regravando o .env. O caminho antigo, por token de Página, continua disponível com INSTAGRAM_LOGIN=facebook.

  • Sem conversa fria no Direct. A Meta só permite responder até 24h depois da última mensagem da pessoa. ig_enviar_dm confere isso antes de chamar a API: o modelo não consegue iniciar conversa, mesmo que alguém peça. Automação de navegador ficou de fora de propósito, porque viola os termos e dispara o "confirme que você é humano" na conta.

  • Resposta no mesmo fio. Ao responder, o destinatário vem do Reply-To (ou From), o assunto ganha Re: uma vez só, e In-Reply-To/References são montados a partir do original. Sem isso, cada resposta abre uma conversa nova no cliente de e-mail de quem recebe.

  • IMAP que funciona em servidor real.

    • Tudo é feito por UID, que não muda quando outras mensagens são apagadas.

    • As pastas especiais são achadas pelo marcador SPECIAL-USE (RFC 6154), com plano B pelo nome, porque o Gmail chama a de enviados de [Gmail]/E-mails enviados e a Hostinger de INBOX.Sent.

    • Busca com acento vai como literal UTF-8 no fim do comando.

    • A data do SINCE não usa strftime('%b'), que segue o locale da máquina: em português sairia set e o servidor recusa.

    • Com UIDPLUS, o expurgo é UID EXPUNGE. Sem ele, o EXPUNGE comum levaria junto qualquer mensagem já marcada para exclusão na pasta.

  • Destinatários sem cabeçalho vazio. Desde a correção do CVE-2023-27043 (Python 3.12+ e também as versões de segurança do 3.11), getaddresses(['a@x.com', '', '']) devolve [('', '')]: um Cc ou Cco vazio na lista zera todos os destinatários, e o SMTP recusa com um SMTPRecipientsRefused({}) que aparece só como {}. Só os cabeçalhos preenchidos entram na conta. O primeiro envio real pegou isso, e há teste de regressão para os três casos.

  • Cópia em Enviados sem duplicar. O SMTP não guarda cópia. O servidor grava em Enviados por IMAP, exceto no Gmail, que já faz isso sozinho e ficaria com duas cópias.

  • Trilha de auditoria. Toda ação que escreve (enviar, apagar, mover, publicar, responder, renovar token) vira uma linha em auditoria.jsonl. Leitura não é registrada.

  • Segredo não passa pelo modelo. Senhas e tokens são digitados no terminal pelo assistente de configuração (getpass), testados contra o servidor e só então gravados. Nenhuma ferramenta recebe credencial como parâmetro.

Como rodar

Requisitos: uv e Python 3.11+.

git clone https://github.com/ronnyarruda20/mcp-email-instagram
cd mcp-email-instagram
uv run mcp-email-instagram-configurar email       # uma vez por caixa
uv run mcp-email-instagram-configurar instagram   # opcional

O assistente grava tudo em ~/.mcp-email-instagram/.env, fora do repositório.

Gmail: com a verificação em duas etapas ligada, crie uma senha de app em myaccount.google.com/apppasswords. A senha normal é recusada por IMAP.

Instagram: a conta precisa ser profissional (Empresa ou Criador).

  1. Crie um app do tipo Empresa em developers.facebook.com.

  2. Adicione o caso de uso Gerenciar mensagens e conteúdo no Instagram e, em Permissões e recursos, as permissões instagram_business_* que for usar.

  3. Em Configuração da API com login do Instagram, clique em Adicionar conta. A conta entra como Testador do Instagram; aceite o convite em instagram.com → Configurações → Apps e sites.

  4. Clique em Gerar token.

Como dono do app e da conta, você usa o acesso padrão, sem App Review. Para o Direct, ligue Permitir acesso às mensagens nas configurações de mensagens do Instagram.

Conectando a um assistente

Claude Code:

claude mcp add email-instagram -- uv run --project /caminho/para/mcp-email-instagram mcp-email-instagram

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "email-instagram": {
      "command": "uv",
      "args": ["run", "--project", "/caminho/para/mcp-email-instagram", "mcp-email-instagram"]
    }
  }
}

Configuração

Tudo por variável de ambiente ou pelo .env da pasta de dados. O ambiente vence o arquivo. Modelo completo em .env.example.

Variável

Para quê

CAIXAS

Nomes das caixas, separados por vírgula; a primeira é a padrão

CAIXA_<NOME>_ENDERECO · _SENHA · _IMAP_HOST · _SMTP_HOST

Credenciais e servidores de cada caixa (portas padrão 993 e 465)

CAIXA_<NOME>_SMTP_GUARDA_ENVIADO

auto (padrão: true no Gmail), true ou false

INSTAGRAM_LOGIN

instagram (padrão) ou facebook

INSTAGRAM_TOKEN · INSTAGRAM_USUARIO_ID · INSTAGRAM_TOKEN_EMITIDO_EM

Gravados pelo assistente de configuração

FACEBOOK_PAGINA_ID

Só no modo facebook

ORIENTACOES_EXTRAS

Texto somado às instruções que o modelo recebe (tom de voz, o que não prometer)

MCP_EMAIL_INSTAGRAM_HOME

Pasta de dados (padrão ~/.mcp-email-instagram)

Estrutura

src/mcp_email_instagram/
├── servidor.py      # as 20 ferramentas MCP: nome, descrição, parâmetros e anotações
├── email_imap.py    # IMAP/SMTP: busca, leitura, envio, resposta no fio, pastas especiais
├── instagram.py     # Graph API: token no cabeçalho, renovação, trava de 24h, publicação
├── config.py        # .env, caixas de e-mail, pasta de dados
├── auditoria.py     # auditoria.jsonl de toda ação que escreve
└── configurar.py    # assistente de terminal que testa e grava as credenciais
tests/               # IMAP, SMTP e Meta falsos: nada sai para a rede
docs/                # imagens do README e o HTML de onde saem

Testes

uv run --group dev pytest -v

Os testes não usam rede: IMAP, SMTP e Graph API são substituídos por versões falsas que registram cada comando. Eles cobrem:

  • o encadeamento da resposta;

  • a ordem dos critérios de busca com acento;

  • a escolha de gravar ou não a cópia enviada;

  • destinatários preservados com Cc e Cco vazios (regressão do getaddresses estrito);

  • a trava de 24h do Direct (conversa fria, fora da janela, dentro dela);

  • o token fora da URL e o log do httpx calado;

  • a renovação do token aos 20 dias;

  • a publicação de carrossel;

  • as anotações de cada ferramenta.

O CI roda em Python 3.11, 3.12 e 3.13.

Limitações

  • SDK MCP 1.x. A versão 2 renomeou FastMCP para MCPServer e mudou a API. O projeto fixa mcp<2 até a migração.

  • Gmail por senha de app, não OAuth. É o caminho mais simples para uso pessoal. Para distribuir a terceiros, o certo seria OAuth com escopo restrito.

  • Métricas do Instagram mudam de nome entre versões da Graph API. Se uma for recusada, o erro diz qual, e basta tirá-la da lista.

  • Publicação exige URL pública da mídia: a Meta baixa o arquivo de lá. Upload de arquivo local não é suportado.

  • Token vazado não se revoga individualmente. Remover o app da conta só suspende o token; reautorizar o app ressuscita os antigos.

Stack

Python 3.11+ · MCP Python SDK (FastMCP) · httpx · imaplib/smtplib da biblioteca padrão · pytest · uv · GitHub Actions

Licença

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to manage Instagram and Threads accounts — publish content, handle comments, view insights, search hashtags, and manage DMs through the Meta Graph API.
    59
    25 npm
    13
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Your real mailbox and calendar for your AI agent — Microsoft 365 via Graph or any IMAP — as 24 tools: read, search, attachments as text, sender history, drafting from identity and knowledge files, free-slot computation. Send, reply, delete and calendar writes need out-of-band human approval: the agent cannot approve its own actions.
    29
    463 PyPI
    16
    AGPL 3.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to run real email operations across multiple IMAP/SMTP and provider OAuth accounts — syncing, searching, reading, drafting, attaching, and sending mail — while requiring explicit human approval for sending, deleting, or forwarding and recording an inspectable audit trail.
    149,589 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to search, retrieve, and send email across multiple ordinary IMAP, POP3, and SMTP mailboxes, with per-account permissions and safe sending checks.
    Apache 2.0