Skip to content

Commit 781c3c4

Browse files
committed
add get project statuses tool
1 parent b901459 commit 781c3c4

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

pkg/github/projects.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package github
22

33
import (
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.
72133
func GetProjectFields(getClient GetGQLClientFn, t translations.TranslationHelperFunc) (mcp.Tool, server.ToolHandlerFunc) {
73134
return mcp.NewTool("get_project_fields",

pkg/github/tools.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
107107
AddReadTools(
108108
toolsets.NewServerTool(ListProjects(getGQLClient, t)),
109109
toolsets.NewServerTool(GetProjectFields(getGQLClient, t)),
110+
toolsets.NewServerTool(GetProjectStatuses(getGQLClient, t)),
110111
toolsets.NewServerTool(GetProjectItems(getGQLClient, t)),
111112
).
112113
AddWriteTools(

0 commit comments

Comments
 (0)