#!/usr/bin/env -S node --import tsx import fs from 'node:fs' import path from 'node:path' import { MCPRegistryService } from '../src/main/services/mcp-registry-service' type Row = { name: string; stars: number; installs: number } const LOG = process.env.LOG_FILE || path.join(process.cwd(), 'mcp-registry-sort.log') const PAGE_SIZE = Number(process.env.PAGE_SIZE || 50) const PAGES = Number(process.env.PAGES || 3) const CLEAR = process.env.CLEAR === '1' const CALL_TIMEOUT_MS = Number(process.env.CALL_TIMEOUT_MS || 15000) const GLOBAL_TIMEOUT_MS = Number(process.env.GLOBAL_TIMEOUT_MS || 60000) function append(line: string) { try { fs.appendFileSync(LOG, line + '\n') } catch {} console.log(line) } function rows(list: any[]): Row[] { return list.map((s: any) => ({ name: s.name, stars: Number(s.githubStars || 0), installs: Number(s.installCount || 0), })) } function verifyOrder(list: Row[]): { ok: boolean; msg?: string } { for (let i = 1; i < list.length; i++) { const a = list[i - 1] const b = list[i] if (a.stars < b.stars) return { ok: false, msg: `stars out of order: ${a.name}(${a.stars}) < ${b.name}(${b.stars})` } if (a.stars === b.stars && a.installs < b.installs) return { ok: false, msg: `installs tie-break out: ${a.name}(${a.installs}) < ${b.name}(${b.installs})` } } return { ok: true } } async function withTimeout(p: Promise, ms: number, label: string): Promise { let t: NodeJS.Timeout const killer = new Promise((_, rej) => { t = setTimeout(() => rej(new Error(`Timeout: ${label} (${ms}ms)`)), ms) }) try { return await Promise.race([p, killer]) as T } finally { clearTimeout(t!) } } async function main() { fs.writeFileSync(LOG, '') append(`Starting MCP registry sort test: PAGE_SIZE=${PAGE_SIZE} PAGES=${PAGES} CLEAR=${CLEAR} CALL_TIMEOUT_MS=${CALL_TIMEOUT_MS} GLOBAL_TIMEOUT_MS=${GLOBAL_TIMEOUT_MS}`) const svc = MCPRegistryService.getInstance() const globalAbort = setTimeout(() => { append('Global timeout reached, exiting') process.exit(2) }, GLOBAL_TIMEOUT_MS) try { if (CLEAR) { append('Clearing registry cache...') await withTimeout(svc.clearCache(), CALL_TIMEOUT_MS, 'clearCache') } const first = await withTimeout(svc.searchServers({ limit: PAGE_SIZE, offset: 0 }), CALL_TIMEOUT_MS, 'page-1') const top = rows(first.servers) append(`Page 1 received: ${top.length} items (total=${first.total}, hasMore=${first.hasMore})`) top.slice(0, 10).forEach(r => append(` - ${r.name} | ${r.stars}★ | ${r.installs} installs`)) const v1 = verifyOrder(top) if (!v1.ok) { append(`Order check failed on page 1: ${v1.msg}`) process.exit(1) } for (let p = 1; p < PAGES; p++) { const res = await withTimeout(svc.searchServers({ limit: PAGE_SIZE, offset: p * PAGE_SIZE }), CALL_TIMEOUT_MS, `page-${p + 1}`) const list = rows(res.servers) append(`Page ${p + 1} received: ${list.length} items (total=${res.total}, hasMore=${res.hasMore})`) const v = verifyOrder(list) if (!v.ok) { append(`Order check failed on page ${p + 1}: ${v.msg}`) process.exit(1) } } append('✔ Star sorting verified across pages') process.exit(0) } catch (err: any) { append(`Test failed: ${err?.message || err}`) process.exit(1) } finally { clearTimeout(globalAbort) } } main()