@@ -69,13 +69,13 @@ func ListProjects(getClient GetClientFn, t translations.TranslationHelperFunc) (
6969
7070var resp * github.Response
7171var projects []* github.ProjectV2
72- minimalProjects := []MinimalProject {}
73-
7472var queryPtr * string
73+
7574if queryStr != "" {
7675queryPtr = & queryStr
7776}
7877
78+ minimalProjects := []MinimalProject {}
7979opts := & github.ListProjectsOptions {
8080ListProjectsPaginationOptions : github.ListProjectsPaginationOptions {PerPage :& perPage },
8181Query :queryPtr ,
@@ -237,27 +237,19 @@ func ListProjectFields(getClient GetClientFn, t translations.TranslationHelperFu
237237return mcp .NewToolResultError (err .Error ()),nil
238238}
239239
240- var url string
241- if ownerType == "org" {
242- url = fmt .Sprintf ("orgs/%s/projectsV2/%d/fields" ,owner ,projectNumber )
243- }else {
244- url = fmt .Sprintf ("users/%s/projectsV2/%d/fields" ,owner ,projectNumber )
245- }
246- projectFields := []projectV2Field {}
247-
248- opts := paginationOptions {PerPage :perPage }
240+ var resp * github.Response
241+ var projectFields []* github.ProjectV2Field
249242
250- url ,err = addOptions (url ,opts )
251- if err != nil {
252- return nil ,fmt .Errorf ("failed to add options to request: %w" ,err )
243+ opts := & github.ListProjectsOptions {
244+ ListProjectsPaginationOptions : github.ListProjectsPaginationOptions {PerPage :& perPage },
253245}
254246
255- httpRequest ,err := client .NewRequest ("GET" ,url ,nil )
256- if err != nil {
257- return nil ,fmt .Errorf ("failed to create request: %w" ,err )
247+ if ownerType == "org" {
248+ projectFields ,resp ,err = client .Projects .ListOrganizationProjectFields (ctx ,owner ,projectNumber ,opts )
249+ }else {
250+ projectFields ,resp ,err = client .Projects .ListUserProjectFields (ctx ,owner ,projectNumber ,opts )
258251}
259252
260- resp ,err := client .Do (ctx ,httpRequest ,& projectFields )
261253if err != nil {
262254return ghErrors .NewGitHubAPIErrorResponse (ctx ,
263255"failed to list project fields" ,
@@ -317,7 +309,7 @@ func GetProjectField(getClient GetClientFn, t translations.TranslationHelperFunc
317309if err != nil {
318310return mcp .NewToolResultError (err .Error ()),nil
319311}
320- fieldID ,err := RequiredInt (req ,"field_id" )
312+ fieldID ,err := RequiredBigInt (req ,"field_id" )
321313if err != nil {
322314return mcp .NewToolResultError (err .Error ()),nil
323315}
@@ -326,21 +318,15 @@ func GetProjectField(getClient GetClientFn, t translations.TranslationHelperFunc
326318return mcp .NewToolResultError (err .Error ()),nil
327319}
328320
329- var url string
321+ var resp * github.Response
322+ var projectField * github.ProjectV2Field
323+
330324if ownerType == "org" {
331- url = fmt . Sprintf ( "orgs/%s/projectsV2/%d/fields/%d" ,owner ,projectNumber ,fieldID )
325+ projectField , resp , err = client . Projects . GetOrganizationProjectField ( ctx ,owner ,projectNumber ,fieldID )
332326}else {
333- url = fmt . Sprintf ( "users/%s/projectsV2/%d/fields/%d" ,owner ,projectNumber ,fieldID )
327+ projectField , resp , err = client . Projects . GetUserProjectField ( ctx ,owner ,projectNumber ,fieldID )
334328}
335329
336- projectField := projectV2Field {}
337-
338- httpRequest ,err := client .NewRequest ("GET" ,url ,nil )
339- if err != nil {
340- return nil ,fmt .Errorf ("failed to create request: %w" ,err )
341- }
342-
343- resp ,err := client .Do (ctx ,httpRequest ,& projectField )
344330if err != nil {
345331return ghErrors .NewGitHubAPIErrorResponse (ctx ,
346332"failed to get project field" ,
@@ -416,41 +402,37 @@ func ListProjectItems(getClient GetClientFn, t translations.TranslationHelperFun
416402if err != nil {
417403return mcp .NewToolResultError (err .Error ()),nil
418404}
419- fields ,err := OptionalStringArrayParam (req ,"fields" )
405+ fields ,err := OptionalBigIntArrayParam (req ,"fields" )
420406if err != nil {
421407return mcp .NewToolResultError (err .Error ()),nil
422408}
423-
424409client ,err := getClient (ctx )
425410if err != nil {
426411return mcp .NewToolResultError (err .Error ()),nil
427412}
428413
429- var url string
430- if ownerType == "org" {
431- url = fmt .Sprintf ("orgs/%s/projectsV2/%d/items" ,owner ,projectNumber )
432- }else {
433- url = fmt .Sprintf ("users/%s/projectsV2/%d/items" ,owner ,projectNumber )
434- }
435- projectItems := []projectV2Item {}
414+ var resp * github.Response
415+ var projectItems []* github.ProjectV2Item
416+ var queryPtr * string
436417
437- opts := listProjectItemsOptions {
438- paginationOptions :paginationOptions {PerPage :perPage },
439- filterQueryOptions :filterQueryOptions {Query :queryStr },
440- fieldSelectionOptions :fieldSelectionOptions {Fields :fields },
418+ if queryStr != "" {
419+ queryPtr = & queryStr
441420}
442421
443- url ,err = addOptions (url ,opts )
444- if err != nil {
445- return nil ,fmt .Errorf ("failed to add options to request: %w" ,err )
422+ opts := & github.ListProjectItemsOptions {
423+ Fields :fields ,
424+ ListProjectsOptions : github.ListProjectsOptions {
425+ ListProjectsPaginationOptions : github.ListProjectsPaginationOptions {PerPage :& perPage },
426+ Query :queryPtr ,
427+ },
446428}
447429
448- httpRequest ,err := client .NewRequest ("GET" ,url ,nil )
449- if err != nil {
450- return nil ,fmt .Errorf ("failed to create request: %w" ,err )
430+ if ownerType == "org" {
431+ projectItems ,resp ,err = client .Projects .ListOrganizationProjectItems (ctx ,owner ,projectNumber ,opts )
432+ }else {
433+ projectItems ,resp ,err = client .Projects .ListUserProjectItems (ctx ,owner ,projectNumber ,opts )
451434}
452435
453- resp ,err := client .Do (ctx ,httpRequest ,& projectItems )
454436if err != nil {
455437return ghErrors .NewGitHubAPIErrorResponse (ctx ,
456438ProjectListFailedError ,
@@ -518,11 +500,11 @@ func GetProjectItem(getClient GetClientFn, t translations.TranslationHelperFunc)
518500if err != nil {
519501return mcp .NewToolResultError (err .Error ()),nil
520502}
521- itemID ,err := RequiredInt (req ,"item_id" )
503+ itemID ,err := RequiredBigInt (req ,"item_id" )
522504if err != nil {
523505return mcp .NewToolResultError (err .Error ()),nil
524506}
525- fields ,err := OptionalStringArrayParam (req ,"fields" )
507+ fields ,err := OptionalBigIntArrayParam (req ,"fields" )
526508if err != nil {
527509return mcp .NewToolResultError (err .Error ()),nil
528510}
@@ -624,7 +606,7 @@ func AddProjectItem(getClient GetClientFn, t translations.TranslationHelperFunc)
624606if err != nil {
625607return mcp .NewToolResultError (err .Error ()),nil
626608}
627- itemID ,err := RequiredInt (req ,"item_id" )
609+ itemID ,err := RequiredBigInt (req ,"item_id" )
628610if err != nil {
629611return mcp .NewToolResultError (err .Error ()),nil
630612}
@@ -642,24 +624,20 @@ func AddProjectItem(getClient GetClientFn, t translations.TranslationHelperFunc)
642624return mcp .NewToolResultError (err .Error ()),nil
643625}
644626
645- var projectsURL string
646- if ownerType == "org" {
647- projectsURL = fmt .Sprintf ("orgs/%s/projectsV2/%d/items" ,owner ,projectNumber )
648- }else {
649- projectsURL = fmt .Sprintf ("users/%s/projectsV2/%d/items" ,owner ,projectNumber )
650- }
651-
652- newItem := & newProjectItem {
653- ID :int64 (itemID ),
627+ newItem := & github.AddProjectItemOptions {
628+ ID :itemID ,
654629Type :toNewProjectType (itemType ),
655630}
656- httpRequest ,err := client .NewRequest ("POST" ,projectsURL ,newItem )
657- if err != nil {
658- return nil ,fmt .Errorf ("failed to create request: %w" ,err )
631+
632+ var resp * github.Response
633+ var addedItem * github.ProjectV2Item
634+
635+ if ownerType == "org" {
636+ addedItem ,resp ,err = client .Projects .AddOrganizationProjectItem (ctx ,owner ,projectNumber ,newItem )
637+ }else {
638+ addedItem ,resp ,err = client .Projects .AddUserProjectItem (ctx ,owner ,projectNumber ,newItem )
659639}
660- addedItem := projectV2Item {}
661640
662- resp ,err := client .Do (ctx ,httpRequest ,& addedItem )
663641if err != nil {
664642return ghErrors .NewGitHubAPIErrorResponse (ctx ,
665643ProjectAddFailedError ,
@@ -827,7 +805,7 @@ func DeleteProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
827805if err != nil {
828806return mcp .NewToolResultError (err .Error ()),nil
829807}
830- itemID ,err := RequiredInt (req ,"item_id" )
808+ itemID ,err := RequiredBigInt (req ,"item_id" )
831809if err != nil {
832810return mcp .NewToolResultError (err .Error ()),nil
833811}
@@ -836,19 +814,13 @@ func DeleteProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
836814return mcp .NewToolResultError (err .Error ()),nil
837815}
838816
839- var projectsURL string
817+ var resp * github. Response
840818if ownerType == "org" {
841- projectsURL = fmt . Sprintf ( "orgs/%s/projectsV2/%d/items/%d" ,owner ,projectNumber ,itemID )
819+ resp , err = client . Projects . DeleteOrganizationProjectItem ( ctx ,owner ,projectNumber ,itemID )
842820}else {
843- projectsURL = fmt . Sprintf ( "users/%s/projectsV2/%d/items/%d" ,owner ,projectNumber ,itemID )
821+ resp , err = client . Projects . DeleteUserProjectItem ( ctx ,owner ,projectNumber ,itemID )
844822}
845823
846- httpRequest ,err := client .NewRequest ("DELETE" ,projectsURL ,nil )
847- if err != nil {
848- return nil ,fmt .Errorf ("failed to create request: %w" ,err )
849- }
850-
851- resp ,err := client .Do (ctx ,httpRequest ,nil )
852824if err != nil {
853825return ghErrors .NewGitHubAPIErrorResponse (ctx ,
854826ProjectDeleteFailedError ,
@@ -869,9 +841,10 @@ func DeleteProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
869841}
870842}
871843
872- type newProjectItem struct {
873- ID int64 `json:"id,omitempty"`
874- Type string `json:"type,omitempty"`
844+ type fieldSelectionOptions struct {
845+ // Specific list of field IDs to include in the response. If not provided, only the title field is included.
846+ // The comma tag encodes the slice as comma-separated values: fields=102589,985201,169875
847+ Fields []int64 `url:"fields,omitempty,comma"`
875848}
876849
877850type updateProjectItemPayload struct {
@@ -883,17 +856,6 @@ type updateProjectItem struct {
883856Value any `json:"value"`
884857}
885858
886- type projectV2Field struct {
887- ID * int64 `json:"id,omitempty"` // The unique identifier for this field.
888- NodeID string `json:"node_id,omitempty"` // The GraphQL node ID for this field.
889- Name string `json:"name,omitempty"` // The display name of the field.
890- DataType string `json:"data_type,omitempty"` // The data type of the field (e.g., "text", "number", "date", "single_select", "multi_select").
891- URL string `json:"url,omitempty"` // The API URL for this field.
892- Options []* any `json:"options,omitempty"` // Available options for single_select and multi_select fields.
893- CreatedAt * github.Timestamp `json:"created_at,omitempty"` // The time when this field was created.
894- UpdatedAt * github.Timestamp `json:"updated_at,omitempty"` // The time when this field was last updated.
895- }
896-
897859type projectV2ItemFieldValue struct {
898860ID * int64 `json:"id,omitempty"` // The unique identifier for this field.
899861Name string `json:"name,omitempty"` // The display name of the field.
@@ -931,26 +893,6 @@ type projectV2ItemContent struct {
931893URL * string `json:"url,omitempty"`
932894}
933895
934- type paginationOptions struct {
935- PerPage int `url:"per_page,omitempty"`
936- }
937-
938- type filterQueryOptions struct {
939- Query string `url:"q,omitempty"`
940- }
941-
942- type fieldSelectionOptions struct {
943- // Specific list of field IDs to include in the response. If not provided, only the title field is included.
944- // Example: fields=102589,985201,169875 or fields[]=102589&fields[]=985201&fields[]=169875
945- Fields []string `url:"fields,omitempty"`
946- }
947-
948- type listProjectItemsOptions struct {
949- paginationOptions
950- filterQueryOptions
951- fieldSelectionOptions
952- }
953-
954896func toNewProjectType (projType string )string {
955897switch strings .ToLower (projType ) {
956898case "issue" :
@@ -994,18 +936,28 @@ func addOptions(s string, opts any) (string, error) {
994936return s ,nil
995937}
996938
997- u ,err := url .Parse (s )
939+ origURL ,err := url .Parse (s )
998940if err != nil {
999941return s ,err
1000942}
1001943
1002- qs ,err := query .Values (opts )
944+ origValues := origURL .Query ()
945+
946+ // Use the github.com/google/go-querystring library to parse the struct
947+ newValues ,err := query .Values (opts )
1003948if err != nil {
1004949return s ,err
1005950}
1006951
1007- u .RawQuery = qs .Encode ()
1008- return u .String (),nil
952+ // Merge the values
953+ for key ,values := range newValues {
954+ for _ ,value := range values {
955+ origValues .Add (key ,value )
956+ }
957+ }
958+
959+ origURL .RawQuery = origValues .Encode ()
960+ return origURL .String (),nil
1009961}
1010962
1011963func ManageProjectItemsPrompt (t translations.TranslationHelperFunc ) (tool mcp.Prompt ,handler server.PromptHandlerFunc ) {