@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
565 lines • 81.4 kB
JavaScript
/**
* Search for content in the collection
*/
import { CollectionSeeder } from './CollectionSeeder.js';
import { logger } from '../utils/logger.js';
import { normalizeSearchTerm, validateSearchQuery, isSearchMatch, debugNormalization } from '../utils/searchUtils.js';
import { ErrorHandler } from '../utils/ErrorHandler.js';
import { InvertedIndex } from './InvertedIndex.js';
export class CollectionSearch {
githubClient;
collectionCache;
indexCache;
searchBaseUrl = 'https://api.github.com/search/code';
// Inverted index for fast search
invertedIndex = null;
lastIndexVersion = null;
constructor(githubClient, collectionCache, indexCache) {
this.githubClient = githubClient;
this.collectionCache = collectionCache;
this.indexCache = indexCache;
}
/**
* Enhanced search using collection index with pagination and filtering
* Falls back to API search and cache when index is unavailable
*/
async searchCollectionWithOptions(query, options = {}) {
const startTime = Date.now();
logger.debug(`CollectionSearch.searchCollectionWithOptions called with query: "${query}"`, options);
// Validate search query for security
try {
validateSearchQuery(query, 1000);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error('Search query validation failed:', { query, error: errorMessage });
ErrorHandler.logError('CollectionSearch.searchWithOptions.validateQuery', error, { query });
return this.createEmptySearchResults(query, options);
}
try {
// Try index-based search first
const indexResults = await this.searchFromIndex(query, options);
const searchTime = Date.now() - startTime;
logger.debug(`Index search completed in ${searchTime}ms with ${indexResults.items.length} results`);
return { ...indexResults, searchTime };
}
catch (error) {
logger.debug('Index search failed, falling back to legacy search:', error);
// Fallback to legacy search
const legacyResults = await this.searchCollection(query);
const searchTime = Date.now() - startTime;
// Convert legacy results to new format
return this.convertLegacyResults(legacyResults, query, options, searchTime);
}
}
/**
* Search collection for content matching query
* Falls back to cached data when GitHub API is not available or not authenticated
*/
async searchCollection(query) {
logger.debug(`CollectionSearch.searchCollection called with query: "${query}"`);
// Validate search query for security
try {
validateSearchQuery(query, 1000);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error('Search query validation failed:', { query, error: errorMessage });
ErrorHandler.logError('CollectionSearch.search.validateQuery', error, { query });
return [];
}
try {
// First, try GitHub API search if authenticated
const searchUrl = `${this.searchBaseUrl}?q=${encodeURIComponent(query)}+repo:DollhouseMCP/collection+path:library+extension:md`;
logger.debug(`Attempting GitHub API search with URL: ${searchUrl}`);
const data = await this.githubClient.fetchFromGitHub(searchUrl, false); // Don't require auth for search
if (data.items && Array.isArray(data.items)) {
logger.debug(`Found ${data.items.length} items via GitHub API search`);
// Update cache with fresh data from API
await this.updateCacheFromGitHubItems(data.items);
return data.items;
}
logger.debug('GitHub API search returned no items, falling back to cache');
return [];
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug(`GitHub API search failed: ${errorMessage}. Falling back to cached search.`);
ErrorHandler.logError('CollectionSearch.search.githubApi', error, { query });
// Fallback to cached search
return this.searchFromCache(query);
}
}
/**
* Search cached collection items
*/
async searchFromCache(query) {
logger.debug(`Searching cache for query: "${query}"`);
try {
// Try to load from cache first
const cachedItems = await this.collectionCache.searchCache(query);
if (cachedItems.length > 0) {
logger.debug(`Found ${cachedItems.length} items from cache`);
return this.convertCacheItemsToGitHubFormat(cachedItems);
}
logger.debug('Cache search returned no results, trying seed data');
// If cache is empty or no results, use seed data
const seedItems = this.searchSeedData(query);
if (seedItems.length > 0) {
logger.debug(`Found ${seedItems.length} items from seed data`);
// Save seed data to cache for future use
try {
await this.collectionCache.saveCache(CollectionSeeder.getSeedData());
logger.debug('Saved seed data to cache');
}
catch (cacheError) {
const cacheErrorMessage = cacheError instanceof Error ? cacheError.message : String(cacheError);
logger.debug(`Failed to save seed data to cache: ${cacheErrorMessage}`);
}
return this.convertCacheItemsToGitHubFormat(seedItems);
}
logger.debug('No items found in cache or seed data');
return [];
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug(`Cache search failed: ${errorMessage}`);
ErrorHandler.logError('CollectionSearch.search.cache', error, { query });
// Last resort: search seed data without cache
const seedItems = this.searchSeedData(query);
logger.debug(`Fallback to seed data found ${seedItems.length} items`);
return this.convertCacheItemsToGitHubFormat(seedItems);
}
}
/**
* Search seed data for matching items with fuzzy matching
*/
searchSeedData(query) {
const seedData = CollectionSeeder.getSeedData();
const normDebug = debugNormalization(query);
logger.debug(`Searching seed data - Original: "${normDebug.original}", Normalized: "${normDebug.normalized}", Partial: "${normDebug.partialMatch}"`);
logger.debug(`Searching against ${seedData.length} seed items`);
const matches = seedData.filter(item => {
// Use the improved matching function that tries multiple strategies
const nameMatches = isSearchMatch(query, item.name);
const pathMatches = isSearchMatch(query, item.path);
const isMatch = nameMatches || pathMatches;
if (isMatch) {
logger.debug(`✓ Match found: ${item.name} (${item.path}) matches query "${query}"`);
}
return isMatch;
});
// If no matches found, let's debug what we have
if (matches.length === 0) {
logger.debug('No matches found. Available seed data:');
seedData.slice(0, 10).forEach(item => {
logger.debug(` - ${item.name} (${item.path})`);
});
if (seedData.length > 10) {
logger.debug(` ... and ${seedData.length - 10} more items`);
}
}
logger.debug(`Found ${matches.length} matches in seed data`);
return matches;
}
/**
* Fuzzy matching algorithm for partial string matches
*/
fuzzyMatch(term, target) {
// Simple fuzzy matching: check if all characters of term appear in order in target
if (term.length === 0)
return true;
if (target.length === 0)
return false;
let termIndex = 0;
let targetIndex = 0;
while (termIndex < term.length && targetIndex < target.length) {
if (term[termIndex] === target[targetIndex]) {
termIndex++;
}
targetIndex++;
}
return termIndex === term.length;
}
/**
* Convert cache items to GitHub API format for consistent response structure
*/
convertCacheItemsToGitHubFormat(cacheItems) {
return cacheItems.map(item => ({
name: item.name,
path: item.path,
sha: item.sha,
url: `https://api.github.com/repos/DollhouseMCP/collection/contents/${item.path}`,
html_url: `https://github.com/DollhouseMCP/collection/blob/main/${item.path}`,
repository: {
name: 'collection',
full_name: 'DollhouseMCP/collection'
}
}));
}
/**
* Update cache with fresh data from GitHub API items
*/
async updateCacheFromGitHubItems(githubItems) {
try {
const cacheItems = githubItems.map(item => ({
name: item.name,
path: item.path,
sha: item.sha,
last_modified: new Date().toISOString()
}));
await this.collectionCache.saveCache(cacheItems);
logger.debug(`Updated cache with ${cacheItems.length} items from GitHub API`);
}
catch (error) {
ErrorHandler.logError('CollectionSearch.updateCacheInBackground', error);
// Don't throw - cache update failures shouldn't break functionality
}
}
/**
* Format search results
*/
formatSearchResults(items, query, personaIndicator = '') {
if (items.length === 0) {
return `${personaIndicator}🔍 No content found for query: "${query}"`;
}
const textParts = [`${personaIndicator}🔍 **Search Results for "${query}"** (${items.length} found)\n\n`];
items.forEach((item) => {
// Extract content type from path (library/personas/creative/writer.md -> personas)
const pathParts = item.path.split('/');
const contentType = pathParts[1] || 'content';
const contentIcons = {
'personas': '🎭',
'skills': '🛠️',
'agents': '🤖',
'prompts': '💬',
'templates': '📄',
'tools': '🔧',
'ensembles': '🎼'
};
const icon = contentIcons[contentType] || '📄';
textParts.push(` ${icon} **${item.name.replace('.md', '')}**\n`, ` 📂 Path: ${item.path}\n`, ` 📥 Install: \`install_collection_content "${item.path}"\`\n`, ` 👁️ Details: \`get_collection_content "${item.path}"\`\n\n`);
});
return textParts.join('');
}
/**
* Search from collection index with full featured search and pagination
*/
async searchFromIndex(query, options) {
const index = await this.indexCache.getIndex();
// Build or rebuild inverted index if needed
await this.ensureInvertedIndex(index);
// If inverted index is available, use it for fast search
if (this.invertedIndex && !this.invertedIndex.isEmpty()) {
return this.searchWithInvertedIndex(query, options);
}
// Fallback to linear search if inverted index is not available
return this.searchWithLinearScan(query, options, index);
}
/**
* Ensure inverted index is built and up-to-date
*/
async ensureInvertedIndex(collectionIndex) {
// Check if we need to rebuild the index
const needsRebuild = !this.invertedIndex ||
this.lastIndexVersion !== collectionIndex.version ||
this.invertedIndex.isEmpty();
if (needsRebuild) {
logger.debug('Building inverted index...');
const allEntries = this.flattenIndexEntries(collectionIndex);
this.invertedIndex = new InvertedIndex();
this.invertedIndex.build(allEntries);
this.lastIndexVersion = collectionIndex.version;
const stats = this.invertedIndex.getStats();
logger.debug(`Inverted index built: ${stats.totalTokens} tokens, ${stats.totalEntries} entries, ${stats.buildTimeMs.toFixed(2)}ms`);
}
}
/**
* Search using inverted index (fast O(k) lookup)
*/
searchWithInvertedIndex(query, options) {
if (!this.invertedIndex) {
throw new Error('Inverted index not initialized');
}
// Search the inverted index
const searchResults = this.invertedIndex.search(query);
// Get full entries from results
let matchedEntries = searchResults
.map(result => {
const entry = this.invertedIndex.getEntry(result.entryId);
return entry ? { entry, score: result.score } : null;
})
.filter((item) => item !== null);
// Filter by element type if specified
if (options.elementType) {
matchedEntries = matchedEntries.filter(item => item.entry.type === options.elementType);
}
// Filter by category if specified
if (options.category) {
matchedEntries = matchedEntries.filter(item => item.entry.category === options.category);
}
// Sort by relevance (already sorted by inverted index, but apply sortBy option)
const sortedEntries = this.sortSearchResultsWithScores(matchedEntries, options.sortBy || 'relevance', query);
// Extract just the entries (scores already used for sorting)
const entries = sortedEntries.map(item => item.entry);
// Apply pagination
const page = options.page || 1;
const pageSize = options.pageSize || 25;
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedEntries = entries.slice(startIndex, endIndex);
return {
items: paginatedEntries,
total: entries.length,
page,
pageSize,
hasMore: endIndex < entries.length,
query,
searchTime: 0 // Will be set by caller
};
}
/**
* Fallback to linear search (legacy O(n) scan)
*/
searchWithLinearScan(query, options, index) {
const allEntries = this.flattenIndexEntries(index);
// Filter by element type if specified
let filteredEntries = allEntries;
if (options.elementType) {
filteredEntries = allEntries.filter(entry => entry.type === options.elementType);
}
// Filter by category if specified
if (options.category) {
filteredEntries = filteredEntries.filter(entry => entry.category === options.category);
}
// Search matching
const matchedEntries = this.performIndexSearch(query, filteredEntries);
// Sort results
const sortedEntries = this.sortSearchResults(matchedEntries, options.sortBy || 'relevance', query);
// Apply pagination
const page = options.page || 1;
const pageSize = options.pageSize || 25;
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedEntries = sortedEntries.slice(startIndex, endIndex);
return {
items: paginatedEntries,
total: sortedEntries.length,
page,
pageSize,
hasMore: endIndex < sortedEntries.length,
query,
searchTime: 0 // Will be set by caller
};
}
/**
* Flatten index entries from all categories into a single array
*/
flattenIndexEntries(index) {
const entries = [];
for (const [, typeEntries] of Object.entries(index.index)) {
entries.push(...typeEntries);
}
return entries;
}
/**
* Perform search matching on index entries
*/
performIndexSearch(query, entries) {
return entries.filter(entry => {
// Use existing search utilities for consistency
const nameMatch = isSearchMatch(query, entry.name);
const descMatch = isSearchMatch(query, entry.description);
const pathMatch = isSearchMatch(query, entry.path);
const tagMatch = entry.tags.some(tag => isSearchMatch(query, tag));
return nameMatch || descMatch || pathMatch || tagMatch;
});
}
/**
* Sort search results by relevance, name, or date
*/
sortSearchResults(entries, sortBy, query) {
const sorted = [...entries];
switch (sortBy) {
case 'name':
sorted.sort((a, b) => a.name.localeCompare(b.name));
break;
case 'date':
sorted.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime());
break;
case 'relevance':
default:
// Calculate relevance scores
sorted.sort((a, b) => {
const scoreA = this.calculateRelevanceScore(query, a);
const scoreB = this.calculateRelevanceScore(query, b);
return scoreB - scoreA;
});
break;
}
return sorted;
}
/**
* Sort search results with pre-calculated scores
*/
sortSearchResultsWithScores(entries, sortBy, _query) {
const sorted = [...entries];
switch (sortBy) {
case 'name':
sorted.sort((a, b) => a.entry.name.localeCompare(b.entry.name));
break;
case 'date':
sorted.sort((a, b) => new Date(b.entry.created).getTime() - new Date(a.entry.created).getTime());
break;
case 'relevance':
default:
// Already sorted by score from inverted index, but can re-sort if needed
sorted.sort((a, b) => b.score - a.score);
break;
}
return sorted;
}
/**
* Calculate relevance score for search results
*/
calculateRelevanceScore(query, entry) {
const normalizedQuery = normalizeSearchTerm(query);
let score = 0;
// Exact name match gets highest score
if (normalizeSearchTerm(entry.name).includes(normalizedQuery)) {
score += 100;
}
// Description match
if (normalizeSearchTerm(entry.description).includes(normalizedQuery)) {
score += 50;
}
// Tag matches
const matchingTags = entry.tags.filter(tag => normalizeSearchTerm(tag).includes(normalizedQuery));
score += matchingTags.length * 25;
// Path match (lower priority)
if (normalizeSearchTerm(entry.path).includes(normalizedQuery)) {
score += 10;
}
// Bonus for recent content
const daysSinceCreated = (Date.now() - new Date(entry.created).getTime()) / (1000 * 60 * 60 * 24);
if (daysSinceCreated < 30) {
score += 5;
}
return score;
}
/**
* Convert legacy search results to new SearchResults format
*/
convertLegacyResults(legacyResults, query, options, searchTime) {
// Convert GitHub API format to IndexEntry format
const entries = legacyResults.map(item => ({
path: item.path,
type: this.extractTypeFromPath(item.path),
name: item.name?.replace('.md', '') || 'Unknown',
description: 'No description available',
version: '1.0.0',
author: 'Unknown',
tags: [],
sha: item.sha || '',
category: this.extractCategoryFromPath(item.path),
created: new Date().toISOString(),
license: 'Unknown'
}));
// Apply pagination
const page = options.page || 1;
const pageSize = options.pageSize || 25;
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedEntries = entries.slice(startIndex, endIndex);
return {
items: paginatedEntries,
total: entries.length,
page,
pageSize,
hasMore: endIndex < entries.length,
query,
searchTime
};
}
/**
* Extract element type from file path
*/
extractTypeFromPath(path) {
const parts = path.split('/');
if (parts.length >= 2 && parts[0] === 'library') {
return parts[1];
}
return 'unknown';
}
/**
* Extract category from file path
*/
extractCategoryFromPath(path) {
const parts = path.split('/');
if (parts.length >= 3 && parts[0] === 'library') {
return parts[2];
}
return 'uncategorized';
}
/**
* Create empty search results for error cases
*/
createEmptySearchResults(query, options) {
return {
items: [],
total: 0,
page: options.page || 1,
pageSize: options.pageSize || 25,
hasMore: false,
query,
searchTime: 0
};
}
/**
* Enhanced format for search results with pagination info
*/
formatSearchResultsWithPagination(results, personaIndicator = '') {
if (results.total === 0) {
return `${personaIndicator}🔍 No content found for query: "${results.query}"`;
}
const startItem = (results.page - 1) * results.pageSize + 1;
const endItem = Math.min(results.page * results.pageSize, results.total);
const textParts = [
`${personaIndicator}🔍 **Search Results for "${results.query}"**\n`,
`📊 Showing ${startItem}-${endItem} of ${results.total} results (Page ${results.page})\n`,
`⚡ Search time: ${results.searchTime}ms\n\n`
];
results.items.forEach((item) => {
const contentIcons = {
'personas': '🎭',
'skills': '🛠️',
'agents': '🤖',
'prompts': '💬',
'templates': '📄',
'tools': '🔧',
'ensembles': '🎼',
'memories': '🧠'
};
const icon = contentIcons[item.type] || '📄';
textParts.push(` ${icon} **${item.name}** (${item.type})\n`, ` 📝 ${item.description}\n`, ` 🏷️ Tags: ${item.tags.join(', ')}\n`, ` 📂 Path: ${item.path}\n`, ` 📥 Install: \`install_collection_content "${item.path}"\`\n`, ` 👁️ Details: \`get_collection_content "${item.path}"\`\n\n`);
});
// Add pagination info
if (results.hasMore) {
const nextPage = results.page + 1;
textParts.push(`📄 More results available. Use page ${nextPage} to see next ${results.pageSize} items.\n`);
}
return textParts.join('');
}
/**
* Get cache statistics for debugging
*/
async getCacheStats() {
const indexStats = this.indexCache.getCacheStats();
const cacheStats = await this.collectionCache.getCacheStats();
return {
index: indexStats,
collection: cacheStats
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29sbGVjdGlvblNlYXJjaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsZWN0aW9uL0NvbGxlY3Rpb25TZWFyY2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFLSCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLG1CQUFtQixFQUFFLGFBQWEsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3RILE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUV4RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFbkQsTUFBTSxPQUFPLGdCQUFnQjtJQUNuQixZQUFZLENBQWU7SUFDM0IsZUFBZSxDQUFrQjtJQUNqQyxVQUFVLENBQXVCO0lBQ2pDLGFBQWEsR0FBRyxvQ0FBb0MsQ0FBQztJQUU3RCxpQ0FBaUM7SUFDekIsYUFBYSxHQUF5QixJQUFJLENBQUM7SUFDM0MsZ0JBQWdCLEdBQWtCLElBQUksQ0FBQztJQUUvQyxZQUNFLFlBQTBCLEVBQzFCLGVBQWdDLEVBQ2hDLFVBQWdDO1FBRWhDLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsMkJBQTJCLENBQUMsS0FBYSxFQUFFLFVBQXlCLEVBQUU7UUFDMUUsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQzdCLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0VBQW9FLEtBQUssR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FB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dXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VhcmNoIGZvciBjb250ZW50IGluIHRoZSBjb2xsZWN0aW9uXG4gKi9cblxuaW1wb3J0IHsgR2l0SHViQ2xpZW50IH0gZnJvbSAnLi9HaXRIdWJDbGllbnQuanMnO1xuaW1wb3J0IHsgQ29sbGVjdGlvbkNhY2hlLCBDb2xsZWN0aW9uSXRlbSB9IGZyb20gJy4uL2NhY2hlL0NvbGxlY3Rpb25DYWNoZS5qcyc7XG5pbXBvcnQgeyBDb2xsZWN0aW9uSW5kZXhDYWNoZSB9IGZyb20gJy4uL2NhY2hlL0NvbGxlY3Rpb25JbmRleENhY2hlLmpzJztcbmltcG9ydCB7IENvbGxlY3Rpb25TZWVkZXIgfSBmcm9tICcuL0NvbGxlY3Rpb25TZWVkZXIuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IG5vcm1hbGl6ZVNlYXJjaFRlcm0sIHZhbGlkYXRlU2VhcmNoUXVlcnksIGlzU2VhcmNoTWF0Y2gsIGRlYnVnTm9ybWFsaXphdGlvbiB9IGZyb20gJy4uL3V0aWxzL3NlYXJjaFV0aWxzLmpzJztcbmltcG9ydCB7IEVycm9ySGFuZGxlciB9IGZyb20gJy4uL3V0aWxzL0Vycm9ySGFuZGxlci5qcyc7XG5pbXBvcnQgeyBJbmRleEVudHJ5LCBTZWFyY2hSZXN1bHRzLCBTZWFyY2hPcHRpb25zLCBDb2xsZWN0aW9uSW5kZXggfSBmcm9tICcuLi90eXBlcy9jb2xsZWN0aW9uLmpzJztcbmltcG9ydCB7IEludmVydGVkSW5kZXggfSBmcm9tICcuL0ludmVydGVkSW5kZXguanMnO1xuXG5leHBvcnQgY2xhc3MgQ29sbG