search_function
Find DayZ vanilla scripting functions using natural language queries. Describe what you need, like 'copy weapon attachments', and get matching functions.
Instructions
Search for functions in DayZ vanilla scripts by semantic description
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Natural language description of what you need, e.g., "copy weapon attachments" | |
| searchType | No | Search type: semantic (default) for meaning, exact for pattern matching | |
| limit | No | Maximum results (1-20, default 5) |
Implementation Reference
- src/server/DayZMCP.ts:19-23 (schema)Zod validation schema for search_function tool: accepts query (string), searchType (enum: semantic/exact/fuzzy, default semantic), limit (number 1-20, default 5)
const SearchFunctionSchema = z.object({ query: z.string().describe('Search query describing what function you need'), searchType: z.enum(['semantic', 'exact', 'fuzzy']).default('semantic'), limit: z.number().min(1).max(20).default(5) }); - src/server/DayZMCP.ts:82-105 (registration)Tool registration in the MCP ListTools handler: defines 'search_function' with description and JSON Schema input schema
tools: [ { name: 'search_function', description: 'Search for functions in DayZ vanilla scripts by semantic description', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Natural language description of what you need, e.g., "copy weapon attachments"' }, searchType: { type: 'string', enum: ['semantic', 'exact', 'fuzzy'], description: 'Search type: semantic (default) for meaning, exact for pattern matching' }, limit: { type: 'number', description: 'Maximum results (1-20, default 5)' } }, required: ['query'] } }, - src/server/DayZMCP.ts:226-254 (handler)Tool handler logic for 'search_function' case in CallToolRequestSchema switch: parses args via SearchFunctionSchema, dispatches to index.semanticSearch or index.exactSearch based on searchType, returns formatted JSON results with type, name, class, text (truncated 300 chars), and similarity
switch (request.params.name) { case 'search_function': { const args = SearchFunctionSchema.parse(request.params.arguments); let results; if (args.searchType === 'semantic') { results = await this.index.semanticSearch(args.query, args.limit); } else { results = await this.index.exactSearch(args.query); } return { content: [ { type: 'text', text: JSON.stringify({ query: args.query, results: results.map(r => ({ type: r.type, name: r.methodName || r.className || r.enumName, class: r.className, text: r.text.substring(0, 300), similarity: r.similarity })) }, null, 2) } ] }; } - semanticSearch() implementation on FileSystemIndex: tokenizes query, creates embedding, computes BM25/semantic/lexical/symbol/field scores with type weighting, intent boosts, and noise penalties, returns top results by similarity
async semanticSearch(query: string, limit: number = 10): Promise<EmbeddingEntry[]> { if (!this.initialized) await this.initialize(); const queryTokens = this.tokenizeForSearch(query); const expandedQueryTokens = this.expandQueryTokens(queryTokens); const queryUniqueTerms = Array.from(new Set(expandedQueryTokens)); const queryVector = this.createEmbedding(query); const queryLower = query.toLowerCase(); const hasActionIntent = this.hasActionIntent(queryUniqueTerms); const hasRpcIntent = queryUniqueTerms.includes('rpc'); const hasClientIntent = queryUniqueTerms.includes('client'); const hasServerIntent = queryUniqueTerms.includes('server'); const queryTermSet = new Set(queryUniqueTerms); const intermediate = this.embeddings.map(entry => { const bm25Score = this.computeBm25Score(queryUniqueTerms, entry.id); const semanticScore = this.cosineSimilarity(queryVector, entry.embedding); const lexicalScore = this.computeLexicalScore(queryTermSet, entry.text); const symbolScore = this.computeSymbolScore(queryLower, entry); const fieldScore = this.computeFieldScore(queryUniqueTerms, entry.id); const typeWeight = this.computeTypeWeight(entry, hasActionIntent); const intentBoost = this.computeIntentBoost(entry, hasRpcIntent, hasClientIntent, hasServerIntent); const noisePenalty = this.computeNoisePenalty(entry); return { entry, bm25Score, semanticScore, lexicalScore, symbolScore, fieldScore, typeWeight, intentBoost, noisePenalty }; }); const maxBm25 = intermediate.reduce((max, item) => Math.max(max, item.bm25Score), 0); const results = intermediate.map(item => { const normalizedBm25 = maxBm25 > 0 ? item.bm25Score / maxBm25 : 0; const baseScore = normalizedBm25 * 0.4 + item.semanticScore * 0.2 + item.lexicalScore * 0.15 + item.symbolScore * 0.1 + item.fieldScore * 0.15; const weightedScore = baseScore * item.typeWeight + item.intentBoost - item.noisePenalty; return { ...item.entry, similarity: Math.max(0, Math.min(1, weightedScore)) }; }); results.sort((a, b) => (b.similarity || 0) - (a.similarity || 0)); return results.slice(0, limit); } - exactSearch() implementation on FileSystemIndex: tries exact method name match, class name match, qualified method (Class.Method) match, then falls back to regex search over embedding text
async exactSearch(pattern: string): Promise<EmbeddingEntry[]> { if (!this.initialized) await this.initialize(); const lowerPattern = pattern.toLowerCase(); // 1. Exact method name match (fast path) const methodMatches = this.methodNameIndex.get(lowerPattern); if (methodMatches && methodMatches.length > 0) { return methodMatches.map(entry => ({ ...entry, similarity: 1 })); } // 2. Exact class name match const classMatches = this.classNameIndex.get(lowerPattern); if (classMatches && classMatches.length > 0) { return classMatches.map(entry => ({ ...entry, similarity: 1 })); } // 3. Full qualified method search (Class.Method) const dotIndex = lowerPattern.indexOf('.'); if (dotIndex > 0) { const classPart = lowerPattern.substring(0, dotIndex); const methodPart = lowerPattern.substring(dotIndex + 1); const entries = this.classNameIndex.get(classPart); if (entries) { const filtered = entries.filter(e => e.methodName && e.methodName.toLowerCase() === methodPart ); if (filtered.length > 0) { return filtered.map(entry => ({ ...entry, similarity: 1 })); } } } // 4. Fallback to regex search over embeddings text const regex = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'); return this.embeddings .filter(entry => regex.test(entry.text)) .map(entry => ({ ...entry, similarity: 1 })); }