Skip to content

Commit d904e07

Browse files
Update GraphQL tools for cursor-based pagination and fix one test
Co-authored-by: SamMorrowDrums <[email protected]>
1 parent a47b0fe commit d904e07

File tree

3 files changed

+76
-89
lines changed

3 files changed

+76
-89
lines changed

pkg/github/actions_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ func Test_ListWorkflows(t *testing.T) {
3030
assert.NotEmpty(t, tool.Description)
3131
assert.Contains(t, tool.InputSchema.Properties, "owner")
3232
assert.Contains(t, tool.InputSchema.Properties, "repo")
33-
assert.Contains(t, tool.InputSchema.Properties, "perPage")
34-
assert.Contains(t, tool.InputSchema.Properties, "page")
33+
assert.Contains(t, tool.InputSchema.Properties, "cursor")
3534
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
3635

3736
tests := []struct {
@@ -122,8 +121,15 @@ func Test_ListWorkflows(t *testing.T) {
122121
}
123122

124123
// Unmarshal and verify the result
124+
var paginatedResponse PaginatedResponse
125+
err = json.Unmarshal([]byte(textContent.Text), &paginatedResponse)
126+
require.NoError(t, err)
127+
128+
// The data field contains the workflows
129+
dataBytes, err := json.Marshal(paginatedResponse.Data)
130+
require.NoError(t, err)
125131
var response github.Workflows
126-
err = json.Unmarshal([]byte(textContent.Text), &response)
132+
err = json.Unmarshal(dataBytes, &response)
127133
require.NoError(t, err)
128134
assert.NotNil(t, response.TotalCount)
129135
assert.Greater(t, *response.TotalCount, 0)

pkg/github/discussions.go

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,16 @@ func ListDiscussions(getGQLClient GetGQLClientFn, t translations.TranslationHelp
174174
return mcp.NewToolResultError(err.Error()), nil
175175
}
176176

177-
// Get pagination parameters and convert to GraphQL format
178-
pagination, err := OptionalCursorPaginationParams(request)
177+
// Get cursor-based pagination parameters
178+
cursorParams, err := GetCursorBasedParams(request)
179179
if err != nil {
180180
return nil, err
181181
}
182-
paginationParams, err := pagination.ToGraphQLParams()
183-
if err != nil {
184-
return nil, err
182+
183+
// For GraphQL, the cursor is the 'after' value
184+
var after *string
185+
if cursorParams.After != "" {
186+
after = &cursorParams.After
185187
}
186188

187189
client, err := getGQLClient(ctx)
@@ -195,13 +197,16 @@ func ListDiscussions(getGQLClient GetGQLClientFn, t translations.TranslationHelp
195197
categoryID = &id
196198
}
197199

200+
// Use fixed page size of 10 for cursor-based pagination
201+
first := int32(cursorParams.PerPage)
202+
198203
vars := map[string]interface{}{
199204
"owner": githubv4.String(owner),
200205
"repo": githubv4.String(repo),
201-
"first": githubv4.Int(*paginationParams.First),
206+
"first": githubv4.Int(first),
202207
}
203-
if paginationParams.After != nil {
204-
vars["after"] = githubv4.String(*paginationParams.After)
208+
if after != nil {
209+
vars["after"] = githubv4.String(*after)
205210
} else {
206211
vars["after"] = (*githubv4.String)(nil)
207212
}
@@ -237,22 +242,20 @@ func ListDiscussions(getGQLClient GetGQLClientFn, t translations.TranslationHelp
237242
}
238243

239244
// Create response with pagination info
245+
hasNextPage := bool(pageInfo.HasNextPage)
246+
var nextCursor string
247+
if hasNextPage {
248+
nextCursor = string(pageInfo.EndCursor)
249+
}
250+
240251
response := map[string]interface{}{
241252
"discussions": discussions,
242-
"pageInfo": map[string]interface{}{
243-
"hasNextPage": pageInfo.HasNextPage,
244-
"hasPreviousPage": pageInfo.HasPreviousPage,
245-
"startCursor": string(pageInfo.StartCursor),
246-
"endCursor": string(pageInfo.EndCursor),
247-
},
248-
"totalCount": totalCount,
253+
"totalCount": totalCount,
249254
}
250255

251-
out, err := json.Marshal(response)
252-
if err != nil {
253-
return nil, fmt.Errorf("failed to marshal discussions: %w", err)
254-
}
255-
return mcp.NewToolResultText(string(out)), nil
256+
// Create paginated response
257+
paginatedResp := NewPaginatedGraphQLResponse(response, hasNextPage, nextCursor)
258+
return MarshalPaginatedResponse(paginatedResp), nil
256259
}
257260
}
258261

@@ -356,25 +359,16 @@ func GetDiscussionComments(getGQLClient GetGQLClientFn, t translations.Translati
356359
return mcp.NewToolResultError(err.Error()), nil
357360
}
358361

359-
// Get pagination parameters and convert to GraphQL format
360-
pagination, err := OptionalCursorPaginationParams(request)
361-
if err != nil {
362-
return nil, err
363-
}
364-
365-
// Check if pagination parameters were explicitly provided
366-
_, perPageProvided := request.GetArguments()["perPage"]
367-
paginationExplicit := perPageProvided
368-
369-
paginationParams, err := pagination.ToGraphQLParams()
362+
// Get cursor-based pagination parameters
363+
cursorParams, err := GetCursorBasedParams(request)
370364
if err != nil {
371365
return nil, err
372366
}
373367

374-
// Use default of 30 if pagination was not explicitly provided
375-
if !paginationExplicit {
376-
defaultFirst := int32(DefaultGraphQLPageSize)
377-
paginationParams.First = &defaultFirst
368+
// For GraphQL, the cursor is the 'after' value
369+
var after *string
370+
if cursorParams.After != "" {
371+
after = &cursorParams.After
378372
}
379373

380374
client, err := getGQLClient(ctx)
@@ -400,14 +394,16 @@ func GetDiscussionComments(getGQLClient GetGQLClientFn, t translations.Translati
400394
} `graphql:"discussion(number: $discussionNumber)"`
401395
} `graphql:"repository(owner: $owner, name: $repo)"`
402396
}
397+
// Use fixed page size of 10 for cursor-based pagination
398+
first := int32(cursorParams.PerPage)
403399
vars := map[string]interface{}{
404400
"owner": githubv4.String(params.Owner),
405401
"repo": githubv4.String(params.Repo),
406402
"discussionNumber": githubv4.Int(params.DiscussionNumber),
407-
"first": githubv4.Int(*paginationParams.First),
403+
"first": githubv4.Int(first),
408404
}
409-
if paginationParams.After != nil {
410-
vars["after"] = githubv4.String(*paginationParams.After)
405+
if after != nil {
406+
vars["after"] = githubv4.String(*after)
411407
} else {
412408
vars["after"] = (*githubv4.String)(nil)
413409
}
@@ -421,23 +417,20 @@ func GetDiscussionComments(getGQLClient GetGQLClientFn, t translations.Translati
421417
}
422418

423419
// Create response with pagination info
424-
response := map[string]interface{}{
425-
"comments": comments,
426-
"pageInfo": map[string]interface{}{
427-
"hasNextPage": q.Repository.Discussion.Comments.PageInfo.HasNextPage,
428-
"hasPreviousPage": q.Repository.Discussion.Comments.PageInfo.HasPreviousPage,
429-
"startCursor": string(q.Repository.Discussion.Comments.PageInfo.StartCursor),
430-
"endCursor": string(q.Repository.Discussion.Comments.PageInfo.EndCursor),
431-
},
432-
"totalCount": q.Repository.Discussion.Comments.TotalCount,
420+
hasNextPage := bool(q.Repository.Discussion.Comments.PageInfo.HasNextPage)
421+
var nextCursor string
422+
if hasNextPage {
423+
nextCursor = string(q.Repository.Discussion.Comments.PageInfo.EndCursor)
433424
}
434425

435-
out, err := json.Marshal(response)
436-
if err != nil {
437-
return nil, fmt.Errorf("failed to marshal comments: %w", err)
426+
response := map[string]interface{}{
427+
"comments": comments,
428+
"totalCount": q.Repository.Discussion.Comments.TotalCount,
438429
}
439430

440-
return mcp.NewToolResultText(string(out)), nil
431+
// Create paginated response
432+
paginatedResp := NewPaginatedGraphQLResponse(response, hasNextPage, nextCursor)
433+
return MarshalPaginatedResponse(paginatedResp), nil
441434
}
442435
}
443436

pkg/github/issues.go

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,48 +1294,37 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
12941294
}
12951295
hasLabels := len(labels) > 0
12961296

1297-
// Get pagination parameters and convert to GraphQL format
1298-
pagination, err := OptionalCursorPaginationParams(request)
1299-
if err != nil {
1300-
return nil, err
1301-
}
1302-
1303-
// Check if someone tried to use page-based pagination instead of cursor-based
1304-
if _, pageProvided := request.GetArguments()["page"]; pageProvided {
1305-
return mcp.NewToolResultError("This tool uses cursor-based pagination. Use the 'after' parameter with the 'endCursor' value from the previous response instead of 'page'."), nil
1306-
}
1307-
1308-
// Check if pagination parameters were explicitly provided
1309-
_, perPageProvided := request.GetArguments()["perPage"]
1310-
paginationExplicit := perPageProvided
1311-
1312-
paginationParams, err := pagination.ToGraphQLParams()
1297+
// Get cursor-based pagination parameters
1298+
cursorParams, err := GetCursorBasedParams(request)
13131299
if err != nil {
13141300
return nil, err
13151301
}
13161302

1317-
// Use default of 30 if pagination was not explicitly provided
1318-
if !paginationExplicit {
1319-
defaultFirst := int32(DefaultGraphQLPageSize)
1320-
paginationParams.First = &defaultFirst
1303+
// For GraphQL, the cursor is the 'after' value
1304+
var after *string
1305+
if cursorParams.After != "" {
1306+
after = &cursorParams.After
13211307
}
13221308

13231309
client, err := getGQLClient(ctx)
13241310
if err != nil {
13251311
return mcp.NewToolResultError(fmt.Sprintf("failed to get GitHub GQL client: %v", err)), nil
13261312
}
13271313

1314+
// Use fixed page size of 10 for cursor-based pagination
1315+
first := int32(cursorParams.PerPage)
1316+
13281317
vars := map[string]interface{}{
13291318
"owner": githubv4.String(owner),
13301319
"repo": githubv4.String(repo),
13311320
"states": states,
13321321
"orderBy": githubv4.IssueOrderField(orderBy),
13331322
"direction": githubv4.OrderDirection(direction),
1334-
"first": githubv4.Int(*paginationParams.First),
1323+
"first": githubv4.Int(first),
13351324
}
13361325

1337-
if paginationParams.After != nil {
1338-
vars["after"] = githubv4.String(*paginationParams.After)
1326+
if after != nil {
1327+
vars["after"] = githubv4.String(*after)
13391328
} else {
13401329
// Used within query, therefore must be set to nil and provided as $after
13411330
vars["after"] = (*githubv4.String)(nil)
@@ -1380,21 +1369,20 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
13801369
}
13811370

13821371
// Create response with issues
1372+
hasNextPage := bool(pageInfo.HasNextPage)
1373+
var nextCursor string
1374+
if hasNextPage {
1375+
nextCursor = string(pageInfo.EndCursor)
1376+
}
1377+
13831378
response := map[string]interface{}{
1384-
"issues": issues,
1385-
"pageInfo": map[string]interface{}{
1386-
"hasNextPage": pageInfo.HasNextPage,
1387-
"hasPreviousPage": pageInfo.HasPreviousPage,
1388-
"startCursor": string(pageInfo.StartCursor),
1389-
"endCursor": string(pageInfo.EndCursor),
1390-
},
1379+
"issues": issues,
13911380
"totalCount": totalCount,
13921381
}
1393-
out, err := json.Marshal(response)
1394-
if err != nil {
1395-
return nil, fmt.Errorf("failed to marshal issues: %w", err)
1396-
}
1397-
return mcp.NewToolResultText(string(out)), nil
1382+
1383+
// Create paginated response
1384+
paginatedResp := NewPaginatedGraphQLResponse(response, hasNextPage, nextCursor)
1385+
return MarshalPaginatedResponse(paginatedResp), nil
13981386
}
13991387
}
14001388

0 commit comments

Comments
 (0)