@@ -6,11 +6,14 @@ import (
66 "fmt"
77 "io"
88 "net/http"
9+ "net/url"
10+ "reflect"
911 "strings"
1012
1113 ghErrors "github.com/github/github-mcp-server/pkg/errors"
1214 "github.com/github/github-mcp-server/pkg/translations"
1315 "github.com/google/go-github/v77/github"
16+ "github.com/google/go-querystring/query"
1417 "github.com/mark3labs/mcp-go/mcp"
1518 "github.com/mark3labs/mcp-go/server"
1619)
@@ -410,12 +413,17 @@ func ListProjectItems(getClient GetClientFn, t translations.TranslationHelperFun
410413
411414 var resp * github.Response
412415 var projectItems []* github.ProjectV2Item
416+ var queryPtr * string
417+
418+ if queryStr != "" {
419+ queryPtr = & queryStr
420+ }
413421
414422 opts := & github.ListProjectItemsOptions {
415423 Fields : fields ,
416424 ListProjectsOptions : github.ListProjectsOptions {
417425 ListProjectsPaginationOptions : github.ListProjectsPaginationOptions {PerPage : & perPage },
418- Query : & queryStr ,
426+ Query : queryPtr ,
419427 },
420428 }
421429
@@ -506,21 +514,32 @@ func GetProjectItem(getClient GetClientFn, t translations.TranslationHelperFunc)
506514 return mcp .NewToolResultError (err .Error ()), nil
507515 }
508516
509- opts := & github.GetProjectItemOptions {}
517+ var url string
518+ if ownerType == "org" {
519+ url = fmt .Sprintf ("orgs/%s/projectsV2/%d/items/%d" , owner , projectNumber , itemID )
520+ } else {
521+ url = fmt .Sprintf ("users/%s/projectsV2/%d/items/%d" , owner , projectNumber , itemID )
522+ }
523+
524+ opts := fieldSelectionOptions {}
510525
511526 if len (fields ) > 0 {
512527 opts .Fields = fields
513528 }
514529
515- var resp * github.Response
516- var projectItem * github.ProjectV2Item
530+ url , err = addOptions (url , opts )
531+ if err != nil {
532+ return mcp .NewToolResultError (err .Error ()), nil
533+ }
517534
518- if ownerType == "org" {
519- projectItem , resp , err = client .Projects .GetOrganizationProjectItem (ctx , owner , projectNumber , itemID , opts )
520- } else {
521- projectItem , resp , err = client .Projects .GetUserProjectItem (ctx , owner , projectNumber , itemID , opts )
535+ projectItem := projectV2Item {}
536+
537+ httpRequest , err := client .NewRequest ("GET" , url , nil )
538+ if err != nil {
539+ return nil , fmt .Errorf ("failed to create request: %w" , err )
522540 }
523541
542+ resp , err := client .Do (ctx , httpRequest , & projectItem )
524543 if err != nil {
525544 return ghErrors .NewGitHubAPIErrorResponse (ctx ,
526545 "failed to get project item" ,
@@ -828,6 +847,44 @@ func DeleteProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
828847 }
829848}
830849
850+ type fieldSelectionOptions struct {
851+ // Specific list of field IDs to include in the response. If not provided, only the title field is included.
852+ // Example: fields=102589,985201,169875 or fields[]=102589&fields[]=985201&fields[]=169875
853+ Fields []int64 `url:"fields,omitempty,comma"`
854+ }
855+
856+ // addOptions adds the parameters in opts as URL query parameters to s. opts
857+ // must be a struct whose fields may contain "url" tags.
858+ func addOptions (s string , opts any ) (string , error ) {
859+ v := reflect .ValueOf (opts )
860+ if v .Kind () == reflect .Ptr && v .IsNil () {
861+ return s , nil
862+ }
863+
864+ origURL , err := url .Parse (s )
865+ if err != nil {
866+ return s , err
867+ }
868+
869+ origValues := origURL .Query ()
870+
871+ // Use the github.com/google/go-querystring library to parse the struct
872+ newValues , err := query .Values (opts )
873+ if err != nil {
874+ return s , err
875+ }
876+
877+ // Merge the values
878+ for key , values := range newValues {
879+ for _ , value := range values {
880+ origValues .Add (key , value )
881+ }
882+ }
883+
884+ origURL .RawQuery = origValues .Encode ()
885+ return origURL .String (), nil
886+ }
887+
831888type updateProjectItemPayload struct {
832889 Fields []updateProjectItem `json:"fields"`
833890}
0 commit comments