Hermes MCP include: uma lista vazia agora bloqueia tudo, em todo lugar

Você conectou um servidor MCP de sistema de arquivos ao Hermes Agent do seu time e, por segurança, desmarcou todas as ferramentas que ele traz de fábrica — a ideia era liberar uma a uma se algum dia alguém precisasse de verdade. A configuração realmente diz tools.include: [], e você considerou o assunto encerrado. Até que, numa tarde qualquer, hermes mcp list imprime all ao lado desse servidor e o agente continua lendo e gravando naqueles diretórios. A lista vazia não estava sendo lida como bloqueio total, e sim como «essa chave não está definida», ou seja, «sem filtro», ou seja, tudo liberado.
Uma frase de contexto: MCP (Model Context Protocol) é o protocolo que permite ao Hermes chamar ferramentas servidas por servidores externos, e tools.include é a lista de permissões de ferramentas daquele servidor — só as ferramentas listadas ali podem ser chamadas.
Três estados para tools, e só um deles bloqueia tudo
Na prática existem apenas três estados, e os significados não poderiam ser mais distantes:
- Ausente: nenhum bloco
tools, ou um blocotoolssem a chaveinclude. Isso significa «sem filtro»: todas as ferramentas que o servidor expõe ficam habilitadas. - Parcialmente preenchido:
include: [read_file, list_directory]. Uma lista de permissões de verdade; só essas ferramentas podem ser chamadas. - Explicitamente vazio:
include: []. Isso é um bloqueio total — nada é registrado.
A armadilha é que os dois últimos casos viram a mesma ramificação de código com uma facilidade impressionante. Uma lista vazia é falsy em Python, então no momento em que você escreve cfg.get("include") or [], «o usuário escreveu uma lista vazia» e «o usuário não escreveu nada» se tornam indistinguíveis — e o segundo caso é exatamente o oposto do que o usuário queria.
Vale registrar: o runtime sempre esteve certo. tools/mcp_tool_registration.py não registra nada quando vê include: [], então nem uma ferramenta sequer chega ao agente. Seu bloqueio estava de fato valendo. Era a interface que mentia para você.
A lista vazia sumiu em metade da interface
Como o runtime se comportava corretamente, o defeito só podia estar nos leitores. Várias interfaces liam include com or [] ou com uma verificação simples de veracidade, então lista vazia e chave ausente eram tratadas como a mesma coisa e exibidas como «all tools enabled». O PR #109188 (mesclado em main em 2026-09-12) corrige os leitores que haviam divergido. O título é «fix(mcp): include: [] no longer reopens as “all tools enabled” in CLI, catalog and desktop»; ele fecha a issue #12865, e o diff é de +107 / −31 em 8 arquivos.
Uma tabela deixa a divergência óbvia («antes» e «depois» significam antes e depois do PR #109188):
| Ponto de verificação | Antes | Depois |
|---|---|---|
hermes mcp list |
all |
0 selected |
linha de lista do hermes tools |
all tools enabled |
[include only: (none)] |
seletor do hermes tools |
todas as ferramentas pré-marcadas; confirmar reativava todas | nada pré-marcado; confirmar mantém include: [] |
runtime _make_tool_filter("demo")("a") |
False | False (inalterado) |
Vale memorizar quatro mudanças:
_tool_filtersemhermes_cli/mcp_config.py: se a chave contém uma lista, devolve essa lista (lista vazia inclusive); devolveNoneapenas quando a chave está ausente ou não é uma lista. A saída de listagem e o seletor do configure agora testamis not Noneem vez de veracidade.hermes_cli/tools_config_mcp.py: o estado pré-marcado do seletor dohermes toolse a linha de lista, que agora mostra[include only: (none)].hermes_cli/mcp_catalog.py: a verificação prévia numa reinstalação interativa respeita um[]anterior em vez de voltar ao padrão do catálogo.apps/desktop/src/lib/mcp-tool-filter.ts:isToolEnabledtrata «include existe» como lista de permissões — falamos disso na próxima seção.
O comentário no código é direto:
Um
include: []explícito é uma lista de permissões real (bloqueio total); o runtime não registra nenhuma ferramenta, então ele não pode ser reduzido aqui a «sem filtro».
Mais um ponto que merece ser dito sem rodeios: o lado do runtime já havia sido corrigido em outro commit (fb1ec36a4b86). Este PR cuida dos leitores que ainda divergiam dele. Não é um recurso novo — é o realinhamento de todas as interfaces com uma semântica que o runtime já havia definido.
A armadilha mais invisível do desktop: apagar a chave e liberar tudo
No painel MCP do desktop, isToolEnabled em apps/desktop/src/lib/mcp-tool-filter.ts agora entende «include está presente» como lista de permissões. Parece uma mudança pequena, mas ela fecha uma armadilha mais traiçoeira do que qualquer uma do lado do CLI: ao desligar a última ferramenta incluída, ele mantém include: [] em vez de apagar a chave.
Por que isso importa: no nível do arquivo de configuração, uma lista vazia e uma chave ausente não são nem de longe a mesma coisa.
- Manter
include: []= bloqueio total explícito; nada é registrado. - Apagar a chave
include= sem filtro; o servidor se reabre por completo, em silêncio.
Na interface as duas situações ficam idênticas: simplesmente nenhuma caixa marcada. Apagar a chave parece uma arrumação inofensiva, mas na prática arranca o bloqueio. Se o seu time tem scripts ou manias que «limpam campos vazios», esse é exatamente o padrão que exige atenção.
Sobre a procedência: a parte do desktop foi trazida por cherry-pick do #52874 (@Bartok9, ele mesmo um resgate do #13096 de @dingn42).
Como bloquear de verdade um servidor MCP
Escreva a intenção explicitamente no YAML, em vez de confiar no padrão da interface:
mcp_servers:
demo:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/srv/data"]
tools:
include: [] # bloqueio total explícito: nenhuma ferramenta registrada
demo2: {} # sem a chave tools = sem filtro, tudo habilitado
Depois verifique, nesta ordem:
- Rode
hermes mcp list. Ao lado dedemovocê deve ver0 selected, nãoall. - Rode
hermes tools. A linha correspondente deve mostrar[include only: (none)]; abra o seletor e nenhuma ferramenta deve estar pré-marcada, e confirmar direto não deve ativar nada. - Quando quiser liberar uma ferramenta específica, adicione o nome dela à lista
include— não apague a chave.
Se você veio de uma versão antiga, vale auditar a configuração existente também: para todo servidor no estado «era para bloquear tudo e ninguém mexeu desde então», verifique se ele realmente tem include: [] ou se simplesmente não tem include nenhum. Os dois se parecem quase igual e fazem o oposto.
Para ler mais: se quiser usar variáveis de contexto dentro da configuração do MCP, veja Hermes MCP config context variables; para entender o limite de segurança em torno da superfície de ferramentas MCP, consulte o Hermes MCP catalog security guide; se ainda está escolhendo quais servidores conectar, o Hermes official remote MCP catalog é um bom ponto de partida; e se ainda não instalou o Hermes, o guia de instalação cobre os pré-requisitos e o primeiro passo.
Resumo
tools.include: []nunca foi «não configurado». É um bloqueio total. O runtime sempre leu assim; várias interfaces liam errado.- O PR #109188 (mesclado em
mainem 2026-09-12) alinhahermes mcp list,hermes mcp configure,hermes tools, a reinstalação do catálogo e o painel MCP do desktop ao runtime: lista vazia explícita significa 0 selecionados. - A armadilha que mais dói é apagar a chave:
include: []e nenhumincludese parecem na interface e significam o contrário. - A verificação custa pouco: se
hermes mcp listdiz0 selected, seu bloqueio está de pé.