@@ -18,22 +18,7 @@ import (
1818 "github.com/shurcooL/githubv4"
1919)
2020
21- var ListIssuesQuery struct {
22- Repository struct {
23- Issues struct {
24- Nodes []IssueFragment `graphql:"nodes"`
25- PageInfo struct {
26- HasNextPage githubv4.Boolean
27- HasPreviousPage githubv4.Boolean
28- StartCursor githubv4.String
29- EndCursor githubv4.String
30- }
31- TotalCount int
32- } `graphql:"issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction})"`
33- } `graphql:"repository(owner: $owner, name: $repo)"`
34- }
35-
36- // NodeFragment represents a fragment of an issue node in the GraphQL API.
21+ // IssueFragment represents a fragment of an issue node in the GraphQL API.
3722type IssueFragment struct {
3823 Number githubv4.Int
3924 Title githubv4.String
@@ -55,11 +40,57 @@ type IssueFragment struct {
5540 } `graphql:"labels(first: 10)"`
5641}
5742
43+ // Common interface for all issue query types
44+ type IssueQueryResult interface {
45+ GetIssueFragment () IssueQueryFragment
46+ }
47+
48+ type IssueQueryFragment struct {
49+ Nodes []IssueFragment `graphql:"nodes"`
50+ PageInfo struct {
51+ HasNextPage githubv4.Boolean
52+ HasPreviousPage githubv4.Boolean
53+ StartCursor githubv4.String
54+ EndCursor githubv4.String
55+ }
56+ TotalCount int
57+ }
58+
59+ // ListIssuesQuery is the root query structure for fetching issues with optional label filtering.
60+ type ListIssuesQueryType struct {
61+ Repository struct {
62+ Issues IssueQueryFragment `graphql:"issues(first: $first, after: $after, labels: $labels, states: $states, orderBy: {field: $orderBy, direction: $direction})"`
63+ } `graphql:"repository(owner: $owner, name: $repo)"`
64+ }
65+
66+ // ListIssuesQueryNoLabels is the query structure for fetching issues without label filtering.
67+ type ListIssuesQueryNoLabelsType struct {
68+ Repository struct {
69+ Issues IssueQueryFragment `graphql:"issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction})"`
70+ } `graphql:"repository(owner: $owner, name: $repo)"`
71+ }
72+
73+ // Implement the interface for both query types
74+ func (q * ListIssuesQueryType ) GetIssueFragment () IssueQueryFragment {
75+ return q .Repository .Issues
76+ }
77+
78+ func (q * ListIssuesQueryNoLabelsType ) GetIssueFragment () IssueQueryFragment {
79+ return q .Repository .Issues
80+ }
81+
82+ func getIssueQueryType (hasLabels bool ) any {
83+ if hasLabels {
84+ return & ListIssuesQueryType {}
85+ }
86+ return & ListIssuesQueryNoLabelsType {}
87+ }
88+
5889func fragmentToIssue (fragment IssueFragment ) * github.Issue {
5990 // Convert GraphQL labels to GitHub API labels format
60- var labels []* github.Label
91+ var foundLabels []* github.Label
6192 for _ , labelNode := range fragment .Labels .Nodes {
62- labels = append (labels , & github.Label {
93+ foundLabels = append (foundLabels , & github.Label {
6394 Name : github .Ptr (string (labelNode .Name )),
6495 NodeID : github .Ptr (string (labelNode .Id )),
6596 Description : github .Ptr (string (labelNode .Description )),
@@ -77,7 +108,7 @@ func fragmentToIssue(fragment IssueFragment) *github.Issue {
77108 State : github .Ptr (string (fragment .State )),
78109 ID : github .Ptr (fragment .DatabaseID ),
79110 Body : github .Ptr (string (fragment .Body )),
80- Labels : labels ,
111+ Labels : foundLabels ,
81112 }
82113}
83114
@@ -850,6 +881,11 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
850881 return mcp .NewToolResultError (err .Error ()), nil
851882 }
852883
884+ //If labels is empty, default to nil for gql query
885+ if len (labels ) == 0 {
886+ labels = nil
887+ }
888+
853889 orderBy , err := OptionalParam [string ](request , "orderBy" )
854890 if err != nil {
855891 return mcp .NewToolResultError (err .Error ()), nil
@@ -868,18 +904,19 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
868904 direction = "DESC"
869905 }
870906
871- since , err := OptionalParam [string ](request , "since" )
872- if err != nil {
873- return mcp .NewToolResultError (err .Error ()), nil
874- }
907+ // since, err := OptionalParam[string](request, "since")
908+ // if err != nil {
909+ // return mcp.NewToolResultError(err.Error()), nil
910+ // }
911+
912+ // var sinceTime time.Time
913+ // if since != "" {
914+ // sinceTime, err = parseISOTimestamp(since)
915+ // if err != nil {
916+ // return mcp.NewToolResultError(fmt.Sprintf("failed to list issues: %s", err.Error())), nil
917+ // }
918+ // }
875919
876- var sinceTime time.Time
877- if since != "" {
878- sinceTime , err = parseISOTimestamp (since )
879- if err != nil {
880- return mcp .NewToolResultError (fmt .Sprintf ("failed to list issues: %s" , err .Error ())), nil
881- }
882- }
883920 // Get pagination parameters and convert to GraphQL format
884921 pagination , err := OptionalCursorPaginationParams (request )
885922 if err != nil {
@@ -926,54 +963,52 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
926963 vars ["after" ] = (* githubv4 .String )(nil )
927964 }
928965
929- if err := client .Query (ctx , & ListIssuesQuery , vars ); err != nil {
966+ // Choose the appropriate query based on whether labels are specified
967+ hasLabels := len (labels ) > 0
968+
969+ if hasLabels {
970+ // Use query with labels filtering - convert string labels to githubv4.String slice
971+ labelStrings := make ([]githubv4.String , len (labels ))
972+ for i , label := range labels {
973+ labelStrings [i ] = githubv4 .String (label )
974+ }
975+ vars ["labels" ] = labelStrings
976+ }
977+
978+ issueQuery := getIssueQueryType (hasLabels )
979+ if err := client .Query (ctx , issueQuery , vars ); err != nil {
930980 return mcp .NewToolResultError (err .Error ()), nil
931981 }
932982
933- //We must filter based on labels after fetching all issues
983+ // Extract and convert all issue nodes using the common interface
934984 var issues []* github.Issue
935- for _ , issue := range ListIssuesQuery .Repository .Issues .Nodes {
936- var issueLabels []string
937- for _ , label := range issue .Labels .Nodes {
938- issueLabels = append (issueLabels , string (label .Name ))
939- }
940-
941- // Filter by since date if specified
942- if ! sinceTime .IsZero () && issue .CreatedAt .Time .Before (sinceTime ) {
943- continue // Skip issues created before the since date
944- }
985+ var pageInfo struct {
986+ HasNextPage githubv4.Boolean
987+ HasPreviousPage githubv4.Boolean
988+ StartCursor githubv4.String
989+ EndCursor githubv4.String
990+ }
991+ var totalCount int
945992
946- // Filter by labels if specified
947- if len (labels ) > 0 {
948- hasMatchingLabel := false
949- for _ , requestedLabel := range labels {
950- for _ , issueLabel := range issueLabels {
951- if strings .EqualFold (requestedLabel , issueLabel ) {
952- hasMatchingLabel = true
953- break
954- }
955- }
956- if hasMatchingLabel {
957- break
958- }
959- }
960- if ! hasMatchingLabel {
961- continue // Skip this issue as it doesn't match any requested labels
962- }
993+ if queryResult , ok := issueQuery .(IssueQueryResult ); ok {
994+ fragment := queryResult .GetIssueFragment ()
995+ for _ , issue := range fragment .Nodes {
996+ issues = append (issues , fragmentToIssue (issue ))
963997 }
964- issues = append (issues , fragmentToIssue (issue ))
998+ pageInfo = fragment .PageInfo
999+ totalCount = fragment .TotalCount
9651000 }
9661001
9671002 // Create response with issues
9681003 response := map [string ]interface {}{
9691004 "issues" : issues ,
9701005 "pageInfo" : map [string ]interface {}{
971- "hasNextPage" : ListIssuesQuery . Repository . Issues . PageInfo .HasNextPage ,
972- "hasPreviousPage" : ListIssuesQuery . Repository . Issues . PageInfo .HasPreviousPage ,
973- "startCursor" : string (ListIssuesQuery . Repository . Issues . PageInfo .StartCursor ),
974- "endCursor" : string (ListIssuesQuery . Repository . Issues . PageInfo .EndCursor ),
1006+ "hasNextPage" : pageInfo .HasNextPage ,
1007+ "hasPreviousPage" : pageInfo .HasPreviousPage ,
1008+ "startCursor" : string (pageInfo .StartCursor ),
1009+ "endCursor" : string (pageInfo .EndCursor ),
9751010 },
976- "totalCount" : ListIssuesQuery . Repository . Issues . TotalCount ,
1011+ "totalCount" : totalCount ,
9771012 }
9781013 out , err := json .Marshal (response )
9791014 if err != nil {
0 commit comments