docs_search_docs
Search documentation across development frameworks using keywords to find relevant information quickly. Filter results by source and limit output for targeted research.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | 搜索关键词 | |
| source | No | 文档源名称(可选) | |
| limit | No | 最大结果数量 |
Implementation Reference
- server.js:394-557 (handler)Main execution logic for the docs_search_docs tool: processes search query, loads documents if needed, performs term matching with scoring across title/content/ID, sorts and limits results, returns JSON.async ({ query, source, limit }) => { log(`收到搜索请求: 关键词="${query}", 源="${source || '所有'}", 限制=${limit}`); log(`当前文档数据状态: docsLoaded=${docsLoaded}, docData键数量=${Object.keys(docData).length}`); log(`当前进程工作目录: ${process.cwd()}`); log(`当前脚本目录: ${__dirname}`); try { // 特殊命令处理 - reload if (query.toLowerCase() === "reload") { log("收到重新加载文档指令"); docsLoaded = false; Object.keys(docData).forEach(key => delete docData[key]); // 修复: 使用docData[key]而不是docData.key const loadResult = await ensureDocsLoaded(); return { content: [{ type: "text", text: JSON.stringify({ message: loadResult ? "文档已重新加载成功" : "文档重新加载失败", sources: Object.keys(docData), count: Object.keys(docData).length, cwd: process.cwd(), scriptDir: __dirname }, null, 2) }] }; } // 确保有数据可用 if (Object.keys(docData).length === 0) { log(`文档数据为空,尝试重新加载...`); const loadResult = await ensureDocsLoaded(); log(`重新加载结果: ${loadResult}, docData键数量=${Object.keys(docData).length}`); if (!loadResult || Object.keys(docData).length === 0) { log(`重新加载后文档仍然不可用`); // 添加示例数据以便于调试 docData['example'] = { source: { name: 'Example Docs' }, lastUpdated: new Date().toISOString(), pages: { 'example-1': { title: '示例文档1', content: '这是一个示例文档内容,用于测试搜索功能。' }, 'example-2': { title: '示例文档2', content: '这是另一个示例文档,包含一些测试关键词。' } } }; log(`已添加示例数据用于测试`); } } // 获取要搜索的文档 let docs = {}; if (source) { const sourceLower = source.toLowerCase(); if (!docData.hasOwnProperty(sourceLower)) { return { content: [{ type: "text", text: JSON.stringify({ error: `未找到文档源 "${source}"`, availableSources: Object.keys(docData), docDataStatus: { keys: Object.keys(docData), count: Object.keys(docData).length } }, null, 2) }] }; } // 确保安全获取pages if (docData[sourceLower] && docData[sourceLower].pages) { docs = docData[sourceLower].pages; } else { docs = {}; // 如果没有pages,使用空对象 } } else { // 从所有源获取文档 Object.entries(docData).forEach(([name, data]) => { if (data && data.pages) { Object.entries(data.pages).forEach(([id, page]) => { docs[id] = { ...page, source: name }; }); } }); } const normalizedQuery = query.toLowerCase().trim(); // 分割查询字符串 const queryTerms = normalizedQuery.split(/\s+/).filter(term => term.length > 0); // 进行搜索 const results = Object.entries(docs) .map(([id, doc]) => { const title = (doc.title || '').toLowerCase(); const content = (doc.content || '').toLowerCase(); // 检查是否所有查询词都包含在标题或内容中 const allTermsMatch = queryTerms.every(term => title.includes(term) || content.includes(term) || id.toLowerCase().includes(term)); if (!allTermsMatch) return null; // 计算匹配度(可以根据需求调整) let score = 0; queryTerms.forEach(term => { if (title.includes(term)) score += 10; if (content.includes(term)) score += 5; if (id.toLowerCase().includes(term)) score += 3; }); return { id, url: id, title: doc.title || id, content: content.length > 200 ? content.substring(0, 200) + "..." : content, score: score, source: doc.source || source || null }; }) .filter(item => item !== null) .sort((a, b) => b.score - a.score) .slice(0, limit); log(`找到 ${results.length} 个匹配结果`); return { content: [{ type: "text", text: JSON.stringify({ success: true, query: query, source: source || "all", resultsCount: results.length, results: results.length > 0 ? results : [ { id: "no-results", title: "没有找到匹配结果", content: `未找到与 '${query}' 中所有关键词匹配的内容`, score: 0, source: null } ] }, null, 2) }] }; } catch (error) { log(`搜索过程中发生错误: ${error.message}`); log(`错误堆栈: ${error.stack}`); return { content: [{ type: "text", text: JSON.stringify({ error: "搜索过程中发生错误", details: error.message, stack: error.stack, query: query, docsLoaded: docsLoaded, docDataKeys: Object.keys(docData), cwd: process.cwd(), scriptDir: __dirname }, null, 2) }] }; } }
- server.js:389-393 (schema)Zod input schema defining parameters: query (required string), source (optional string), limit (optional number default 10).{ query: z.string().describe("搜索关键词"), source: z.string().optional().describe("文档源名称(可选)"), limit: z.number().optional().default(10).describe("最大结果数量") },
- server.js:387-558 (registration)MCP server tool registration call for 'docs_search_docs' with name, schema, and handler function.server.tool( "docs_search_docs", // 修改工具名称,添加命名空间前缀 { query: z.string().describe("搜索关键词"), source: z.string().optional().describe("文档源名称(可选)"), limit: z.number().optional().default(10).describe("最大结果数量") }, async ({ query, source, limit }) => { log(`收到搜索请求: 关键词="${query}", 源="${source || '所有'}", 限制=${limit}`); log(`当前文档数据状态: docsLoaded=${docsLoaded}, docData键数量=${Object.keys(docData).length}`); log(`当前进程工作目录: ${process.cwd()}`); log(`当前脚本目录: ${__dirname}`); try { // 特殊命令处理 - reload if (query.toLowerCase() === "reload") { log("收到重新加载文档指令"); docsLoaded = false; Object.keys(docData).forEach(key => delete docData[key]); // 修复: 使用docData[key]而不是docData.key const loadResult = await ensureDocsLoaded(); return { content: [{ type: "text", text: JSON.stringify({ message: loadResult ? "文档已重新加载成功" : "文档重新加载失败", sources: Object.keys(docData), count: Object.keys(docData).length, cwd: process.cwd(), scriptDir: __dirname }, null, 2) }] }; } // 确保有数据可用 if (Object.keys(docData).length === 0) { log(`文档数据为空,尝试重新加载...`); const loadResult = await ensureDocsLoaded(); log(`重新加载结果: ${loadResult}, docData键数量=${Object.keys(docData).length}`); if (!loadResult || Object.keys(docData).length === 0) { log(`重新加载后文档仍然不可用`); // 添加示例数据以便于调试 docData['example'] = { source: { name: 'Example Docs' }, lastUpdated: new Date().toISOString(), pages: { 'example-1': { title: '示例文档1', content: '这是一个示例文档内容,用于测试搜索功能。' }, 'example-2': { title: '示例文档2', content: '这是另一个示例文档,包含一些测试关键词。' } } }; log(`已添加示例数据用于测试`); } } // 获取要搜索的文档 let docs = {}; if (source) { const sourceLower = source.toLowerCase(); if (!docData.hasOwnProperty(sourceLower)) { return { content: [{ type: "text", text: JSON.stringify({ error: `未找到文档源 "${source}"`, availableSources: Object.keys(docData), docDataStatus: { keys: Object.keys(docData), count: Object.keys(docData).length } }, null, 2) }] }; } // 确保安全获取pages if (docData[sourceLower] && docData[sourceLower].pages) { docs = docData[sourceLower].pages; } else { docs = {}; // 如果没有pages,使用空对象 } } else { // 从所有源获取文档 Object.entries(docData).forEach(([name, data]) => { if (data && data.pages) { Object.entries(data.pages).forEach(([id, page]) => { docs[id] = { ...page, source: name }; }); } }); } const normalizedQuery = query.toLowerCase().trim(); // 分割查询字符串 const queryTerms = normalizedQuery.split(/\s+/).filter(term => term.length > 0); // 进行搜索 const results = Object.entries(docs) .map(([id, doc]) => { const title = (doc.title || '').toLowerCase(); const content = (doc.content || '').toLowerCase(); // 检查是否所有查询词都包含在标题或内容中 const allTermsMatch = queryTerms.every(term => title.includes(term) || content.includes(term) || id.toLowerCase().includes(term)); if (!allTermsMatch) return null; // 计算匹配度(可以根据需求调整) let score = 0; queryTerms.forEach(term => { if (title.includes(term)) score += 10; if (content.includes(term)) score += 5; if (id.toLowerCase().includes(term)) score += 3; }); return { id, url: id, title: doc.title || id, content: content.length > 200 ? content.substring(0, 200) + "..." : content, score: score, source: doc.source || source || null }; }) .filter(item => item !== null) .sort((a, b) => b.score - a.score) .slice(0, limit); log(`找到 ${results.length} 个匹配结果`); return { content: [{ type: "text", text: JSON.stringify({ success: true, query: query, source: source || "all", resultsCount: results.length, results: results.length > 0 ? results : [ { id: "no-results", title: "没有找到匹配结果", content: `未找到与 '${query}' 中所有关键词匹配的内容`, score: 0, source: null } ] }, null, 2) }] }; } catch (error) { log(`搜索过程中发生错误: ${error.message}`); log(`错误堆栈: ${error.stack}`); return { content: [{ type: "text", text: JSON.stringify({ error: "搜索过程中发生错误", details: error.message, stack: error.stack, query: query, docsLoaded: docsLoaded, docDataKeys: Object.keys(docData), cwd: process.cwd(), scriptDir: __dirname }, null, 2) }] }; } } );