Token导航 LogoToken导航TokenDH.com
Mcpluceneserver logo
搜索检索stdio官方级别未说明来源级核验

Mcpluceneserver

MCP Server

MCP Lucene Server 是一个基于 Apache Lucene 的全文搜索服务器,提供自动文档爬取、索引和强大的搜索功能,适用于个人文档管理和企业知识库。

工具数

0

提示词数

0

GitHub Stars

3

资源数

0
JavaClaude全文搜索Claude DesktopClaudeVS Code

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

作者 / 组织

mirkosertic

提供方

mirkosertic

最后核验

2026/5/17 20:22

运行时

Docker

快速接入

先看主来源和安装命令,再打开仓库或文档;下面只保留这个条目的关键接入事实。

命令预览

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

详细介绍

MCP Lucene服务器

![Build and Release](https://github.com/mirkosertic/MCPLuceneServer/actions/workflows/build.yml)

一个模型上下文协议(MCP)服务器,它公开了Apache Lucene全文搜索功能,并具有自动文档爬行和索引功能。此服务器支持STDIO传输(用于Claude Desktop集成)和HTTP传输(用于基于web的客户端和远程访问)。

特性

自动文档爬网

  • 自动索引PDF、Microsoft Office和OpenOffice文档
  • 多线程爬行实现快速索引
  • 实时目录监控以实现自动更新
  • 增量索引与完全对账(跳过未更改的文件,删除孤立文件)

强大的搜索功能

  • 简单的关键字搜索(不需要Lucene语法)和完整的Lucene查询语法搜索
  • 特定字段过滤(按作者、语言、文件类型等)
  • 用于LLM消费的具有高质量元数据的结构化通道
  • 带有过滤器建议的分页结果

语义搜索

  • 基于多语言e5嵌入和后期分块的可选纯KNN嵌入语义搜索
  • 即使没有精确的关键字匹配,也能查找语义相关的文档
  • 需要 VECTOR_MODEL 待配置。看 语义研究.md 了解详情。

查询分析和调试

  • 深度查询分析和分析(profileQuery 工具)
  • 了解查询返回某些结果的原因以及评分的工作原理
  • 过滤器影响分析,显示每个过滤器的文档减少
  • BM25细分文件评分说明
  • 术语统计(IDF、稀有性、文档频率)
  • 可操作的优化建议
  • LLM优化的结构化输出,便于解释

丰富元数据提取

  • 自动语言检测
  • 作者、标题、创建日期提取
  • 文件类型和大小信息
  • 用于更改检测的SHA-256内容哈希

JDBC元数据扩展

  • 在索引时从PostgreSQL、MySQL或任何兼容JDBC的数据库加载其他元数据
  • 基于JSON的元数据,具有显式字段类型(关键字、文本、int、long、date)
  • 多值字段支持,自动刻面注册
  • 增量元数据更新的后台同步作业(可配置间隔)
  • 所有数据库源字段前缀为 dbmeta_ 为了避免模式冲突

文本归一化

  • 自动删除损坏/无效字符(替换字符、控制字符、零宽度字符)
  • 空白归一化(多个空格折叠为单个空格)
  • 确保搜索结果和段落清晰易读

性能优化

  • 批处理以实现高效索引
  • 具有动态优化的NRT(近实时)搜索
  • 用于并行处理的可配置线程池
  • 批量操作期间的进度通知

易于集成

  • 双传输支持:STDIO(默认)和HTTP
  • STDIO传输用于无缝集成Claude Desktop
  • 基于web的客户端和远程访问的HTTP传输
  • 用于搜索和爬虫控制的综合MCP工具
  • 通过YAML和系统属性进行灵活配置
  • 跨平台通知(macOS通知中心、Windows Toast、Linux通知发送)

目录

- 搜索工具 - 语义搜索工具 - 调试工具 - 履带工具 - 索引信息工具 - 观察性工具 - 管理工具

- 文档爬网程序配置

- 为发展而奔跑 - 使用MCP检查器进行调试 - 将文档添加到索引

文档

附加技术文件:

  • 管道.md --分析器链、查询管道和标记化详细信息
  • 语义研究.md --语义搜索架构:后期分块、块连接索引、KNN评分和配置
  • ONNX.md --e5-base和e5-large的ONNX模型导出、优化和INT8量化指南

快速开始

通过三个步骤启动并运行MCP-Lucene服务器。

先决条件

  • Java 25或更高版本 -需要运行服务器
  • Maven 3.9+(仅当从源代码构建时)

步骤1:获取服务器

选项A:下载预构建JAR(推荐)

  1. 操作选项卡
  2. 单击最近成功运行的工作流
  3. 向下滚动到“工件”并下载 luceneserver-X.X.X-SNAPSHOT
  4. 解压缩ZIP文件以获取JAR

对于标记的版本,您还可以从以下网址下载 发布页面.

选项B:从源代码构建

./mvnw clean package -DskipTests

这将在以下位置创建一个可执行JAR target/luceneserver-0.0.1-SNAPSHOT.jar.

选项C:使用Docker(只有HTTP传输可用)

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

这将启动一个Docker容器,服务器监听端口9000。所有配置数据,包括 索引文件存储在 ./lucene-data-dir 主机上的目录。请注意,Lucene indexer只能访问Docker容器可见的文件,因此所有文件都必须放置在 ./lucene-data-dir JVM设置可以通过以下方式进行调整 JAVA_OPTS 环境变量,可以使用Docker CLI或Docker Compose文件进行修改。默认值 JVM堆的最大大小(-Xmx)为2GB。

启用 语义搜索,设置 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
环境变量默认值描述
VECTOR_MODEL(无)ONNX嵌入模型: e5-base (768调暗,更快)或 e5-large (1024调光,更高质量)。设置为启用语义搜索。
JAVA_OPTS-Xmx2gJVM选项。增加到 -Xmx4g 或者在使用语义搜索时更高。

步骤2:配置Claude桌面

找到您的Claude Desktop配置文件:

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

将Lucene MCP服务器添加到 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"
      ]
    }
  }
}

重要提示: 替换 /absolute/path/to/luceneserver-0.0.1-SNAPSHOT.jar 使用JAR文件的实际绝对路径。

-Dspring.profiles.active=deployed 干净的STDIO通信需要标志(禁用控制台日志记录和启动横幅)。

第三步:开始使用

  1. 重新启动克劳德桌面 加载新配置
  2. 验证 服务器正在Claude Desktop的开发人员设置中运行
  3. 告诉克劳德 要添加文档,请执行以下操作:
"Add /Users/yourname/Documents as a crawlable directory and start crawling"

就是这样!配置已保存到 ~/.mcplucene/config.yaml 并在重新启动后持续存在。现在,您可以通过Claude搜索您的文档。

示例搜索:

  • “搜索机器学习论文”
  • “查找John Doe的所有PDF文件”
  • “哪些文件提到季度报告?”

MCP工具

工具被组织成组。使用 LUCENE_TOOLS_INCLUDELUCENE_TOOLS_EXCLUDE 控制 哪些工具是暴露的(参见 工具曝光配置).

______________________________________________________________________

搜索工具(组: search)

simpleSearch

使用纯文本关键字搜索Lucene全文索引。特殊字符被视为文字,不需要Lucene语法知识。使用BM25搭配德语和英语词干。

参数:

  • query (可选):纯文本搜索查询。可以 null"*" 匹配所有文档(与过滤器一起使用很有用)。
  • filters (可选):用于精确场级过滤的结构化过滤器阵列(请参见 结构化过滤器 在......下面
  • page (可选):页码,从0开始(默认值:0)
  • pageSize (可选):每页结果(默认值:10,最大值:100)
  • sortBy (可选):排序字段- _score (默认), modified_date, created_date, file_size,或任何 dbmeta_* 从JDBC富集中注册的元数据字段(INT/LONG/DATE/KEYWORD)
  • sortOrder (可选):排序顺序- ascdesc (默认值: desc)

extendedSearch

使用完整的Lucene查询语法搜索Lucene全文索引。支持布尔运算符、通配符、邻近查询和特定于字段的查询。使用BM25搭配德语和英语词干。

参数:

  • query (可选):使用Lucene查询语法的搜索查询。可以 null"*" 匹配所有文档(与过滤器一起使用很有用)。
  • filters (可选):用于精确场级过滤的结构化过滤器阵列(请参见 结构化过滤器 在......下面
  • page (可选):页码,从0开始(默认值:0)
  • pageSize (可选):每页结果(默认值:10,最大值:100)
  • sortBy (可选):排序字段- _score (默认), modified_date, created_date, file_size,或任何 dbmeta_* 从JDBC富集中注册的元数据字段(INT/LONG/DATE/KEYWORD)
  • sortOrder (可选):排序顺序- ascdesc (默认值: desc)

排序结果:

默认情况下,结果按相关性得分排序(最相关的排名第一)。您可以按元数据字段排序:

排序字段描述默认顺序
_score相关性得分(默认)降序(最佳匹配优先)
modified_date最后修改日期降序(最近日期在前)
created_date创建日期降序(最近日期在前)
file_size文件大小(以字节为单位)降序(先大后小)
dbmeta_*任何类型为INT、LONG、DATE或KEYWORD升序或降序的单值JDBC元数据字段

排序示例:

// 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" }
  ]
}

注: 在按元数据字段排序时,仍然会计算相关性得分,并将其用作决胜局的次要排序标准。

结构化过滤器:

filters array接受具有以下字段的对象:

字段必填描述
fieldyes要筛选的字段名
operator没有eq (默认), in, not, not_in, range
value对于eq/not精确匹配或排除的单个值
valuesfor in/not_in值数组(字段内的OR语义)
from用于范围范围开始(含)
to范围范围结束(含)
addedAtno客户端时间戳--在中发生了循环 activeFilters 回应

操作员参考:

操作员描述示例
eq完全匹配(默认){field: "language", value: "en"}
in匹配任何值{field: "file_extension", operator: "in", values: ["pdf", "docx"]}
not排除值{field: "language", operator: "not", value: "unknown"}
not_in排除多个值{field: "language", operator: "not_in", values: ["unknown", ""]}
range数字/日期范围{field: "modified_date", operator: "range", from: "2024-01-01", to: "2025-12-31"}

可筛选字段:

  • 多面的 (钻孔侧道): language, file_extension, file_type, author
  • 字符串(完全匹配): file_path, content_hash
  • 数字/日期(范围): file_size, created_date, modified_date, indexed_date

日期格式: ISO-8601-- "2024-01-15", "2024-01-15T10:30:00",或 "2024-01-15T10:30:00Z"

筛选器组合规则:

  • 过滤器打开 不同的 字段使用AND逻辑
  • 多个 eq 过滤器或 in 值在 相同 分面字段使用OR逻辑(DrillSideways)
  • not/not_in 过滤器作为MUST_NOT子句应用

AI驱动的同义词扩展:

该服务器旨在与Claude等人工智能助手配合使用。AI通过构造OR查询自动生成上下文相关的同义词,而不是使用传统的Lucene同义词文件。

为什么这比传统的同义词更好:

  • 上下文感知:人工智能理解你的意图,并选择相关的同义词(例如,法律语境中的“合同”与建筑中的“合约”)
  • 无需维护:无需维护静态同义词配置文件
  • 领域自适应:自动跨法律、技术、医学或休闲语言工作
  • 多语言:生成任何语言的同义词,无需配置

当你要求克劳德“查找有关汽车的文件”时,它会自动搜索 (car OR automobile OR vehicle) -比静态同义词列表给你更好的结果。

技术细节(词汇匹配):

服务器使用多分析器索引管道和多字段加权查询管道进行全面搜索:

  • 万国码规范化 --NFKC归一化、变音折叠、通过ICUFoldingFilter进行结扎扩展
  • 领先的通配符优化content_reversed 字段存储反向令牌以提高效率 *vertrag-样式查询
  • 不区分大小写的通配符 --通配符/前缀术语会自动小写
  • OpenNLP词形化 --基于词典的德语和英语词形化,包括不规则形式(ran→跑,老→gehen,付费→薪酬、分析→分析)
  • 双语索引 --为所有文档索引德语和英语引理字段,实现混合语言匹配
  • 德语变音音译content_translit_de 阴影场图有向图(Mueller→穆勒)
  • 自动短语扩展 --精确短语会自动展开以包括邻近匹配(见下文)
  • 自适应前缀评分 --特定前缀的BM25评分(>=4个字符)

管道.md 获取完整的分析器链文档、具体示例和查询管道详细信息。

AI助手通过智能扩展查询来补偿剩余的限制(没有同义词扩展,没有语音匹配)。

获得更好结果的最佳实践:

  1. 自己生成同义词: 使用OR组合相关术语:

- 而不是: contract - 用途: (contract OR agreement OR deal)

  1. 使用通配符表示变体: 处理不同的单词形式:

- 而不是: contract - 用途: contract* (匹配合同、承包、签约)

  1. 杠杆面: 使用返回的方面值来发现索引中的确切项:

- 检查 facets.author 查找确切的作者姓名 - 检查 facets.language 查看可用语言 - 使用这些精确值进行筛选

  1. 组合技术:
   (contract* OR agreement*) AND (sign* OR execut*) AND author:"John Doe"

支持的查询语法(extendedSearch):

  • 简单术语: hello world (术语之间隐含AND)
  • 短语查询: "exact phrase" (保留词序)
  • 布尔运算符 term1 AND term2, term1 OR term2, NOT term
  • 尾随通配符: contract* 匹配合同,签订合同
  • 前导通配符: *vertrag 有效地找到Arbeitsvertrag、Kaufvertrag(通过反向令牌字段优化)
  • Infix通配符: *vertrag* finds both 合同条款 and 劳动合同
  • 单字符通配符: te?t 匹配测试、文本
  • 模糊搜索: term~2 查找Levenshtein编辑距离2内的术语(默认值:2)
  • 邻近搜索: "term1 term2"~5 查找彼此相距5个单词以内的术语
  • 特定字段搜索: title:hello content:world
  • 分组: (contract OR agreement) AND signed
  • 范围查询: modified_date:[1609459200000 TO 1640995200000] (时间戳,单位为毫秒)

自动短语邻近扩展:

多单词短语查询会自动展开: "Domain Design" 成为 ("Domain Design")^2.0 OR ("Domain Design"~3)精确匹配排名最高(2.0倍提升),而接近匹配(3个单词以内)的得分也较低。单字短语和用户指定的脏话不会展开。

管道.md 以获取详细的示例和配置。

自适应前缀查询评分:

使用>=4个字符作为查询前缀(vertrag*, design*)使用真实的BM25评分,将较短/更频繁的术语排名高于长复合词。更短的前缀(ver*)对绩效进行持续评分。这会自动平衡排名质量和速度。

管道.md 用于评分示例和技术细节。

德语复合词搜索:

德语化合物使用通配符: *vertrag 找到劳动合同, vertrag* 发现Vertragsbedingungen。前导通配符通过以下方式进行优化 content_reversed 现场。

自动Lemmatization:

OpenNLP词形化自动处理形态变体。德语:“Haus”表示“Häuser”,“gehen”表示“ging”。中文:“run”找到“ran”,“pay”找到“payed”。精确匹配总是排名最高。

双语支持:

所有文档都使用德语和英语词形字段进行索引,从而实现混合语言匹配。带有英语技术术语(“推荐引擎”)的德语文档通过英语引理器匹配单数查询(“推荐发动机”),反之亦然。

德语Umlaut音译:

content_translit_de 字段将ASCII有向图映射到变音:“Mueller”匹配“Müller”,“Kaese”匹配“Käse”。

管道.md 获取完整的分析器链、具体的令牌示例和查询管道详细信息。

退货:

  • 分页文档结果,每个结果包含一个 passages 带有突出显示的文本和质量元数据的数组
  • 文档级相关性得分
  • facets:结果集中的分面值和计数(当分面过滤器处于活动状态时使用DrillSideways,显示替代值)
  • activeFilters:镜像输入 filters 带着一个 matchCount 对于每个过滤器(从刻面开始计数,对于范围/非刻面过滤器为-1)
  • 搜索执行时间(毫秒)(searchTimeMs)

筛选器示例:

// 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" }
]}

______________________________________________________________________

语义搜索工具(组: semantic)

语义搜索工具需要 VECTOR_MODEL 待配置(例如。, VECTOR_MODEL=e5-base).

semanticSearch

基于纯KNN嵌入的语义搜索。即使没有精确的关键字匹配,也能查找语义相关的文档。结果按余弦相似度排序。需要 VECTOR_MODEL 待配置。

参数:

  • query (必填):自然语言查询——服务器计算嵌入并找到最近的文档块。
  • filters (可选):结构化过滤器数组(格式与 simpleSearch/extendedSearch)
  • page (可选):页码,从0开始(默认值:0)
  • pageSize (可选):每页结果(默认值:10,最大值:100)
  • similarityThreshold (可选):包含结果的最小余弦相似性得分(0.0-1.0,默认值:0.70)。更低=更多结果(更广泛的匹配);更高=更少的结果(更接近匹配)。

使用 profileSemanticSearch 调音 similarityThreshold 为了你的语料库。

profileSemanticSearch

语义搜索调试工具。显示嵌入时间、余弦分数、匹配块以及通过相似性阈值的候选者数量。使用此功能进行调谐 similarityThreshold 为了您的数据。

参数:

  • query (必填):对个人资料进行自然语言查询
  • filters (可选):结构化过滤器阵列
  • similarityThreshold (可选):测试阈值(0.0-1.0,默认值:0.70)

______________________________________________________________________

调试工具(组: debug)

profileQuery

分析和调试 simpleSearch / extendedSearch 查询。提供有关Lucene如何处理查询、哪些术语有助于评分、过滤器如何影响结果以及存在哪些优化机会的详细见解。

参数:

  • query (可选):搜索查询(与 simpleSearch/extendedSearch)
  • filters (可选):结构化过滤器数组(与搜索工具相同)
  • page (可选):页码,从0开始(默认值:0)
  • pageSize (可选):每页结果(默认值:10,最大值:100)
  • sortBy (可选):排序字段(与搜索工具相同)
  • sortOrder (可选):排序顺序(与搜索工具相同)
  • queryMode (可选): SIMPLE (默认)或 EXTENDED --选择查询解析器模式以匹配您正在分析的搜索工具
  • analyzeFilterImpact (可选):如果 true,分析每个过滤器如何减少结果计数。 警告: 需要多次查询的昂贵操作。违约: false
  • analyzeDocumentScoring (可选):如果 true,使用Lucene的解释API为顶级文档提供了详细的评分解释。 警告: 昂贵的操作。违约: false
  • analyzeFacetCost (可选):如果 true,测量分面计算开销。 警告: 昂贵的操作。违约: false
  • maxDocExplanations (可选):解释时的最大文档数量 analyzeDocumentScoring=true (默认值:5,最大值:10)

分析级别:

第一级:快速分析(始终包括在内)

  • 查询结构和组件分解
  • 查询类型标识(BooleanQuery、TermQuery、通配符Query等)
  • 每个查询组件的估计成本
  • 术语统计(文档频率、IDF、稀有性分类)
  • 搜索指标(总点击量、过滤器减少百分比)

第2级:过滤器影响分析(选择加入,费用高昂)

  • 显示每个筛选器如何影响结果计数
  • 计算选择性(低/中/高/非常高)
  • 测量每个筛选器的执行时间
  • 帮助识别冗余或无效的过滤器

第三级:文档评分解释(选择加入,费用高昂)

  • 排名靠前的文档的详细分数细分
  • 显示哪些术语对每个文档的得分贡献最大
  • 提供人类可读的评分摘要
  • 使用Lucene的解释API,但解析为LLM友好格式

第4级:分面成本分析(选择加入,昂贵)

  • 度量分面计算开销
  • 显示每个面维度的成本
  • 帮助决定是否应禁用刻面以提高性能

退货:

一种结构化分析对象,包含:

{
  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
}

示例:基本查询分析

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

这将执行快速分析,显示:

  • 查询结构(带两个词的布尔AND查询)
  • 期限统计(“合同”和“已签署”的常见程度)
  • 成本估算(将检查多少份文件)
  • 优化建议

示例:带评分的深度分析

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

这为前3个文档提供了详细的评分解释,显示:

  • 每个文档中匹配的术语
  • 每学期对最终成绩的贡献有多大
  • 为什么文件A的排名高于文件B

示例:过滤器优化

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

这分析了过滤器的有效性,可能揭示:

  • file_extension=pdf 将结果减少75%(高选择性)
  • file_type=application/pdf 将结果减少0%(文件扩展冗余)
  • 建议:删除冗余 file_type 过滤器

示例:理解自动短语扩展

当你搜索一个精确的短语时,比如 "Domain Design",查询会自动扩展以提高召回率,同时保持准确性:

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

分析器揭示了查询是如何扩展的:

查询分析:

  • 原始查询: "Domain Design"
  • 解析类型: BooleanQuery
  • 重写: 自动短语邻近扩展(精确匹配增强+邻近变体)
  • 查询组件:

- PhraseQuery (boost=4.0) - "domain design" (精确匹配,最大提升) - PhraseQuery (boost=2.0) - "domain design"~3 (接近匹配,斜率=3) - 具有较低增压的其他带茎变体

文档评分:

  • 精确匹配 (“领域设计”):得分0.81-匹配两个子句,精确子句占主导地位
  • 近距离匹配 (“领域驱动设计”):得分0.15-仅匹配邻近条款
  • 近距离匹配 (“领域有效设计”):得分0.15-仅匹配邻近条款

这表明:

  1. 精确匹配排名最高 由于4.0倍的累积提升(2.0来自词干x 2.0来自短语扩展)
  2. 仍然找到接近匹配项 slop=3(术语之间最多允许有3个单词)
  3. 清晰的分数分离 精确匹配和接近匹配之间确保了精度

性能说明:

  • 基本分析 (默认):非常快,开销可以忽略不计(~5-10ms)
  • 过滤器影响分析:需要N+1个查询,其中N是过滤器的数量。对于复杂的过滤器集,可能需要几秒钟的时间。
  • 文档评分分析:需要Lucene计算完整的说明对象。成本随着 maxDocExplanations.
  • 分面成本分析:需要面计算。成本取决于唯一方面值的数量。

最佳实践:

  1. 从基本分析(没有可选标志)开始,以获得快速见解
  2. 仅在调试特定性能问题时启用昂贵的分析
  3. 使用 analyzeDocumentScoring 了解为什么某些文档排名很高
  4. 使用 analyzeFilterImpact 优化过滤器顺序并删除冗余过滤器
  5. 注意 recommendations 可操作的优化提示数组

______________________________________________________________________

爬行器工具(组: crawler)

startCrawl

开始爬网配置的目录以对文档进行索引。

参数:

  • fullReindex (可选):如果为true,则在爬网前清除索引(默认值:false)。当错误和 reconciliation-enabled 如果是真的,则执行增量爬网。

特征:

  • 自动从PDF、Office文档和OpenOffice文件中提取内容
  • 检测文档语言
  • 提取元数据(作者、标题、创建日期等)
  • 多线程处理,实现快速索引
  • 爬行过程中的进度通知
  • 增量模式 (默认):只有新的或修改过的文件才会被索引;已删除的文件会自动从索引中删除。如果对账遇到错误,则会恢复到完全爬行状态。

getCrawlerStats

获取爬虫进度的实时统计数据。

退货:

  • filesFound:发现的文件总数
  • filesProcessed:到目前为止处理的文件
  • filesIndexed:文件已成功索引
  • filesFailed:无法处理的文件
  • bytesProcessed:已处理的总字节数
  • filesPerSecond:处理吞吐量
  • megabytesPerSecond:数据吞吐量
  • elapsedTimeMs:自爬网开始以来经过的时间
  • perDirectoryStats:每个目录的统计细分
  • orphansDeleted:由于文件在磁盘上不再存在而删除的索引条目数(增量模式)
  • filesSkippedUnchanged:由于自上次爬网以来未被修改而跳过的文件数(增量模式)
  • reconciliationTimeMs:将索引与文件系统进行比较所花费的时间(增量模式)
  • crawlMode:要么 "full""incremental"
  • currentlyProcessing:当前正在处理(提取/索引)的文件数组。每个条目包含:

- filePath:正在处理的文件的完整路径 - processingDurationMs:文件处理了多长时间(以毫秒为单位)

  • lastCrawlCompletionTimeMs:上次成功爬网完成的Unix时间戳(ms)(如果之前没有爬网,则为null)
  • lastCrawlDocumentCount:上次成功爬网后索引中的文档数(如果之前没有爬网,则为空)
  • lastCrawlMode:上次爬网的模式- "full""incremental" (如果之前没有爬网,则为null)

getCrawlerStatus

获取爬虫的当前状态。

退货:

  • state:其中之一 IDLE, CRAWLING, PAUSED,或 WATCHING

pauseCrawler

暂停正在进行的爬网操作。稍后可以使用以下命令恢复爬虫 resumeCrawler.

resumeCrawler

恢复暂停的爬网操作。

listCrawlableDirectories

列出所有已配置的可爬网目录。

退货:

  • success:布尔值表示操作成功
  • directories:当前配置的绝对目录路径列表
  • totalDirectories:已配置目录的计数
  • configPath:配置文件的路径(~/.mcplucene/config.yaml)
  • environmentOverride:布尔值表示是否 LUCENE_CRAWLER_DIRECTORIES env变量已设置

示例响应:

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

addCrawlableDirectory

将目录添加到爬网程序配置中。

参数:

  • path (必需):要爬网的目录的绝对路径
  • crawlNow (可选):如果为true,则立即开始爬网新目录(默认值:false)

退货:

  • success:布尔值表示操作成功
  • message:确认消息
  • totalDirectories:已配置目录的更新计数
  • directories:所有目录的更新列表
  • crawlStarted (可选):如果 crawlNow=true,表示已触发爬网

验证:

  • 目录必须存在且可访问
  • 路径必须是目录(不是文件)
  • 防止重复目录
  • 如果失败 LUCENE_CRAWLER_DIRECTORIES 环境变量已设置

例子:

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

配置持久性: 目录立即保存到 ~/.mcplucene/config.yaml 并且将在未来服务器重新启动时自动爬网。

removeCrawlableDirectory

从爬网程序配置中删除目录。

参数:

  • path (必需):要删除的目录的绝对路径

退货:

  • success:布尔值表示操作成功
  • message:确认消息
  • totalDirectories:已配置目录的更新计数
  • directories:剩余目录的更新列表

重要提示:

  • 这不会从已删除的目录中删除已索引的文档
  • 要删除索引文档,请使用 startCrawl(fullReindex=true) 删除目录后
  • 如果失败 LUCENE_CRAWLER_DIRECTORIES 环境变量已设置
  • 目录必须存在于当前配置中

例子:

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

______________________________________________________________________

索引信息工具(组: info)

getIndexStats

获取Lucene索引的统计信息,包括引理化器缓存性能指标、查询运行时百分位数(p50-p99)和每个字段方面的计算时间。

退货:

  • documentCount:索引中的文档总数
  • indexPath:索引目录的路径
  • schemaVersion:当前索引架构版本
  • softwareVersion:服务器软件版本
  • buildTimestamp:服务器构建时间戳
  • dateFieldHints:日期字段的最小/最大日期范围(created_date, modified_date, indexed_date)ISO-8601格式——适用于构建日期范围过滤器
  • sortableFields:动态注册可排序地图 dbmeta_* 从JDBC元数据丰富到排序类型的字段("numeric""keyword").当JDBC富集没有注册可排序字段时为空。用它来发现 dbmeta_* 字段可以传递为 sortBy.原生田(file_size, created_date, modified_date)总是可排序的,不在这里列出。
  • lemmatizerCacheMetrics:OpenNLP引理器缓存的性能指标(每种语言一个:德语和英语)

- language:语言代码(de或en) - hitRate:缓存命中率百分比(例如“85.3%”) - totalHits:在缓存中找到令牌的次数 - totalMisses:令牌需要词形转换的次数 - cacheSize:缓存中的当前条目数 - evictions:由于大小限制而被逐出的缓存条目数

  • queryRuntimeMetrics:聚合搜索查询性能统计信息(在执行任何搜索之前为null)

- totalQueries:自服务器启动以来执行的搜索查询总数 - averageDurationMs:平均查询持续时间(毫秒)(例如,“12.5”) - minDurationMs:最快查询持续时间(毫秒) - maxDurationMs:最慢查询持续时间(毫秒) - averageHitCount:每次查询的匹配文档的平均数量(例如“42.3”) - p50Ms / p75Ms / p90Ms / p95Ms / p99Ms:查询持续时间百分比(毫秒)(根据最近1000个查询计算) - averageFacetDurationMs:每个查询的平均方面计算时间(毫秒)(例如,“0.125”) - perFieldAverageFacetDurationMs:每场平均面计算时间(毫秒)(例如。, {"language": "0.031", "file_extension": "0.028", ...})

Lemmatizer缓存性能:

服务器使用单令牌缓存进行OpenNLP词形化,以减少索引和查询过程中的CPU使用率。每个语言分析器(德语和英语)都维护一个共享的LRU缓存,其中最多有1500000个条目,在所有Lucene索引线程之间共享。缓存对常用词使用不区分大小写的键(例如,“Vertrag”和“Vertrag”共享同一个缓存条目),同时保持专有名词区分大小写(例如“Berlin”vs“Berlin”)。

关键指标:

  • 命中率:越高越好。在索引了几千份文档后,85-95%是典型的。更高的命中率意味着更少的CPU使用率。
  • 缓存大小:缓存(令牌、POS标签)到引理映射的当前数量。每种语言最多可添加1500000个条目。
  • 驱逐:为了给新条目腾出空间,删除了多少条目。对于大型文件集,一些驱逐是正常的。

性能影响: 如果没有缓存,词形化在索引过程中可能会消耗70-80%的CPU。通过缓存,CPU使用率通常会降至20-30%,从而使具有重复词汇的文档集的索引吞吐量提高2-3倍。

listIndexedFields

列出Lucene索引中存在的所有字段名。

退货:

  • fields:可用于搜索和筛选的字段名数组

示例响应:

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

getDocumentDetails

通过文件路径从Lucene索引中检索文档的所有存储字段和完整内容。此工具直接从索引中检索文档详细信息 无需文件系统访问 -即使原始文件已被移动或删除,也可用于检查索引内容。

参数:

  • filePath (必填):文件的绝对路径(必须与 file_path 存储在索引中)

退货:

  • success:布尔值表示操作成功
  • document:包含所有存储字段的对象:

- file_path:文件的完整路径 - file_name:文件名称 - file_extension:文件扩展名(例如。, pdf, docx) - file_type:MIME类型 - file_size:文件大小(字节) - title:文档标题 - author:作者姓名 - creator:创建者应用程序 - subject:文件主题 - keywords:文档关键字/标签 - language:检测到的语言代码 - created_date:创建时间戳 - modified_date:修改时间戳 - indexed_date:索引时间戳 - content_hash:内容的SHA-256哈希 - content:完整提取的文本内容(限制为500KB) - contentTruncated:布尔值,指示内容是否被截断 - originalContentLength:原始内容长度(仅在截断时显示)

内容大小限制:content 字段限制为500000个字符(500KB),以确保响应安全地保持在1MB MCP响应限制以下。检查 contentTruncated 字段,以确定是否返回了完整内容。

例子:

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

示例响应:

{
  "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
  }
}

______________________________________________________________________

观察性工具(组: observability)

suggestTerms

建议使用与前缀匹配的索引项。可用于发现词汇、查找德语复合词、探索作者姓名或自动完成字段值。

参数:

  • field (必填):用于建议术语的字段名称(例如。 content, author, file_extension)
  • prefix (必填):用于匹配术语的前缀(例如。 ver 寻找 vertrag, version)
  • limit (可选):要返回的最大术语数(默认值:20,最大值:100)

笔记:

  • 对于已分析的字段(content, title等),前缀会自动降低大小以匹配索引令牌
  • 对于字符串字段(file_extension, language),前缀按原样使用(完全匹配)
  • 数字/日期字段(file_size, modified_date等)不受支持--使用 getIndexStats 用于日期范围
  • 返回按文档频率排序的术语(最常见的第一个)
  • 对于不存在的字段返回空结果(不是错误)

示例--发现德语复合词:

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

示例响应:

{
  "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

获取一个字段中最常用的术语。有助于理解索引词汇表、发现常见值(语言、文件类型、作者)和识别主导术语。

参数:

  • field (必填):从中获取顶级术语的字段名(例如。 content, author, file_extension)
  • limit (可选):要返回的最大术语数(默认值:20,最大值:100)

笔记:

  • 返回按文档频率排序的术语(最常见的第一个)
  • 对于大型内容字段(>10万个独立术语),会包含一条警告,建议 suggestTerms 相反
  • 不支持数字/日期字段--请使用 getIndexStats 用于日期范围
  • 对于不存在的字段返回空结果(不是错误)

示例--探索索引中的文件类型:

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

示例响应:

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

示例——探索内容词汇:

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

______________________________________________________________________

管理工具(组: admin)

indexAdmin

MCP应用程序 它直接在MCP客户端(例如Claude Desktop)内为索引维护任务提供可视化用户界面。调用时,该应用程序将在对话中内联呈现,并提供一键访问管理操作,而不需要手动调用工具。

Index Administration App

可用操作:

  • 解锁索引 --删除陈旧 write.lock 不干净关机后的文件(相当于调用 unlockIndexconfirm=true)
  • 优化指标 --合并索引段以提高搜索性能(相当于调用 optimizeIndex)
  • 清除索引 --从索引中删除所有文档(相当于调用 purgeIndexconfirm=true)

每个操作都直接在应用程序UI中显示内联状态反馈(成功、错误或进度详细信息)。

例子:

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

optimizeIndex

通过合并段来优化Lucene索引。这是一个 长时间运行 它在后台运行。

参数:

  • maxSegments (可选):优化后的目标段数(默认值:1表示最大优化)

退货:

  • success:布尔值,表示操作已启动
  • operationId:UUID用于跟踪操作
  • targetSegments:目标分段计数
  • currentSegments:优化前的当前分段计数
  • message:状态消息

行为:

  • 启动后台操作后立即返回
  • 使用 getIndexAdminStatus 轮询进度
  • 爬网程序正在主动爬网时无法运行
  • 一次只能运行一个管理操作

例子:

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

性能说明:

  • 优化通过减少分段数量来提高搜索性能
  • 在合并过程中临时增加磁盘使用量
  • 对于大型指数,这可能需要几分钟到几小时

purgeIndex

从Lucene索引中删除所有文档。这是一个 破坏性的、长期运行的操作 它在后台运行。

参数:

  • confirm (必填):必须设置为 true 继续。这是一项安全措施。
  • fullPurge (可选):如果 true,还会删除索引文件并重新初始化(默认值: false)

退货:

  • success:布尔值,表示操作已启动
  • operationId:UUID用于跟踪操作
  • documentsDeleted:将被删除的文档数量
  • fullPurge:是否要求进行全面清除
  • message:状态消息

行为:

  • 启动后台操作后立即返回
  • 使用 getIndexAdminStatus 轮询进度
  • 一次只能运行一个管理操作

净化模式:

  • 标准吹扫 (fullPurge=false):删除所有文档,但保留索引文件。在未来的合并过程中,磁盘空间会逐渐被回收。
  • 完全清除 (fullPurge=true):删除所有文档和索引文件,然后重新初始化空索引。磁盘空间会立即回收。

例子:

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

警告: 此操作无法撤消。所有索引文档都将被永久删除。您需要重新抓取目录以重新填充索引。

unlockIndex

移除 write.lock Lucene索引目录中的文件。这是一个 危险恢复操作 -仅当您确定没有其他进程正在使用该索引时才使用。

参数:

  • confirm (必填):必须设置为 true 继续。这是一项安全措施。

退货:

  • success:布尔值表示操作成功
  • message:确认消息
  • lockFileExisted:布尔值,指示是否存在锁文件
  • lockFilePath:锁定文件的路径

何时使用: 当服务器无法启动时使用此工具 LockObtainFailedException 在不干净的关机之后。看 故障排除 了解详情。

例子:

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

警告: 解锁另一个进程正在积极写入的索引可能会导致数据损坏。仅当您确定锁已过时时才使用此选项。

getIndexAdminStatus

获取长时间运行的索引管理操作的状态(优化、清除)。

参数:

退货:

  • success:表示已检索状态的布尔值
  • state:当前状态: IDLE, OPTIMIZING, PURGING, COMPLETED,或 FAILED
  • operationId:当前/上次操作的UUID
  • progressPercent:进度百分比(0-100)
  • progressMessage:人类可读的进度信息
  • elapsedTimeMs:自操作开始以来经过的时间(毫秒)
  • lastOperationResult:上次完成操作的结果消息

示例响应(优化期间):

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

示例响应(完成后空闲):

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

例子:

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

______________________________________________________________________

工具曝光配置

使用两个环境变量控制哪些MCP工具被暴露:

变量默认值描述
LUCENE_TOOLS_INCLUDE* (所有工具)以逗号分隔的工具名称或要公开的组快捷键
LUCENE_TOOLS_EXCLUDE(空)逗号分隔的工具名称或要隐藏的组快捷键; 总是赢 过度包括

工具组

工具
searchsimpleSearch,扩展搜索
semantic语义搜索,个人资料语义搜索
debugprofile查询
infogetIndexStats,listIndexedFields,getDocumentDetails
observabilitysuggestTerms,getTopTerms
crawlerstartCrawl、getCrawlerStats、getCrawlerStatus、pauseCrawler、resumeCrawler,listCrawlableDirectories,addCrawlableDirectory,removeCrawlableDirectory
adminoptimizeIndex、purgeIndex、unlockIndex、getIndexAdminStatus、indexAdmin

除了组速记员外,还可以使用单个工具名称。

示例

# 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

______________________________________________________________________

索引字段架构

当文档被爬虫索引时,会自动提取和存储以下字段:

内容字段

  • content:文档的全文内容(已分析、可搜索)
  • content_reversed:内容的反转标记(用 ReverseUnicodeNormalizingAnalyzer,未存储)。内部用于高效的前导通配符查询,用户无法直接搜索。
  • content_lemma_de:使用德国OpenNLP引理器进行引理化标记(用 OpenNLPLemmatizingAnalyzer,未存储)。无论检测到何种语言,所有文档都始终存在,以实现混合语言匹配。内部用于基于词形化的搜索,用户不能直接搜索。
  • content_lemma_en:使用英语OpenNLP引理器进行引理化标记(用 OpenNLPLemmatizingAnalyzer,未存储)。无论检测到何种语言,所有文档都始终存在,以实现混合语言匹配。内部用于基于词形化的搜索,用户不能直接搜索。
  • content_translit_de:德语音译阴影场,映射变音二字图(ae→啊,oe→呃,呃→ü)标准Unicode规范化之前(用 GermanTransliteratingAnalyzer,未存储)。始终存在于所有文件中。启用ASCII有向图查询,如“Mueller”,以匹配包含“Müller”等文档的变音。内部使用——用户无法直接搜索。
  • passages:搜索结果中返回的突出显示的段落数组(参见 搜索响应格式 在......下面

文件信息

  • file_path:文件的完整路径(唯一ID)
  • file_name:文件名称
  • file_extension:文件扩展名(例如。, pdf, docx)
  • file_typeMIME类型(例如。, application/pdf)
  • file_size:文件大小(字节)

文档元数据

  • title:文档标题(从元数据中提取)
  • author:作者姓名
  • creator:创建文档的创建者/应用程序
  • subject:文件主题
  • keywords:文档关键字/标签

语言和日期

  • language:自动检测语言代码(例如。, en, de, fr)
  • created_date:文件创建时间戳
  • modified_date:文件修改时间戳
  • indexed_date:文档被编入索引时

技术的

  • content_hash:用于更改检测的SHA-256哈希

搜索响应格式

搜索结果针对MCP响应(\search term highlighted in context...", "score": 1.0, "matchedTerms": ["search term"], "termCoverage": 1.0, "position": 0.12, "source": "keyword" }, { "text": "...another occurrence of search 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 } ] }


每份文件 `documents[]` 也有自己的 `_actions` 块:

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


**HATEOAS风格 `_actions` (LLM链式):**

每个搜索响应都包括两个预先计算的动作块,使LLM能够链接工具调用,而无需推理参数映射:

- **`_search`** --捕获用于生成此响应的确切搜索状态(查询、筛选器、页面、页面大小)。有助于自省和构建后续查询。

- **响应级别 `_actions`** --包含用于导航结果集的即用型工具调用:

  |动作类型|出现时|说明|
  |---|---|---|
  | `prevPage` |page>0 |转到上一个结果页。通过 `parameters` 直接到命名 `tool`. |
  | `nextPage` |hasNextPage=true |转到下一个结果页。通过 `parameters` 直接到命名 `tool`. |
  | `drillDown` |可用面|通过添加面值作为过滤器来缩小结果。这 `hits` 字段显示预期结果计数。限制为每个面尺寸的前2个值;仅包括尚未作为过滤器激活的值。 |

- **文档级别 `_actions`** --每份文件 `documents[]` 包括:

  |动作类型|描述|
  |---|---|
  | `fetchContent` |使用以下命令获取完整文档文本和元数据 `getDocumentDetails`The `filePath` 已预先填充。 |

要使用某个操作,请调用 `tool` 在行动中命名为 `parameters` 映射按原样传递——不需要转换。

**主要特点:**

- **搜索性能指标:** 每个搜索响应包括 `searchTimeMs` 以毫秒为单位显示确切的执行时间,从而实现性能监控和优化。

- **突出显示的段落:** 完整版 `content` 字段不包含在搜索结果中,以保持响应大小可控。相反,每个文档都包含一个 `passages` 阵列最多 `max-passages` (默认值:3)单独突出显示摘录。每一段都是一个单独的句子级摘录(不是一个连接的字符串),按相关性排序(最佳优先)。长段落被截断为 `max-passage-char-length` (默认值:200)以突出显示的术语为中心,修剪不相关的前导/尾随文本。每段内容包括:

  - `text` --突出显示的摘录中包含了匹配的术语 `` 标签。
  - `score` --标准化相关性得分(0.0-1.0),来源于Lucene的BM25段落得分。最佳段落得分为1.0;其他段落的分数是相对于最佳段落的。
  - `matchedTerms` --本文中出现的不同查询词(摘自 `` 标签)。有助于理解一篇文章满足多词查询的哪些部分。
  - `termCoverage` --本文中出现的所有查询词的分数(0.0-1.0)。值1.0表示匹配的每个查询项。LLM可以使用这一点来选择解决完整查询的段落。
  - `position` --源文档中的位置(0.0=开始,1.0=结束),由段落的字符偏移量导出。有助于引用或理解文档结构。
  - `source` --指示此段落是如何生成的: `"keyword"` 指BM25高亮显示在索引文档文本中找到的术语匹配; `"semantic"` 意味着使用了最匹配的向量块作为代码段(相关,因为文档是通过向量相似性检索的,即使文本中没有出现确切的查询词)。

- **Lucene Faceting:** 这 `facets` 对象用途 **Lucene的SortedSetDocValues** 用于高效的分面搜索。它显示搜索结果中的实际方面值和文档计数,而不仅仅是可用字段。仅返回在结果集中具有值的方面维度。

- **小平面尺寸:** 以下字段被索引为方面:

  - `language` -检测到的文档语言(ISO 639-1代码)
  - `file_extension` -文件扩展名(pdf、docx等)
  - `file_type` -MIME类型
  - `author` -文档作者(多值)

### 分面搜索示例

使用方面构建深入查询并优化搜索结果:

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" }]


**面驱动工作流:**

1. 使用广泛查询执行初始搜索
1. 审查 `facets` 查看可用的优化选项
1. 使用方面值应用过滤器以缩小结果范围
1. 迭代以深入到特定的子集

## 用法示例

### 示例1:为文档文件夹建立索引

1. 编辑 `application.yaml`:

lucene: crawler: directories: - "/Users/yourname/Documents" crawl-on-startup: true


2. 启动服务器:

java -jar target/luceneserver-0.0.1-SNAPSHOT.jar


3. 爬虫会自动启动并索引“文档”文件夹中所有支持的文档。

### 示例2:使用筛选进行搜索

问克劳德:

Search for "machine learning" in PDF documents only


克劳德将使用:

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


### 示例3:按作者查找文档

问克劳德:

Find all documents written by John Doe


克劳德将使用:

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


### 示例4:监控爬网程序进度

问克劳德:

Show me the crawler statistics


克劳德打电话来 `getCrawlerStats()` 并显示:

- 处理的文件数:1234/5000
- 吞吐量:85个文件/秒
- 指数:1200(98%)
- 失败:34(2%)

### 示例5:完全重新索引的手动爬行

问克劳德:

Reindex all documents from scratch


克劳德打电话来 `startCrawl(fullReindex: true)`,其中:

1. 清除现有索引
1. 重新抓取所有已配置的目录
1. 索引所有新文档

### 示例6:特定语言搜索

问克劳德:

Find German documents about "Technologie"


克劳德使用:

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


### 示例7:使用密码搜索

搜索结果包括 `passages` 带有突出显示的摘录和高质量元数据的数组:

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


这允许您在不下载完整文档的情况下查看相关摘录。元数据字段帮助LLM快速识别最佳段落:更喜欢高 `termCoverage` (涵盖更多查询),使用 `position` 用于文档结构上下文,并检查 `source` 了解文章是否是通过关键字匹配找到的(`"keyword"`)或通过向量相似性(`"semantic"`).

### 示例8:在运行时管理可爬目录

让Claude在不编辑配置文件的情况下管理目录:

"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)


**配置持久性:**

您通过MCP工具添加的目录将保存到 `~/.mcplucene/config.yaml`:

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


此配置在服务器重新启动时仍然存在,无需每次重新配置。

**环境变量覆盖:**

如果你设置 `LUCENE_CRAWLER_DIRECTORIES` 环境变量,它优先:

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


当这被设置时, `addCrawlableDirectory` 和 `removeCrawlableDirectory` 将返回一条错误消息,指示环境覆盖处于活动状态。

### 示例9:使用词汇搜索(同义词和变体)

> **注:** 当通过Claude或其他AI助手使用此服务器时,同义词扩展会自动发生——AI会根据您的自然语言请求为您构建or查询。下面的示例显示了用于参考或直接使用API的基本查询语法。

由于搜索引擎执行 **精确词汇匹配** 在没有自动同义词扩展的情况下,您需要在查询中明确包含同义词和单词变体:

**基本搜索(可能会错过相关结果):**

query: "car"


这将仅匹配包含确切单词“car”的文档,缺少包含“automotive”、“vehicle”等的文档。

**更好的做法是:用OR包含同义词:**

query: "(car OR automobile OR vehicle)"


**最好:将同义词与通配符结合使用以进行变体:**

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


这匹配:汽车,轿车,汽车,汽车,车辆,车辆等。

**现实世界示例-查找合同:**

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


这将找到包含以下变体的文档:

- “合同已签署”、“协议已执行”、“交易已敲定”
- “合同签署”、“协议执行”、“交易敲定”

**提示:** 使用 `facets` 在搜索响应中发现文档中使用的确切术语,然后相应地优化查询。

## 文档爬网程序功能

### 自动爬行

爬虫在服务器启动时自动启动(如果 `crawl-on-startup: true`)以及:

1. **发现文件** 匹配包括配置目录中的模式
1. **提取内容** 使用Apache Tika(支持100多种文件格式)
1. **检测语言** 自动为每个文档
1. **提取元数据** (作者、标题、日期等)
1. **索引文档** 批量生产以获得最佳性能
1. **监视目录** 更改(创建、修改、删除)

### 增量索引(对账)

默认情况下(`reconciliation-enabled: true`),每一次爬行 **不** 完整的reindex首先执行增量遍历。这使得重复的抓取速度大大加快,因为未更改的文件永远不会被重新处理。

**它是如何工作的:**

1. **索引快照** --全部 `(file_path, modified_date)` 从Lucene索引中读取对。
1. **文件系统快照** --已配置的目录将被遍历,当前 `(file_path, mtime)` 收集配对(现阶段不进行内容提取)。
1. **四向差异** 计算:
   - **删除** --索引中不再存在于磁盘上的路径(孤立路径)。
   - **加** --磁盘上尚未在索引中的路径。
   - **更新** --磁盘上的mtime比存储的mtime新的路径 `modified_date`.
   - **跳过** --相同的路径;这些从未被触碰过。
1. **孤儿删除** 首先应用(通过单个Lucene查询进行批量删除)。
1. 仅对ADD和UPDATE文件进行爬网、提取和索引。
1. 成功完成后,爬网状态(时间戳、文档计数、模式)将持久化到 `~/.mcplucene/crawl-state.yaml`.

**回退行为:**
如果协调因任何原因失败(读取索引时发生I/O错误、文件系统漫游失败等),系统将自动回退到完全爬网。数据不会丢失,也不需要人工干预。

**禁用增量索引:**
集 `reconciliation-enabled: false` 在 `application.yaml` 始终执行完全爬行。或者,通过 `fullReindex: true` 到 `startCrawl` 强制执行一次完整爬网而不更改默认值。

**持久状态文件:**

~/.mcplucene/crawl-state.yaml


此文件记录上次成功爬网的完成时间、文档计数和模式。只有在爬网成功完成后才会写入。

### 架构版本管理

服务器跟踪索引架构版本,以检测软件更新之间架构何时更改。这消除了升级后手动重新索引的需要。

**它是如何工作的:**

1. 每个版本都嵌入了一个 `SCHEMA_VERSION` 反映当前索引字段模式的常数。
1. 模式版本与软件版本一起保存在Lucene的提交元数据中。
1. 启动时,服务器将存储的架构版本与当前版本进行比较。
1. 如果它们不同(或者如果旧索引没有版本),则会自动触发完整的重新索引。

**什么会触发模式版本冲突:**

- 添加或删除索引字段
- 更换现场分析仪
- 修改字段索引选项(存储、术语向量等)

**正在检查版本信息:**
使用 `getIndexStats` 查看当前模式版本、软件版本和构建时间戳。

### 实时监控

启用目录监视(`watch-enabled: true`):

- **新文件** 添加时会自动索引
- **已修改的文件** 用更新的内容重新索引
- **已删除的文件** 从索引中删除

### 性能优化

**多线程:**

- 并行爬取多个目录(可配置线程池)
- 每个目录都由一个单独的线程处理

**批量处理:**

- 文档分批索引(默认:100个文档)
- 减少I/O开销并提高索引速度

**NRT(近实时)优化:**

- 正常运行:100ms刷新间隔,快速搜索更新
- 批量索引(>1000个文件):自动减慢到5秒以减少开销
- 批量操作完成后恢复到100ms

**进度通知:**

- 基于定时器:每30秒更新一次(可通过以下方式配置 `progress-notification-interval-ms`)
- 显示吞吐量(文件/秒、MB/秒)、进度和当前处理的文件名
- 非阻塞:出现在系统通知区域,不会中断工作流程
  - **macOS**:通知出现在通知中心(右上角)
  - **视窗**:系统托盘区域中的吐司通知
  - **Linux**:使用notice send进行桌面通知

### 错误处理

- 记录失败的文件,但不会停止爬网
- 统计跟踪成功与失败的文件
- 大型文档已完全编入索引(默认情况下不截断)
- 损坏或无法访问的文件会被优雅地跳过

## 故障排除

### 在哪里可以找到日志?

当与 `deployed` 配置文件中,禁用控制台日志记录以确保与MCP客户端的干净STDIO通信。相反,日志被写入以下文件:

~/.mcplucene/log/mcplucene.log


日志目录为 `${user.home}/.mcplucene/log` 默认情况下(在中配置 `logback.xml`).日志文件会自动轮换:

- 每个文件最大10MB
- 最多保留5个日志文件
- 总大小上限为50MB

**要查看最近的日志,请执行以下操作:**

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


**开发时** (没有 `deployed` 配置文件),日志被写入控制台而不是文件。

### 架构版本更改和自动重新索引

服务器现在包括 **自动模式版本管理**。当您升级到更改索引架构的新版本时(例如,添加新字段、更改分析器或修改字段索引选项),服务器会在启动时检测到版本不匹配,并自动触发完整的重新索引。

**发生了什么:**

1. 启动时,服务器将存储的架构版本与当前版本进行比较
1. 如果它们不同,则会自动触发完整的重新索引
1. 您将看到一条日志消息: `Schema version changed — triggering full reindex`
1. reindex在后台运行;您可以通过以下方式查看进度 `getCrawlerStats`

**手动重新索引:**
如果你出于任何原因需要强制手动重新索引,你仍然可以触发它:

Ask Claude: "Reindex all documents from scratch"


这叫 `startCrawl(fullReindex: true)`,这将清除现有索引并重新爬网所有配置的目录。

**版本信息:**
使用 `getIndexStats` 查看当前模式版本、软件版本和构建时间戳。

### 索引锁文件阻止启动(write.lock)

**症状:** 服务器无法启动,出现以下错误 `Lock held by another program` 或 `LockObtainFailedException`.

**原因:** 当MCP服务器没有完全关闭时(例如,进程被强制终止、系统崩溃或Claude Desktop突然终止),Lucene可能会留下 `write.lock` 索引目录中的文件。此锁文件用于防止多个进程同时写入同一索引。当它在不干净的关闭后被留下时,它会阻止服务器启动,因为Lucene认为另一个进程仍在使用该索引。

**解决方案:** 手动删除锁定文件:

Remove the write.lock file from the index directory

rm ~/.mcplucene/luceneindex/write.lock


删除锁定文件后,服务器应正常启动。

**预防:** 尽可能优雅地关闭Claude Desktop。如果需要强制退出,请注意在下次启动之前可能需要删除锁定文件。

**注:** 默认索引路径为 `~/.mcplucene/luceneindex`。如果您已通过配置自定义索引路径 `LUCENE_INDEX_PATH` 或 `application.yaml`,寻找 `write.lock` 请将文件改为该目录中的文件。

### 服务器显示为“正在运行”,但工具不起作用

这通常表示STDIO通信问题:

1. 确保 `-Dspring.profiles.active=deployed` 参数存在于配置中
1. 检查是否没有其他输出写入stdout
1. 验证JAR路径是绝对路径,而不是相对路径
1. 如果修改了配置,请确保“已部署”配置文件设置正确

### Claude Desktop未显示服务器

1. 验证配置中的JAR文件路径是否正确和绝对
1. 检查是否安装了Java 25+: `java -version`
1. 验证配置文件中的JSON语法
1. 检查Claude Desktop日志中的错误消息
1. 尝试手动运行JAR以检查启动错误:

java -jar /path/to/luceneserver-0.0.1-SNAPSHOT.jar


### 服务器无法启动

1. 确保Lucene索引目录路径有效
1. 检查是否没有其他进程锁定索引目录
1. 验证索引是否有足够的磁盘空间

### 空搜索结果

索引可能为空,原因有几个:

1. **未配置目录**:将目录添加到 `application.yaml` 在...之下 `lucene.crawler.directories`
1. **爬行器未启动**:使用 `startCrawl` MCP工具或启用 `crawl-on-startup: true`
1. **未找到匹配的文件**:检查您的目录是否包含与包含模式匹配的文件
1. **文件索引失败**:检查日志中的错误,使用 `getCrawlerStats` 查看失败的文件计数

### 爬网程序未为文件建立索引

1. **检查目录路径**:确保路径 `application.yaml` 绝对存在
1. **验证文件权限**:服务器需要读取所有文件
1. **检查包括图案**:文件必须至少匹配一个包含模式
1. **检查排除模式**:文件不得与任何排除模式匹配
1. **监控爬虫状态**:使用 `getCrawlerStatus` 和 `getCrawlerStats` MCP工具
1. **检查日志**:查找解析错误或I/O异常

### 索引过程中出现内存不足错误

如果您在处理非常大的文档时遇到OOM错误:

1. **设置内容限制**:更改 `max-content-length` 在 `application.yaml` (例如。, `5242880` 5MB)
1. **增加JVM堆**:添加 `-Xmx2g` 到Claude Desktop配置中的JVM参数
1. **减少线程池**:较低 `thread-pool-size` 减少并发处理
1. **减少批量大小**:较低 `batch-size` 更频繁地承诺

### 索引性能缓慢

1. **增加线程池**:提高 `thread-pool-size` (默认值:4)
1. **增加批量大小**:提高 `batch-size` 更少的提交(默认值:100)
1. **禁用语言检测**:设置 `detect-language: false` 如果不需要
1. **禁用元数据提取**:设置 `extract-metadata: false` 如果不需要
1. **检查磁盘I/O**:磁盘速度慢会造成索引瓶颈

## 安全考虑

**不受信任的文档内容**

MCP-Lucene服务器对已爬网目录中的文档进行索引,并在MCP工具响应中返回其内容(段落、元数据、全文)。此内容本质上是不可信的——放置在爬网目录中的任何文档都会影响MCP客户端(LLM)在工具响应中看到的内容。

**间接快速注射风险**

这为间接提示注入创造了可能性:恶意制作的文档可能包含旨在操纵处理搜索结果的LLM的文本。例如,文档可能包含看似自然文本的指令,但旨在影响LLM的行为或响应。

**建议**

- **MCP客户端应将工具响应中的所有文档派生内容视为不受信任的数据**
- 服务器添加了一个 `contentNote` 包含文档内容作为提醒的响应字段
- 配置服务器时考虑已爬网目录的信任级别
- 请注意,索引内容可以通过搜索结果影响LLM行为

这是检索外部内容并将其呈现给语言模型的系统的固有特征。

## 配置选项

> **注:** 这 [快速开始](#quick-start) 上面使用零配置。本节介绍高级自定义选项。

服务器可以通过环境变量和 `application.yaml`:

### 日志记录配置文件

服务器支持两种日志记录配置文件(为了向后兼容,使用与Spring Boot相同的系统属性):

|配置文件|使用情况|日志记录输出|
|--------------|---------------------------|-------------------------|
| **默认** |IDE中的开发|已启用控制台日志记录|
| **部署** |生产/Claude桌面|仅记录文件|

**默认配置文件(未指定配置文件):**

- 控制台已启用完整日志记录
- 适用于调试和开发

**已部署配置文件(`-Dspring.profiles.active=deployed`):**

- 控制台日志记录已禁用(STDIO传输需要)
- 已启用文件日志记录(`~/.mcplucene/log/mcplucene.log`)
- 在Claude Desktop或其他MCP客户端下运行时使用

### 运输配置

服务器支持两种传输类型: **工作室** (默认)和 **超文本传输协议**通过以下方式选择运输方式 `mcp.transport` 系统属性。

#### STDIO传输(默认)

STDIO传输是Claude Desktop集成的默认和推荐模式。不需要额外的配置。

**Claude桌面配置:**

{ "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" ] } } }


#### HTTP传输

HTTP传输允许使用 **MCP流式HTTP协议(规范2025-03-26)**。要启用HTTP传输,请设置 `mcp.transport` 系统属性 `http`.

**从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


**自定义HTTP配置:**

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


**HTTP配置属性:**

|系统属性|默认值|描述|
|---------------------|----------------|---------------------------------------------|
| `mcp.transport` | `stdio` |运输类型: `stdio` 或 `http` |
| `mcp.http.host` | `0.0.0.0` |HTTP服务器绑定地址(仅限HTTP模式)|
| `mcp.http.port` | `8080` |HTTP服务器端口(仅限HTTP模式)|
| `mcp.http.endpoint` | `/mcp/message` |MCP消息端点路径(仅限HTTP模式)\*|

\*默认值 `/mcp/message` 是标准MCP端点,通常不需要更改。

**重要提示:**

- HTTP传输使用 **MCP流式HTTP协议** 使用无状态异步模式
- STDIO传输用途 **有状态同步** 模式(适用于持久连接)
- HTTP模式确实如此 **不** 支持HTTPS/TLS-使用反向代理(nginx、Caddy)进行加密
- 对于HTTP的生产使用,始终将服务器置于具有适当身份验证的反向代理之后
- 这 `deployed` 配置文件在HTTP中是可选的(控制台日志记录不会干扰)

**示例:在其他端口上运行**

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


**示例:仅限本地主机(更安全)**

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


### 语义搜索配置

语义向量搜索是一个可选功能,通过设置 `VECTOR_MODEL` 环境变量。

**启用语义搜索:**

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


|环境变量|默认值|描述|
|----------------------|---------|-------------------------------------------------------------------------------------------------------------------------------|
| `VECTOR_MODEL` |(无)|嵌入模型: `e5-base` (768调暗,更快)或 `e5-large` (1024调光,更高质量)。设置为启用语义搜索工具。 |

看 [语义研究.md](SEMANTICSEARCH.md) 了解完整的架构细节、调优指导和KNN评分配置。

### 语义搜索与语义鸿沟

矢量搜索旨在关闭 **语义鸿沟**:当用户搜索“car”时,查找有关“automotive”的文档,因为嵌入模型将这两个概念映射到向量空间中的附近点。

**然而,当将此服务器与LLM(Claude、GPT等)一起使用时,情况发生了根本性的变化。**

作为推理过程的一部分,LLM已经弥合了语义鸿沟。在调用搜索工具之前,提示良好的LLM可以将“查找有关汽车的文档”重写为显式的OR查询: `(car OR automobile OR vehicle OR sedan)`这意味着LLM处理同义词扩展和查询重新表述——这正是向量搜索所要解决的问题。

**当语义搜索增加真正的价值时:**

- 直接面向用户的搜索UI,循环中没有LLM
- 无需LLM查询重新制定的批处理或自动化管道
- 涉及领域特定术语的查询,其中同义词不明显
- 相关文件确切措辞未知的概念查询

**当语义搜索增加边际价值时(基于LLM的用例):**

- LLM客户端在调用工具之前使用同义词展开查询
- LLM将模糊查询重新表述为精确的Lucene表达式
- 搜索语料库使用一致的术语,BM25处理得很好

**需要考虑的权衡:**

- 嵌入计算增加了延迟(索引期间约31ms/doc,e5基约5ms/查询)
- ONNX型号需要约100-200MB的磁盘空间和额外的RAM
- 索引复杂性增加(父文档+通过块连接的子块文档)

### 环境变量

|环境变量|默认值|描述|
|------------------------------|---------------------------------------|---------------------------------------------------------------------------|
| `LUCENE_INDEX_PATH` | `${user.home}/.mcplucene/luceneindex` |Lucene索引目录的路径|
| `LUCENE_CRAWLER_DIRECTORIES` |(无)|以逗号分隔的要爬网的目录列表(覆盖配置文件)|
| `VECTOR_MODEL` |(无)|嵌入模型(`e5-base` 或 `e5-large`).设置为启用语义搜索。 |
| `LUCENE_TOOLS_INCLUDE` | `*` (all)|以逗号分隔的工具名称或要公开的组快捷键|
| `LUCENE_TOOLS_EXCLUDE` |(空)|逗号分隔的工具名称或要隐藏的组快捷键|

**注意 `LUCENE_CRAWLER_DIRECTORIES`:**
设置此环境变量后,它优先于 `~/.mcplucene/config.yaml` 和 `application.yaml`MCP配置工具(`addCrawlableDirectory`, `removeCrawlableDirectory`)当此覆盖处于活动状态时,将拒绝修改配置。要使用运行时配置,请删除此环境变量。

### 文档爬网程序配置

爬虫目录可以通过三种方式配置,优先级如下(从高到低):

1. **环境变量**: `LUCENE_CRAWLER_DIRECTORIES` (逗号分隔的路径)
1. **运行时配置**: `~/.mcplucene/config.yaml` (通过MCP工具管理)
1. **应用程序默认值**: `src/main/resources/application.yaml`

#### 通过MCP工具进行运行时配置(推荐)

服务器提供MCP工具,用于在运行时管理可爬目录,而无需编辑配置文件:

**`listCrawlableDirectories`** -列出所有已配置的目录

Ask Claude: "What directories are being crawled?"


**`addCrawlableDirectory`** -添加要爬网的新目录

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


**`removeCrawlableDirectory`** -从爬网中删除目录

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


**运行时配置的好处:**

- 无需重建JAR或重新启动服务器
- 配置在重新启动后仍然有效 `~/.mcplucene/config.yaml`
- 易于分发预构建的JAR
- Claude对话界面

**配置文件位置:**

~/.mcplucene/config.yaml


**config.yaml示例:**

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


#### 通过application.yaml进行静态配置

在中配置文档爬网程序 `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)


**支持的文件格式:**

- PDF文档(`.pdf`)
- 微软办公软件:Word(`.doc`, `.docx`),Excel(`.xls`, `.xlsx`),PowerPoint(`.ppt`, `.pptx`)
- OpenOffice/LibreOffice:作家(`.odt`),Calc(`.ods`印象`.odp`)
- 纯文本文件(`.txt`)
- 电子邮件:Outlook(`.msg`),EML(`.eml`)
- 标记:Markdown(`.md`),重新结构化文本(`.rst`),HTML(`.html`, `.htm`)
- 富文本格式(`.rtf`)
- 电子书:EPUB(`.epub`)

**完整配置示例:**

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


## JDBC元数据扩展

服务器可以在索引时从关系数据库加载额外的元数据来丰富索引文档。当业务元数据(如客户ID、项目代码、标签)存储在数据库中而不是文件本身中时,这很有用。

### 运作原理

1. 对于爬行过程中的每个文档,富集器都会执行一个可配置的SQL查询。
1. 查询结果是一行,其中JSON列包含元数据有效载荷。
1. JSON有效负载被解析,类型字段被添加到Lucene文档中。
1. 当文件的数据库元数据发生变化时,后台同步作业会重新索引文件。

### 字段命名

所有JDBC源字段都以前缀 `dbmeta_` 以避免与基本文档模式发生冲突。

|JSON字段名| Lucene字段名|
|-----------------|----------------------|
| `customer_id` | `dbmeta_customer_id` |
| `tags` | `dbmeta_tags` |
| `department` | `dbmeta_department` |

### JSON元数据格式

数据库查询必须返回一列(可通过配置 `json.columnName`)包含以下格式的JSON:

{ "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" } ] }


**字段类型:**

|类型| Lucene存储| Facetable |备注|
|-----------|-------------------------|-----------|---------------------------------------------------|
| `keyword` |StringField |是|完全匹配;用于ID、代码、类别|
| `text` |文本字段|否|已分析全文;适合长篇描述|
| `int` |IntPoint+StoredField |是| 32位整数;支持范围查询|
| `long` |LongPoint+StoredField |是|64位整数;支持范围查询|
| `date` |LongPoint+存储字段|编号|ISO-8601字符串→ 纪元毫秒|

**可选的每个字段标志:**

|标志|默认值|描述|
|--------------|---------|----------------------------------------------------------|
| `faceted` | `false` |显示为搜索方面(仅关键字/长)|
| `stored` | `true` |存储该值,以便从搜索结果中检索|
| `searchable` | `true` |为查询字段建立索引|

### 配置

将以下部分添加到 `~/.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


### 高级示例:从表动态构建元数据(MySQL)

元数据通常不存储为预构建的JSON,而是分布在规范化的表中。MySQL的 `JSON_OBJECT()` / `JSON_ARRAY()` / `JSON_ARRAYAGG()` 函数允许您在SQL查询中直接组装元数据负载,无需单独的物化视图或ETL作业。

#### 场景

文档是自由职业者个人资料PDF。文件名遵循以下模式 `.../ABC-1234_Profile.pdf`,在哪里 `ABC-1234` 是一个独特的自由职业者代码。相关表格:

-- 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 );


#### 配置

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


#### 它是如何一步一步工作的

**1.参数绑定——将文件路径作为查找键**

在爬行过程中,索引器将绝对文件路径存储在Lucene字段中 `file_path` (例如。 `/docs/profiles/ABC-1234_Profile.pdf`).经由 `parameters.sourceField: file_path`,该值作为命名参数传递 `:file_path` SQL查询。

**2.使用正则表达式提取自由职业者代码**

因为完整的文件路径被传递给数据库,所以必须在那里提取代码。 `REGEXP_SUBSTR(:file_path, '[A-Z]+-[0-9]+')` 拉 `ABC-1234` 在...之外 `/docs/profiles/ABC-1234_Profile.pdf` 并将其与 `freelancer.code`数据库不需要了解目录结构——正则表达式完全在数据库引擎内运行。

**3.在SQL中组装JSON有效载荷**

`JSON_OBJECT(...)` 生成一个JSON对象。里面,a `JSON_ARRAY(...)` 每个元数据字段包含一个元素:

- **`daily_rate`** (类型 `long`):来自的单个标量值 `f.salary_per_day_long`
- **`tags`** (类型 `long`,多值):由相关子查询生成的数组-- `JSON_ARRAYAGG(ft.tag_id)` 将自由职业者的所有标签ID聚合到JSON数组中

查询返回一行一列 `metadata_json`:

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


**4.索引器的处理**

`JdbcMetadataEnricher` 读取此JSON响应并将字段添加到Lucene文档中:

- `dbmeta_daily_rate` → `LongPoint(850)` + `StoredField(850)` + `SortedNumericDocValuesField(850)` (可搜索、可检索和 **可排序的**)
- `dbmeta_tags` → three `LongPoint` 值条目 `12`, `47`, `103` (多值--跳过DocValues,因此无法排序)

因为 `faceted: false`,没有 `SortedSetDocValuesFacetField` 条目已创建。这些字段可用于目标查询和范围过滤器,而不会在每个搜索请求上增加方面计算的开销。

**按JDBC元数据字段排序:** 单值INT、LONG和DATE字段会自动获得 `SortedNumericDocValuesField`,单值关键字字段得到 `SortedDocValuesField`。这使它们可用作 `sortBy` 搜索请求中的值。多值字段跳过DocValues(未定义对多值字段进行排序)。使用 `getIndexStats` 看看哪个 `dbmeta_*` 字段当前通过以下方式注册为可排序 `sortableFields` 地图。

**5.运行时查询**

爬行后,这些字段可以用作中的筛选器 `extendedSearch`:

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


#### 注意 `CAST(FALSE AS JSON)`

MySQL没有原生JSON布尔值。 `CAST(FALSE AS JSON)` 生成JSON值 `false`,其中 `JsonMetadataParser` 正确解释为 `faceted: false`.使用 `CAST(TRUE AS JSON)` 为了 `faceted: true`.

______________________________________________________________________

### 高级示例:通过索引查找进行后台同步(PostgreSQL)

#### 场景

与丰富示例相同的自由职业者PDF设置。当自由职业者的每日费率或标签在数据库中发生变化时,服务器应该自动重新索引受影响的PDF,而数据库不需要知道文件路径。

**先决条件:** 富集查询存储 `customer_id` 作为 `dbmeta_customer_id` (类型 `keyword`)在Lucene索引中 `document_metadata` 桌子也有 `customer_id` 列加a `updated_at` 时间戳。

#### 配置

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


#### 它是如何一步一步工作的

**1.时间戳过滤器**

这 `:last_sync_timestamp` 参数绑定到最后一次成功同步时间(持久化于 `~/.mcplucene/metadata-sync-state.yaml`).首次运行时,它默认为 `1970-01-01T00:00:00Z`,因此扫描了整个表格。

**2.列名为Lucene字段**

结果集只有一列。它的名字-- `dbmeta_customer_id` (通过设置 `AS` alias)--从JDBC读取 `ResultSetMetaData`。这将成为服务器将搜索的Lucene字段。

**3.TermQuery查询**

对于每一行(例如值 `C-42`),服务器执行Lucene `TermQuery` 上 `dbmeta_customer_id = "C-42"` 仅限于父文档。这将查找每个使用该客户ID丰富的索引文件。

**4.文件路径解析**

`file_path` 从每个匹配的Lucene文档中提取。索引(而不是数据库)是文件物理位置的真实来源。

**5.重新索引或删除**

如果文件仍然存在于磁盘上,则会重新爬网,这会再次触发富集查询,以便Lucene文档从数据库中获取最新的元数据。如果文件已被删除,则其索引条目也将被删除。

**6.时间戳提前**

成功运行后,当前时间将另存为新时间 `lastSyncTimestamp`。下一次同步只返回在此点之后修改的行。

#### 使用数字连接键

如果连接键是数字数据库ID而不是字符串代码,请使用适当的SQL整数类型,以便服务器构建正确的Lucene点查询:

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


这里 `freelancer_id` 是一个 `BIGINT` 列,因此服务器使用 `LongPoint.newExactQuery("dbmeta_freelancer_id", …)`。浓缩物必须已储存 `freelancer_id` 作为类型字段 `long` 以便查询匹配。

|SQL列类型|Lucene查询|必须与富集类型匹配|
|------------------------|-----------------------------|----------------------------|
| `VARCHAR` / `CHAR` | `TermQuery` | `keyword` |
| `INTEGER` / `SMALLINT` | `IntPoint.newExactQuery()` | `int` |
| `BIGINT` / `NUMERIC` | `LongPoint.newExactQuery()` | `long` |

______________________________________________________________________

### 支持的数据库

|数据库|驱动程序依赖性|注释|
|------------|-----------------------------|----------------------------------|
|PostgreSQL |已包含(可选运行时)| `jdbc:postgresql://...` |
|MySQL |已包含(可选运行时)| `jdbc:mysql://...` |
|H2 |仅测试范围| `jdbc:h2:...` (用于测试)|
|任何JDBC |添加到类路径|设置 `driverClassName` 明确|

### Facet集成

用以下方式声明的字段 `"faceted": true` 被自动注册为动态面维度。它们出现在内置刻面旁边(`language`, `file_extension`, `file_type`, `author`)在搜索结果中,可以用作过滤值。

多值字段(使用 `"values": [...]`)被自动配置为多值面维度。

### 背景同步

当 `sync.enabled: true`,服务器每运行一次后台作业 `intervalMinutes` 分钟:

1. 查询数据库中自上次同步以来修改的记录(使用 `:last_sync_timestamp`).
1. 读取结果集——恰好一列,N行。这 **列名** 是要搜索的Lucene字段;这 **列值** 是匹配的术语。
1. 按行执行Lucene查询以查找匹配的索引文档,然后提取它们的 `file_path`.
1. 使用最新元数据重新索引磁盘上仍然存在的文件。
1. 删除不再存在的文件的索引条目。

最后一个同步时间戳保存在 `~/.mcplucene/metadata-sync-state.yaml`.

**支持的列类型:**

|SQL列类型|Lucene查询|兼容 `dbmeta_` 字段类型|
|----------------------------------|-----------------------------|---------------------------------|
| `VARCHAR`, `CHAR`, …             | `TermQuery` | `keyword` |
| `INTEGER`, `SMALLINT`, `TINYINT` | `IntPoint.newExactQuery()` | `int` |
| `BIGINT`, `NUMERIC`, `DECIMAL` | `LongPoint.newExactQuery()` | `long` |

查询类型是从JDBC列类型自动推断出来的,不需要额外的配置。SQL列类型必须与富集期间使用的Lucene字段类型匹配(`IntPoint` 和 `LongPoint` 是单独的字段类型)。分析 `text` 字段不适合作为同步密钥。

### 错误处理

富集者遵循“跳过并警告”的弹性模式:

- 数据库连接失败:文档被索引而没有内容丰富,记录了警告。
- 查询错误:相同的跳过和警告行为。
- JSON有效载荷无效:记录解析错误,跳过字段。
- NULL值:每个字段都会被静默忽略。
- 字段名与基本架构冲突:记录错误,跳过字段。

## 发展

### 为发展而奔跑

在IDE中开发和调试时,运行服务器 **没有** “部署”配置文件以获取完整日志记录:

**在您的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


这为您提供了:

- 完成调试日志输出
- 从类路径和用户配置加载配置
- 控制台中可见的所有调试信息

**对于生产/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


### 使用MCP检查器进行调试

这 [MCP检查员](https://github.com/modelcontextprotocol/inspector) 提供了一个用于测试MCP服务器的可视化调试界面。使用它来检查请求、响应和调试工具行为,而不需要像Claude Desktop这样的完整MCP客户端。

**使用STDIO连接检查器运行服务器:**

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


或者在HTTP流媒体的情况下:

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


这将打开一个基于web的UI,您可以在其中:

- 交互式测试所有MCP工具
- 检查JSON请求/响应有效载荷
- 调试STDIO通信问题
- 验证工具参数和返回值

**注:** 检查器需要与生产部署相同的JVM参数(`--enable-native-access=ALL-UNNAMED`, `-Dspring.profiles.active=deployed`)以确保行为的一致性。

### 将文档添加到索引

**推荐方法:** 通过在中配置目录来使用文档爬网程序 `application.yaml`爬虫自动处理内容提取、元数据和语言检测。

**程序化方法:** 对于自定义文档类型或直接索引:

// 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(); }


有关完整字段架构,请参阅 [索引字段架构](#index-field-schema) 部分。

目录标签

目录标签

JavaClaude全文搜索全文检索本地部署文档管理多语言搜索自动索引知识检索

支持客户端

Claude DesktopClaudeVS Code

接入字段

传输方式(transport,传输协议)

stdio

鉴权方式(authType,认证方式)

none

运行时(runtime,运行环境)

Docker

工具数量(toolCount,工具数)

0

资源数量(resourceCount,资源数)

0

提示词数量(promptCount,提示词数)

0

权限和风险

stdionone部署方式未说明

接入前请确认传输方式、认证方式和部署位置,并根据实际工具能力限制访问范围。

安装前确认

不要直接授予不必要的文件、网络或账号权限;先核对安装命令和配置内容。

来源信息

继续浏览同类 MCP