| 16 | }) |
| 17 | |
| 18 | export async function paginate<T, R extends { nextCursor?: string }>( |
| 19 | list: (cursor?: string) => Promise<R>, |
| 20 | items: (result: R) => T[], |
| 21 | ) { |
| 22 | const result: T[] = [] |
| 23 | const cursors = new Set<string>() |
| 24 | let cursor: string | undefined |
| 25 | |
| 26 | for (let page = 0; page < MAX_LIST_PAGES; page++) { |
| 27 | const page = await list(cursor) |
| 28 | result.push(...items(page)) |
| 29 | if (page.nextCursor === undefined) return result |
| 30 | if (cursors.has(page.nextCursor)) throw new Error(`MCP list returned duplicate cursor: ${page.nextCursor}`) |
| 31 | cursors.add(page.nextCursor) |
| 32 | cursor = page.nextCursor |
| 33 | } |
| 34 | |
| 35 | throw new Error(`MCP list exceeded ${MAX_LIST_PAGES} pages`) |
| 36 | } |
| 37 | |
| 38 | export function defs(client: Client, timeout?: number) { |
| 39 | return listTools(client, timeout ?? DEFAULT_TIMEOUT).pipe(Effect.catch(() => Effect.void)) |