Skip to content

Commit 6ae0022

Browse files
authored
Feat limit search (#27)
* feat(search): restrict search results to top 10 and those within 10 of the top score (remove less relevant items) * chore(release): version bump * feat(searchIndex): add tests for search limit functions
1 parent dbf5e8b commit 6ae0022

File tree

4 files changed

+92
-6
lines changed

4 files changed

+92
-6
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@serverless-dna/powertools-mcp",
3-
"version": "0.5.0",
3+
"version": "0.6.0",
44
"description": "Powertools for AWS Lambda Documentation MCP Server",
55
"main": "dist/bundle.js",
66
"bin": {
@@ -32,7 +32,8 @@
3232
"test:ci": "jest --ci",
3333
"lint:fix": "eslint --fix --config eslint.config.mjs",
3434
"postversion": "pnpm build",
35-
"release": "semantic-release"
35+
"release": "semantic-release",
36+
"mcp:local": "pnpm build && npx -y @modelcontextprotocol/inspector node dist/bundle.js"
3637
},
3738
"keywords": [
3839
"aws",

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const fetchDocSchema = z.object({
3030
const server = new Server(
3131
{
3232
name: "powertools-mcp-server",
33-
version: "0.1.0",
33+
version: "0.6.0",
3434
},
3535
{
3636
capabilities: {

src/searchIndex.spec.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,66 @@ describe('[Search-Index] When testing URL construction', () => {
357357
});
358358
});
359359

360+
describe('[Search-Index] When limiting search results', () => {
361+
it('should limit results to 10 items by default', async () => {
362+
const factory = new SearchIndexFactory();
363+
const index = await factory.getIndex('python');
364+
365+
if (!index?.index || !index?.documents) {
366+
throw new Error('Python index not properly loaded');
367+
}
368+
369+
// Mock the lunr search to return more than 10 results
370+
const originalSearch = index.index.search;
371+
index.index.search = jest.fn().mockImplementation(() => {
372+
// Generate 20 mock results
373+
return Array.from({ length: 20 }, (_, i) => ({
374+
ref: `doc${i}.html`,
375+
score: 100 - i, // Decreasing scores
376+
matchData: {}
377+
}));
378+
});
379+
380+
// Perform the search
381+
const results = searchDocuments(index.index, index.documents, 'common term');
382+
383+
// Verify results are limited to 10
384+
expect(results.length).toBe(10);
385+
386+
// Restore original search function
387+
index.index.search = originalSearch;
388+
});
389+
390+
it('should allow custom limit values', async () => {
391+
const factory = new SearchIndexFactory();
392+
const index = await factory.getIndex('python');
393+
394+
if (!index?.index || !index?.documents) {
395+
throw new Error('Python index not properly loaded');
396+
}
397+
398+
// Mock the lunr search to return more than 5 results
399+
const originalSearch = index.index.search;
400+
index.index.search = jest.fn().mockImplementation(() => {
401+
// Generate 20 mock results
402+
return Array.from({ length: 20 }, (_, i) => ({
403+
ref: `doc${i}.html`,
404+
score: 100 - i, // Decreasing scores
405+
matchData: {}
406+
}));
407+
});
408+
409+
// Perform the search with custom limit of 5
410+
const results = searchDocuments(index.index, index.documents, 'common term', 5);
411+
412+
// Verify results are limited to 5
413+
expect(results.length).toBe(5);
414+
415+
// Restore original search function
416+
index.index.search = originalSearch;
417+
});
418+
});
419+
360420
// Add a final summary after all tests
361421
afterAll(() => {
362422
console.log('\n===== FINAL TEST SUMMARY =====');

src/searchIndex.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,40 @@ export class SearchIndexFactory {
172172
* @param index The lunr index to search
173173
* @param documents The document map for retrieving full documents
174174
* @param query The search query
175-
* @returns Array of search results with scores
175+
* @param limit Maximum number of results to return (default: 10)
176+
* @param scoreThreshold Score threshold below max score (default: 10)
177+
* @returns Array of search results with scores, filtered by relevance and limited to the top results
176178
*/
177-
export function searchDocuments(index: lunr.Index, documents: Map<string, any>, query: string) {
179+
export function searchDocuments(
180+
index: lunr.Index,
181+
documents: Map<string, any>,
182+
query: string,
183+
limit: number = 10,
184+
scoreThreshold: number = 10
185+
) {
178186
try {
179187
// Perform the search
180188
const results = index.search(query);
181189

190+
if (results.length === 0) {
191+
return [];
192+
}
193+
194+
// Find the maximum score
195+
const maxScore = results[0].score;
196+
197+
// Filter results to only include those within the threshold of the max score
198+
const filteredResults = results.filter(result => {
199+
return (maxScore - result.score) <= scoreThreshold;
200+
});
201+
202+
// Apply limit if there are still too many results
203+
const limitedResults = filteredResults.length > limit
204+
? filteredResults.slice(0, limit)
205+
: filteredResults;
206+
182207
// Enhance results with document data
183-
return results.map(result => {
208+
return limitedResults.map(result => {
184209
const doc = documents.get(result.ref);
185210
return {
186211
ref: result.ref,

0 commit comments

Comments
 (0)