search_data_file
Search and retrieve specific data entries from files in the OSRS MCP Server's data directory. Input a filename and query term to locate relevant information with pagination support for efficient results management.
Instructions
Search any file in the data directory for matching entries.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filename | Yes | The filename to search in the data directory (e.g., 'varptypes.txt') | |
| page | No | Page number for pagination | |
| pageSize | No | Number of results per page | |
| query | Yes | The term to search for in the file |
Input Schema (JSON Schema)
{
"additionalProperties": false,
"properties": {
"filename": {
"description": "The filename to search in the data directory (e.g., 'varptypes.txt')",
"type": "string"
},
"page": {
"default": 1,
"description": "Page number for pagination",
"minimum": 1,
"type": "integer"
},
"pageSize": {
"default": 10,
"description": "Number of results per page",
"maximum": 100,
"minimum": 1,
"type": "integer"
},
"query": {
"description": "The term to search for in the file",
"type": "string"
}
},
"required": [
"filename",
"query"
],
"type": "object"
}
Implementation Reference
- index.ts:408-423 (handler)Handler logic for the 'search_data_file' tool: parses arguments using GenericFileSearchSchema, performs security validation on filename, checks file existence, constructs file path, calls searchFile helper, and returns formatted results.case "search_data_file": const { filename: genericFilename, query: searchQuery, page: genericFilePage = 1, pageSize: genericFilePageSize = 10 } = GenericFileSearchSchema.parse(args); // Security check to prevent directory traversal if (genericFilename.includes('..') || genericFilename.includes('/') || genericFilename.includes('\\')) { throw new Error('Invalid filename'); } if (!fileExists(genericFilename)) { return responseToString({ error: `${genericFilename} not found in data directory` }); } const genericFilePath = path.join(DATA_DIR, genericFilename); const genericFileResults = await searchFile(genericFilePath, searchQuery, genericFilePage, genericFilePageSize); return responseToString(genericFileResults);
- index.ts:55-60 (schema)Zod schema defining the input parameters for the search_data_file tool: filename, query, optional page and pageSize.const GenericFileSearchSchema = z.object({ filename: z.string().describe("The filename to search in the data directory (e.g., 'varptypes.txt')"), query: z.string().describe("The term to search for in the file"), page: z.number().int().min(1).optional().default(1).describe("Page number for pagination"), pageSize: z.number().int().min(1).max(100).optional().default(10).describe("Number of results per page") });
- index.ts:323-327 (registration)Tool registration entry in the list returned by ListToolsRequestSchema handler, including name, description, and input schema reference.{ name: "search_data_file", description: "Search any file in the data directory for matching entries.", inputSchema: convertZodToJsonSchema(GenericFileSearchSchema), },
- index.ts:99-165 (helper)Core search helper function used by search_data_file and other search tools: reads file line-by-line, finds case-insensitive matches (spaces normalized to underscores), paginates results, formats as key-value pairs when possible, returns structured results with pagination info.async function searchFile(filePath: string, searchTerm: string, page: number = 1, pageSize: number = 10): Promise<any> { //replace spaces with underscores searchTerm = searchTerm.replace(" ", "_"); return new Promise((resolve, reject) => { if (!fs.existsSync(filePath)) { reject(new Error(`File not found: ${filePath}`)); return; } const results: {line: string, lineNumber: number}[] = []; const fileStream = fs.createReadStream(filePath); const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity }); let lineNumber = 0; rl.on('line', (line) => { lineNumber++; if (line.toLowerCase().includes(searchTerm.toLowerCase())) { results.push({ line, lineNumber }); } }); rl.on('close', () => { const totalResults = results.length; const totalPages = Math.ceil(totalResults / pageSize); const startIndex = (page - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedResults = results.slice(startIndex, endIndex); // Process the results to extract key-value pairs if possible const formattedResults = paginatedResults.map(result => { // Try to format as key-value pair (common for ID data files) const parts = result.line.split(/\s+/); if (parts.length >= 2) { const id = parts[0]; const value = parts.slice(1).join(' '); return { ...result, id, value, formatted: `${id}\t${value}` }; } return result; }); resolve({ results: formattedResults, pagination: { page, pageSize, totalResults, totalPages, hasNextPage: page < totalPages, hasPreviousPage: page > 1 } }); }); rl.on('error', (err) => { reject(err); }); }); }