MCP Lucene Server

O servidor MCP Lucene Server é um servidor do Model Context Protocol (MCP) que expõe as capacidades de busca em texto completo do Apache Lucene por meio de uma interface conversacional. Ele permite que assistentes de IA (como o Claude) ajudem usuários a pesquisar, indexar e gerenciar coleções de documentos sem exigir conhecimento técnico sobre Lucene ou mecanismos de busca.

Documentação

MCP Lucene Server

Build and Release

Um servidor Model Context Protocol (MCP) que expõe recursos de busca fulltext do Apache Lucene com rastreamento e indexação automática de documentos. Este servidor suporta transporte STDIO (para integração com Claude Desktop) e transporte HTTP (para clientes baseados na web e acesso remoto).

Recursos

Rastreamento Automático de Documentos

  • Indexa automaticamente PDFs, documentos Microsoft Office e OpenOffice
  • Rastreamento multithread para indexação rápida
  • Monitoramento de diretório em tempo real para atualizações automáticas
  • Indexação incremental com reconciliação completa (ignora arquivos inalterados, remove órfãos)

Busca Poderosa

  • Busca por palavras-chave simples (sem necessidade de sintaxe Lucene) e busca com sintaxe completa de consulta Lucene
  • Filtragem por campo específico (por autor, idioma, tipo de arquivo, etc.)
  • Passagens estruturadas com metadados de qualidade para consumo por LLM
  • Resultados paginados com sugestões de filtro

Busca Semântica

  • Busca semântica opcional baseada puramente em embeddings KNN usando embeddings multilingual-e5 com Late Chunking
  • Encontra documentos semanticamente relacionados mesmo sem correspondência exata de palavras-chave
  • Requer VECTOR_MODEL configurado. Consulte SEMANTICSEARCH.md para detalhes.

Perfilamento e Depuração de Consultas

  • Análise e perfilamento profundo de consultas (ferramenta profileQuery)
  • Entenda por que consultas retornam determinados resultados e como a pontuação funciona
  • Análise de impacto de filtros mostrando redução de documentos por filtro
  • Explicações de pontuação de documentos com detalhamento BM25
  • Estatísticas de termos (IDF, raridade, frequência de documentos)
  • Recomendações acionáveis de otimização
  • Saída estruturada otimizada para LLM para fácil interpretação

Extração Rica de Metadados

  • Detecção automática de idioma
  • Extração de autor, título e data de criação
  • Informações de tipo e tamanho de arquivo
  • Hash de conteúdo SHA-256 para detecção de alterações

Enriquecimento de Metadados JDBC

  • Carrega metadados adicionais de PostgreSQL, MySQL ou qualquer banco compatível com JDBC no momento da indexação
  • Metadados baseados em JSON com tipos de campo explícitos (keyword, text, int, long, date)
  • Suporte a campos multivalorados, registro automático de facetas
  • Job de sincronização em segundo plano para atualizações incrementais de metadados (intervalo configurável)
  • Todos os campos originados do banco prefixados com dbmeta_ para evitar colisões de esquema

Normalização de Texto

  • Remoção automática de caracteres quebrados/inválidos (caracteres de substituição, caracteres de controle, caracteres de largura zero)
  • Normalização de espaços em branco (espaços múltiplos colapsados em espaço único)
  • Garante resultados de busca e passagens limpos e legíveis

Otimização de Desempenho

  • Processamento em lote para indexação eficiente
  • Busca NRT (Near Real-Time) com otimização dinâmica
  • Pools de threads configuráveis para processamento paralelo
  • Notificações de progresso durante operações em massa

Integração Fácil

  • Suporte a transporte duplo: STDIO (padrão) e HTTP
  • Transporte STDIO para integração perfeita com Claude Desktop
  • Transporte HTTP para clientes baseados na web e acesso remoto
  • Ferramentas MCP abrangentes para controle de busca e rastreador
  • Configuração flexível via YAML e propriedades de sistema
  • Notificações multiplataforma (Central de Notificações do macOS, Toast do Windows, notify-send do Linux)

Sumário

Documentação

Documentação técnica adicional:

  • PIPELINE.md — Cadeias de analisadores, pipeline de consulta e detalhes de tokenização
  • SEMANTICSEARCH.md — Arquitetura de busca semântica: Late Chunking, indexação Block Join, pontuação KNN e configuração
  • ONNX.md — Guia de exportação de modelo ONNX, otimização e quantização INT8 para e5-base e e5-large

Início Rápido

Comece a usar o MCP Lucene Server em três etapas.

Pré-requisitos

  • Java 25 ou posterior - Necessário para executar o servidor
  • Maven 3.9+ (apenas se compilar a partir do código-fonte)

Etapa 1: Obter o Servidor

Opção A: Baixar JAR Pré-compilado (Recomendado)

  1. Vá para a aba Actions
  2. Clique na execução de workflow bem-sucedida mais recente
  3. Role até "Artifacts" e baixe luceneserver-X.X.X-SNAPSHOT
  4. Extraia o arquivo ZIP para obter o JAR

Para releases com tags, você também pode baixar da página Releases.

Opção B: Compilar a partir do Código-Fonte

./mvnw clean package -DskipTests

Isso cria um JAR executável em target/luceneserver-0.0.1-SNAPSHOT.jar.

Opção C: Usar Docker (Apenas Transporte HTTP Disponível)

docker run -v ./lucene-data-dir:/userdata -p 9000:9000 -it mirkosertic42/mcpluceneserver:main

Isso inicia um contêiner Docker com o servidor escutando na porta 9000. Todos os dados de configuração, incluindo os arquivos de índice, são armazenados no diretório ./lucene-data-dir na máquina host. Observe que o indexador Lucene só pode acessar arquivos visíveis ao contêiner Docker, portanto, todos os arquivos devem ser colocados no diretório ./lucene-data-dir ou em um subdiretório dele. As configurações da JVM podem ser ajustadas pela variável de ambiente JAVA_OPTS, que pode ser modificada usando a CLI do Docker ou um arquivo Docker Compose. O tamanho máximo padrão do heap da JVM (-Xmx) é 2GB.

Para habilitar a busca semântica, defina a variável de ambiente VECTOR_MODEL:

docker run -v ./lucene-data-dir:/userdata -p 9000:9000 \
  -e VECTOR_MODEL=e5-base \
  -e JAVA_OPTS="-Xmx4g" \
  -it mirkosertic42/mcpluceneserver:main
Variável de AmbientePadrãoDescrição
VECTOR_MODEL(nenhum)Modelo de embedding ONNX: e5-base (768 dimensões, mais rápido) ou e5-large (1024 dimensões, maior qualidade). Defina para habilitar a busca semântica.
JAVA_OPTS-Xmx2gOpções da JVM. Aumente para -Xmx4g ou mais ao usar busca semântica.

Etapa 2: Configurar o Claude Desktop

Localize seu arquivo de configuração do Claude Desktop:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Adicione o servidor MCP Lucene à seção mcpServers:

{
  "mcpServers": {
    "lucene-search": {
      "command": "java",
      "args": [
        "--enable-native-access=ALL-UNNAMED",
        "-Xmx2g",
        "-Dspring.profiles.active=deployed",
        "-jar",
        "/absolute/path/to/luceneserver-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}

Importante: Substitua /absolute/path/to/luceneserver-0.0.1-SNAPSHOT.jar pelo caminho absoluto real para seu arquivo JAR.

A flag -Dspring.profiles.active=deployed é necessária para comunicação STDIO limpa (desativa o log de console e o banner de inicialização).

Etapa 3: Começar a Usar

  1. Reinicie o Claude Desktop para carregar a nova configuração
  2. Verifique se o servidor está em execução nas configurações de desenvolvedor do Claude Desktop
  3. Diga ao Claude para adicionar seus documentos:
"Add /Users/yourname/Documents as a crawlable directory and start crawling"

Pronto! A configuração é salva em ~/.mcplucene/config.yaml e persiste entre reinicializações. Agora você pode pesquisar seus documentos através do Claude.

Exemplos de busca:

  • "Pesquisar artigos sobre aprendizado de máquina"
  • "Encontrar todos os PDFs de João Silva"
  • "Quais documentos mencionam relatórios trimestrais?"

Ferramentas MCP

As ferramentas são organizadas em grupos. Use LUCENE_TOOLS_INCLUDE e LUCENE_TOOLS_EXCLUDE para controlar quais ferramentas são expostas (consulte Configuração de Exposição de Ferramentas).


Ferramentas de Busca (grupo: search)

simpleSearch

Pesquise o índice fulltext do Lucene usando busca por palavras-chave em texto simples. Caracteres especiais são tratados como literais — nenhum conhecimento de sintaxe Lucene é necessário. Usa BM25 com stemming em alemão e inglês.

Parâmetros:

  • query (opcional): Consulta de busca em texto simples. Pode ser null ou "*" para corresponder a todos os documentos (útil com filtros).
  • filters (opcional): Matriz de filtros estruturados para filtragem precisa por campo (consulte Filtros Estruturados abaixo)
  • page (opcional): Número da página, baseado em 0 (padrão: 0)
  • pageSize (opcional): Resultados por página (padrão: 10, máximo: 100)
  • sortBy (opcional): Campo de ordenação - _score (padrão), modified_date, created_date, file_size, ou qualquer campo de metadados dbmeta_* (INT/LONG/DATE/KEYWORD) registrado a partir do enriquecimento JDBC
  • sortOrder (opcional): Ordem de ordenação - asc ou desc (padrão: desc)

extendedSearch

Pesquise o índice fulltext do Lucene usando sintaxe completa de consulta Lucene. Suporta operadores booleanos, curingas, consultas de proximidade e consultas por campo específico. Usa BM25 com stemming em alemão e inglês.

Parâmetros:

  • query (opcional): A consulta de busca usando sintaxe de consulta Lucene. Pode ser null ou "*" para corresponder a todos os documentos (útil com filtros).
  • filters (opcional): Matriz de filtros estruturados para filtragem precisa por campo (consulte Filtros Estruturados abaixo)
  • page (opcional): Número da página, baseado em 0 (padrão: 0)
  • pageSize (opcional): Resultados por página (padrão: 10, máximo: 100)
  • sortBy (opcional): Campo de ordenação - _score (padrão), modified_date, created_date, file_size, ou qualquer campo de metadados dbmeta_* (INT/LONG/DATE/KEYWORD) registrado a partir do enriquecimento JDBC
  • sortOrder (opcional): Ordem de ordenação - asc ou desc (padrão: desc)

Ordenação de Resultados:

Por padrão, os resultados são ordenados por pontuação de relevância (mais relevante primeiro). Você pode ordenar por campos de metadados:

Campo de OrdenaçãoDescriçãoOrdem Padrão
_scorePontuação de relevância (padrão)Decrescente (melhor correspondência primeiro)
modified_dateData da última modificaçãoDecrescente (mais recente primeiro)
created_dateData de criaçãoDecrescente (mais recente primeiro)
file_sizeTamanho do arquivo em bytesDecrescente (maior primeiro)
dbmeta_*Qualquer campo de metadados JDBC de valor único com tipo INT, LONG, DATE ou KEYWORDCrescente ou decrescente

Exemplos de Ordenação:

// Most recently modified documents
{ "query": "contract", "sortBy": "modified_date", "sortOrder": "desc" }

// Oldest documents first
{ "query": "contract", "sortBy": "created_date", "sortOrder": "asc" }

// Smallest files (for quick review)
{ "query": "summary", "sortBy": "file_size", "sortOrder": "asc" }

// Combine sorting with filters
{
  "query": "*",
  "sortBy": "modified_date",
  "sortOrder": "desc",
  "filters": [
    { "field": "file_extension", "value": "pdf" },
    { "field": "modified_date", "operator": "range", "from": "2024-01-01" }
  ]
}

Nota: Ao ordenar por campos de metadados, as pontuações de relevância ainda são calculadas e usadas como critério de ordenação secundário para desempate.

Filtros Estruturados:

A matriz filters aceita objetos com estes campos:

CampoObrigatórioDescrição
fieldsimNome do campo para filtrar
operatornãoeq (padrão), in, not, not_in, range
valuepara eq/notValor único para correspondência exata ou exclusão
valuespara in/not_inMatriz de valores (semântica OR dentro do campo)
frompara rangeInício do intervalo (inclusivo)
topara rangeFim do intervalo (inclusivo)
addedAtnãoCarimbo de data/hora do cliente — retornado na resposta activeFilters

Referência de operadores:

OperadorDescriçãoExemplo
eqCorrespondência exata (padrão){field: "language", value: "en"}
inCorresponder a qualquer um dos valores{field: "file_extension", operator: "in", values: ["pdf", "docx"]}
notExcluir valor{field: "language", operator: "not", value: "unknown"}
not_inExcluir múltiplos valores{field: "language", operator: "not_in", values: ["unknown", ""]}
rangeIntervalo numérico/de data{field: "modified_date", operator: "range", from: "2024-01-01", to: "2025-12-31"}

Campos filtráveis:

  • Facetados (DrillSideways): language, file_extension, file_type, author
  • String (correspondência exata): file_path, content_hash
  • Numérico/data (intervalo): file_size, created_date, modified_date, indexed_date

Formato de data: ISO-8601 — "2024-01-15", "2024-01-15T10:30:00" ou "2024-01-15T10:30:00Z"

Regras de combinação de filtros:

  • Filtros em campos diferentes usam lógica AND
  • Múltiplos filtros eq ou valores in no mesmo campo facetado usam lógica OR (DrillSideways)
  • Filtros not/not_in são aplicados como cláusulas MUST_NOT

Expansão de sinônimos com IA:

Este servidor foi projetado para trabalhar com assistentes de IA como o Claude. Em vez de usar arquivos de sinônimos tradicionais do Lucene, a IA gera sinônimos apropriados ao contexto automaticamente, construindo consultas OR.

Por que isso é melhor que sinônimos tradicionais:

  • Consciente do contexto: A IA entende sua intenção e seleciona sinônimos relevantes (ex.: "contrato" em contexto jurídico vs. "contrato" em construção)
  • Sem manutenção: Não é necessário manter arquivos de configuração de sinônimos estáticos
  • Adaptável ao domínio: Funciona automaticamente em linguagem jurídica, técnica, médica ou casual
  • Multilíngue: Gera sinônimos em qualquer idioma sem configuração

Quando você pede ao Claude para "encontrar documentos sobre carros", ele automaticamente busca por (car OR automobile OR vehicle) — dando melhores resultados do que uma lista estática de sinônimos.

Detalhes técnicos (correspondência lexical):

O servidor usa um pipeline de indexação multi-analisador e um pipeline de consulta ponderada de múltiplos campos para busca abrangente:

  • Normalização Unicode — normalização NFKC, dobra de diacríticos, expansão de ligaduras via ICUFoldingFilter
  • Otimização de curinga inicial — o campo content_reversed armazena tokens invertidos para consultas eficientes do tipo *vertrag
  • Curingas sem distinção de maiúsculas/minúsculas — termos curinga/prefixo são automaticamente convertidos para minúsculas
  • Lematização OpenNLP — lematização baseada em dicionário para alemão e inglês, incluindo formas irregulares (ran→run, ging→gehen, paid→pay, analyses→analysis)
  • Indexação bilíngue — campos de lema em alemão e inglês indexados para todos os documentos, permitindo correspondência em idiomas mistos
  • Transliteração de umlaut alemão — o campo sombra content_translit_de mapeia dígrafos (Mueller→Müller)
  • Expansão automática de frases — frases exatas são automaticamente expandidas para incluir correspondências de proximidade (veja abaixo)
  • Pontuação adaptativa de prefixo — pontuação BM25 para prefixos específicos (>= 4 caracteres)

Consulte PIPELINE.md para documentação completa da cadeia de analisadores, exemplos concretos e detalhes do pipeline de consulta.

O assistente de IA compensa as limitações restantes (sem expansão de sinônimos, sem correspondência fonética) expandindo consultas de forma inteligente.

Melhores práticas para melhores resultados:

  1. Gere sinônimos você mesmo: Use OR para combinar termos relacionados:

    • Em vez de: contract
    • Use: (contract OR agreement OR deal)
  2. Use curingas para variações: Lide com diferentes formas de palavras:

    • Em vez de: contract
    • Use: contract* (corresponde a contracts, contracting, contracted)
  3. Aproveite os facetas: Use os valores de faceta retornados para descobrir termos exatos no índice:

    • Verifique facets.author para encontrar nomes exatos de autores
    • Verifique facets.language para ver idiomas disponíveis
    • Use esses valores exatos para filtrar
  4. Combine técnicas:

    (contract* OR agreement*) AND (sign* OR execut*) AND author:"John Doe"
    

Sintaxe de consulta suportada (extendedSearch):

  • Termos simples: hello world (AND implícito entre termos)
  • Consultas de frase: "exact phrase" (preserva a ordem das palavras)
  • Operadores booleanos: term1 AND term2, term1 OR term2, NOT term
  • Curinga final: contract* corresponde a contracts, contracting, contracted
  • Curinga inicial: *vertrag encontra eficientemente Arbeitsvertrag, Kaufvertrag (otimizado via campo de token reverso)
  • Curinga infixo: *vertrag* encontra tanto Vertragsbedingungen quanto Arbeitsvertrag
  • Curinga de caractere único: te?t corresponde a test, text
  • Busca difusa: term~2 encontra termos dentro da distância de edição Levenshtein 2 (padrão: 2)
  • Busca por proximidade: "term1 term2"~5 encontra termos a até 5 palavras um do outro
  • Busca específica de campo: title:hello content:world
  • Agrupamento: (contract OR agreement) AND signed
  • Consultas de intervalo: modified_date:[1609459200000 TO 1640995200000] (carimbos de data/hora em milissegundos)

Expansão automática de proximidade de frases:

Consultas de frases com múltiplas palavras são automaticamente expandidas: "Domain Design" torna-se ("Domain Design")^2.0 OR ("Domain Design"~3). Correspondências exatas têm a maior pontuação (boost de 2,0x), enquanto correspondências aproximadas (a até 3 palavras) também aparecem com pontuações menores. Frases de uma única palavra e slop especificado pelo usuário não são expandidos.

Consulte PIPELINE.md para exemplos detalhados e configuração.

Pontuação adaptativa de consultas de prefixo:

Consultas de prefixo com >= 4 caracteres (vertrag*, design*) usam pontuação BM25 real, classificando termos mais curtos/frequentes acima de compostos longos. Prefixos mais curtos (ver*) usam pontuação constante por desempenho. Isso equilibra qualidade de classificação e velocidade automaticamente.

Consulte PIPELINE.md para exemplos de pontuação e detalhes técnicos.

Busca de palavras compostas em alemão:

Use curingas para compostos alemães: *vertrag encontra Arbeitsvertrag, vertrag* encontra Vertragsbedingungen. Curingas iniciais são otimizados via campo content_reversed.

Lematização automática:

A lematização OpenNLP lida com variações morfológicas automaticamente. Alemão: "Haus" encontra "Häuser", "gehen" encontra "ging". Inglês: "run" encontra "ran", "pay" encontra "paid". Correspondências exatas sempre têm a maior pontuação.

Suporte bilíngue:

Todos os documentos são indexados com campos de lema em alemão e inglês, permitindo correspondência em idiomas mistos. Documentos em alemão com termos técnicos em inglês ("Recommendation Engines") correspondem a consultas no singular ("Recommendation Engine") via o lematizador de inglês, e vice-versa.

Transliteração de umlaut alemão:

O campo content_translit_de mapeia dígrafos ASCII para umlauts: "Mueller" corresponde a "Müller", "Kaese" corresponde a "Käse".

Consulte PIPELINE.md para cadeias de analisadores completas, exemplos concretos de tokens e detalhes do pipeline de consulta.

Retornos:

  • Resultados de documentos paginados, cada um contendo uma matriz passages com texto destacado e metadados de qualidade
  • Pontuações de relevância em nível de documento
  • facets: Valores de faceta e contagens do conjunto de resultados (usa DrillSideways quando filtros de faceta estão ativos, mostrando valores alternativos)
  • activeFilters: Espelha o filters de entrada com um matchCount para cada filtro (contagem dos facetas, ou -1 para filtros de intervalo/não facetados)
  • Tempo de execução da busca em milissegundos (searchTimeMs)

Exemplos de filtros:

// Browse all English PDFs
{ "query": null, "filters": [
    { "field": "language", "value": "en" },
    { "field": "file_extension", "value": "pdf" }
]}

// Date range filter
{ "query": "contract*", "filters": [
    { "field": "modified_date", "operator": "range", "from": "2024-01-01", "to": "2025-12-31" }
]}

// Multiple values with exclusion
{ "query": "report", "filters": [
    { "field": "file_extension", "operator": "in", "values": ["pdf", "docx"] },
    { "field": "language", "operator": "not", "value": "unknown" }
]}

Ferramentas de busca semântica (grupo: semantic)

As ferramentas de busca semântica exigem que VECTOR_MODEL esteja configurado (ex.: VECTOR_MODEL=e5-base).

semanticSearch

Busca semântica pura baseada em embeddings KNN. Encontra documentos semanticamente relacionados mesmo sem correspondências exatas de palavras-chave. Os resultados são ordenados por similaridade de cosseno. Requer VECTOR_MODEL configurado.

Parâmetros:

  • query (obrigatório): Consulta em linguagem natural — o servidor calcula um embedding e encontra os trechos de documento mais próximos.
  • filters (opcional): Matriz de filtros estruturados (mesmo formato de simpleSearch/extendedSearch)
  • page (opcional): Número da página, baseado em 0 (padrão: 0)
  • pageSize (opcional): Resultados por página (padrão: 10, máximo: 100)
  • similarityThreshold (opcional): Pontuação mínima de similaridade de cosseno para incluir um resultado (0,0–1,0, padrão: 0,70). Menor = mais resultados (correspondência mais ampla); maior = menos resultados (correspondência mais próxima).

Use profileSemanticSearch para ajustar similarityThreshold para seu corpus.

profileSemanticSearch

Ferramenta de depuração para busca semântica. Mostra tempo de embedding, pontuações de cosseno, trechos correspondentes e quantos candidatos passaram no limite de similaridade. Use esta ferramenta para ajustar similarityThreshold para seus dados.

Parâmetros:

  • query (obrigatório): Consulta em linguagem natural para perfil
  • filters (opcional): Matriz de filtros estruturados
  • similarityThreshold (opcional): Limite a testar (0,0–1,0, padrão: 0,70)

Ferramentas de depuração (grupo: debug)

profileQuery

Analise e depure consultas simpleSearch / extendedSearch. Fornece insights detalhados sobre como o Lucene processa sua consulta, quais termos contribuem para a pontuação, como os filtros afetam os resultados e onde existem oportunidades de otimização.

Parâmetros:

  • query (opcional): A consulta de busca (mesma de simpleSearch/extendedSearch)
  • filters (opcional): Matriz de filtros estruturados (mesma das ferramentas de busca)
  • page (opcional): Número da página, baseado em 0 (padrão: 0)
  • pageSize (opcional): Resultados por página (padrão: 10, máximo: 100)
  • sortBy (opcional): Campo de ordenação (mesmo das ferramentas de busca)
  • sortOrder (opcional): Ordem de ordenação (mesma das ferramentas de busca)
  • queryMode (opcional): SIMPLE (padrão) ou EXTENDED — seleciona o modo do analisador de consulta para corresponder à ferramenta de busca que você está analisando
  • analyzeFilterImpact (opcional): Se true, analisa como cada filtro reduz a contagem de resultados. AVISO: Operação cara que requer múltiplas consultas. Padrão: false
  • analyzeDocumentScoring (opcional): Se true, fornece explicações detalhadas de pontuação para os principais documentos usando a API Explanation do Lucene. AVISO: Operação cara. Padrão: false
  • analyzeFacetCost (opcional): Se true, mede a sobrecarga de cálculo de facetas. AVISO: Operação cara. Padrão: false
  • maxDocExplanations (opcional): Número máximo de documentos a explicar quando analyzeDocumentScoring=true (padrão: 5, máximo: 10)

Níveis de análise:

Nível 1: Análise rápida (sempre incluída)

  • Estrutura da consulta e detalhamento de componentes
  • Identificação do tipo de consulta (BooleanQuery, TermQuery, WildcardQuery, etc.)
  • Custo estimado por componente da consulta
  • Estatísticas de termos (frequência de documentos, IDF, classificação de raridade)
  • Métricas de busca (total de resultados, porcentagem de redução por filtro) Nível 2: Análise de Impacto de Filtros (Opcional, Custoso)
  • Mostra como cada filtro afeta a contagem de resultados
  • Calcula a seletividade (baixa/média/alta/muito alta)
  • Mede o tempo de execução por filtro
  • Ajuda a identificar filtros redundantes ou ineficazes

Nível 3: Explicações de Pontuação de Documentos (Opcional, Custoso)

  • Detalhamento de pontuação para os documentos mais bem classificados
  • Mostra quais termos contribuem mais para a pontuação de cada documento
  • Fornece resumos de pontuação legíveis para humanos
  • Usa a API Explanation do Lucene, mas formatada para ser amigável a LLMs

Nível 4: Análise de Custo de Facetas (Opcional, Custoso)

  • Mede a sobrecarga de computação de facetas
  • Mostra o custo por dimensão de faceta
  • Ajuda a decidir se a faceta deve ser desabilitada por questões de desempenho

Retorna:

Um objeto de análise estruturado contendo:

{
  success: boolean,
  queryAnalysis: {
    originalQuery: string,
    parsedQueryType: string,
    components: [{
      type: string,              // "TermQuery", "WildcardQuery", etc.
      field: string,
      value: string,
      occur: string,             // "MUST", "SHOULD", "FILTER", "MUST_NOT"
      estimatedCost: number,
      costDescription: string    // "~450 documents (moderate)"
    }],
    rewrites: [{                 // Query optimizations performed by Lucene
      original: string,
      rewritten: string,
      reason: string
    }],
    warnings: string[]
  },
  searchMetrics: {
    totalIndexedDocuments: number,
    documentsMatchingQuery: number,
    documentsAfterFilters: number,
    filterReductionPercent: number,
    termStatistics: {
      [term: string]: {
        term: string,
        documentFrequency: number,
        totalTermFrequency: number,
        idf: number,
        rarity: string           // "very common", "common", "uncommon", "rare"
      }
    }
  },
  filterImpact?: {               // Only if analyzeFilterImpact=true
    baselineHits: number,
    finalHits: number,
    filterImpacts: [{
      filter: {...},
      hitsBeforeFilter: number,
      hitsAfterFilter: number,
      documentsRemoved: number,
      reductionPercent: number,
      selectivity: string,       // "low", "medium", "high", "very high"
      executionTimeMs: number
    }],
    totalExecutionTimeMs: number
  },
  documentExplanations?: [{      // Only if analyzeDocumentScoring=true
    filePath: string,
    rank: number,
    score: number,
    scoringBreakdown: {
      totalScore: number,
      components: [{
        term: string,
        field: string,
        contribution: number,
        contributionPercent: number,
        details: {
          idf: number,
          tf: number,
          termFrequency: number,
          documentLength: number,
          averageDocumentLength: number,
          explanation: string
        }
      }],
      summary: string            // "Score dominated by term 'contract' (60.8%)"
    },
    matchedTerms: string[]
  }],
  facetCost?: {                  // Only if analyzeFacetCost=true
    facetingOverheadMs: number,
    facetingOverheadPercent: number,
    dimensions: {
      [dimension: string]: {
        dimension: string,
        uniqueValues: number,
        totalCount: number,
        computationTimeMs: number
      }
    }
  },
  recommendations: string[]      // Actionable optimization suggestions
}

Exemplo: Análise Básica de Consulta

Ask Claude: "Profile my search for 'contract AND signed' to understand its performance"

Isso executa uma análise rápida mostrando:

  • Estrutura da consulta (consulta booleana AND com dois termos)
  • Estatísticas dos termos (quão comuns são "contrato" e "assinado")
  • Estimativas de custo (quantos documentos serão examinados)
  • Recomendações de otimização

Exemplo: Análise Profunda com Pontuação

{
  "query": "(contract OR agreement) AND signed",
  "filters": [
    { "field": "language", "value": "en" },
    { "field": "modified_date", "operator": "range", "from": "2024-01-01" }
  ],
  "analyzeDocumentScoring": true,
  "maxDocExplanations": 3
}

Isso fornece explicações detalhadas de pontuação para os 3 principais documentos, mostrando:

  • Quais termos corresponderam em cada documento
  • Quanto cada termo contribuiu para a pontuação final
  • Por que o documento A ficou classificado acima do documento B

Exemplo: Otimização de Filtros

{
  "query": "*",
  "filters": [
    { "field": "file_extension", "value": "pdf" },
    { "field": "language", "value": "en" },
    { "field": "file_type", "value": "application/pdf" }
  ],
  "analyzeFilterImpact": true
}

Isso analisa a eficácia dos filtros, potencialmente revelando:

  • file_extension=pdf reduz os resultados em 75% (alta seletividade)
  • file_type=application/pdf reduz os resultados em 0% (redundante com file_extension)
  • Recomendação: Remover o filtro redundante file_type

Exemplo: Entendendo a Expansão Automática de Frases

Quando você pesquisa por uma frase exata como "Domain Design", a consulta é automaticamente expandida para melhorar a recuperação, mantendo a precisão:

{
  "query": "\"Domain Design\"",
  "analyzeDocumentScoring": true,
  "maxDocExplanations": 3
}

O profiler revela como a consulta foi expandida:

Análise da Consulta:

  • Consulta Original: "Domain Design"
  • Tipo Analisado: BooleanQuery
  • Reescrita: Expansão automática de proximidade de frases (correspondência exata com boost + variantes de proximidade)
  • Componentes da Consulta:
    • PhraseQuery (boost=4.0) - "domain design" (correspondência exata, maior boost)
    • PhraseQuery (boost=2.0) - "domain design"~3 (correspondência de proximidade, slop=3)
    • Variantes adicionais com stemming e boosts menores

Pontuação de Documentos:

  • Correspondência exata ("Domain Design"): Pontuação 0.81 - corresponde a ambas as cláusulas, a cláusula exata domina
  • Correspondência de proximidade ("Domain-driven Design"): Pontuação 0.15 - corresponde apenas à cláusula de proximidade
  • Correspondência de proximidade ("Domain Effective Design"): Pontuação 0.15 - corresponde apenas à cláusula de proximidade

Isso mostra:

  1. Correspondências exatas ficam no topo devido ao boost acumulado de 4.0x (2.0 do stemming x 2.0 da expansão de frase)
  2. Correspondências de proximidade ainda são encontradas com slop=3 (permitindo até 3 palavras entre os termos)
  3. Separação clara de pontuação entre correspondências exatas e de proximidade garante precisão

Notas de Desempenho:

  • Análise básica (padrão): Muito rápida, sobrecarga insignificante (~5-10ms)
  • Análise de impacto de filtros: Requer consultas N+1, onde N é o número de filtros. Pode levar segundos para conjuntos de filtros complexos.
  • Análise de pontuação de documentos: Requer que o Lucene compute objetos Explanation completos. O custo cresce com maxDocExplanations.
  • Análise de custo de facetas: Requer computação de facetas. O custo depende do número de valores de faceta únicos.

Melhores Práticas:

  1. Comece com análise básica (sem flags opcionais) para obter insights rápidos
  2. Habilite análises custosas apenas ao depurar problemas específicos de desempenho
  3. Use analyzeDocumentScoring para entender por que certos documentos ficam bem classificados
  4. Use analyzeFilterImpact para otimizar a ordem dos filtros e remover filtros redundantes
  5. Preste atenção ao array recommendations para dicas de otimização acionáveis

Ferramentas de Crawler (grupo: crawler)

startCrawl

Inicia o rastreamento dos diretórios configurados para indexar documentos.

Parâmetros:

  • fullReindex (opcional): Se verdadeiro, limpa o índice antes de rastrear (padrão: falso). Quando falso e reconciliation-enabled é verdadeiro, um rastreamento incremental é realizado.

Recursos:

  • Extrai automaticamente conteúdo de PDFs, documentos do Office e arquivos do OpenOffice
  • Detecta o idioma do documento
  • Extrai metadados (autor, título, data de criação, etc.)
  • Processamento multithread para indexação rápida
  • Notificações de progresso durante o rastreamento
  • Modo incremental (padrão): Apenas arquivos novos ou modificados são indexados; arquivos excluídos são removidos do índice automaticamente. Recorre a um rastreamento completo se a reconciliação encontrar um erro.

getCrawlerStats

Obtém estatísticas em tempo real sobre o progresso do crawler.

Retorna:

  • filesFound: Total de arquivos descobertos
  • filesProcessed: Arquivos processados até agora
  • filesIndexed: Arquivos indexados com sucesso
  • filesFailed: Arquivos que falharam ao processar
  • bytesProcessed: Total de bytes processados
  • filesPerSecond: Taxa de transferência de processamento
  • megabytesPerSecond: Taxa de transferência de dados
  • elapsedTimeMs: Tempo decorrido desde o início do rastreamento
  • perDirectoryStats: Estatísticas detalhadas por diretório
  • orphansDeleted: Número de entradas de índice removidas porque o arquivo não existe mais no disco (modo incremental)
  • filesSkippedUnchanged: Número de arquivos ignorados porque não foram modificados desde o último rastreamento (modo incremental)
  • reconciliationTimeMs: Tempo gasto comparando o índice com o sistema de arquivos (modo incremental)
  • crawlMode: Ou "full" ou "incremental"
  • currentlyProcessing: Array de arquivos atualmente sendo processados (extraídos/indexados). Cada entrada contém:
    • filePath: Caminho completo para o arquivo sendo processado
    • processingDurationMs: Há quanto tempo o arquivo está sendo processado (em milissegundos)
  • lastCrawlCompletionTimeMs: Timestamp Unix (ms) da última conclusão bem-sucedida do rastreamento (nulo se não houver rastreamento anterior)
  • lastCrawlDocumentCount: Número de documentos no índice após o último rastreamento bem-sucedido (nulo se não houver rastreamento anterior)
  • lastCrawlMode: Modo do último rastreamento - "full" ou "incremental" (nulo se não houver rastreamento anterior)

getCrawlerStatus

Obtém o estado atual do crawler.

Retorna:

  • state: Um de IDLE, CRAWLING, PAUSED ou WATCHING

pauseCrawler

Pausa uma operação de rastreamento em andamento. O crawler pode ser retomado posteriormente com resumeCrawler.

resumeCrawler

Retoma uma operação de rastreamento pausada.

listCrawlableDirectories

Lista todos os diretórios rastreáveis configurados.

Retorna:

  • success: Booleano indicando sucesso da operação
  • directories: Lista de caminhos absolutos de diretórios atualmente configurados
  • totalDirectories: Contagem de diretórios configurados
  • configPath: Caminho para o arquivo de configuração (~/.mcplucene/config.yaml)
  • environmentOverride: Booleano indicando se a variável de ambiente LUCENE_CRAWLER_DIRECTORIES está definida

Exemplo de resposta:

{
  "success": true,
  "directories": [
    "/Users/yourname/Documents",
    "/Users/yourname/Downloads"
  ],
  "totalDirectories": 2,
  "configPath": "/Users/yourname/.mcplucene/config.yaml",
  "environmentOverride": false
}

addCrawlableDirectory

Adiciona um diretório à configuração do crawler.

Parâmetros:

  • path (obrigatório): Caminho absoluto para o diretório a ser rastreado
  • crawlNow (opcional): Se verdadeiro, inicia imediatamente o rastreamento do novo diretório (padrão: falso)

Retorna:

  • success: Booleano indicando sucesso da operação
  • message: Mensagem de confirmação
  • totalDirectories: Contagem atualizada de diretórios configurados
  • directories: Lista atualizada de todos os diretórios
  • crawlStarted (opcional): Presente se crawlNow=true, indica que o rastreamento foi acionado

Validação:

  • O diretório deve existir e ser acessível
  • O caminho deve ser um diretório (não um arquivo)
  • Diretórios duplicados são impedidos
  • Falha se a variável de ambiente LUCENE_CRAWLER_DIRECTORIES estiver definida

Exemplo:

Ask Claude: "Add /Users/yourname/Documents as a crawlable directory"
Ask Claude: "Add /path/to/research and crawl it now"

Persistência da Configuração: O diretório é imediatamente salvo em ~/.mcplucene/config.yaml e será rastreado automaticamente em futuras reinicializações do servidor.

removeCrawlableDirectory

Remove um diretório da configuração do crawler.

Parâmetros:

  • path (obrigatório): Caminho absoluto para o diretório a ser removido

Retorna:

  • success: Booleano indicando sucesso da operação
  • message: Mensagem de confirmação
  • totalDirectories: Contagem atualizada de diretórios configurados
  • directories: Lista atualizada dos diretórios restantes

Notas Importantes:

  • Isso NÃO remove documentos já indexados do diretório removido
  • Para remover documentos indexados, use startCrawl(fullReindex=true) após remover os diretórios
  • Falha se a variável de ambiente LUCENE_CRAWLER_DIRECTORIES estiver definida
  • O diretório deve existir na configuração atual

Exemplo:

Ask Claude: "Stop crawling /Users/yourname/Downloads"
Ask Claude: "Remove /path/to/old/archive from the crawler"

Ferramentas de Informações do Índice (grupo: info)

getIndexStats

Obtém estatísticas sobre o índice Lucene, incluindo métricas de desempenho do cache do lematizador, percentis de tempo de execução de consultas (p50-p99) e tempo de computação de facetas por campo.

Retorna:

  • documentCount: Número total de documentos no índice
  • indexPath: Caminho para o diretório do índice
  • schemaVersion: Versão atual do esquema do índice
  • softwareVersion: Versão do software do servidor
  • buildTimestamp: Timestamp de build do servidor
  • dateFieldHints: Intervalos de data mín/máx para campos de data (created_date, modified_date, indexed_date) no formato ISO-8601 — útil para construir filtros de intervalo de datas
  • sortableFields: Mapa de campos dbmeta_* ordenáveis registrados dinamicamente a partir do enriquecimento de metadados JDBC para seu tipo de ordenação ("numeric" ou "keyword"). Nulo quando nenhum enriquecimento JDBC registrou campos ordenáveis. Use isso para descobrir quais campos dbmeta_* podem ser passados como sortBy. Campos nativos (file_size, created_date, modified_date) são sempre ordenáveis e não estão listados aqui.
  • lemmatizerCacheMetrics: Métricas de desempenho para os caches do lematizador OpenNLP (um por idioma: alemão e inglês)
    • language: Código do idioma (de ou en)
    • hitRate: Taxa de acerto do cache como porcentagem (ex.: "85,3%")
    • totalHits: Número de vezes que um token foi encontrado no cache
    • totalMisses: Número de vezes que um token exigiu lematização
    • cacheSize: Número atual de entradas no cache
    • evictions: Número de entradas de cache removidas devido a limites de tamanho
  • queryRuntimeMetrics: Estatísticas agregadas de desempenho de consultas de busca (nulo antes de qualquer busca ser executada)
    • totalQueries: Número total de consultas de busca executadas desde o início do servidor
    • averageDurationMs: Duração média de consulta em milissegundos (ex.: "12,5")
    • minDurationMs: Duração de consulta mais rápida em milissegundos
    • maxDurationMs: Duração de consulta mais lenta em milissegundos
    • averageHitCount: Número médio de documentos correspondentes por consulta (ex.: "42,3")
    • p50Ms / p75Ms / p90Ms / p95Ms / p99Ms: Percentis de duração de consulta em milissegundos (calculados a partir das últimas 1000 consultas)
    • averageFacetDurationMs: Tempo médio de computação de facetas por consulta em milissegundos (ex.: "0,125")
    • perFieldAverageFacetDurationMs: Tempo médio de computação de facetas por campo em milissegundos (ex.: {"language": "0.031", "file_extension": "0.028", ...})

Desempenho do Cache do Lematizador:

O servidor usa cache de token único para lematização OpenNLP para reduzir o uso de CPU durante indexação e consultas. Cada analisador de idioma (alemão e inglês) mantém um cache LRU compartilhado com até 1.500.000 entradas, compartilhado entre todas as threads de indexação do Lucene. O cache usa chaves insensíveis a maiúsculas/minúsculas para palavras comuns (ex.: "Vertrag" e "vertrag" compartilham a mesma entrada de cache), mantendo nomes próprios sensíveis a maiúsculas/minúsculas (ex.: "Berlin" vs "berlin").

Métricas Principais:

  • Taxa de Acerto: Quanto maior, melhor. 85-95% é típico após indexar alguns milhares de documentos. Taxas de acerto mais altas significam menos uso de CPU.
  • Tamanho do Cache: Número atual de mapeamentos (token, POS tag) para lema em cache. Cresce até 1.500.000 entradas por idioma.
  • Remoções: Quantas entradas foram removidas para abrir espaço para novas. Algumas remoções são normais com grandes conjuntos de documentos. Impacto no desempenho: Sem cache, a lematização pode consumir 70-80% da CPU durante a indexação. Com cache, o uso de CPU normalmente cai para 20-30%, resultando em uma taxa de indexação 2-3x mais rápida para conjuntos de documentos com vocabulário repetitivo.

listIndexedFields

Lista todos os nomes de campos presentes no índice Lucene.

Retorna:

  • fields: Matriz de nomes de campos disponíveis para busca e filtragem

Exemplo de resposta:

{
  "success": true,
  "fields": [
    "file_name",
    "file_path",
    "title",
    "author",
    "content",
    "language",
    "file_extension",
    "file_type",
    "created_date",
    "modified_date"
  ]
}

getDocumentDetails

Recupera todos os campos armazenados e o conteúdo completo de um documento do índice Lucene pelo seu caminho de arquivo. Esta ferramenta recupera detalhes do documento diretamente do índice sem exigir acesso ao sistema de arquivos — útil para examinar conteúdo indexado mesmo se o arquivo original foi movido ou excluído.

Parâmetros:

  • filePath (obrigatório): Caminho absoluto para o arquivo (deve corresponder exatamente ao file_path armazenado no índice)

Retorna:

  • success: Booleano indicando sucesso da operação
  • document: Objeto contendo todos os campos armazenados:
    • file_path: Caminho completo para o arquivo
    • file_name: Nome do arquivo
    • file_extension: Extensão do arquivo (ex.: pdf, docx)
    • file_type: Tipo MIME
    • file_size: Tamanho do arquivo em bytes
    • title: Título do documento
    • author: Nome do autor
    • creator: Aplicativo criador
    • subject: Assunto do documento
    • keywords: Palavras-chave/etiquetas do documento
    • language: Código de idioma detectado
    • created_date: Carimbo de data/hora de criação
    • modified_date: Carimbo de data/hora de modificação
    • indexed_date: Carimbo de data/hora de indexação
    • content_hash: Hash SHA-256 do conteúdo
    • content: Conteúdo de texto extraído completo (limitado a 500KB)
    • contentTruncated: Booleano indicando se o conteúdo foi truncado
    • originalContentLength: Tamanho original do conteúdo (presente apenas se truncado)

Limite de tamanho do conteúdo: O campo content é limitado a 500.000 caracteres (500KB) para garantir que a resposta permaneça com segurança abaixo do limite de resposta MCP de 1MB. Verifique o campo contentTruncated para determinar se o conteúdo completo foi retornado.

Exemplo:

Ask Claude: "Show me the indexed details of /Users/yourname/Documents/report.pdf"
Ask Claude: "What content was extracted from /path/to/contract.docx?"

Exemplo de resposta:

{
  "success": true,
  "document": {
    "file_path": "/Users/yourname/Documents/report.pdf",
    "file_name": "report.pdf",
    "file_extension": "pdf",
    "file_type": "application/pdf",
    "file_size": "125432",
    "title": "Annual Report 2024",
    "author": "John Doe",
    "language": "en",
    "indexed_date": "1706540400000",
    "content_hash": "a1b2c3d4...",
    "content": "This is the full extracted text content of the document...",
    "contentTruncated": false
  }
}

Ferramentas de Observabilidade (grupo: observability)

suggestTerms

Sugere termos do índice que correspondem a um prefixo. Útil para descobrir vocabulário, encontrar palavras compostas em alemão, explorar nomes de autores ou preencher automaticamente valores de campos.

Parâmetros:

  • field (obrigatório): Nome do campo para sugerir termos (ex.: content, author, file_extension)
  • prefix (obrigatório): Prefixo para corresponder aos termos (ex.: ver para encontrar vertrag, version)
  • limit (opcional): Número máximo de termos a retornar (padrão: 20, máximo: 100)

Observações:

  • Para campos analisados (content, title, etc.), o prefixo é automaticamente convertido para minúsculas para corresponder aos tokens indexados
  • Para StringFields (file_extension, language), o prefixo é usado como está (correspondência exata)
  • Campos numéricos/de data (file_size, modified_date, etc.) não são suportados — use getIndexStats para intervalos de data
  • Retorna termos ordenados por frequência no documento (mais comuns primeiro)
  • Retorna resultados vazios para campos inexistentes (não é um erro)

Exemplo — descobrir palavras compostas em alemão:

{
  "field": "content",
  "prefix": "vertrag",
  "limit": 10
}

Exemplo de resposta:

{
  "success": true,
  "field": "content",
  "prefix": "vertrag",
  "terms": [
    {"term": "vertrag", "docFreq": 45},
    {"term": "vertrags", "docFreq": 23},
    {"term": "vertragsklausel", "docFreq": 8},
    {"term": "vertragsbedingungen", "docFreq": 5}
  ],
  "totalTermsMatched": 4
}

getTopTerms

Obtém os termos mais frequentes em um campo. Útil para entender o vocabulário do índice, descobrir valores comuns (idiomas, tipos de arquivo, autores) e identificar termos dominantes.

Parâmetros:

  • field (obrigatório): Nome do campo para obter os principais termos (ex.: content, author, file_extension)
  • limit (opcional): Número máximo de termos a retornar (padrão: 20, máximo: 100)

Observações:

  • Retorna termos ordenados por frequência no documento (mais comuns primeiro)
  • Para campos de conteúdo grandes (>100K termos únicos), um aviso é incluído sugerindo suggestTerms em vez disso
  • Campos numéricos/de data não são suportados — use getIndexStats para intervalos de data
  • Retorna resultados vazios para campos inexistentes (não é um erro)

Exemplo — explorar tipos de arquivo no índice:

{
  "field": "file_extension",
  "limit": 10
}

Exemplo de resposta:

{
  "success": true,
  "field": "file_extension",
  "terms": [
    {"term": "pdf", "docFreq": 234},
    {"term": "docx", "docFreq": 156},
    {"term": "txt", "docFreq": 89},
    {"term": "md", "docFreq": 45}
  ],
  "uniqueTermCount": 12
}

Exemplo — explorar vocabulário de conteúdo:

{
  "field": "content",
  "limit": 20
}

Ferramentas de Administração (grupo: admin)

indexAdmin

Um aplicativo MCP que fornece uma interface visual de usuário para tarefas de manutenção do índice diretamente dentro do seu cliente MCP (ex.: Claude Desktop). Quando invocado, o aplicativo é renderizado inline na conversa e oferece acesso com um clique a operações administrativas sem exigir chamadas manuais de ferramentas.

Index Administration App

Ações disponíveis:

  • Desbloquear Índice — Remove um arquivo write.lock obsoleto após um desligamento inadequado (equivalente a chamar unlockIndex com confirm=true)
  • Otimizar Índice — Mescla segmentos do índice para melhorar o desempenho de busca (equivalente a chamar optimizeIndex)
  • Purgar Índice — Exclui todos os documentos do índice (equivalente a chamar purgeIndex com confirm=true)

Cada ação mostra feedback de status inline (sucesso, erro ou detalhes de progresso) diretamente na interface do aplicativo.

Exemplo:

Ask Claude: "Can you invoke the indexAdmin tool please?"

optimizeIndex

Otimiza o índice Lucene mesclando segmentos. Esta é uma operação de longa duração que é executada em segundo plano.

Parâmetros:

  • maxSegments (opcional): Número alvo de segmentos após a otimização (padrão: 1 para otimização máxima)

Retorna:

  • success: Booleano indicando que a operação foi iniciada
  • operationId: UUID para rastrear a operação
  • targetSegments: A contagem alvo de segmentos
  • currentSegments: A contagem atual de segmentos antes da otimização
  • message: Mensagem de status

Comportamento:

  • Retorna imediatamente após iniciar a operação em segundo plano
  • Use getIndexAdminStatus para consultar o progresso
  • Não pode ser executado enquanto o rastreador está ativamente rastreando
  • Apenas uma operação administrativa pode ser executada por vez

Exemplo:

Ask Claude: "Optimize the search index"
Ask Claude: "What's the status of the optimization?"

Observações de desempenho:

  • A otimização melhora o desempenho de busca reduzindo o número de segmentos
  • Aumenta temporariamente o uso de disco durante a mesclagem
  • Para índices grandes, isso pode levar de vários minutos a horas

purgeIndex

Exclui todos os documentos do índice Lucene. Esta é uma operação destrutiva e de longa duração que é executada em segundo plano.

Parâmetros:

  • confirm (obrigatório): Deve ser definido como true para prosseguir. Esta é uma medida de segurança.
  • fullPurge (opcional): Se true, também exclui arquivos de índice e reinicializa (padrão: false)

Retorna:

  • success: Booleano indicando que a operação foi iniciada
  • operationId: UUID para rastrear a operação
  • documentsDeleted: Número de documentos que serão excluídos
  • fullPurge: Se uma purga completa foi solicitada
  • message: Mensagem de status

Comportamento:

  • Retorna imediatamente após iniciar a operação em segundo plano
  • Use getIndexAdminStatus para consultar o progresso
  • Apenas uma operação administrativa pode ser executada por vez

Modos de purga:

  • Purga padrão (fullPurge=false): Exclui todos os documentos, mas mantém os arquivos de índice. O espaço em disco é recuperado gradualmente durante mesclagens futuras.
  • Purga completa (fullPurge=true): Exclui todos os documentos E arquivos de índice, depois reinicializa um índice vazio. O espaço em disco é recuperado imediatamente.

Exemplo:

Ask Claude: "Delete all documents from the index - I confirm this"
Ask Claude: "Purge the index completely and reclaim disk space - I confirm this"

Aviso: Esta operação não pode ser desfeita. Todos os documentos indexados serão excluídos permanentemente. Você precisará rastrear novamente os diretórios para repovoar o índice.

unlockIndex

Remove o arquivo write.lock do diretório do índice Lucene. Esta é uma operação de recuperação perigosa — use apenas se tiver certeza de que nenhum outro processo está usando o índice.

Parâmetros:

  • confirm (obrigatório): Deve ser definido como true para prosseguir. Esta é uma medida de segurança.

Retorna:

  • success: Booleano indicando sucesso da operação
  • message: Mensagem de confirmação
  • lockFileExisted: Booleano indicando se um arquivo de bloqueio estava presente
  • lockFilePath: Caminho para o arquivo de bloqueio

Quando usar: Use esta ferramenta quando o servidor falhar ao iniciar com um LockObtainFailedException após um desligamento inadequado. Consulte Solução de problemas para detalhes.

Exemplo:

Ask Claude: "Unlock the Lucene index - I confirm this is safe"

Aviso: Desbloquear um índice que está sendo ativamente gravado por outro processo pode causar corrupção de dados. Use apenas quando tiver certeza de que o bloqueio está obsoleto.

getIndexAdminStatus

Obtém o status de operações administrativas de longa duração do índice (otimizar, purgar).

Parâmetros: Nenhum

Retorna:

  • success: Booleano indicando que o status foi recuperado
  • state: Estado atual: IDLE, OPTIMIZING, PURGING, COMPLETED ou FAILED
  • operationId: UUID da operação atual/última
  • progressPercent: Porcentagem de progresso (0-100)
  • progressMessage: Mensagem de progresso legível por humanos
  • elapsedTimeMs: Tempo decorrido desde o início da operação (em milissegundos)
  • lastOperationResult: Mensagem de resultado da última operação concluída

Exemplo de resposta (durante otimização):

{
  "success": true,
  "state": "OPTIMIZING",
  "operationId": "a1b2c3d4-...",
  "progressPercent": 45,
  "progressMessage": "Merging segments...",
  "elapsedTimeMs": 12500,
  "lastOperationResult": null
}

Exemplo de resposta (ocioso após conclusão):

{
  "success": true,
  "state": "IDLE",
  "operationId": null,
  "progressPercent": null,
  "progressMessage": "No admin operation running",
  "elapsedTimeMs": null,
  "lastOperationResult": "Optimization completed successfully. Merged to 1 segment(s)."
}

Exemplo:

Ask Claude: "What's the status of the index optimization?"
Ask Claude: "Is the purge operation complete?"

Configuração de Exposição de Ferramentas

Controle quais ferramentas MCP são expostas usando duas variáveis de ambiente:

VariávelPadrãoDescrição
LUCENE_TOOLS_INCLUDE* (todas as ferramentas)Nomes de ferramentas separados por vírgula ou abreviações de grupo para expor
LUCENE_TOOLS_EXCLUDE(vazio)Nomes de ferramentas separados por vírgula ou abreviações de grupo para ocultar; sempre vence sobre incluir

Grupos de Ferramentas

GrupoFerramentas
searchsimpleSearch, extendedSearch
semanticsemanticSearch, profileSemanticSearch
debugprofileQuery
infogetIndexStats, listIndexedFields, getDocumentDetails
observabilitysuggestTerms, getTopTerms
crawlerstartCrawl, getCrawlerStats, getCrawlerStatus, pauseCrawler, resumeCrawler, listCrawlableDirectories, addCrawlableDirectory, removeCrawlableDirectory
adminoptimizeIndex, purgeIndex, unlockIndex, getIndexAdminStatus, indexAdmin

Nomes individuais de ferramentas podem ser usados além das abreviações de grupo.

Exemplos

# Default — all tools (semantic tools require VECTOR_MODEL)
java -jar mcpluceneserver.jar

# Small LLM — search tools only
LUCENE_TOOLS_INCLUDE=search java -jar mcpluceneserver.jar

# Search + semantic search
LUCENE_TOOLS_INCLUDE=search,semantic VECTOR_MODEL=e5-base java -jar mcpluceneserver.jar

# All tools except destructive admin
LUCENE_TOOLS_EXCLUDE=purgeIndex,unlockIndex java -jar mcpluceneserver.jar

# All tools except entire admin group
LUCENE_TOOLS_EXCLUDE=admin java -jar mcpluceneserver.jar

Esquema de Campos do Índice

Quando os documentos são indexados pelo rastreador, os seguintes campos são automaticamente extraídos e armazenados:

Campos de Conteúdo

  • content: Texto completo do documento (analisado, pesquisável)
  • content_reversed: Tokens invertidos do conteúdo (analisados com ReverseUnicodeNormalizingAnalyzer, não armazenados). Usados internamente para consultas eficientes de curinga à esquerda -- não diretamente pesquisáveis pelos usuários.
  • content_lemma_de: Tokens lematizados usando o lematizador OpenNLP alemão (analisados com OpenNLPLemmatizingAnalyzer, não armazenados). SEMPRE presente para TODOS os documentos, independentemente do idioma detectado, para permitir correspondência em idiomas mistos. Usado internamente para busca baseada em lematização -- não diretamente pesquisável pelos usuários.
  • content_lemma_en: Tokens lematizados usando o lematizador OpenNLP inglês (analisados com OpenNLPLemmatizingAnalyzer, não armazenados). SEMPRE presente para TODOS os documentos, independentemente do idioma detectado, para permitir correspondência em idiomas mistos. Usado internamente para busca baseada em lematização -- não diretamente pesquisável pelos usuários.
  • content_translit_de: Campo de sombra de transliteração alemã que mapeia dígrafos de trema (ae→ä, oe→ö, ue→ü) antes da normalização Unicode padrão (analisado com GermanTransliteratingAnalyzer, não armazenado). SEMPRE presente para TODOS os documentos. Permite consultas de dígrafos ASCII como "Mueller" corresponderem a documentos com trema como "Müller". Usado internamente -- não diretamente pesquisável pelos usuários.
  • passages: Matriz de passagens destacadas retornadas nos resultados de busca (veja Formato de Resposta de Busca abaixo)

Informações do Arquivo

  • file_path: Caminho completo para o arquivo (ID único)
  • file_name: Nome do arquivo
  • file_extension: Extensão do arquivo (ex.: pdf, docx)
  • file_type: Tipo MIME (ex.: application/pdf)
  • file_size: Tamanho do arquivo em bytes

Metadados do Documento

  • title: Título do documento (extraído dos metadados)
  • author: Nome do autor
  • creator: Criador/aplicativo que criou o documento
  • subject: Assunto do documento
  • keywords: Palavras-chave/etiquetas do documento

Idioma e Datas

  • language: Código de idioma detectado automaticamente (ex.: en, de, fr)
  • created_date: Carimbo de data/hora de criação do arquivo
  • modified_date: Carimbo de data/hora de modificação do arquivo
  • indexed_date: Quando o documento foi indexado

Técnico

  • content_hash: Hash SHA-256 para detecção de alterações

Formato de Resposta de Busca

Os resultados de busca são otimizados para respostas MCP (< 1 MB) e incluem:

{
  "success": true,
  "documents": [
    {
      "score": 0.85,
      "file_name": "example.pdf",
      "file_path": "/path/to/example.pdf",
      "title": "Example Document",
      "author": "John Doe",
      "language": "en",
      "passages": [
        {
          "text": "...relevant <em>search term</em> highlighted in context...",
          "score": 1.0,
          "matchedTerms": ["search term"],
          "termCoverage": 1.0,
          "position": 0.12,
          "source": "keyword"
        },
        {
          "text": "...another occurrence of <em>search</em> in a later section...",
          "score": 0.75,
          "matchedTerms": ["search"],
          "termCoverage": 0.5,
          "position": 0.67,
          "source": "keyword"
        }
      ]
    }
  ],
  "totalHits": 42,
  "page": 0,
  "pageSize": 10,
  "totalPages": 5,
  "hasNextPage": true,
  "hasPreviousPage": false,
  "searchTimeMs": 12,
  "facets": {
    "language": [
      { "value": "en", "count": 25 },
      { "value": "de", "count": 12 },
      { "value": "fr", "count": 5 }
    ],
    "file_extension": [
      { "value": "pdf", "count": 30 },
      { "value": "docx", "count": 8 },
      { "value": "xlsx", "count": 4 }
    ],
    "file_type": [
      { "value": "application/pdf", "count": 30 },
      { "value": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "count": 8 }
    ],
    "author": [
      { "value": "John Doe", "count": 15 },
      { "value": "Jane Smith", "count": 10 }
    ]
  },
  "_search": {
    "query": "contract",
    "filters": [],
    "page": 0,
    "pageSize": 10
  },
  "_actions": [
    {
      "type": "nextPage",
      "tool": "simpleSearch",
      "parameters": { "query": "contract", "filters": [], "page": 1, "pageSize": 10 }
    },
    {
      "type": "drillDown",
      "tool": "simpleSearch",
      "parameters": { "query": "contract", "filters": [{ "field": "language", "operator": "eq", "value": "en" }], "page": 0, "pageSize": 10 },
      "hits": 25
    }
  ]
}

Cada documento em documents[] também carrega seu próprio bloco _actions:

{
  "score": 0.85,
  "file_path": "/path/to/example.pdf",
  "_actions": [
    {
      "type": "fetchContent",
      "tool": "getDocumentDetails",
      "parameters": { "filePath": "/path/to/example.pdf" }
    }
  ]
}

_actions Estilo HATEOAS (Encadeamento de LLM):

Cada resposta de busca inclui dois blocos de ação pré-calculados que permitem que um LLM encadeie chamadas de ferramenta sem raciocinar sobre o mapeamento de parâmetros:

  • _search -- Captura o estado exato da busca (consulta, filtros, página, pageSize) usado para produzir esta resposta. Útil para introspecção e para construir consultas de acompanhamento.

  • _actions em nível de resposta -- Contém chamadas de ferramenta prontas para uso para navegar pelo conjunto de resultados:

    Tipo de açãoQuando presenteDescrição
    prevPagepage > 0Ir para a página anterior de resultados. Passe parameters diretamente para o tool nomeado.
    nextPagehasNextPage = trueIr para a próxima página de resultados. Passe parameters diretamente para o tool nomeado.
    drillDownfacetas disponíveisRestringir resultados adicionando um valor de faceta como filtro. O campo hits mostra a contagem esperada de resultados. Limitado aos 2 principais valores por dimensão de faceta; apenas valores que ainda não estão ativos como filtros são incluídos.
  • _actions em nível de documento -- Cada documento em documents[] inclui:

    Tipo de açãoDescrição
    fetchContentBuscar o texto completo do documento e metadados usando getDocumentDetails. O filePath é pré-preenchido.

Para usar uma ação, chame o tool nomeado na ação com o mapa parameters passado como está — nenhuma transformação necessária.

Principais Recursos:

  • Métricas de Desempenho de Busca: Cada resposta de busca inclui searchTimeMs mostrando o tempo exato de execução em milissegundos, permitindo monitoramento de desempenho e otimização.

  • Passagens com Destaque: O campo completo content NÃO é incluído nos resultados de busca para manter os tamanhos de resposta gerenciáveis. Em vez disso, cada documento contém uma matriz passages com até max-passages (padrão: 3) trechos destacados individualmente. Cada passagem é um trecho separado em nível de frase (não uma única string concatenada), ordenado por relevância (melhor primeiro). Passagens longas são truncadas para max-passage-char-length (padrão: 200) centralizadas em torno dos termos destacados, removendo texto irrelevante no início/fim. Cada passagem inclui:

    • text -- O trecho destacado com termos correspondentes envolvidos em tags <em>.
    • score -- Pontuação de relevância normalizada (0.0-1.0), derivada da pontuação de passagem BM25 do Lucene. A melhor passagem pontua 1.0; outras passagens são pontuadas em relação à melhor.
    • matchedTerms -- Os termos de consulta distintos que aparecem nesta passagem (extraídos das tags <em>). Úteis para entender quais partes de uma consulta de múltiplos termos uma passagem satisfaz.
    • termCoverage -- A fração de todos os termos da consulta presentes nesta passagem (0.0-1.0). Um valor de 1.0 significa que todos os termos da consulta corresponderam. LLMs podem usar isso para preferir passagens que atendam à consulta completa.
    • position -- Localização dentro do documento de origem (0.0 = início, 1.0 = fim), derivada do deslocamento de caracteres da passagem. Útil para citações ou para entender a estrutura do documento.
    • source -- Indica como esta passagem foi produzida: "keyword" significa que o realçador BM25 encontrou correspondências de termos no texto do documento indexado; "semantic" significa que o melhor trecho vetorial correspondente foi usado como o trecho (relevante porque o documento foi recuperado por similaridade vetorial, mesmo que as palavras exatas da consulta não apareçam no texto).
  • Facetamento Lucene: O objeto facets usa SortedSetDocValues do Lucene para busca facetada eficiente. Mostra valores reais de facetas e contagens de documentos dos resultados de busca, não apenas campos disponíveis. Apenas dimensões de facetas que possuem valores no conjunto de resultados são retornadas.

  • Dimensões de Facetas: Os seguintes campos são indexados como facetas:

    • language - Idioma do documento detectado (código ISO 639-1)
    • file_extension - Extensão do arquivo (pdf, docx, etc.)
    • file_type - Tipo MIME
    • author - Autor do documento (multivalorado)

Exemplos de Busca Facetada

Use facetas para criar consultas de drill-down e refinar os resultados da busca:

# Filter by file type using facet values
filters: [{ field: "file_extension", value: "pdf" }]

# Filter by language using facet values
filters: [{ field: "language", value: "de" }]

# Filter by author using facet values
filters: [{ field: "author", value: "John Doe" }]

# Combine search query with facet filter
query: "contract agreement"
filters: [{ field: "file_extension", value: "pdf" }]

Fluxo de Trabalho Orientado por Facetas:

  1. Realize a busca inicial com uma consulta ampla
  2. Revise facets na resposta para ver as opções de refinamento disponíveis
  3. Aplique filtros usando valores de facetas para restringir os resultados
  4. Itere para aprofundar em subconjuntos específicos

Exemplos de Uso

Exemplo 1: Indexe sua Pasta de Documentos

  1. Edite application.yaml:
lucene:
  crawler:
    directories:
      - "/Users/yourname/Documents"
    crawl-on-startup: true
  1. Inicie o servidor:
java -jar target/luceneserver-0.0.1-SNAPSHOT.jar
  1. O rastreador inicia automaticamente e indexa todos os documentos suportados na sua pasta de Documentos.

Exemplo 2: Busca com Filtragem

Pergunte ao Claude:

Search for "machine learning" in PDF documents only

Claude usará:

query: "machine learning"
filters: [{ field: "file_extension", value: "pdf" }]

Exemplo 3: Encontrar Documentos por Autor

Pergunte ao Claude:

Find all documents written by John Doe

Claude usará:

query: "*"
filters: [{ field: "author", value: "John Doe" }]

Exemplo 4: Monitorar o Progresso do Rastreador

Pergunte ao Claude:

Show me the crawler statistics

Claude chama getCrawlerStats() e mostra:

  • Arquivos processados: 1,234 / 5,000
  • Taxa de transferência: 85 arquivos/seg
  • Indexados: 1,200 (98%)
  • Falhas: 34 (2%)

Exemplo 5: Rastreamento Manual com Reindexação Completa

Pergunte ao Claude:

Reindex all documents from scratch

Claude chama startCrawl(fullReindex: true), que:

  1. Limpa o índice existente
  2. Re-rastreia todos os diretórios configurados
  3. Indexa todos os documentos do zero

Exemplo 6: Busca Específica por Idioma

Pergunte ao Claude:

Find German documents about "Technologie"

Claude usa:

query: "Technologie"
filters: [{ field: "language", value: "de" }]

Exemplo 7: Busca com Passagens

Os resultados da busca incluem uma matriz passages com trechos destacados e metadados de qualidade:

{
  "file_name": "report.pdf",
  "passages": [
    {
      "text": "...discusses the impact of <em>machine learning</em> on modern software development. The study shows...",
      "score": 1.0,
      "matchedTerms": ["machine learning"],
      "termCoverage": 1.0,
      "position": 0.08,
      "source": "keyword"
    },
    {
      "text": "...<em>machine learning</em> algorithms were applied to the dataset in Section 4...",
      "score": 0.75,
      "matchedTerms": ["machine learning"],
      "termCoverage": 1.0,
      "position": 0.45,
      "source": "keyword"
    }
  ]
}

Isso permite que você veja trechos relevantes sem baixar o documento completo. Os campos de metadados ajudam LLMs a identificar rapidamente a melhor passagem: prefira passagens com alto termCoverage (cobre mais da consulta), use position para contexto de estrutura do documento e verifique source para entender se a passagem foi encontrada por correspondência de palavras-chave ("keyword") ou por similaridade vetorial ("semantic").

Exemplo 8: Gerenciando Diretórios Rastreáveis em Tempo de Execução

Pergunte ao Claude para gerenciar diretórios sem editar arquivos de configuração:

"What directories are currently being crawled?"
# Claude calls listCrawlableDirectories()
# Response: Shows all configured directories and config file location

"Add /Users/yourname/Research as a crawlable directory"
# Claude calls addCrawlableDirectory(path="/Users/yourname/Research")
# Directory is added to ~/.mcplucene/config.yaml

"Add /Users/yourname/Projects and start crawling it now"
# Claude calls addCrawlableDirectory(path="/Users/yourname/Projects", crawlNow=true)
# Directory is added and crawl starts immediately

"Stop crawling /Users/yourname/Downloads"
# Claude calls removeCrawlableDirectory(path="/Users/yourname/Downloads")
# Directory is removed from config (indexed documents remain)

Persistência de Configuração:

Os diretórios que você adiciona por meio das ferramentas MCP são salvos em ~/.mcplucene/config.yaml:

lucene:
  crawler:
    directories:
      - /Users/yourname/Documents
      - /Users/yourname/Research
      - /Users/yourname/Projects

Essa configuração persiste entre reinicializações do servidor - não é necessário reconfigurar a cada vez.

Substituição por Variável de Ambiente:

Se você definir a variável de ambiente LUCENE_CRAWLER_DIRECTORIES, ela terá precedência:

{
  "mcpServers": {
    "lucene-search": {
      "command": "java",
      "args": ["-Dspring.profiles.active=deployed", "-jar", "/path/to/jar"],
      "env": {
        "LUCENE_CRAWLER_DIRECTORIES": "/path1,/path2"
      }
    }
  }
}

Quando isso é definido, addCrawlableDirectory e removeCrawlableDirectory retornarão uma mensagem de erro indicando que a substituição por ambiente está ativa.

Exemplo 9: Trabalhando com Busca Lexical (Sinônimos e Variações)

Nota: Ao usar este servidor por meio do Claude ou de outro assistente de IA, a expansão de sinônimos acontece automaticamente - a IA constrói consultas OR para você com base na sua solicitação em linguagem natural. Os exemplos abaixo mostram a sintaxe de consulta subjacente para referência ou uso direto da API.

Como o mecanismo de busca realiza correspondência lexical exata sem expansão automática de sinônimos, você precisa incluir explicitamente sinônimos e variações de palavras na sua consulta:

Busca básica (pode perder resultados relevantes):

query: "car"

Isso corresponderá SOMENTE a documentos que contenham a palavra exata "car", perdendo documentos com "automobile", "vehicle", etc.

Melhor: Inclua sinônimos com OR:

query: "(car OR automobile OR vehicle)"

Melhor ainda: Combine sinônimos com curingas para variações:

query: "(car* OR automobile* OR vehicle*)"

Isso corresponde a: car, cars, automobile, automobiles, vehicle, vehicles, etc.

Exemplo do mundo real - Encontrando contratos:

query: "(contract* OR agreement* OR deal*) AND (sign* OR execut* OR finali*)"
filters: [{ field: "file_extension", value: "pdf" }]

Isso encontrará documentos contendo variações como:

  • "contract signed", "agreement executed", "deal finalized"
  • "contracts signing", "agreements execute", "deals finalizing"

Dica: Use o facets na resposta da busca para descobrir os termos exatos usados nos seus documentos e refine sua consulta de acordo.

Recursos do Rastreador de Documentos

Rastreamento Automático

O rastreador inicia automaticamente na inicialização do servidor (se crawl-on-startup: true) e:

  1. Descobre arquivos que correspondem aos padrões de inclusão nos diretórios configurados
  2. Extrai conteúdo usando Apache Tika (suporta mais de 100 formatos de arquivo)
  3. Detecta idioma automaticamente para cada documento
  4. Extrai metadados (autor, título, datas, etc.)
  5. Indexa documentos em lotes para desempenho ideal
  6. Monitora diretórios para alterações (criar, modificar, excluir)

Indexação Incremental (Reconciliação)

Por padrão (reconciliation-enabled: true), todo rastreamento que não seja uma reindexação completa realiza uma passagem incremental primeiro. Isso torna rastreamentos repetidos significativamente mais rápidos porque arquivos inalterados nunca são reprocessados.

Como funciona:

  1. Index snapshot — Todos os pares (file_path, modified_date) são lidos do índice Lucene.
  2. Filesystem snapshot — Os diretórios configurados são percorridos e os pares (file_path, mtime) atuais são coletados (sem extração de conteúdo nesta etapa).
  3. Diff de quatro vias é calculado:
    • DELETE — caminhos no índice que não existem mais no disco (órfãos).
    • ADD — caminhos no disco que ainda não estão no índice.
    • UPDATE — caminhos onde o mtime no disco é mais recente que o modified_date armazenado.
    • SKIP — caminhos idênticos; estes nunca são tocados.
  4. Exclusões de órfãos são aplicadas primeiro (exclusão em massa via uma única consulta Lucene).
  5. Apenas arquivos ADD e UPDATE são rastreados, extraídos e indexados.
  6. Após a conclusão bem-sucedida, o estado do rastreamento (timestamp, contagem de documentos, modo) é persistido em ~/.mcplucene/crawl-state.yaml.

Comportamento de fallback: Se a reconciliação falhar por qualquer motivo (erro de I/O ao ler o índice, falha na varredura do filesystem, etc.), o sistema automaticamente cai para um rastreamento completo. Nenhum dado é perdido e nenhuma intervenção manual é necessária.

Desabilitando indexação incremental: Defina reconciliation-enabled: false em application.yaml para sempre executar um rastreamento completo. Alternativamente, passe fullReindex: true para startCrawl para forçar um único rastreamento completo sem alterar o padrão.

Arquivo de estado persistido:

~/.mcplucene/crawl-state.yaml

Este arquivo registra o horário de conclusão, a contagem de documentos e o modo do último rastreamento bem-sucedido. Ele é gravado somente após um rastreamento concluir com sucesso.

Gerenciamento de Versão de Esquema

O servidor rastreia a versão do esquema do índice para detectar quando o esquema muda entre atualizações de software. Isso elimina a necessidade de reindexação manual após atualizações.

Como funciona:

  1. Cada versão incorpora uma constante SCHEMA_VERSION que reflete o esquema atual de campos do índice.
  2. A versão do esquema é persistida nos metadados de commit do Lucene junto com a versão do software.
  3. Na inicialização, o servidor compara a versão do esquema armazenada com a atual.
  4. Se forem diferentes (ou se um índice legado não tiver versão), uma reindexação completa é acionada automaticamente.

O que aciona um aumento de versão de esquema:

  • Adicionar ou remover campos indexados
  • Alterar analisadores de campos
  • Modificar opções de indexação de campos (armazenados, vetores de termos, etc.)

Verificando informações de versão: Use getIndexStats para ver a versão atual do esquema, a versão do software e o timestamp de build.

Monitoramento em Tempo Real

Com o monitoramento de diretórios habilitado (watch-enabled: true):

  • Novos arquivos são automaticamente indexados quando adicionados
  • Arquivos modificados são reindexados com conteúdo atualizado
  • Arquivos excluídos são removidos do índice

Otimização de Desempenho

Multithreading:

  • Rastreia múltiplos diretórios em paralelo (pool de threads configurável)
  • Cada diretório é processado por uma thread separada

Processamento em Lote:

  • Documentos são indexados em lotes (padrão: 100 documentos)
  • Reduz a sobrecarga de I/O e melhora a velocidade de indexação

Otimização NRT (Near Real-Time):

  • Operação normal: intervalo de atualização de 100ms para atualizações rápidas de busca
  • Indexação em massa (>1000 arquivos): Reduz automaticamente para 5s para reduzir sobrecarga
  • Restaura para 100ms após a conclusão da operação em massa

Notificações de Progresso:

  • Baseadas em timer: atualizações a cada 30 segundos (configurável via progress-notification-interval-ms)
  • Mostra throughput (arquivos/seg, MB/seg), progresso e nomes de arquivos em processamento
  • Não bloqueante: Aparecem na área de notificação do sistema sem interromper o fluxo de trabalho
    • macOS: Notificações aparecem na Central de Notificações (canto superior direito)
    • Windows: Notificações toast na área de notificação do sistema
    • Linux: Usa notify-send para notificações de desktop

Tratamento de Erros

  • Arquivos com falha são registrados, mas não interrompem o rastreamento
  • Estatísticas rastreiam arquivos bem-sucedidos vs. com falha
  • Documentos grandes são totalmente indexados (sem truncamento por padrão)
  • Arquivos corrompidos ou inacessíveis são ignorados graciosamente

Solução de Problemas

Onde encontrar os logs?

Ao executar com o perfil deployed, o log de console é desabilitado para garantir comunicação STDIO limpa com clientes MCP. Em vez disso, os logs são gravados em arquivos em:

~/.mcplucene/log/mcplucene.log

O diretório de logs é ${user.home}/.mcplucene/log por padrão (configurado em logback.xml). Os arquivos de log são rotacionados automaticamente:

  • Máximo de 10MB por arquivo
  • Até 5 arquivos de log retidos
  • Tamanho total limitado a 50MB

Para visualizar logs recentes:

# View the current log file
cat ~/.mcplucene/log/mcplucene.log

# Follow logs in real-time
tail -f ~/.mcplucene/log/mcplucene.log

# View last 100 lines
tail -n 100 ~/.mcplucene/log/mcplucene.log

Durante o desenvolvimento (sem o perfil deployed), os logs são gravados no console em vez de arquivos.

Mudanças de versão de esquema e reindexação automática

O servidor agora inclui gerenciamento automático de versão de esquema. Quando você atualiza para uma nova versão que altera o esquema do índice (por exemplo, adiciona novos campos, altera analisadores ou modifica opções de indexação de campos), o servidor detecta a incompatibilidade de versão na inicialização e aciona automaticamente uma reindexação completa.

O que acontece:

  1. Na inicialização, o servidor compara a versão do esquema armazenada com a versão atual
  2. Se forem diferentes, uma reindexação completa é acionada automaticamente
  3. Você verá uma mensagem de log: Schema version changed — triggering full reindex
  4. A reindexação é executada em segundo plano; você pode verificar o progresso com getCrawlerStats

Reindexação manual: Se você precisar forçar uma reindexação manual por qualquer motivo, ainda pode acioná-la:

Ask Claude: "Reindex all documents from scratch"

Isso chama startCrawl(fullReindex: true), que limpa o índice existente e re-rastreia todos os diretórios configurados.

Informações de versão: Use getIndexStats para ver a versão atual do esquema, a versão do software e o timestamp de build.

Arquivo de bloqueio do índice impede a inicialização (write.lock)

Sintoma: O servidor falha ao iniciar com um erro como Lock held by another program ou LockObtainFailedException.

Causa: Quando o servidor MCP não é encerrado corretamente (por exemplo, o processo foi morto à força, o sistema travou ou o Claude Desktop foi encerrado abruptamente), o Lucene pode deixar um arquivo write.lock no diretório do índice. Este arquivo de bloqueio é usado para impedir que múltiplos processos gravem no mesmo índice simultaneamente. Quando é deixado para trás após um encerramento não limpo, ele bloqueia a inicialização do servidor porque o Lucene pensa que outro processo ainda está usando o índice.

Solução: Exclua o arquivo de bloqueio manualmente:

# Remove the write.lock file from the index directory
rm ~/.mcplucene/luceneindex/write.lock

Após remover o arquivo de bloqueio, o servidor deve iniciar normalmente.

Prevenção: Tente encerrar o Claude Desktop graciosamente quando possível. Se você precisar forçar o encerramento, esteja ciente de que pode ser necessário remover o arquivo de bloqueio antes da próxima inicialização.

Nota: O caminho padrão do índice é ~/.mcplucene/luceneindex. Se você configurou um caminho de índice personalizado via LUCENE_INDEX_PATH ou application.yaml, procure o arquivo write.lock nesse diretório.

Servidor mostra "em execução" mas as ferramentas não funcionam

Isso geralmente indica problemas de comunicação STDIO:

  1. Certifique-se de que o argumento -Dspring.profiles.active=deployed está presente na configuração
  2. Verifique se nenhuma outra saída está sendo gravada no stdout
  3. Confirme que o caminho do JAR é absoluto, não relativo
  4. Se você modificou a configuração, certifique-se de que as configurações do perfil "deployed" estão corretas

Claude Desktop não mostra o servidor

  1. Verifique se o caminho do arquivo JAR na configuração está correto e é absoluto
  2. Confirme que o Java 25+ está instalado: java -version
  3. Valide a sintaxe JSON no arquivo de configuração
  4. Verifique os logs do Claude Desktop para mensagens de erro
  5. Tente executar o JAR manualmente para verificar erros de inicialização:
    java -jar /path/to/luceneserver-0.0.1-SNAPSHOT.jar
    

Servidor falha ao iniciar

  1. Certifique-se de que o caminho do diretório do índice Lucene é válido
  2. Verifique se nenhum outro processo está bloqueando o diretório do índice
  3. Confirme espaço em disco suficiente para o índice

Resultados de busca vazios

O índice pode estar vazio por vários motivos:

  1. Nenhum diretório configurado: Adicione diretórios a application.yaml sob lucene.crawler.directories
  2. Crawler não iniciado: Use a ferramenta MCP startCrawl ou habilite crawl-on-startup: true
  3. Nenhum arquivo correspondente: Verifique se seus diretórios contêm arquivos que correspondem aos padrões de inclusão
  4. Arquivos com falha na indexação: Verifique os logs para erros, use getCrawlerStats para ver a contagem de arquivos com falha

Crawler não está indexando arquivos

  1. Verifique os caminhos dos diretórios: Certifique-se de que os caminhos em application.yaml são absolutos e existem
  2. Verifique as permissões de arquivo: O servidor precisa de acesso de leitura a todos os arquivos
  3. Verifique os padrões de inclusão: Os arquivos devem corresponder a pelo menos um padrão de inclusão
  4. Verifique os padrões de exclusão: Os arquivos não devem corresponder a nenhum padrão de exclusão
  5. Monitore o status do crawler: Use as ferramentas MCP getCrawlerStatus e getCrawlerStats
  6. Verifique os logs: Procure por erros de parsing ou exceções de I/O

Erros de falta de memória durante a indexação

Se você encontrar erros OOM com documentos muito grandes:

  1. Defina o limite de conteúdo: Altere max-content-length em application.yaml (por exemplo, 5242880 para 5MB)
  2. Aumente o heap do JVM: Adicione -Xmx2g aos argumentos JVM na configuração do Claude Desktop
  3. Reduza o pool de threads: Diminua thread-pool-size para reduzir o processamento concorrente
  4. Reduza o tamanho do lote: Diminua batch-size para fazer commits mais frequentes

Desempenho de indexação lento

  1. Aumente o pool de threads: Aumente thread-pool-size (padrão: 4)
  2. Aumente o tamanho do lote: Aumente batch-size para menos commits (padrão: 100)
  3. Desabilite a detecção de idioma: Defina detect-language: false se não for necessário
  4. Desabilite a extração de metadados: Defina extract-metadata: false se não for necessário
  5. Verifique o I/O do disco: Disco lento pode ser um gargalo para a indexação

Considerações de Segurança

Conteúdo de Documentos Não Confiável

O MCP Lucene Server indexa documentos de diretórios rastreados e retorna seu conteúdo (passagens, metadados, texto completo) nas respostas das ferramentas MCP. Este conteúdo é inerentemente não confiável — qualquer documento colocado em um diretório rastreado pode influenciar o que o cliente MCP (LLM) vê nas respostas das ferramentas.

Risco de Injeção Indireta de Prompt

Isso cria um potencial para injeção indireta de prompt: um documento maliciosamente elaborado pode conter texto projetado para manipular um LLM que processa os resultados da busca. Por exemplo, um documento pode incluir instruções que parecem texto natural, mas são destinadas a influenciar o comportamento ou as respostas do LLM.

Recomendações

  • Clientes MCP devem tratar todo conteúdo derivado de documentos nas respostas das ferramentas como dados não confiáveis
  • O servidor adiciona um campo contentNote às respostas contendo conteúdo de documentos como um lembrete
  • Considere o nível de confiança dos diretórios rastreados ao configurar o servidor
  • Esteja ciente de que o conteúdo indexado pode influenciar o comportamento do LLM através dos resultados da busca

Esta é uma característica inerente de sistemas que recuperam e apresentam conteúdo externo a modelos de linguagem.

Opções de Configuração

Nota: O Quick Start acima usa configuração zero. Esta seção cobre opções avançadas de personalização.

O servidor pode ser configurado via variáveis de ambiente e application.yaml:

Perfis de Logging

O servidor suporta dois perfis de logging (para compatibilidade retroativa, usa a mesma propriedade de sistema do Spring Boot):

PerfilUsoSaída de Logging
defaultDesenvolvimento em IDELogging de console habilitado
deployedProdução/Claude DesktopApenas logging em arquivo

Perfil padrão (nenhum perfil especificado):

  • Logging completo habilitado no console
  • Adequado para depuração e desenvolvimento

Perfil deployed (-Dspring.profiles.active=deployed):

  • Logging de console desabilitado (necessário para transporte STDIO)
  • Logging em arquivo habilitado (~/.mcplucene/log/mcplucene.log)
  • Usado ao executar sob Claude Desktop ou outros clientes MCP

Configuração de Transporte

O servidor suporta dois tipos de transporte: STDIO (padrão) e HTTP. O transporte é selecionado via a propriedade de sistema mcp.transport.

Transporte STDIO (Padrão)

O transporte STDIO é o modo padrão e recomendado para integração com Claude Desktop. Nenhuma configuração adicional é necessária.

Configuração do Claude Desktop:

{
  "mcpServers": {
    "lucene-search": {
      "command": "java",
      "args": [
        "--enable-native-access=ALL-UNNAMED",
        "-Xmx2g",
        "-Dspring.profiles.active=deployed",
        "-jar",
        "/absolute/path/to/luceneserver-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}

Transporte HTTP

O transporte HTTP permite acesso remoto e integração com clientes MCP baseados na web usando o protocolo MCP Streamable HTTP (Spec 2025-03-26). Para habilitar o transporte HTTP, defina a propriedade de sistema mcp.transport como http.

Iniciando com o transporte HTTP:

# Minimal HTTP configuration (uses defaults: 0.0.0.0:8080/mcp/message)
java --enable-native-access=ALL-UNNAMED \
  -Xmx2g \
  -Dmcp.transport=http \
  -jar luceneserver-0.0.1-SNAPSHOT.jar

Configuração HTTP personalizada:

java --enable-native-access=ALL-UNNAMED \
  -Xmx2g \
  -Dmcp.transport=http \
  -Dmcp.http.port=9000 \
  -Dmcp.http.host=localhost \
  -jar luceneserver-0.0.1-SNAPSHOT.jar

Propriedades de configuração HTTP:

Propriedade do SistemaPadrãoDescrição
mcp.transportstdioTipo de transporte: stdio ou http
mcp.http.host0.0.0.0Endereço de bind do servidor HTTP (somente modo HTTP)
mcp.http.port8080Porta do servidor HTTP (somente modo HTTP)
mcp.http.endpoint/mcp/messageCaminho do endpoint de mensagens MCP (somente modo HTTP)*

*O /mcp/message padrão é o endpoint MCP padrão e normalmente não precisa ser alterado.

Notas importantes:

  • O transporte HTTP usa o protocolo MCP Streamable HTTP com modo assíncrono sem estado
  • O transporte STDIO usa modo síncrono com estado (adequado para conexões persistentes)
  • O modo HTTP não suporta HTTPS/TLS - use um proxy reverso (nginx, Caddy) para criptografia
  • Para uso em produção com HTTP, sempre coloque o servidor atrás de um proxy reverso com autenticação adequada
  • O perfil deployed é opcional com HTTP (o log do console não interferirá)

Exemplo: Executando em uma porta diferente

java -Dmcp.transport=http -Dmcp.http.port=9090 -jar luceneserver-0.0.1-SNAPSHOT.jar

Exemplo: Somente localhost (mais seguro)

java -Dmcp.transport=http -Dmcp.http.host=127.0.0.1 -jar luceneserver-0.0.1-SNAPSHOT.jar

Configuração de busca semântica

A busca vetorial semântica é um recurso opcional ativado ao definir a variável de ambiente VECTOR_MODEL.

Habilitando a busca semântica:

java --enable-native-access=ALL-UNNAMED \
  -Xmx4g \
  -Dspring.profiles.active=deployed \
  -jar luceneserver-0.0.1-SNAPSHOT.jar
# With VECTOR_MODEL set in environment:
VECTOR_MODEL=e5-base java --enable-native-access=ALL-UNNAMED \
  -Xmx4g \
  -Dspring.profiles.active=deployed \
  -jar luceneserver-0.0.1-SNAPSHOT.jar
Variável de AmbientePadrãoDescrição
VECTOR_MODEL(nenhum)Modelo de embedding: e5-base (768 dims, mais rápido) ou e5-large (1024 dims, maior qualidade). Defina para habilitar as ferramentas de busca semântica.

Consulte SEMANTICSEARCH.md para detalhes completos da arquitetura, orientações de ajuste e configuração de pontuação KNN.

Nota sobre busca semântica e a lacuna semântica

A busca vetorial foi projetada para fechar a lacuna semântica: encontrar documentos sobre "automóvel" quando o usuário pesquisa por "carro", porque o modelo de embedding mapeia ambos os conceitos para pontos próximos no espaço vetorial.

No entanto, ao usar este servidor com um LLM (Claude, GPT, etc.), a situação muda fundamentalmente.

Um LLM já preenche a lacuna semântica como parte do seu processo de raciocínio. Antes de chamar a ferramenta de busca, um LLM bem instruído pode reescrever "encontrar documentos sobre carros" em uma consulta OR explícita: (car OR automobile OR vehicle OR sedan). Isso significa que o LLM lida com a expansão de sinônimos e a reformulação de consultas — exatamente o problema que a busca vetorial foi projetada para resolver.

Quando a busca semântica agrega valor genuíno:

  • Interfaces de busca diretas voltadas ao usuário, sem LLM no fluxo
  • Pipelines em lote ou automatizados sem reformulação de consultas por LLM
  • Consultas envolvendo jargão específico de domínio onde os sinônimos não são óbvios
  • Consultas conceituais onde a redação exata dos documentos relevantes é desconhecida

Quando a busca semântica agrega valor marginal (casos de uso baseados em LLM):

  • O cliente LLM expande consultas com sinônimos antes de chamar a ferramenta
  • O LLM reformula consultas vagas em expressões Lucene precisas
  • O corpus de busca usa terminologia consistente que o BM25 trata bem

Compensações a considerar:

  • O cálculo de embeddings adiciona latência (~31ms/doc durante a indexação, ~5ms/consulta para e5-base)
  • Os modelos ONNX exigem ~100-200MB de espaço em disco e RAM adicional
  • A complexidade do índice aumenta (documentos pai + documentos filhos (chunks) via Block Join)

Variáveis de Ambiente

Variável de AmbientePadrãoDescrição
LUCENE_INDEX_PATH${user.home}/.mcplucene/luceneindexCaminho para o diretório do índice Lucene
LUCENE_CRAWLER_DIRECTORIES(nenhum)Lista separada por vírgulas de diretórios a rastrear (substitui o arquivo de configuração)
VECTOR_MODEL(nenhum)Modelo de embedding (e5-base ou e5-large). Defina para habilitar a busca semântica.
LUCENE_TOOLS_INCLUDE* (todos)Nomes de ferramentas ou abreviações de grupos separados por vírgulas a expor
LUCENE_TOOLS_EXCLUDE(vazio)Nomes de ferramentas ou abreviações de grupos separados por vírgulas a ocultar

Nota sobre LUCENE_CRAWLER_DIRECTORIES: Quando esta variável de ambiente é definida, ela tem precedência sobre ~/.mcplucene/config.yaml e application.yaml. As ferramentas de configuração MCP (addCrawlableDirectory, removeCrawlableDirectory) se recusarão a modificar a configuração enquanto esta substituição estiver ativa. Para usar a configuração em tempo de execução, remova esta variável de ambiente.

Configuração do rastreador de documentos

Os diretórios do rastreador podem ser configurados de três maneiras, com a seguinte prioridade (da maior para a menor):

  1. Variável de Ambiente: LUCENE_CRAWLER_DIRECTORIES (caminhos separados por vírgulas)
  2. Configuração em tempo de execução: ~/.mcplucene/config.yaml (gerenciada via ferramentas MCP)
  3. Padrão da aplicação: src/main/resources/application.yaml

Configuração em tempo de execução via ferramentas MCP (recomendado)

O servidor fornece ferramentas MCP para gerenciar diretórios rastreáveis em tempo de execução sem editar arquivos de configuração:

listCrawlableDirectories - Lista todos os diretórios configurados

Ask Claude: "What directories are being crawled?"

addCrawlableDirectory - Adiciona um novo diretório para rastreamento

Ask Claude: "Add /Users/yourname/Documents as a crawlable directory"
Ask Claude: "Add /path/to/folder and start crawling it immediately"

removeCrawlableDirectory - Remove um diretório do rastreamento

Ask Claude: "Stop crawling /Users/yourname/Downloads"

Benefícios da configuração em tempo de execução:

  • Não é necessário recompilar o JAR ou reiniciar o servidor
  • A configuração persiste entre reinicializações em ~/.mcplucene/config.yaml
  • Fácil distribuição de JARs pré-compilados
  • Interface conversacional via Claude

Localização do arquivo de configuração:

~/.mcplucene/config.yaml

Exemplo de config.yaml:

lucene:
  crawler:
    directories:
      - /Users/yourname/Documents
      - /Users/yourname/Downloads

Configuração estática via application.yaml

Configure o rastreador de documentos em src/main/resources/application.yaml:

lucene:
  index:
    path: ${LUCENE_INDEX_PATH:./lucene-index}
  crawler:
    # Directories to crawl and index
    directories:
      - "/path/to/your/documents"
      - "/another/path/to/index"

    # File patterns to include
    include-patterns:
      - "*.pdf"
      - "*.doc"
      - "*.docx"
      - "*.odt"
      - "*.ppt"
      - "*.pptx"
      - "*.xls"
      - "*.xlsx"
      - "*.ods"
      - "*.txt"
      - "*.eml"
      - "*.msg"
      - "*.md"
      - "*.rst"
      - "*.html"
      - "*.htm"
      - "*.rtf"
      - "*.epub"

    # File patterns to exclude
    exclude-patterns:
      - "**/node_modules/**"
      - "**/.git/**"
      - "**/target/**"
      - "**/build/**"

    # Performance settings
    thread-pool-size: 4                    # Parallel crawling threads
    batch-size: 100                        # Documents per batch
    batch-timeout-ms: 5000                 # Batch processing timeout

    # Directory watching
    watch-enabled: true                    # Monitor directories for changes
    watch-poll-interval-ms: 2000          # Watch polling interval

    # NRT optimization
    bulk-index-threshold: 1000            # Files before NRT slowdown
    slow-nrt-refresh-interval-ms: 5000    # NRT interval during bulk indexing

    # Content extraction
    max-content-length: -1                 # -1 = unlimited, or max characters
    extract-metadata: true                 # Extract author, title, etc.
    detect-language: true                  # Auto-detect document language

    # Auto-crawl
    crawl-on-startup: true                 # Start crawling on server startup

    # Progress notifications
    progress-notification-files: 100       # Notify every N files
    progress-notification-interval-ms: 30000  # Or every N milliseconds

    # Incremental indexing
    reconciliation-enabled: true           # Skip unchanged files, remove orphans (default: true)

    # Search passages
    max-passages: 3                        # Max highlighted passages per search result (default: 3)
    max-passage-char-length: 200           # Max character length per passage; longer ones are truncated (default: 200, 0 = no limit)

Formatos de arquivo suportados:

  • Documentos PDF (.pdf)
  • Microsoft Office: Word (.doc, .docx), Excel (.xls, .xlsx), PowerPoint (.ppt, .pptx)
  • OpenOffice/LibreOffice: Writer (.odt), Calc (.ods), Impress (.odp)
  • Arquivos de texto simples (.txt)
  • E-mail: Outlook (.msg), EML (.eml)
  • Marcação: Markdown (.md), reStructuredText (.rst), HTML (.html, .htm)
  • Rich Text Format (.rtf)
  • E-books: EPUB (.epub)

Exemplo completo de configuração:

lucene:
  index:
    path: /Users/yourname/lucene-index
  crawler:
    # Add your document directories here
    directories:
      - "/Users/yourname/Documents"
      - "/Users/yourname/Downloads"
      - "/Volumes/ExternalDrive/Archive"

    # Include only these file types
    include-patterns:
      - "*.pdf"
      - "*.docx"
      - "*.xlsx"

    # Exclude these directories
    exclude-patterns:
      - "**/node_modules/**"
      - "**/.git/**"

    # Performance tuning
    thread-pool-size: 8              # Use more threads for faster indexing
    batch-size: 200                  # Larger batches for better throughput

    # Auto-start crawler
    crawl-on-startup: true

    # Real-time monitoring
    watch-enabled: true

    # No content limit (index full documents)
    max-content-length: -1

Enriquecimento de metadados JDBC

O servidor pode enriquecer documentos indexados com metadados adicionais carregados de um banco de dados relacional no momento da indexação. Isso é útil quando os metadados de negócio (por exemplo, IDs de clientes, códigos de projeto, tags) são armazenados em um banco de dados em vez de nos próprios arquivos.

Como funciona

  1. Para cada documento durante o rastreamento, o enriquecedor executa uma consulta SQL configurável.
  2. O resultado da consulta é uma única linha com uma coluna JSON contendo o payload de metadados.
  3. O payload JSON é analisado e campos tipados são adicionados ao documento Lucene.
  4. Um trabalho de sincronização em segundo plano reindexa os arquivos quando seus metadados de banco de dados mudam.

Nomenclatura de campos

Todos os campos originados de JDBC são prefixados com dbmeta_ para evitar colisões com o esquema base do documento.

Nome do campo JSONNome do campo Lucene
customer_iddbmeta_customer_id
tagsdbmeta_tags
departmentdbmeta_department

Formato de metadados JSON

A consulta ao banco de dados deve retornar uma coluna (configurável via json.columnName) contendo JSON neste formato:

{
  "fields": [
    {
      "name": "customer_id",
      "type": "keyword",
      "value": "C-42",
      "faceted": true
    },
    {
      "name": "tags",
      "type": "keyword",
      "values": ["invoice", "2024", "urgent"],
      "faceted": true
    },
    {
      "name": "description",
      "type": "text",
      "value": "Some free-text description"
    },
    {
      "name": "amount",
      "type": "long",
      "value": 9999,
      "faceted": true
    },
    {
      "name": "doc_date",
      "type": "date",
      "value": "2024-01-15T00:00:00Z"
    }
  ]
}

Tipos de campo:

TipoArmazenamento LuceneFacetableNotas
keywordStringFieldSimCorrespondência exata; use para IDs, códigos, categorias
textTextFieldNãoTexto completo analisado; adequado para descrições longas
intIntPoint + StoredFieldSimInteiro de 32 bits; consultas de intervalo suportadas
longLongPoint + StoredFieldSimInteiro de 64 bits; consultas de intervalo suportadas
dateLongPoint + StoredFieldNãoString ISO-8601 → epoch millis

Flags opcionais por campo:

FlagPadrãoDescrição
facetedfalseExpor como faceta de busca (somente keyword/long)
storedtrueArmazenar o valor para que possa ser recuperado nos resultados de busca
searchabletrueIndexar o campo para consulta

Configuração

Adicione a seguinte seção a ~/.mcplucene/config.yaml:

lucene:
  crawler:
    directories:
      - /path/to/your/documents
  metadata:
    jdbc:
      enabled: true
      url: "jdbc:postgresql://localhost:5432/mydb"
      username: "myuser"
      password: "${DB_PASSWORD}"   # env-var substitution supported
      poolSize: 5
      connectionTimeout: 30000    # ms
      queryTimeout: 5000          # ms
      query: >
        SELECT metadata_json
        FROM document_metadata
        WHERE file_path = :file_path
      parameters:
        - name: file_path
          sourceField: file_path   # Lucene field to use as query parameter
      json:
        columnName: metadata_json  # Column in the result set containing the JSON

      # Optional: background sync when DB metadata changes
      sync:
        enabled: true
        intervalMinutes: 5
        query: >
          SELECT dbmeta_customer_id
          FROM document_metadata
          WHERE updated_at > :last_sync_timestamp

Exemplo avançado: Construindo metadados dinamicamente a partir de uma tabela (MySQL)

Os metadados geralmente não são armazenados como JSON pré-construído, mas distribuídos em tabelas normalizadas. As funções JSON_OBJECT() / JSON_ARRAY() / JSON_ARRAYAGG() do MySQL permitem montar o payload de metadados diretamente na consulta SQL — sem necessidade de view materializada separada ou job de ETL.

Cenário

Os documentos são PDFs de perfis de freelancers. Os nomes de arquivo seguem o padrão .../ABC-1234_Profile.pdf, onde ABC-1234 é um código único de freelancer. As tabelas relevantes:

-- Master data
CREATE TABLE freelancer (
    id               BIGINT PRIMARY KEY,
    code             VARCHAR(20) UNIQUE,   -- e.g. "ABC-1234"
    salary_per_day   DECIMAL(10, 2)
);

-- n:m tags
CREATE TABLE freelancer_tags (
    freelancer_id    BIGINT,
    tag_id           BIGINT
);

Configuração

lucene:
  metadata:
    jdbc:
      enabled: true
      url: "jdbc:mysql://localhost:3306/mydb"
      username: "myuser"
      password: "${DB_PASSWORD}"
      poolSize: 5
      connectionTimeout: 30000
      queryTimeout: 5000
      query: |
        SELECT JSON_OBJECT(
                      'fields', JSON_ARRAY(
                            JSON_OBJECT('name', 'daily_rate', 'type', 'long', 'value', f.salary_per_day_long, 'faceted', CAST(FALSE AS JSON)),
                            JSON_OBJECT('name', 'tags',       'type', 'long', 'values', (
                                SELECT JSON_ARRAYAGG(ft.tag_id)
                                FROM freelancer_tags ft
                                WHERE ft.freelancer_id = f.id
                            ), 'faceted', CAST(FALSE AS JSON))
                      )
              ) as metadata_json
        FROM
            freelancer f
        WHERE
            f.code = REGEXP_SUBSTR(:file_path, '[A-Z]+-[0-9]+')
      parameters:
        - name: file_path
          sourceField: file_path   # Lucene field to use as query parameter
      json:
        columnName: metadata_json  # Column in the result set containing the JSON

Como funciona passo a passo

1. Vinculação de parâmetros — o caminho do arquivo como chave de consulta

Durante o rastreamento, o indexador armazena o caminho absoluto do arquivo no campo Lucene file_path (por exemplo, /docs/profiles/ABC-1234_Profile.pdf). Via parameters.sourceField: file_path, esse valor é passado como o parâmetro nomeado :file_path para a consulta SQL.

2. Extraindo o código do freelancer com uma regex

Como o caminho completo do arquivo é passado ao banco de dados, o código deve ser extraído lá. REGEXP_SUBSTR(:file_path, '[A-Z]+-[0-9]+') extrai ABC-1234 de /docs/profiles/ABC-1234_Profile.pdf e o compara com freelancer.code. O banco de dados não precisa conhecer as estruturas de diretórios — a regex é executada inteiramente dentro do mecanismo do banco de dados.

3. Montando o payload JSON em SQL

JSON_OBJECT(...) produz um objeto JSON. Dentro dele, um JSON_ARRAY(...) contém um elemento por campo de metadados:

  • daily_rate (tipo long): um único valor escalar de f.salary_per_day_long
  • tags (tipo long, multivalorado): um array produzido por uma subconsulta correlacionada — JSON_ARRAYAGG(ft.tag_id) agrega todos os IDs de tags do freelancer em um array JSON

A consulta retorna uma única linha com uma única coluna metadata_json:

{
  "fields": [
    { "name": "daily_rate", "type": "long", "value": 850,              "faceted": false },
    { "name": "tags",       "type": "long", "values": [12, 47, 103],   "faceted": false }
  ]
}

4. Processamento pelo indexador

JdbcMetadataEnricher lê esta resposta JSON e adiciona campos ao documento Lucene:

  • dbmeta_daily_rate → LongPoint(850) + StoredField(850) + SortedNumericDocValuesField(850) (pesquisável, recuperável e ordenável)
  • dbmeta_tags → três entradas LongPoint para valores 12, 47, 103 (multivalorado — DocValues ignorados, portanto não ordenável)

Porque faceted: false, nenhuma entrada SortedSetDocValuesFacetField é criada. Os campos estão disponíveis para consultas direcionadas e filtros de intervalo sem adicionar sobrecarga ao cálculo de facetas em cada solicitação de pesquisa.

Ordenação por campos de metadados JDBC: Campos INT, LONG e DATE de valor único recebem automaticamente um SortedNumericDocValuesField, e campos KEYWORD de valor único recebem um SortedDocValuesField. Isso os torna utilizáveis como valores sortBy em solicitações de pesquisa. Campos com múltiplos valores ignoram DocValues (a ordenação em campos com múltiplos valores é indefinida). Use getIndexStats para ver quais campos dbmeta_* estão atualmente registrados como ordenáveis por meio do mapa sortableFields.

5. Consulta em tempo de execução

Após a varredura, esses campos podem ser usados como filtros em extendedSearch:

{
  "query": "Java developer",
  "filters": [
    { "field": "dbmeta_daily_rate", "operator": "range", "from": "500", "to": "1000" },
    { "field": "dbmeta_tags",       "operator": "in",    "values": ["47", "103"] }
  ]
}

Nota sobre CAST(FALSE AS JSON)

MySQL não possui literal booleano JSON nativo. CAST(FALSE AS JSON) produz o valor JSON false, que JsonMetadataParser interpreta corretamente como faceted: false. Use CAST(TRUE AS JSON) para faceted: true.


Exemplo Avançado: Sincronização em Segundo Plano via Consulta de Índice (PostgreSQL)

Cenário

Mesma configuração de PDF do freelancer do exemplo de enriquecimento. Quando a tarifa diária ou as tags de um freelancer mudam no banco de dados, o servidor deve reindexar automaticamente o PDF afetado — sem que o banco de dados precise saber os caminhos dos arquivos.

Pré-requisito: A consulta de enriquecimento armazena customer_id como dbmeta_customer_id (tipo keyword) no índice Lucene, e a tabela document_metadata também possui uma coluna customer_id além de um timestamp updated_at.

Configuração

sync:
  enabled: true
  intervalMinutes: 5
  query: >
    SELECT customer_id AS dbmeta_customer_id
    FROM document_metadata
    WHERE updated_at > :last_sync_timestamp

Como Funciona Passo a Passo

1. Filtro de timestamp

O parâmetro :last_sync_timestamp está vinculado ao horário da última sincronização bem-sucedida (persistido em ~/.mcplucene/metadata-sync-state.yaml). Na primeira execução, o padrão é 1970-01-01T00:00:00Z, então a tabela inteira é varrida.

2. Nome da coluna como campo Lucene

O conjunto de resultados tem exatamente uma coluna. Seu nome — dbmeta_customer_id (definido via alias AS) — é lido do ResultSetMetaData JDBC. Isso se torna o campo Lucene que o servidor usará para pesquisar.

3. Consulta TermQuery

Para cada linha (por exemplo, valor C-42), o servidor executa um TermQuery Lucene em dbmeta_customer_id = "C-42" restrito a documentos pai. Isso encontra todos os arquivos indexados que foram enriquecidos com esse ID de cliente.

4. Resolução do caminho do arquivo

file_path é extraído de cada documento Lucene correspondente. O índice — não o banco de dados — é a fonte da verdade para a localização física do arquivo.

5. Reindexar ou excluir

Se o arquivo ainda existir no disco, ele é re-varrido, o que aciona novamente a consulta de enriquecimento para que o documento Lucene capture os metadados mais recentes do banco de dados. Se o arquivo foi removido, sua entrada de índice é excluída.

6. Avanço do timestamp

Após uma execução bem-sucedida, o horário atual é salvo como o novo lastSyncTimestamp. A próxima sincronização retorna apenas linhas modificadas após esse ponto.

Usando uma Chave de Junção Numérica

Se a chave de junção for um ID numérico do banco de dados em vez de um código de string, use o tipo inteiro SQL apropriado para que o servidor construa a consulta de ponto Lucene correta:

sync:
  enabled: true
  intervalMinutes: 5
  query: >
    SELECT freelancer_id AS dbmeta_freelancer_id
    FROM document_metadata
    WHERE updated_at > :last_sync_timestamp

Aqui freelancer_id é uma coluna BIGINT, então o servidor usa LongPoint.newExactQuery("dbmeta_freelancer_id", …). O enriquecimento deve ter armazenado freelancer_id como um campo do tipo long para que a consulta corresponda.

Tipo de coluna SQLConsulta LuceneDeve corresponder ao tipo de enriquecimento
VARCHAR / CHARTermQuerykeyword
INTEGER / SMALLINTIntPoint.newExactQuery()int
BIGINT / NUMERICLongPoint.newExactQuery()long

Bancos de Dados Suportados

Banco de DadosDependência do driverObservações
PostgreSQLincluído (runtime opcional)jdbc:postgresql://...
MySQLincluído (runtime opcional)jdbc:mysql://...
H2apenas escopo de testejdbc:h2:... (para testes)
Qualquer JDBCAdicione ao classpathDefina driverClassName explicitamente

Integração de Facetas

Campos declarados com "faceted": true são automaticamente registrados como dimensões de facetas dinâmicas. Eles aparecem ao lado das facetas integradas (language, file_extension, file_type, author) nos resultados de pesquisa e podem ser usados como valores de filtro.

Campos com múltiplos valores (usando "values": [...]) são automaticamente configurados como dimensões de facetas multivaloradas.

Sincronização em Segundo Plano

Quando sync.enabled: true, o servidor executa um trabalho em segundo plano a cada intervalMinutes minutos que:

  1. Consulta o banco de dados em busca de registros modificados desde a última sincronização (usando :last_sync_timestamp).
  2. Lê o conjunto de resultados — exatamente uma coluna, N linhas. O nome da coluna é o campo Lucene a ser pesquisado; o valor da coluna é o termo a ser correspondido.
  3. Executa uma consulta Lucene por linha para encontrar documentos de índice correspondentes e extrai seus file_path.
  4. Reindexa arquivos que ainda existem no disco com os metadados mais recentes.
  5. Remove entradas de índice para arquivos que não existem mais.

O timestamp da última sincronização é persistido em ~/.mcplucene/metadata-sync-state.yaml.

Tipos de coluna suportados:

Tipo de coluna SQLConsulta LuceneTipo de campo dbmeta_ compatível
VARCHAR, CHAR, …TermQuerykeyword
INTEGER, SMALLINT, TINYINTIntPoint.newExactQuery()int
BIGINT, NUMERIC, DECIMALLongPoint.newExactQuery()long

O tipo de consulta é inferido automaticamente a partir do tipo de coluna JDBC — nenhuma configuração extra é necessária. O tipo de coluna SQL deve corresponder ao tipo de campo Lucene usado durante o enriquecimento (IntPoint e LongPoint são tipos de campo separados). Campos text analisados não são adequados como chaves de sincronização.

Tratamento de Erros

O enriquecedor segue um padrão de resiliência "pular e avisar":

  • Falhas de conexão com o banco de dados: o documento é indexado sem enriquecimento, um aviso é registrado.
  • Erros de consulta: mesmo comportamento de pular e avisar.
  • Payloads JSON inválidos: erros de análise são registrados, o campo é ignorado.
  • Valores NULL: ignorados silenciosamente por campo.
  • Colisões de nomes de campos com o esquema base: erro registrado, campo ignorado.

Desenvolvimento

Executando para Desenvolvimento

Ao desenvolver e depurar em sua IDE, execute o servidor sem o perfil "deployed" para obter registro completo:

Na sua IDE (IntelliJ, Eclipse, VS Code):

# Just run the main class directly - no profile needed
# You'll see full console logging and debug output
java -jar target/luceneserver-0.0.1-SNAPSHOT.jar

Isso fornece a você:

  • Saída de registro completa para depuração
  • Configuração carregada do classpath e da configuração do usuário
  • Todas as informações de depuração visíveis no console

Para implantação em produção/Claude Desktop:

# Use the deployed profile for clean STDIO
java --enable-native-access=ALL-UNNAMED -Xmx2g -Dspring.profiles.active=deployed -jar target/luceneserver-0.0.1-SNAPSHOT.jar

Depuração com o MCP Inspector

O MCP Inspector fornece uma interface visual de depuração para testar servidores MCP. Use-o para inspecionar solicitações, respostas e depurar o comportamento das ferramentas sem precisar de um cliente MCP completo como o Claude Desktop.

Execute o servidor com o inspetor para conexão STDIO:

npx @modelcontextprotocol/inspector java -jar --enable-native-access=ALL-UNNAMED -Xmx2g -Dspring.profiles.active=deployed -jar ./target/luceneserver-0.0.1-SNAPSHOT.jar

ou no caso de Streaming HTTP:

npx @modelcontextprotocol/inspector http://localhost:9000/mcp/message --transport http

Isso abre uma interface baseada na web onde você pode:

  • Testar todas as ferramentas MCP interativamente
  • Inspecionar payloads JSON de solicitação/resposta
  • Depurar problemas de comunicação STDIO
  • Verificar parâmetros e valores de retorno das ferramentas

Nota: O inspetor requer os mesmos argumentos JVM da implantação em produção (--enable-native-access=ALL-UNNAMED, -Dspring.profiles.active=deployed) para garantir um comportamento consistente.

Adicionando Documentos ao Índice

Abordagem recomendada: Use o rastreador de documentos configurando diretórios em application.yaml. O rastreador lida automaticamente com extração de conteúdo, metadados e detecção de idioma.

Abordagem programática: Para tipos de documentos personalizados ou indexação direta:

// Get the LuceneIndexService instance from your application
LuceneIndexService indexService = // ... from your application

public void addDocument(String title, String content) throws IOException {
    Document doc = new Document();
    doc.add(new TextField("title", title, Field.Store.YES));
    doc.add(new TextField("content", content, Field.Store.YES));
    doc.add(new StringField("file_path", "/custom/path", Field.Store.YES));
    indexService.getIndexWriter().addDocument(doc);
    indexService.getIndexWriter().commit();
}

Para o esquema completo de campos, consulte a seção Esquema de Campos do Índice.