Class: ModelContextProtocol::Server::Pagination

Inherits:
Object
  • Object
show all
Defined in:
lib/model_context_protocol/server/pagination.rb

Defined Under Namespace

Classes: InvalidCursorError

Constant Summary collapse

DEFAULT_PAGE_SIZE =
100
MAX_PAGE_SIZE =
1000
PaginatedResponse =
Data.define(:items, :next_cursor) do
  def serialized(key)
    result = {key => items}
    result[:nextCursor] = next_cursor if next_cursor
    result
  end
end

Class Method Summary collapse

Class Method Details

.decode_cursor(cursor, validate_ttl: true) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/model_context_protocol/server/pagination.rb', line 44

def decode_cursor(cursor, validate_ttl: true)
  data = JSON.parse(Base64.urlsafe_decode64(cursor))

  if validate_ttl && data["expires_at"] && Time.now.to_i > data["expires_at"]
    raise InvalidCursorError, "Cursor has expired"
  end

  data["offset"]
rescue JSON::ParserError, ArgumentError => e
  raise InvalidCursorError, "Invalid cursor format: #{e.message}"
end

.encode_cursor(offset, total, ttl: nil) ⇒ Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/model_context_protocol/server/pagination.rb', line 33

def encode_cursor(offset, total, ttl: nil)
  data = {
    offset: offset,
    total: total,
    timestamp: Time.now.to_i
  }
  data[:expires_at] = Time.now.to_i + ttl if ttl

  Base64.urlsafe_encode64(JSON.generate(data), padding: false)
end

.extract_pagination_params(params, default_page_size: DEFAULT_PAGE_SIZE, max_page_size: MAX_PAGE_SIZE) ⇒ Object



60
61
62
63
64
65
66
67
68
# File 'lib/model_context_protocol/server/pagination.rb', line 60

def extract_pagination_params(params, default_page_size: DEFAULT_PAGE_SIZE, max_page_size: MAX_PAGE_SIZE)
  page_size = if params["pageSize"]
    [params["pageSize"].to_i, max_page_size].min
  else
    default_page_size
  end

  {cursor: params["cursor"], page_size:}
end

.paginate(items, cursor: nil, page_size: DEFAULT_PAGE_SIZE, cursor_ttl: nil) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/model_context_protocol/server/pagination.rb', line 21

def paginate(items, cursor: nil, page_size: DEFAULT_PAGE_SIZE, cursor_ttl: nil)
  page_size = [page_size, MAX_PAGE_SIZE].min
  offset = cursor ? decode_cursor(cursor) : 0
  page_items = items[offset, page_size] || []
  next_offset = offset + page_items.length
  next_cursor = if next_offset < items.length
    encode_cursor(next_offset, items.length, ttl: cursor_ttl)
  end

  PaginatedResponse[items: page_items, next_cursor: next_cursor]
end

.pagination_requested?(params) ⇒ Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/model_context_protocol/server/pagination.rb', line 56

def pagination_requested?(params)
  params.key?("cursor") || params.key?("pageSize")
end