UNPKG

mcp-omnisearch

Version:

MCP server for integrating Omnisearch with LLMs

173 lines (172 loc) 5.5 kB
// Common utility functions for the MCP Omnisearch server import { ErrorType, ProviderError } from './types.js'; const normalize_api_key = (raw) => { // Trim whitespace and strip a single pair of wrapping quotes if present const trimmed = raw.trim(); return trimmed.replace(/^(['"])(.*)\1$/, '$2'); }; export const validate_api_key = (key, provider) => { if (!key) { throw new ProviderError(ErrorType.INVALID_INPUT, `API key not found for ${provider}`, provider); } return normalize_api_key(key); }; /** * Checks if an API key exists and is potentially valid without throwing an error * @param key The API key to check * @param provider The name of the provider (for logging purposes) * @returns boolean indicating if the key exists and is not empty */ export const is_api_key_valid = (key, provider) => { if (!key || key.trim() === '') { console.warn(`API key not found or empty for ${provider}`); return false; } return true; }; export const handle_rate_limit = (provider, reset_time) => { throw new ProviderError(ErrorType.RATE_LIMIT, `Rate limit exceeded for ${provider}${reset_time ? `. Reset at ${reset_time.toISOString()}` : ''}`, provider, { reset_time }); }; export const sanitize_query = (query) => { return query.trim().replace(/[\n\r]+/g, ' '); }; export const create_error_response = (error) => { if (error instanceof ProviderError) { return { error: `${error.provider} error: ${error.message}`, }; } return { error: `Unexpected error: ${error.message}`, }; }; export const merge_search_results = (results, limit) => { const sorted = [...results].sort((a, b) => { const score_a = a.score ?? 0; const score_b = b.score ?? 0; return score_b - score_a; }); return limit ? sorted.slice(0, limit) : sorted; }; export const extract_domain = (url) => { try { const domain = new URL(url).hostname; return domain.startsWith('www.') ? domain.slice(4) : domain; } catch { return ''; } }; export const is_valid_url = (url) => { try { new URL(url); return true; } catch { return false; } }; export const delay = (ms) => { return new Promise((resolve) => setTimeout(resolve, ms)); }; export const retry_with_backoff = async (fn, max_retries = 3, initial_delay = 1000) => { let retries = 0; while (true) { try { return await fn(); } catch (error) { if (retries >= max_retries) { throw error; } const delay_time = initial_delay * Math.pow(2, retries); await delay(delay_time); retries++; } } }; const operator_patterns = { site: /site:([^\s]+)/g, exclude_site: /-site:([^\s]+)/g, filetype: /filetype:([^\s]+)/g, intitle: /intitle:([^\s]+)/g, inurl: /inurl:([^\s]+)/g, before: /before:(\d{4}(?:-\d{2}(?:-\d{2})?)?)/g, after: /after:(\d{4}(?:-\d{2}(?:-\d{2})?)?)/g, exact: /"([^"]+)"/g, boolean: /\b(AND|OR|NOT)\b/g, }; export const parse_search_operators = (query) => { const operators = []; let modified_query = query; // Extract operators Object.entries(operator_patterns).forEach(([type, pattern]) => { modified_query = modified_query.replace(pattern, (match, value) => { operators.push({ type: type, value: value, original_text: match, }); return ''; }); }); // Clean up the base query const base_query = modified_query.replace(/\s+/g, ' ').trim(); return { base_query, operators, }; }; export const apply_search_operators = (parsed_query) => { const params = { query: parsed_query.base_query, }; for (const operator of parsed_query.operators) { switch (operator.type) { case 'site': params.include_domains = [ ...(params.include_domains || []), operator.value, ]; break; case 'exclude_site': params.exclude_domains = [ ...(params.exclude_domains || []), operator.value, ]; break; case 'filetype': params.file_type = operator.value; break; case 'intitle': params.title_filter = operator.value; break; case 'inurl': params.url_filter = operator.value; break; case 'before': params.date_before = operator.value; break; case 'after': params.date_after = operator.value; break; case 'exact': params.exact_phrases = [ ...(params.exact_phrases || []), operator.value, ]; break; case 'boolean': // Handle boolean operators in the query string if (!params.boolean_operators) { params.boolean_operators = []; } params.boolean_operators.push({ type: operator.value, terms: [], }); break; } } return params; };