search
Find songs and music files on the Soulseek peer-to-peer network by searching with artist names, song titles, or album queries.
Instructions
Search for songs/files on the Soulseek network. Returns a list of available files matching the query.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query (artist name, song title, album, etc.) | |
| limit | No | Maximum number of results to return (default: 50) |
Implementation Reference
- src/index.ts:128-156 (handler)MCP tool handler for 'search' tool: parses input with searchSchema, calls soulseekClient.search, formats results, and returns formatted text response.
case 'search': { const parsed = searchSchema.parse(args); const results = await soulseekClient.search(parsed.query, parsed.limit); if (results.length === 0) { return { content: [ { type: 'text', text: `No results found for "${parsed.query}".`, }, ], }; } const formatted = results.map((r, i) => formatSearchResult(r, i)).join('\n\n'); // Also return structured data for programmatic use const jsonData = JSON.stringify(results, null, 2); return { content: [ { type: 'text', text: `Found ${results.length} result(s) for "${parsed.query}":\n\n${formatted}\n\n---\nTo download a file, use the download tool with the username and full filename path.`, }, ], }; } - src/index.ts:11-14 (schema)Zod schema for validating 'search' tool input parameters: query (required string), limit (optional number, default 50).
const searchSchema = z.object({ query: z.string().describe('Search query for songs/files'), limit: z.number().optional().default(50).describe('Maximum number of results to return'), }); - src/index.ts:74-91 (registration)Registration of 'search' tool in ListToolsRequestHandler: defines name, description, and inputSchema matching searchSchema.
{ name: 'search', description: 'Search for songs/files on the Soulseek network. Returns a list of available files matching the query.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query (artist name, song title, album, etc.)', }, limit: { type: 'number', description: 'Maximum number of results to return (default: 50)', }, }, required: ['query'], }, }, - src/soulseek-client.ts:67-111 (helper)Core search implementation in SoulseekClientWrapper: performs Soulseek network search, processes results into SearchResult[], sorts by availability and speed, limits results.
async search(query: string, limit: number = 50): Promise<SearchResult[]> { await this.ensureConnected(); if (!this.client) { throw new Error('Client not connected'); } const results: SearchResult[] = []; try { const searchResults = await this.client.search(query, { timeout: 10000, onResult: (result) => { for (const file of result.files) { // Extract attributes const bitrate = file.attrs.get(0) ?? null; // FileAttribute.Bitrate = 0 const duration = file.attrs.get(1) ?? null; // FileAttribute.Duration = 1 results.push({ username: result.username, filename: file.filename, size: Number(file.size), bitrate, duration, slotsFree: result.slotsFree, speed: result.avgSpeed, queueLength: result.queueLength, }); } }, }); // Sort by: slots free first, then by speed descending results.sort((a, b) => { if (a.slotsFree !== b.slotsFree) { return a.slotsFree ? -1 : 1; } return b.speed - a.speed; }); return results.slice(0, limit); } catch (error) { throw new Error(`Search failed: ${error instanceof Error ? error.message : String(error)}`); } } - src/soulseek-client.ts:5-14 (schema)TypeScript interface defining the structure of search results returned by the search tool.
export interface SearchResult { username: string; filename: string; size: number; bitrate: number | null; duration: number | null; slotsFree: boolean; speed: number; queueLength: number; }