Skip to content

Commit a290fe2

Browse files
committed
Extract MCP::Client pagination loop into fetch_all_pages
`#tools`, `#resources`, `#resource_templates`, and `#prompts` each repeated the same loop to follow `next_cursor` and collect every page, differing only in the `list_*` method called and the items field read from each page. Move that loop into a single private `fetch_all_pages` helper so the four methods are one-liners and the cursor-cycle guard lives in one place. Behavior is unchanged; the existing `MCP::Client` list tests cover it.
1 parent ac07f8f commit a290fe2

1 file changed

Lines changed: 25 additions & 60 deletions

File tree

lib/mcp/client.rb

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -146,21 +146,7 @@ def list_tools(cursor: nil)
146146
# end
147147
def tools
148148
# TODO: consider renaming to `list_all_tools`.
149-
all_tools = []
150-
seen = Set.new
151-
cursor = nil
152-
153-
loop do
154-
page = list_tools(cursor: cursor)
155-
all_tools.concat(page.tools)
156-
next_cursor = page.next_cursor
157-
break if next_cursor.nil? || seen.include?(next_cursor)
158-
159-
seen << next_cursor
160-
cursor = next_cursor
161-
end
162-
163-
all_tools
149+
fetch_all_pages { |cursor| list_tools(cursor: cursor) }.flat_map(&:tools)
164150
end
165151

166152
# Returns a single page of resources from the server.
@@ -189,21 +175,7 @@ def list_resources(cursor: nil)
189175
# @return [Array<Hash>] An array of available resources.
190176
def resources
191177
# TODO: consider renaming to `list_all_resources`.
192-
all_resources = []
193-
seen = Set.new
194-
cursor = nil
195-
196-
loop do
197-
page = list_resources(cursor: cursor)
198-
all_resources.concat(page.resources)
199-
next_cursor = page.next_cursor
200-
break if next_cursor.nil? || seen.include?(next_cursor)
201-
202-
seen << next_cursor
203-
cursor = next_cursor
204-
end
205-
206-
all_resources
178+
fetch_all_pages { |cursor| list_resources(cursor: cursor) }.flat_map(&:resources)
207179
end
208180

209181
# Returns a single page of resource templates from the server.
@@ -232,21 +204,7 @@ def list_resource_templates(cursor: nil)
232204
# @return [Array<Hash>] An array of available resource templates.
233205
def resource_templates
234206
# TODO: consider renaming to `list_all_resource_templates`.
235-
all_templates = []
236-
seen = Set.new
237-
cursor = nil
238-
239-
loop do
240-
page = list_resource_templates(cursor: cursor)
241-
all_templates.concat(page.resource_templates)
242-
next_cursor = page.next_cursor
243-
break if next_cursor.nil? || seen.include?(next_cursor)
244-
245-
seen << next_cursor
246-
cursor = next_cursor
247-
end
248-
249-
all_templates
207+
fetch_all_pages { |cursor| list_resource_templates(cursor: cursor) }.flat_map(&:resource_templates)
250208
end
251209

252210
# Returns a single page of prompts from the server.
@@ -275,21 +233,7 @@ def list_prompts(cursor: nil)
275233
# @return [Array<Hash>] An array of available prompts.
276234
def prompts
277235
# TODO: consider renaming to `list_all_prompts`.
278-
all_prompts = []
279-
seen = Set.new
280-
cursor = nil
281-
282-
loop do
283-
page = list_prompts(cursor: cursor)
284-
all_prompts.concat(page.prompts)
285-
next_cursor = page.next_cursor
286-
break if next_cursor.nil? || seen.include?(next_cursor)
287-
288-
seen << next_cursor
289-
cursor = next_cursor
290-
end
291-
292-
all_prompts
236+
fetch_all_pages { |cursor| list_prompts(cursor: cursor) }.flat_map(&:prompts)
293237
end
294238

295239
# Calls a tool via the transport layer and returns the full response from the server.
@@ -380,6 +324,27 @@ def ping
380324

381325
private
382326

327+
# Walks every page of a list endpoint, following `next_cursor`, and returns
328+
# the page results. The `seen` set guards against a server that repeats or
329+
# cycles cursors, so the loop always terminates.
330+
def fetch_all_pages
331+
pages = []
332+
seen = Set.new
333+
cursor = nil
334+
335+
loop do
336+
page = yield(cursor)
337+
pages << page
338+
next_cursor = page.next_cursor
339+
break if next_cursor.nil? || seen.include?(next_cursor)
340+
341+
seen << next_cursor
342+
cursor = next_cursor
343+
end
344+
345+
pages
346+
end
347+
383348
def request(method:, params: nil)
384349
request_body = {
385350
jsonrpc: JsonRpcHandler::Version::V2_0,

0 commit comments

Comments
 (0)