@@ -716,49 +716,158 @@ func AddIssueToProject(getClient GetGQLClientFn, t translations.TranslationHelpe
716716 }
717717}
718718
719- // UpdateProjectItemField updates a field value on a project item.
720- func UpdateProjectItemField (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
721- return mcp .NewTool ("update_project_item_field" ,
722- mcp .WithDescription (t ("TOOL_UPDATE_PROJECT_ITEM_FIELD_DESCRIPTION" , "Update a project item field" )),
723- mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_UPDATE_PROJECT_ITEM_FIELD_USER_TITLE" , "Update project item field" ), ReadOnlyHint : ToBoolPtr (false )}),
724- mcp .WithString ("project_id" , mcp .Required (), mcp .Description ("Project ID" )),
725- mcp .WithString ("item_id" , mcp .Required (), mcp .Description ("Item ID" )),
726- mcp .WithString ("field_id" , mcp .Required (), mcp .Description ("Field ID" )),
727- mcp .WithString ("text_value" , mcp .Description ("Text value" )),
728- ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
729- projectID , err := RequiredParam [string ](req , "project_id" )
730- if err != nil {
731- return mcp .NewToolResultError (err .Error ()), nil
732- }
733- itemID , err := RequiredParam [string ](req , "item_id" )
734- if err != nil {
735- return mcp .NewToolResultError (err .Error ()), nil
736- }
737- fieldID , err := RequiredParam [string ](req , "field_id" )
738- if err != nil {
739- return mcp .NewToolResultError (err .Error ()), nil
740- }
741- textValue , err := OptionalParam [string ](req , "text_value" )
742- if err != nil {
743- return mcp .NewToolResultError (err .Error ()), nil
744- }
745- client , err := getClient (ctx )
746- if err != nil {
747- return mcp .NewToolResultError (err .Error ()), nil
748- }
749- val := githubv4.ProjectV2FieldValue {}
750- if textValue != "" {
751- val .Text = githubv4 .NewString (githubv4 .String (textValue ))
752- }
753- var mut struct {
754- UpdateProjectV2ItemFieldValue struct { Typename githubv4.String } `graphql:"updateProjectV2ItemFieldValue(input: $input)"`
755- }
756- input := githubv4.UpdateProjectV2ItemFieldValueInput {ProjectID : githubv4 .ID (projectID ), ItemID : githubv4 .ID (itemID ), FieldID : githubv4 .ID (fieldID ), Value : val }
757- if err := client .Mutate (ctx , & mut , input , nil ); err != nil {
758- return mcp .NewToolResultError (err .Error ()), nil
719+ // UpdateProjectItemStatus updates the status field of a project item, allowing items to be moved between columns.
720+ func UpdateProjectItemStatus (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
721+ return mcp .NewTool ("update_project_item_status" ,
722+ mcp .WithDescription (t ("TOOL_UPDATE_PROJECT_ITEM_STATUS_DESCRIPTION" , "Update a project item's status to move it between columns" )),
723+ mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_UPDATE_PROJECT_ITEM_STATUS_USER_TITLE" , "Update project item status" ), ReadOnlyHint : ToBoolPtr (false )}),
724+ mcp .WithString ("project_id" , mcp .Required (), mcp .Description ("Project ID" )),
725+ mcp .WithString ("item_id" , mcp .Required (), mcp .Description ("Item ID" )),
726+ mcp .WithString ("status_option_id" , mcp .Required (), mcp .Description ("Status option ID (use get_project_statuses to find available options)" )),
727+ ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
728+ projectID , err := RequiredParam [string ](req , "project_id" )
729+ if err != nil {
730+ return mcp .NewToolResultError (err .Error ()), nil
731+ }
732+ itemID , err := RequiredParam [string ](req , "item_id" )
733+ if err != nil {
734+ return mcp .NewToolResultError (err .Error ()), nil
735+ }
736+ statusOptionID , err := RequiredParam [string ](req , "status_option_id" )
737+ if err != nil {
738+ return mcp .NewToolResultError (err .Error ()), nil
739+ }
740+
741+ client , err := getClient (ctx )
742+ if err != nil {
743+ return mcp .NewToolResultError (err .Error ()), nil
744+ }
745+
746+ var statusFieldQuery struct {
747+ Node struct {
748+ ProjectV2 struct {
749+ Field struct {
750+ ProjectV2SingleSelectField struct {
751+ ID githubv4.ID
752+ Name githubv4.String
753+ Options []struct {
754+ ID githubv4.ID
755+ Name githubv4.String
756+ }
757+ } `graphql:"... on ProjectV2SingleSelectField"`
758+ } `graphql:"field(name: \"Status\")"`
759+ } `graphql:"... on ProjectV2"`
760+ } `graphql:"node(id: $projectId)"`
761+ }
762+
763+ variables := map [string ]any {
764+ "projectId" : githubv4 .ID (projectID ),
765+ }
766+
767+ if err := client .Query (ctx , & statusFieldQuery , variables ); err != nil {
768+ return mcp .NewToolResultError (fmt .Sprintf ("Failed to get Status field for project: %s" , err .Error ())), nil
769+ }
770+
771+ statusField := statusFieldQuery .Node .ProjectV2 .Field .ProjectV2SingleSelectField
772+ if statusField .ID == "" {
773+ 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
774+ }
775+
776+ // Validate that the provided status option ID exists
777+ var validOption bool
778+ var optionName string
779+ for _ , option := range statusField .Options {
780+ if option .ID .(string ) == statusOptionID {
781+ validOption = true
782+ optionName = string (option .Name )
783+ break
759784 }
760- return MarshalledTextResult (mut ), nil
761785 }
786+
787+ if ! validOption {
788+ return mcp .NewToolResultError (fmt .Sprintf ("Invalid status_option_id '%s' for project '%s'. Use get_project_statuses to see available options." , statusOptionID , projectID )), nil
789+ }
790+
791+ val := githubv4.ProjectV2FieldValue {
792+ SingleSelectOptionID : githubv4 .NewString (githubv4 .String (statusOptionID )),
793+ }
794+
795+ var mut struct {
796+ UpdateProjectV2ItemFieldValue struct {
797+ ProjectV2Item struct {
798+ ID githubv4.ID
799+ } `graphql:"projectV2Item"`
800+ } `graphql:"updateProjectV2ItemFieldValue(input: $input)"`
801+ }
802+
803+ input := githubv4.UpdateProjectV2ItemFieldValueInput {
804+ ProjectID : githubv4 .ID (projectID ),
805+ ItemID : githubv4 .ID (itemID ),
806+ FieldID : statusField .ID ,
807+ Value : val ,
808+ }
809+
810+ if err := client .Mutate (ctx , & mut , input , nil ); err != nil {
811+ return mcp .NewToolResultError (fmt .Sprintf ("Failed to update project item status: %s" , err .Error ())), nil
812+ }
813+
814+ result := map [string ]interface {}{
815+ "success" : true ,
816+ "message" : fmt .Sprintf ("Successfully updated item status to '%s'" , optionName ),
817+ "project_id" : projectID ,
818+ "item_id" : itemID ,
819+ "new_status" : optionName ,
820+ "status_option_id" : statusOptionID ,
821+ }
822+
823+ return MarshalledTextResult (result ), nil
824+ }
825+ }
826+
827+
828+ // UpdateProjectItemField updates a field value on a project item.
829+ func UpdateProjectItemField (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
830+ return mcp .NewTool ("update_project_item_field" ,
831+ mcp .WithDescription (t ("TOOL_UPDATE_PROJECT_ITEM_FIELD_DESCRIPTION" , "Update a project item field" )),
832+ mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_UPDATE_PROJECT_ITEM_FIELD_USER_TITLE" , "Update project item field" ), ReadOnlyHint : ToBoolPtr (false )}),
833+ mcp .WithString ("project_id" , mcp .Required (), mcp .Description ("Project ID" )),
834+ mcp .WithString ("item_id" , mcp .Required (), mcp .Description ("Item ID" )),
835+ mcp .WithString ("field_id" , mcp .Required (), mcp .Description ("Field ID" )),
836+ mcp .WithString ("text_value" , mcp .Description ("Text value" )),
837+ ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
838+ projectID , err := RequiredParam [string ](req , "project_id" )
839+ if err != nil {
840+ return mcp .NewToolResultError (err .Error ()), nil
841+ }
842+ itemID , err := RequiredParam [string ](req , "item_id" )
843+ if err != nil {
844+ return mcp .NewToolResultError (err .Error ()), nil
845+ }
846+ fieldID , err := RequiredParam [string ](req , "field_id" )
847+ if err != nil {
848+ return mcp .NewToolResultError (err .Error ()), nil
849+ }
850+ textValue , err := OptionalParam [string ](req , "text_value" )
851+ if err != nil {
852+ return mcp .NewToolResultError (err .Error ()), nil
853+ }
854+ client , err := getClient (ctx )
855+ if err != nil {
856+ return mcp .NewToolResultError (err .Error ()), nil
857+ }
858+ val := githubv4.ProjectV2FieldValue {}
859+ if textValue != "" {
860+ val .Text = githubv4 .NewString (githubv4 .String (textValue ))
861+ }
862+ var mut struct {
863+ UpdateProjectV2ItemFieldValue struct { Typename githubv4.String } `graphql:"updateProjectV2ItemFieldValue(input: $input)"`
864+ }
865+ input := githubv4.UpdateProjectV2ItemFieldValueInput {ProjectID : githubv4 .ID (projectID ), ItemID : githubv4 .ID (itemID ), FieldID : githubv4 .ID (fieldID ), Value : val }
866+ if err := client .Mutate (ctx , & mut , input , nil ); err != nil {
867+ return mcp .NewToolResultError (err .Error ()), nil
868+ }
869+ return MarshalledTextResult (mut ), nil
870+ }
762871}
763872
764873// CreateDraftIssue creates a draft issue in a project.
0 commit comments