file-search
Search and filter files by category or keyword in the 360 AI Cloud Drive. Retrieve detailed file information with pagination support for efficient file management.
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:112-198 (handler)Main execution logic for the file-search tool: 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 blocks.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:107-110 (schema)Input schema using Zod for validating tool parameters: file_category (file type filter), key (search keyword), page, page_size.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 McpServer instance, specifying name, description, input 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/index.ts:21-21 (registration)Calls registerFileSearchTool(server) as part of the registerAllTools function to include the file-search tool.registerFileSearchTool(server);
- src/tools/file-search.ts:42-100 (helper)searchFiles helper function: constructs and sends POST request to the cloud pan API endpoint for searching files, handles response parsing.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; } }