MCP Compass

MIT License
10
7
  • Apple
  • Linux
  • src
import axios, { AxiosInstance } from 'axios'; import { KagiConfig, KagiError, SearchParams, SearchResponse, SummarizeParams, SummarizationResponse, FastGPTParams, FastGPTResponse, EnrichParams, EnrichResponse } from './types.js'; /** * Client for interacting with the Kagi Search API * @example * ```typescript * const kagi = new KagiAPI({ apiKey: 'your-api-key' }); * const results = await kagi.search({ q: 'typescript' }); * ``` */ export class KagiAPI { private readonly client: AxiosInstance; private static readonly DEFAULT_BASE_URL = 'https://kagi.com/api/v0'; private static readonly DEFAULT_TIMEOUT = 30000; /** * Creates a new Kagi API client * @param config - Configuration options * @throws {Error} When API key is missing */ constructor(config: KagiConfig) { if (!config.apiKey) { throw new Error('API key is required'); } this.client = axios.create({ baseURL: config.baseURL || KagiAPI.DEFAULT_BASE_URL, timeout: config.timeout || KagiAPI.DEFAULT_TIMEOUT, headers: { 'Authorization': `Bot ${config.apiKey}`, 'Content-Type': 'application/json' } }); // Add response interceptor for error handling this.client.interceptors.response.use( response => response, error => { throw new KagiError( error.response?.data?.message || error.message, error.response?.status, error.response?.data ); } ); } /** * Perform a web search * @param params - Search parameters * @param params.q - Search query * @param params.limit - Maximum number of results (default: 10) * @returns Promise resolving to search results * @throws {KagiError} On API errors * @example * ```typescript * const results = await kagi.search({ * q: 'typescript tutorial', * limit: 5 * }); * ``` */ async search(params: SearchParams): Promise<SearchResponse> { const response = await this.client.get<SearchResponse>('/search', { params: { q: params.q, limit: params.limit || 10 } }); return response.data; } /** * Generate a summary from a URL or text * @param params - Summarization parameters * @returns Promise resolving to summary response * @throws {Error} When neither url nor text is provided, or both are provided * @throws {KagiError} On API errors * @example * ```typescript * const summary = await kagi.summarize({ * url: 'https://example.com', * engine: 'cecil' * }); * ``` */ async summarize(params: SummarizeParams): Promise<SummarizationResponse> { if (!params.url && !params.text) { throw new Error('Either url or text parameter is required'); } if (params.url && params.text) { throw new Error('Cannot provide both url and text parameters'); } const response = await this.client.get<SummarizationResponse>('/summarize', { params: { ...params, cache: params.cache !== undefined ? String(params.cache) : undefined } }); return response.data; } /** * Get a FastGPT response * @param params - FastGPT parameters * @returns Promise resolving to FastGPT response * @throws {KagiError} On API errors * @example * ```typescript * const result = await kagi.fastgpt({ * query: 'Explain quantum computing' * }); * ``` */ async fastgpt(params: FastGPTParams): Promise<FastGPTResponse> { const response = await this.client.post<FastGPTResponse>('/fastgpt', { query: params.query, cache: params.cache !== undefined ? String(params.cache) : undefined }); return response.data; } /** * Get enriched news results * @param params - News enrichment parameters * @returns Promise resolving to enriched news response * @throws {KagiError} On API errors * @example * ```typescript * const news = await kagi.enrich({ * q: 'artificial intelligence' * }); * ``` */ async enrich(params: EnrichParams): Promise<EnrichResponse> { const response = await this.client.get<EnrichResponse>('/enrich/news', { params: { q: params.q } }); return response.data; } /** * Test API connectivity and credentials * @returns Promise resolving to boolean indicating success * @example * ```typescript * const isConnected = await kagi.testConnection(); * console.log(isConnected ? 'Connected!' : 'Connection failed'); * ``` */ async testConnection(): Promise<boolean> { try { // Perform a minimal search to test connectivity await this.search({ q: 'test', limit: 1 }); return true; } catch (error) { return false; } } }