search
Execute Elasticsearch searches by specifying an index and a query DSL object. Supports size, sort, and filters. Highlights are automatically included in results.
Instructions
Perform an Elasticsearch search with the provided query DSL. Highlights are always enabled.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| index | Yes | Name of the Elasticsearch index to search | |
| queryBody | Yes | Complete Elasticsearch query DSL object that can include query, size, from, sort, etc. |
Implementation Reference
- src/tools/search.ts:3-94 (handler)The main handler function for the 'search' tool. It takes an Elasticsearch client, index name, and query DSL body, fetches index mappings to determine text fields, enables search highlighting, executes the search, formats the results as MCP text content blocks, and returns them with metadata about total results.
export async function search( esClient: Client, index: string, queryBody: Record<string, any> ) { try { const mappingResponse = await esClient.indices.getMapping({ index, }); const indexMappings = mappingResponse[index]?.mappings || {}; const searchRequest: estypes.SearchRequest = { index, ...queryBody, }; // enable highlight if (indexMappings.properties) { const textFields: Record<string, estypes.SearchHighlightField> = {}; for (const [fieldName, fieldData] of Object.entries( indexMappings.properties )) { if (fieldData.type === "text" || "dense_vector" in fieldData) { textFields[fieldName] = {}; } } searchRequest.highlight = { fields: textFields, pre_tags: ["<em>"], post_tags: ["</em>"], }; } const result = await esClient.search(searchRequest); const from = queryBody.from || 0; const contentFragments = result.hits.hits.map((hit) => { const highlightedFields = hit.highlight || {}; const sourceData = hit._source || {}; let content = ""; for (const [field, highlights] of Object.entries(highlightedFields)) { if (highlights && highlights.length > 0) { content += `${field} (Highlight): ${highlights.join(" ... ")}\n`; } } for (const [field, value] of Object.entries(sourceData)) { if (!(field in highlightedFields)) { content += `${field}: ${JSON.stringify(value)}\n`; } } return { type: "text" as const, text: content.trim(), }; }); const metadataFragment = { type: "text" as const, text: `Total search results: ${ typeof result.hits.total === "number" ? result.hits.total : result.hits.total?.value || 0 }, Displaying ${result.hits.hits.length} records starting from position ${from}`, }; return { content: [metadataFragment, ...contentFragments], }; } catch (error) { console.error( `Search failed: ${error instanceof Error ? error.message : String(error)}` ); return { content: [ { type: "text" as const, text: `Error: ${ error instanceof Error ? error.message : String(error) }`, }, ], }; } } - src/server.ts:71-104 (registration)Registration of the 'search' tool on the McpServer. Defines the tool name as 'search', its description, the input schema (index string and queryBody record with Zod refinement), and the handler that delegates to the search function.
// search with query DSL server.tool( "search", "Perform an Elasticsearch search with the provided query DSL. Highlights are always enabled.", { index: z .string() .trim() .min(1, "Index name is required") .describe("Name of the Elasticsearch index to search"), queryBody: z .record(z.any()) .refine( (val) => { try { JSON.parse(JSON.stringify(val)); return true; } catch (e) { return false; } }, { message: "queryBody must be a valid Elasticsearch query DSL object", } ) .describe( "Complete Elasticsearch query DSL object that can include query, size, from, sort, etc." ), }, async ({ index, queryBody }) => { return await search(esClient, index, queryBody); } ); - src/server.ts:76-99 (schema)Input schema for the 'search' tool. 'index' is a required string. 'queryBody' is a required record of any type, validated to be a valid JSON-serializable Elasticsearch query DSL object.
index: z .string() .trim() .min(1, "Index name is required") .describe("Name of the Elasticsearch index to search"), queryBody: z .record(z.any()) .refine( (val) => { try { JSON.parse(JSON.stringify(val)); return true; } catch (e) { return false; } }, { message: "queryBody must be a valid Elasticsearch query DSL object", } ) .describe( "Complete Elasticsearch query DSL object that can include query, size, from, sort, etc." ), - src/server.ts:15-27 (registration)Re-export of the search function from the server module, making it available as part of the public API.
export { listIndices, getMappings, search, getClusterHealth, createIndex, createMapping, bulk, reindex, createIndexTemplate, getIndexTemplate, deleteIndexTemplate };