@@ -2,6 +2,7 @@ package github
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
6
7
"github.com/github/github-mcp-server/pkg/translations"
7
8
"github.com/go-viper/mapstructure/v2"
@@ -68,6 +69,66 @@ func ListProjects(getClient GetGQLClientFn, t translations.TranslationHelperFunc
68
69
}
69
70
}
70
71
72
+ // GetProjectStatuses retrieves the Status field options for a specific GitHub ProjectV2.
73
+ // It returns the status options with their IDs, names, and descriptions.
74
+ func GetProjectStatuses (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
75
+ return mcp .NewTool ("get_project_statuses" ,
76
+ mcp .WithDescription (t ("TOOL_GET_PROJECT_STATUSES_DESCRIPTION" , "Get status field options for a project" )),
77
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_GET_PROJECT_STATUSES_TITLE" , "Get project statuses" ), ReadOnlyHint : ToBoolPtr (true )}),
78
+ mcp .WithString ("project_id" , mcp .Required (), mcp .Description ("The global node ID of the project (e.g., 'PVT_kwDOA_dmc84A7u-a')" )),
79
+ ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
80
+ projectID , err := RequiredParam [string ](req , "project_id" )
81
+ if err != nil {
82
+ return mcp .NewToolResultError (err .Error ()), nil
83
+ }
84
+
85
+ client , err := getClient (ctx )
86
+ if err != nil {
87
+ return mcp .NewToolResultError (err .Error ()), nil
88
+ }
89
+
90
+ // This struct defines the shape of the GraphQL query.
91
+ // It fetches the Status field for a ProjectV2 by ID.
92
+ var q struct {
93
+ Node struct {
94
+ ProjectV2 struct {
95
+ Field struct {
96
+ ProjectV2SingleSelectField struct {
97
+ ID githubv4.ID
98
+ Name githubv4.String
99
+ Options []struct {
100
+ ID githubv4.ID
101
+ Name githubv4.String
102
+ Description githubv4.String
103
+ }
104
+ } `graphql:"... on ProjectV2SingleSelectField"`
105
+ } `graphql:"field(name: \"Status\")"`
106
+ } `graphql:"... on ProjectV2"`
107
+ } `graphql:"node(id: $projectId)"`
108
+ }
109
+
110
+ variables := map [string ]any {
111
+ "projectId" : githubv4 .ID (projectID ),
112
+ }
113
+
114
+ if err := client .Query (ctx , & q , variables ); err != nil {
115
+ // Provide a more helpful error message if the ID is malformed.
116
+ if err .Error () == "Could not resolve to a node with the global id of '" + projectID + "'" {
117
+ return mcp .NewToolResultError (fmt .Sprintf ("Invalid project_id: '%s'. Please provide a valid global node ID for a project." , projectID )), nil
118
+ }
119
+ return mcp .NewToolResultError (err .Error ()), nil
120
+ }
121
+
122
+ // Check if the Status field exists and has options
123
+ statusField := q .Node .ProjectV2 .Field .ProjectV2SingleSelectField
124
+ if statusField .Name == "" {
125
+ return mcp .NewToolResultError (fmt .Sprintf ("Could not find a Status field for project with ID '%s'. The project might not have a Status field configured." , projectID )), nil
126
+ }
127
+
128
+ return MarshalledTextResult (statusField ), nil
129
+ }
130
+ }
131
+
71
132
// GetProjectFields lists fields for a project.
72
133
func GetProjectFields (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
73
134
return mcp .NewTool ("get_project_fields" ,
0 commit comments