@@ -2,6 +2,7 @@ package github
22
33import (
44 "context"
5+ "fmt"
56
67 "github.com/github/github-mcp-server/pkg/translations"
78 "github.com/go-viper/mapstructure/v2"
@@ -68,6 +69,66 @@ func ListProjects(getClient GetGQLClientFn, t translations.TranslationHelperFunc
6869 }
6970}
7071
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+
71132// GetProjectFields lists fields for a project.
72133func GetProjectFields (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
73134 return mcp .NewTool ("get_project_fields" ,
0 commit comments