list_sources
Retrieve all indexed documentation sources with URLs, titles, and update times to verify available content for searching.
Instructions
List all documentation sources currently stored in the system. Returns a comprehensive list of all indexed documentation including source URLs, titles, and last update times. Use this to understand what documentation is available for searching or to verify if specific sources have been indexed.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/handlers/list-sources.ts:75-153 (handler)The handle() method implementing the core logic of the list_sources tool: paginates Qdrant scroll on 'documentation' collection, filters payloads for title/url, groups sources by domain/subdomain using helper methods, formats into structured text list, handles auth/connection errors specifically.async handle(): Promise<McpToolResponse> { try { await this.apiClient.initCollection(COLLECTION_NAME); const pageSize = 100; let offset = null; const sources: Source[] = []; while (true) { const scroll = await this.apiClient.qdrantClient.scroll(COLLECTION_NAME, { with_payload: true, with_vector: false, limit: pageSize, offset, }); if (scroll.points.length === 0) break; for (const point of scroll.points) { if (point.payload && typeof point.payload === 'object' && 'url' in point.payload && 'title' in point.payload) { const payload = point.payload as any; sources.push({ title: payload.title, url: payload.url }); } } if (scroll.points.length < pageSize) break; offset = scroll.points[scroll.points.length - 1].id; } if (sources.length === 0) { return { content: [ { type: 'text', text: 'No documentation sources found.', }, ], }; } const grouped = this.groupSourcesByDomainAndSubdomain(sources); const formattedOutput = this.formatGroupedSources(grouped); return { content: [ { type: 'text', text: formattedOutput, }, ], }; } catch (error) { if (error instanceof Error) { if (error.message.includes('unauthorized')) { throw new McpError( ErrorCode.InvalidRequest, 'Failed to authenticate with Qdrant cloud while listing sources' ); } else if (error.message.includes('ECONNREFUSED') || error.message.includes('ETIMEDOUT')) { throw new McpError( ErrorCode.InternalError, 'Connection to Qdrant cloud failed while listing sources' ); } } return { content: [ { type: 'text', text: `Failed to list sources: ${error}`, }, ], isError: true, }; } }
- src/handler-registry.ts:70-76 (schema)Hardcoded ToolDefinition schema for the list_sources tool in the ListToolsRequestHandler response, including name, description, and empty input schema.name: 'list_sources', description: 'List all documentation sources currently stored in the system. Returns a comprehensive list of all indexed documentation including source URLs, titles, and last update times. Use this to understand what documentation is available for searching or to verify if specific sources have been indexed.', inputSchema: { type: 'object', properties: {}, }, } as ToolDefinition,
- src/handler-registry.ts:36-45 (registration)setupHandlers() method registers all tool handlers in a Map, including 'list_sources' -> new ListSourcesHandler(server, apiClient).private setupHandlers() { this.handlers.set('add_documentation', new AddDocumentationHandler(this.server, this.apiClient)); this.handlers.set('search_documentation', new SearchDocumentationHandler(this.server, this.apiClient)); this.handlers.set('list_sources', new ListSourcesHandler(this.server, this.apiClient)); this.handlers.set('remove_documentation', new RemoveDocumentationHandler(this.server, this.apiClient)); this.handlers.set('extract_urls', new ExtractUrlsHandler(this.server, this.apiClient)); this.handlers.set('list_queue', new ListQueueHandler(this.server, this.apiClient)); this.handlers.set('run_queue', new RunQueueHandler(this.server, this.apiClient)); this.handlers.set('clear_queue', new ClearQueueHandler(this.server, this.apiClient)); }
- src/handlers/list-sources.ts:19-42 (helper)Helper method to group sources by domain and first path segment (subdomain).private groupSourcesByDomainAndSubdomain(sources: Source[]): GroupedSources { const grouped: GroupedSources = {}; for (const source of sources) { try { const url = new URL(source.url); const domain = url.hostname; const pathParts = url.pathname.split('/').filter(p => p); const subdomain = pathParts[0] || '/'; if (!grouped[domain]) { grouped[domain] = {}; } if (!grouped[domain][subdomain]) { grouped[domain][subdomain] = []; } grouped[domain][subdomain].push(source); } catch (error) { console.error(`Invalid URL: ${source.url}`); } } return grouped; }
- src/handlers/list-sources.ts:44-73 (helper)Helper method to format grouped sources into a numbered list: domains numbered, sources under each as domain.N. title (url), deduplicated by url, sorted by title.private formatGroupedSources(grouped: GroupedSources): string { const output: string[] = []; let domainCounter = 1; for (const [domain, subdomains] of Object.entries(grouped)) { output.push(`${domainCounter}. ${domain}`); // Create a Set of unique URL+title combinations const uniqueSources = new Map<string, Source>(); for (const sources of Object.values(subdomains)) { for (const source of sources) { uniqueSources.set(source.url, source); } } // Convert to array and sort const sortedSources = Array.from(uniqueSources.values()) .sort((a, b) => a.title.localeCompare(b.title)); // Use letters for subdomain entries sortedSources.forEach((source, index) => { output.push(`${domainCounter}.${index + 1}. ${source.title} (${source.url})`); }); output.push(''); // Add blank line between domains domainCounter++; } return output.join('\n'); }