Pylos

Leia, pesquise e rascunhe e-mails em qualquer caixa de correio IMAP, com cada mensagem isolada como entrada não confiável e o envio restrito a uma lista de permissões.

Documentação

pylos-mcp logo, an envelope with a keyhole in its flap

pylos-mcp

Servidor MCP de e-mail focado em leitura e endurecido contra injeção de prompt, para qualquer provedor IMAP.

Qualquer pessoa no mundo pode colocar texto na sua caixa de entrada, e no momento em que um assistente de IA lê essa caixa de entrada, qualquer pessoa no mundo pode colocar texto na frente do seu assistente. pylos-mcp é um servidor MCP de e-mail construído em torno desse fato. Ele permite que o Claude, ou qualquer cliente MCP, pesquise, leia e rascunhe seus e-mails tratando cada mensagem como o que ela realmente é: entrada de um estranho. O conteúdo da caixa de entrada é isolado como dado antes que o modelo o veja, e não há campo bcc para um e-mail injetado copiar alguém silenciosamente.

Ele roda na sua máquina e fala IMAP puro, então funciona com Gmail, iCloud, Yahoo, GMX, Fastmail, mailbox.org, Posteo, Proton via Bridge, ou qualquer coisa auto-hospedada, e suas credenciais nunca saem de casa. Pronto para uso, ele pode ler e rascunhar. Qualquer coisa mais arriscada — mover, enviar, excluir — é um interruptor separado que permanece desligado até você ativá-lo.

O que isto nunca pode fazer

E-mail é texto controlado por atacantes, então os limites rígidos estão na arquitetura, não em um prompt. Nenhuma mensagem pode convencer o servidor a violar qualquer um destes pontos.

  • Nenhum HTML bruto jamais chega ao modelo. Os corpos vêm da parte de texto simples quando existe, ou são convertidos para texto caso contrário. Caracteres invisíveis que escondem instruções de um leitor humano enquanto permanecem legíveis para um modelo são removidos.
  • Conteúdo não confiável é isolado. Tudo da caixa de entrada — corpos, assuntos, nomes de remetentes, listagens de pastas, texto de script Sieve — é envolvido em um delimitador rotulado antes que o modelo o veja, e o delimitador é neutralizado dentro do conteúdo, para que uma mensagem não possa forjar sua saída do isolamento. As poucas linhas fora dele são escritas pelo servidor e nunca carregam conteúdo de mensagem.
  • Nenhum campo bcc existe em lugar algum, em rascunhos ou e-mails enviados. Um destinatário em cópia oculta recebe uma cópia completa de uma mensagem sem aparecer em lugar nenhum dela, exatamente a invisibilidade que um e-mail injetado deseja. O campo está ausente, não apenas protegido, então não há nada para convencer o modelo a fazer.
  • Excluir uma mensagem a move para a Lixeira. Não há expurgo nem opção de exclusão permanente, e o resultado da ferramenta nunca afirma uma permanência que este servidor não oferece.
  • O acesso ao Sieve é somente leitura, permanentemente. Regras de filtro no lado do servidor podem encaminhar, responder automaticamente e notificar, cada uma um canal de exfiltração que sobrevive à revogação da senha de aplicativo ou à desinstalação deste servidor. O acesso de escrita é totalmente omitido, não defendido.

Enviar é a outra porta arriscada, então ela começa fechada mesmo com o recurso send ativado. Até que SEND_ALLOWLIST diga quem pode ser endereçado, todo envio é recusado, e a recusa nomeia as duas maneiras de abrir o portão. SEND_ALLOWLIST=* permite qualquer pessoa, visível e deliberadamente.

O isolamento reduz o risco de injeção de prompt; nada o elimina. O modelo ainda lê texto escrito por estranhos, então trate toda resposta que inclua conteúdo de mensagem como entrada não confiável, não como verdade absoluta. As notas de design mais detalhadas estão em SECURITY.md.

Início rápido

Adicione o servidor à configuração do seu cliente MCP. Para o Claude Desktop, esse arquivo é claude_desktop_config.json.

{
  "mcpServers": {
    "pylos-mcp": {
      "command": "npx",
      "args": ["-y", "pylos-mcp"],
      "env": {
        "PROVIDER": "mailbox.org",
        "EMAIL_USER": "you@example.com",
        "EMAIL_PASSWORD": "your-app-password"
      }
    }
  }
}

Use uma senha de aplicativo, não a senha normal de login da sua conta. A próxima seção diz quais provedores exigem uma. Reinicie o cliente e as ferramentas de leitura e rascunho aparecem. Mudanças posteriores na configuração precisam do mesmo tratamento: um recurso recém-habilitado só registra suas ferramentas após uma reinicialização completa do cliente, e no Claude Desktop alternar o servidor entre desligado e ligado nem sempre é suficiente.

Configuração do provedor

Defina PROVIDER como um de gmail, icloud, yahoo, gmx, fastmail, mailbox.org ou posteo e os hosts e portas IMAP, SMTP e Sieve correspondentes se preenchem automaticamente.

Gmail, iCloud, Yahoo e Fastmail recusam senhas normais de conta via IMAP, então uma senha de aplicativo é o único caminho. O Google só oferece uma depois que a Verificação em Duas Etapas está ativada, e o iCloud quer autenticação de dois fatores no Apple ID primeiro. mailbox.org, GMX e Posteo aceitam a senha da conta, embora uma senha de aplicativo ainda seja a escolha mais sábia.

O Proton Mail passa pelo Bridge. Deixe PROVIDER não definido e defina IMAP_HOST e IMAP_PORT com o que o Bridge mostra. O nome de usuário é o endereço que o Bridge diz para você usar, e a senha é a da seção IMAP nos detalhes da Caixa de Correio do Bridge, não a senha da sua conta Proton. O Bridge usa STARTTLS por padrão, enquanto este servidor só fala TLS implícito, então mude o Bridge para SSL nas Configurações Avançadas. O certificado do Bridge é autoassinado, então exporte-o e aponte TLS_CA_FILE para ele.

Servidores auto-hospedados também deixam PROVIDER não definido. Defina IMAP_HOST, além de SMTP_HOST ou SIEVE_HOST quando esses níveis opcionais estiverem habilitados, e autentique conforme seu servidor exigir. Para uma CA privada, aponte TLS_CA_FILE para o certificado da CA. A verificação em si permanece sempre ativada; isso apenas adiciona uma âncora de confiança.

Recursos

Os recursos são interruptores independentes, não uma escada. A leitura está sempre ativada, o rascunho começa ativado, e todo o resto permanece desligado até você listá-lo em CAPABILITIES. Um nível desligado tem suas ferramentas omitidas da lista de ferramentas por completo, não apenas recusadas, para que um modelo nunca saiba que uma ferramenta desabilitada existe.

NívelPadrãoFerramentas
readsempre ativadosearch_emails, get_email, get_attachment, list_folders
draftsativadocreate_draft
managedesligadomove_email, set_flags
senddesligadosend_email
deletedesligadodelete_email
sieve-readdesligadolist_sieve_scripts, get_sieve_script

Habilite mais com uma lista separada por vírgulas, por exemplo CAPABILITIES=drafts,manage,delete.

Mover uma mensagem para a Lixeira é uma exclusão por outra rota, então move_email recusa a Lixeira a menos que delete também esteja ativado.

Avisos de suspeita

O servidor também informa o que é suspeito em uma mensagem. Cinco detectores anotam resultados de get_email com uma linha acima do conteúdo, escrita inteiramente nas próprias palavras do servidor e nunca citando o conteúdo que os acionou.

Warnings: hidden_text (412 hidden characters via display:none), encoded_blob (base64 run of 600 characters)
  • Texto oculto. Texto escondido com os truques comuns de CSS, display:none, fontes invisíveis ou de um pixel, cores de texto e fundo iguais, posicionamento fora da tela, aria-hidden. Isso cobre estilos e atributos inline, um alarme, não um mecanismo de renderização. Newsletters legitimamente escondem texto curto de pré-visualização, então o aviso só dispara acima de um limite, a menos que o próprio texto oculto contenha uma frase semelhante a instrução ou uma sequência codificada, o que avisa em qualquer comprimento. O texto permanece no corpo por padrão. STRIP_HIDDEN_TEXT=true o remove em vez disso, com uma nota de quanto foi removido.
  • Padrões de instrução. Um conjunto deliberadamente pequeno de frases que se dirigem a uma IA como alvo de instrução, como "ignore instruções anteriores". Pequeno para que uma caixa de entrada que apenas fala sobre IA permaneça silenciosa. Estenda-o com FLAG_EXTRA_PATTERNS, frases separadas por barras verticais correspondidas como literais sem diferenciar maiúsculas de minúsculas. Assuntos, linhas de remetente e nomes de anexos também são verificados, além do corpo, e espaços extras ou quebras de linha dentro de uma frase não a escondem.
  • Blocos codificados. Sequências longas e contínuas de base64 ou hex no corpo, relatadas com seu comprimento e nunca decodificadas.
  • Incompatibilidade de remetente. Um endereço de Reply-To em um domínio diferente do endereço de From, ou um nome de exibição de From carregando um endereço em um domínio que o remetente real não usa. Subdomínios contam como o mesmo domínio, então um provedor respondendo de um de seus próprios permanece silencioso. O próprio endereço de Reply-To é mostrado dentro do conteúdo isolado, para que o modelo possa ver para onde uma resposta realmente iria.
  • Scripts mistos. Palavras que misturam letras latinas com letras cirílicas ou gregas desenhadas para parecerem latinas, como um "paypal" escrito com um а cirílico. Apenas letras semelhantes contam, então unidades como μm e texto comum em russo ou grego permanecem silenciosas.

Os avisos anotam, nunca retêm. A mensagem sempre volta, e cada detector tem seu próprio interruptor na referência abaixo.

Referência de configuração

Toda a configuração é feita por variáveis de ambiente, validadas na inicialização. Configuração inválida falha imediatamente com uma mensagem acionável, nunca no meio de uma conversa. Um valor vazio conta como não definido, pois gerenciadores de pacotes preenchem campos opcionais que os usuários deixam em branco com strings vazias.

VariávelPadrãoObservações
PROVIDERnenhumUm de gmail, icloud, yahoo, gmx, fastmail, mailbox.org, posteo. Preenche os hosts e portas de IMAP, SMTP e Sieve.
EMAIL_USERobrigatórioLogin da conta.
EMAIL_PASSWORDnenhumSenha do aplicativo. Ou esta ou EMAIL_PASSWORD_CMD é obrigatória.
EMAIL_PASSWORD_CMDnenhumComando cuja saída padrão é a senha, como uma consulta ao chaveiro ou pass, para que o segredo nunca fique no arquivo de configuração do cliente. Tem 60 segundos para terminar.
IMAP_HOST / IMAP_PORTpredefinido / 993Valores explícitos para servidores auto-hospedados. Defina qualquer um para substituir o predefinido.
SMTP_HOST / SMTP_PORTpredefinido / 465Obrigatório apenas quando send está habilitado.
SIEVE_HOST / SIEVE_PORTIMAP_HOST / 4190Usado apenas quando sieve-read está habilitado.
CAPABILITIESdraftsLista separada por vírgulas de níveis além de read, que está sempre incluído.
MAX_BODY_KB64Limite de truncamento do corpo da mensagem.
MAX_ATTACHMENT_MB25Limite de tamanho do anexo, verificado contra o tamanho que o servidor declara antes de qualquer byte ser baixado.
DOWNLOAD_DIR~/DownloadsOnde get_attachment grava arquivos.
SEND_SESSION_CAP5Chamadas bem-sucedidas de send_email permitidas por tempo de vida do processo do servidor.
SEND_SAVE_COPYtrueAnexa uma cópia de cada mensagem enviada à pasta Enviados, marcada como lida. Desative para provedores que já arquivam mensagens enviadas no servidor (o Gmail faz isso), o que, de outra forma, mostraria duplicatas.
SEND_ALLOWLISTnenhum (envio fechado)Endereços separados por vírgulas ou padrões de *@domain, ou apenas * para permitir qualquer pessoa. Com send habilitado e nenhum valor definido, todo envio é recusado e a recusa explica esta variável. Um valor explicitamente vazio também não permite ninguém. Uma entrada que nunca poderia corresponder, como um domínio simples, falha na inicialização.
DRAFTS_NO_RECIPIENTSfalseQuando true, create_draft rejeita to e cc completamente. Rascunhos não carregam endereçamento e ele é adicionado depois no seu cliente de e-mail.
FLAG_HIDDEN_TEXTtrueAvisa quando o HTML da mensagem esconde texto com estilos inline ou aria-hidden.
FLAG_INSTRUCTION_PATTERNStrueAvisa quando o corpo, o assunto, a linha do remetente ou os nomes dos anexos contêm frases que tratam uma IA como alvo de instrução.
FLAG_ENCODED_BLOBStrueAvisa sobre longas sequências contíguas de base64 ou hex no corpo.
FLAG_SENDER_MISMATCHtrueAvisa quando um endereço de Reply-To está em um domínio diferente do endereço de From, ou quando o nome de exibição de From carrega um endereço em outro domínio.
FLAG_MIXED_SCRIPTtrueAvisa quando uma palavra mistura letras latinas com caracteres cirílicos ou gregos semelhantes.
STRIP_HIDDEN_TEXTfalseRemove texto oculto detectado do corpo em vez de apenas avisar, com uma nota de quanto foi removido. Exige que FLAG_HIDDEN_TEXT permaneça ativado; a combinação com o detector desativado é recusada na inicialização.
FLAG_EXTRA_PATTERNSnenhumFrases separadas por pipe adicionadas ao conjunto de padrões de instrução, correspondidas como substrings literais sem diferenciar maiúsculas de minúsculas.
TLS_CA_FILEnenhumCaminho para um certificado CA PEM adicionado como âncora de confiança extra, para servidores auto-hospedados com CA privada. A verificação de certificado não pode ser desativada; isso apenas estende o que é confiável. Definir isso confia no armazenamento raiz agrupado do Node mais este arquivo, o que significa que âncoras adicionadas por meio de NODE_EXTRA_CA_CERTS não estão nesse conjunto. Se você depender delas, aponte TLS_CA_FILE para o mesmo certificado.

Expectativas de manutenção

pylos-mcp é construído para o uso diário do próprio autor e mantido com base nisso. Issues e pull requests são bem-vindos, e CONTRIBUTING.md traz uma lista de desejos de direções que realmente ajudariam. O escopo permanece estreito de propósito; então, se você precisar de algo mais amplo do que a postura de segurança permite, faça um fork à vontade. A base de código é deliberadamente pequena o suficiente para tornar isso agradável.

Desenvolvimento

npm install
npm test                  # unit and MCP-layer tests, entirely offline
npm run test:integration  # starts a disposable local Dovecot container, tests against it, tears it down
npm run build

Nenhum teste neste projeto se conecta a uma caixa de correio real, em desenvolvimento ou em CI. npm test executa fakes em processo, e npm run test:integration inicia seu próprio contêiner Dovecot local via Docker, semeado com mensagens de fixture sintéticas, e o remove quando a execução termina.