search_code
Find exact code strings in Mozilla repositories using literal matching. Search for specific terms, function names, or code snippets across Mozilla codebases.
Instructions
Search for code in Mozilla repositories using Searchfox. IMPORTANT: Uses exact string matching only - no search operators, no OR logic, no phrase matching with quotes. Multiple words are treated as a single literal string.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query using exact literal string matching. CRITICAL: Do NOT use multiple words expecting OR logic (e.g., 'profiler raptor' won't find files containing either word separately). Do NOT use quotes around terms (e.g., '"profiler" "raptor"' searches for literal quotes). Use single specific terms, function names, or exact code snippets. For broader searches, use separate queries or enable regexp mode. | |
| repo | No | Repository to search in (e.g., mozilla-central, comm-central) | mozilla-central |
| path | No | Filter results by file path using glob patterns. Path matching uses substring matching - a path matches even if only part of it matches the glob. Use ^ and $ operators to match beginning or end of path (e.g., '^tools/profiler' to match paths starting with tools/profiler, 'profiler$' to match paths ending with profiler). | |
| case | No | Enable case sensitive search (default: case insensitive) | |
| regexp | No | Treat query as regular expression pattern | |
| limit | No | Maximum number of results to return |
Implementation Reference
- src/index.ts:206-334 (handler)Implements the 'search_code' tool logic: builds Searchfox search URL from options, fetches JSON response, parses complex nested structure of results (handling sections like 'normal', 'test', categories), extracts matches with path/line/snippet/context/bounds, applies limit, formats as JSON text response.private async searchCode(options: SearchOptions) { try { const searchParams = new URLSearchParams({ q: options.query, case: options.case ? "true" : "false", regexp: options.regexp ? "true" : "false", }); if (options.path) { searchParams.append("path", options.path); } const url = `${this.baseUrl}/${options.repo || "mozilla-central"}/search?${searchParams}`; const response = await fetch(url, { headers: { Accept: "application/json", }, }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } // Searchfox returns JSON with a specific structure const data = (await response.json()) as SearchfoxResponse; const results: SearchResult[] = []; // Process all sections dynamically (normal, test, thirdparty, generated, etc.) for (const [sectionKey, sectionValue] of Object.entries(data)) { // Skip metadata fields if (sectionKey.startsWith("*")) { continue; } // Handle sections that contain categorized results (like "normal", "test", "thirdparty") if (typeof sectionValue === "object" && sectionValue !== null) { // Check if it's a direct array (like "Textual Occurrences") if (Array.isArray(sectionValue)) { const files = sectionValue as SearchfoxFile[]; for (const file of files) { if (file.lines && Array.isArray(file.lines)) { for (const line of file.lines) { if (options.limit && results.length >= options.limit) { break; } results.push({ path: file.path, line: line.lno, column: line.bounds?.[0] || 0, snippet: line.line, context: sectionKey, contextsym: line.contextsym, peekRange: line.peekRange, upsearch: line.upsearch, bounds: line.bounds, }); } } } } else { // Handle sections with categorized results (Record<string, Array<...>>) const categoryMap = sectionValue as Record<string, SearchfoxFile[]>; for (const [category, categoryResults] of Object.entries( categoryMap )) { if (Array.isArray(categoryResults)) { for (const file of categoryResults) { if (file.lines && Array.isArray(file.lines)) { for (const line of file.lines) { if (options.limit && results.length >= options.limit) { break; } results.push({ path: file.path, line: line.lno, column: line.bounds?.[0] || 0, snippet: line.line, context: line.context || `${sectionKey}: ${category}`, contextsym: line.contextsym, peekRange: line.peekRange, upsearch: line.upsearch, bounds: line.bounds, }); } } } } } } } // Break if we've reached the limit if (options.limit && results.length >= options.limit) { break; } } return { content: [ { type: "text", text: JSON.stringify( { query: options.query, repo: options.repo || "mozilla-central", count: results.length, title: data["*title*"], timedout: data["*timedout*"], limits: data["*limits*"], total_available: data["*timedout*"] ? "Search timed out - more results may be available" : undefined, results, }, null, 2 ), }, ], }; } catch (error) { throw new McpError( ErrorCode.InternalError, `Search failed: ${error instanceof Error ? error.message : String(error)}` ); } }
- src/index.ts:81-123 (registration)Registers the 'search_code' tool in the MCP server's ListTools handler, defining name, detailed description with usage notes, and comprehensive inputSchema with properties for query (required), repo, path (glob), case/regexp flags, limit.{ name: "search_code", description: "Search for code in Mozilla repositories using Searchfox. IMPORTANT: Uses exact string matching only - no search operators, no OR logic, no phrase matching with quotes. Multiple words are treated as a single literal string.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query using exact literal string matching. CRITICAL: Do NOT use multiple words expecting OR logic (e.g., 'profiler raptor' won't find files containing either word separately). Do NOT use quotes around terms (e.g., '\"profiler\" \"raptor\"' searches for literal quotes). Use single specific terms, function names, or exact code snippets. For broader searches, use separate queries or enable regexp mode.", }, repo: { type: "string", description: "Repository to search in (e.g., mozilla-central, comm-central)", default: "mozilla-central", }, path: { type: "string", description: "Filter results by file path using glob patterns. Path matching uses substring matching - a path matches even if only part of it matches the glob. Use ^ and $ operators to match beginning or end of path (e.g., '^tools/profiler' to match paths starting with tools/profiler, 'profiler$' to match paths ending with profiler).", }, case: { type: "boolean", description: "Enable case sensitive search (default: case insensitive)", default: false, }, regexp: { type: "boolean", description: "Treat query as regular expression pattern", default: false, }, limit: { type: "number", description: "Maximum number of results to return", default: 50, }, }, required: ["query"], }, },
- src/index.ts:22-29 (schema)TypeScript interface defining the input options for the searchCode handler, matching the tool's inputSchema properties.interface SearchOptions { query: string; repo?: string; path?: string; case?: boolean; regexp?: boolean; limit?: number; }
- src/index.ts:155-182 (handler)Dispatch handler in CallToolRequestSchema: validates 'search_code' arguments, constructs SearchOptions with defaults, invokes the searchCode method.case "search_code": { const searchArgs = args as Record<string, unknown>; if (!searchArgs.query || typeof searchArgs.query !== "string") { throw new McpError( ErrorCode.InvalidParams, "Query parameter is required and must be a string" ); } const options: SearchOptions = { query: searchArgs.query, repo: typeof searchArgs.repo === "string" ? searchArgs.repo : "mozilla-central", path: typeof searchArgs.path === "string" ? searchArgs.path : undefined, case: typeof searchArgs.case === "boolean" ? searchArgs.case : false, regexp: typeof searchArgs.regexp === "boolean" ? searchArgs.regexp : false, limit: typeof searchArgs.limit === "number" ? searchArgs.limit : 50, }; return await this.searchCode(options); }
- src/index.ts:10-20 (schema)TypeScript interface for formatted search results output by the handler.interface SearchResult { path: string; line: number; column: number; snippet: string; context?: string; contextsym?: string; peekRange?: string; upsearch?: string; bounds?: number[]; }