file-search
Search for files and folders in your cloud drive using keywords, filter by file type, and browse results with pagination.
Instructions
在云盘中根据关键词搜索文件和文件夹,支持按文件类型筛选和分页查询。返回符合条件的文件详细信息。
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_category | No | 文件类型筛选:-1(全部)、0(其他)、1(图片)、2(文档)、3(音乐)、4(视频) | |
| key | No | 搜索关键词,当file_category 不为 -1 时,可以为空,否则必填 | |
| page | No | 页码,从1开始 | |
| page_size | No | 每页显示的条目数,默认20条,最大100条 |
Implementation Reference
- src/tools/file-search.ts:113-198 (handler)The main execution handler for the 'file-search' tool. It handles input parameters, retrieves authentication info, calls the searchFiles helper to query the cloud storage API, processes the response, formats file information, and returns structured content or error messages.const httpContext = gethttpContext(mcpReq, server); // 使用transport中的authInfo const transportAuthInfo = httpContext.authInfo; try { let authInfo: AuthInfo; // 参数验证 if (!key && file_category === -1) { throw new Error("必须提供搜索关键词(key)或指定文件类型(file_category)"); } const extraParams: Record<string|number, string|number> = { file_category, key, page: page || 1, page_size: page_size || 20, } try { // 传入方法名和路径等参数 authInfo = await getAuthInfo({ method: 'File.searchList', extraParams: extraParams }, transportAuthInfo); authInfo.request_url = getConfig(transportAuthInfo?.ecsEnv).request_url } catch (authError) { throw new Error("获取鉴权信息失败,请提供有效的API_KEY"); } // 调用API搜索文件 const apiResponse = await searchFiles(authInfo, extraParams); // 检查API响应是否成功 if (apiResponse && apiResponse.errno === 0) { const files = (apiResponse.data && apiResponse.data.node_list) || []; if (files.length === 0) { return { content: [ { type: "text", text: "没有找到符合条件的文件", }, ], }; } // 统计文件夹和文件数量 const dirCount = files.filter((file: YunPanFile) => file.type === "1").length; const fileCount = files.length - dirCount; // 格式化结果 const formattedFiles = files.map(formatFileInfo); const filesText = `云盘文件搜索结果 (关键词: ${key})\n共 ${files.length} 项 (${dirCount} 个文件夹, ${fileCount} 个文件)\n\n${formattedFiles.join("\n")}`; return { content: [ { type: "text", text: filesText, }, { type: "text", text: TOOL_LIMIT_NOTE, }, ], }; } else { throw new Error(apiResponse?.errmsg || "API请求失败"); } } catch (error: any) { return { content: [ { type: "text", text: `搜索文件时发生错误: ${error.message}`, }, { type: "text", text: TOOL_LIMIT_NOTE, }, ], }; } },
- src/tools/file-search.ts:107-111 (schema)Zod input schema defining parameters for the file-search tool: file_category (file type filter), key (search keyword), page (pagination), page_size (items per page).file_category: z.number().optional().default(-1).describe("文件类型筛选:-1(全部)、0(其他)、1(图片)、2(文档)、3(音乐)、4(视频)"), key: z.string().optional().default("").describe("搜索关键词,当file_category 不为 -1 时,可以为空,否则必填"), page: z.number().optional().default(1).describe("页码,从1开始"), page_size: z.number().optional().default(20).describe("每页显示的条目数,默认20条,最大100条"), },
- src/tools/file-search.ts:102-200 (registration)registerFileSearchTool function that registers the 'file-search' tool on the MCP server using server.tool(), including name, description, schema, and handler.export function registerFileSearchTool(server: McpServer) { server.tool( "file-search", "在云盘中根据关键词搜索文件和文件夹,支持按文件类型筛选和分页查询。返回符合条件的文件详细信息。", { file_category: z.number().optional().default(-1).describe("文件类型筛选:-1(全部)、0(其他)、1(图片)、2(文档)、3(音乐)、4(视频)"), key: z.string().optional().default("").describe("搜索关键词,当file_category 不为 -1 时,可以为空,否则必填"), page: z.number().optional().default(1).describe("页码,从1开始"), page_size: z.number().optional().default(20).describe("每页显示的条目数,默认20条,最大100条"), }, async ({ file_category, key, page, page_size }, mcpReq: any) => { const httpContext = gethttpContext(mcpReq, server); // 使用transport中的authInfo const transportAuthInfo = httpContext.authInfo; try { let authInfo: AuthInfo; // 参数验证 if (!key && file_category === -1) { throw new Error("必须提供搜索关键词(key)或指定文件类型(file_category)"); } const extraParams: Record<string|number, string|number> = { file_category, key, page: page || 1, page_size: page_size || 20, } try { // 传入方法名和路径等参数 authInfo = await getAuthInfo({ method: 'File.searchList', extraParams: extraParams }, transportAuthInfo); authInfo.request_url = getConfig(transportAuthInfo?.ecsEnv).request_url } catch (authError) { throw new Error("获取鉴权信息失败,请提供有效的API_KEY"); } // 调用API搜索文件 const apiResponse = await searchFiles(authInfo, extraParams); // 检查API响应是否成功 if (apiResponse && apiResponse.errno === 0) { const files = (apiResponse.data && apiResponse.data.node_list) || []; if (files.length === 0) { return { content: [ { type: "text", text: "没有找到符合条件的文件", }, ], }; } // 统计文件夹和文件数量 const dirCount = files.filter((file: YunPanFile) => file.type === "1").length; const fileCount = files.length - dirCount; // 格式化结果 const formattedFiles = files.map(formatFileInfo); const filesText = `云盘文件搜索结果 (关键词: ${key})\n共 ${files.length} 项 (${dirCount} 个文件夹, ${fileCount} 个文件)\n\n${formattedFiles.join("\n")}`; return { content: [ { type: "text", text: filesText, }, { type: "text", text: TOOL_LIMIT_NOTE, }, ], }; } else { throw new Error(apiResponse?.errmsg || "API请求失败"); } } catch (error: any) { return { content: [ { type: "text", text: `搜索文件时发生错误: ${error.message}`, }, { type: "text", text: TOOL_LIMIT_NOTE, }, ], }; } }, ); }
- src/tools/file-search.ts:42-100 (helper)searchFiles helper function that constructs and sends HTTP POST request to the cloud disk API's File.searchList endpoint with authentication and search parameters.async function searchFiles(authInfo: AuthInfo, extraParams: Record<string|number, string|number>): Promise<any> { try { const url = new URL(authInfo.request_url || ''); // 构建请求头 const headers = { 'Access-Token': authInfo.access_token || '', 'Content-Type': 'application/x-www-form-urlencoded' }; // 构建基本请求参数 const baseParams: Record<string, string> = { 'method': 'File.searchList', 'access_token': authInfo.access_token || '', 'qid': authInfo.qid || '', 'sign': authInfo.sign || '' }; // 添加所有基本参数到URL Object.entries(baseParams).forEach(([key, value]) => { url.searchParams.append(key, String(value)); }); // 构建表单数据 const body = new URLSearchParams(); // 添加额外参数到表单数据 for (const [key, value] of Object.entries(extraParams)) { // 去除 access_token,因为已经在URL中添加 if (key !== 'access_token') { body.append(String(key), String(value)); } } const response = await fetch(url.toString(), { method: 'POST', headers: headers, body }); if (!response.ok) { throw new Error(`API 请求失败,状态码: ${response.status}`); } // 先获取原始响应文本 const responseText = await response.text(); try { // 尝试解析为JSON const data = JSON.parse(responseText); return data; } catch (jsonError) { throw new Error(`无法解析API响应: ${responseText.substring(0, 100)}...`); } } catch (error) { console.error('搜索文件失败:', error); throw error; } }
- src/tools/index.ts:21-21 (registration)Call to registerFileSearchTool(server) within registerAllTools to include the file-search tool in the server's toolset.registerFileSearchTool(server);