@@ -518,167 +518,131 @@ func GetProjectFields(getClient GetGQLClientFn, t translations.TranslationHelper
518518 }
519519}
520520
521- // GetProjectItems lists items for a project.
522- func GetProjectItems (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
523- return mcp .NewTool ("get_project_items" ,
524- mcp .WithDescription (t ("TOOL_GET_PROJECT_ITEMS_DESCRIPTION" , "Get items for a project" )),
525- mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_GET_PROJECT_ITEMS_USER_TITLE" , "Get project items" ), ReadOnlyHint : ToBoolPtr (true )}),
526- mcp .WithString ("owner" , mcp .Required (), mcp .Description ("Owner login" )),
527- mcp .WithString ("owner_type" , mcp .Description ("Owner type" ), mcp .Enum ("user" , "organization" )),
528- mcp .WithNumber ("number" , mcp .Required (), mcp .Description ("Project number" )),
529- ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
530- owner , err := RequiredParam [string ](req , "owner" )
531- if err != nil {
532- return mcp .NewToolResultError (err .Error ()), nil
533- }
534- number , err := RequiredInt (req , "number" )
535- if err != nil {
536- return mcp .NewToolResultError (err .Error ()), nil
537- }
538- ownerType , err := OptionalParam [string ](req , "owner_type" )
539- if err != nil {
540- return mcp .NewToolResultError (err .Error ()), nil
541- }
542- if ownerType == "" {
543- ownerType = "organization"
544- }
545- client , err := getClient (ctx )
546- if err != nil {
547- return mcp .NewToolResultError (err .Error ()), nil
548- }
549- if ownerType == "user" {
550- var q struct {
551- User struct {
552- Project struct {
553- Items struct {
554- Nodes []struct {
555- ID githubv4.ID
556- FieldValues struct {
557- Nodes []struct {
558- ProjectV2ItemFieldTextValue struct {
559- Text githubv4.String
560- Field struct {
561- ProjectV2FieldCommon struct {
562- Name githubv4.String
563- } `graphql:"... on ProjectV2FieldCommon"`
564- }
565- } `graphql:"... on ProjectV2ItemFieldTextValue"`
566- ProjectV2ItemFieldDateValue struct {
567- Date githubv4.Date
568- Field struct {
569- ProjectV2FieldCommon struct {
570- Name githubv4.String
571- } `graphql:"... on ProjectV2FieldCommon"`
572- }
573- } `graphql:"... on ProjectV2ItemFieldDateValue"`
574- ProjectV2ItemFieldSingleSelectValue struct {
575- Name githubv4.String
576- Field struct {
577- ProjectV2FieldCommon struct {
578- Name githubv4.String
579- } `graphql:"... on ProjectV2FieldCommon"`
580- }
581- } `graphql:"... on ProjectV2ItemFieldSingleSelectValue"`
582- }
583- } `graphql:"fieldValues(first: 8)"`
584- Content struct {
585- DraftIssue struct {
586- Title githubv4.String
587- Body githubv4.String
588- } `graphql:"... on DraftIssue"`
589- Issue struct {
590- Title githubv4.String
591- Assignees struct {
592- Nodes []struct {
593- Login githubv4.String
594- }
595- } `graphql:"assignees(first: 10)"`
596- } `graphql:"... on Issue"`
597- PullRequest struct {
598- Title githubv4.String
599- Assignees struct {
600- Nodes []struct {
601- Login githubv4.String
602- }
603- } `graphql:"assignees(first: 10)"`
604- } `graphql:"... on PullRequest"`
605- }
606- }
607- } `graphql:"items(first: 100)"`
608- } `graphql:"projectV2(number: $number)"`
609- } `graphql:"user(login: $login)"`
521+ // FieldNameFragment defines the fields we want from a ProjectV2FieldCommon interface.
522+ type FieldNameFragment struct {
523+ Name githubv4.String
524+ }
525+
526+ // Field represents the 'field' interface on a project item's field value.
527+ // It uses an embedded struct with a graphql tag to act as an inline fragment.
528+ type Field struct {
529+ OnProjectV2FieldCommon FieldNameFragment `graphql:"... on ProjectV2FieldCommon"`
530+ }
531+
532+ // ProjectItem defines the structure of a single item within a project,
533+ // including its field values and content.
534+ type ProjectItem struct {
535+ ID githubv4.ID
536+ FieldValues struct {
537+ Nodes []struct {
538+ TypeName string `graphql:"__typename"`
539+ // Fragment for Text values
540+ OnTextValue struct {
541+ Text githubv4.String
542+ Field Field
543+ } `graphql:"... on ProjectV2ItemFieldTextValue"`
544+ // Fragment for Date values
545+ OnDateValue struct {
546+ Date githubv4.DateTime
547+ Field Field
548+ } `graphql:"... on ProjectV2ItemFieldDateValue"`
549+ // Fragment for Single Select values
550+ OnSingleSelectValue struct {
551+ Name githubv4.String
552+ Field Field
553+ } `graphql:"... on ProjectV2ItemFieldSingleSelectValue"`
554+ }
555+ } `graphql:"fieldValues(first: 8)"`
556+ Content struct {
557+ TypeName string `graphql:"__typename"`
558+ OnDraftIssue struct {
559+ Title githubv4.String
560+ Body githubv4.String
561+ } `graphql:"... on DraftIssue"`
562+ OnIssue struct {
563+ Title githubv4.String
564+ Assignees struct {
565+ Nodes []struct {
566+ Login githubv4.String
610567 }
611- if err := client .Query (ctx , & q , map [string ]any {"login" : githubv4 .String (owner ), "number" : githubv4 .Int (number )}); err != nil {
612- return mcp .NewToolResultError (err .Error ()), nil
568+ } `graphql:"assignees(first: 10)"`
569+ } `graphql:"... on Issue"`
570+ OnPullRequest struct {
571+ Title githubv4.String
572+ Assignees struct {
573+ Nodes []struct {
574+ Login githubv4.String
613575 }
614- return MarshalledTextResult (q ), nil
615- }
576+ } `graphql:"assignees(first: 10)"`
577+ } `graphql:"... on PullRequest"`
578+ }
579+ }
580+
581+ func GetProjectItems (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
582+ return mcp .NewTool ("get_project_items" ,
583+ mcp .WithDescription (t ("TOOL_GET_PROJECT_ITEMS_DESCRIPTION" , "Get items for a project" )),
584+ mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_GET_PROJECT_ITEMS_USER_TITLE" , "Get project items" ), ReadOnlyHint : ToBoolPtr (true )}),
585+ mcp .WithString ("owner" , mcp .Required (), mcp .Description ("Owner login" )),
586+ mcp .WithString ("owner_type" , mcp .Description ("Owner type" ), mcp .Enum ("user" , "organization" )),
587+ mcp .WithNumber ("number" , mcp .Required (), mcp .Description ("Project number" )),
588+ ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
589+ owner , err := RequiredParam [string ](req , "owner" )
590+ if err != nil {
591+ return mcp .NewToolResultError (err .Error ()), nil
592+ }
593+ number , err := RequiredInt (req , "number" )
594+ if err != nil {
595+ return mcp .NewToolResultError (err .Error ()), nil
596+ }
597+ ownerType , err := OptionalParam [string ](req , "owner_type" )
598+ if err != nil {
599+ return mcp .NewToolResultError (err .Error ()), nil
600+ }
601+ if ownerType == "" {
602+ ownerType = "organization"
603+ }
604+
605+ client , err := getClient (ctx )
606+ if err != nil {
607+ return mcp .NewToolResultError (err .Error ()), nil
608+ }
609+
610+ variables := map [string ]any {
611+ "login" : githubv4 .String (owner ),
612+ "number" : githubv4 .Int (number ),
613+ }
614+
615+ if ownerType == "user" {
616616 var q struct {
617- Organization struct {
617+ User struct {
618618 Project struct {
619619 Items struct {
620- Nodes []struct {
621- ID githubv4.ID
622- FieldValues struct {
623- Nodes []struct {
624- ProjectV2ItemFieldTextValue struct {
625- Text githubv4.String
626- Field struct {
627- ProjectV2FieldCommon struct {
628- Name githubv4.String
629- } `graphql:"... on ProjectV2FieldCommon"`
630- }
631- } `graphql:"... on ProjectV2ItemFieldTextValue"`
632- ProjectV2ItemFieldDateValue struct {
633- Date githubv4.Date
634- Field struct {
635- ProjectV2FieldCommon struct {
636- Name githubv4.String
637- } `graphql:"... on ProjectV2FieldCommon"`
638- }
639- } `graphql:"... on ProjectV2ItemFieldDateValue"`
640- ProjectV2ItemFieldSingleSelectValue struct {
641- Name githubv4.String
642- Field struct {
643- ProjectV2FieldCommon struct {
644- Name githubv4.String
645- } `graphql:"... on ProjectV2FieldCommon"`
646- }
647- } `graphql:"... on ProjectV2ItemFieldSingleSelectValue"`
648- }
649- } `graphql:"fieldValues(first: 8)"`
650- Content struct {
651- DraftIssue struct {
652- Title githubv4.String
653- Body githubv4.String
654- } `graphql:"... on DraftIssue"`
655- Issue struct {
656- Title githubv4.String
657- Assignees struct {
658- Nodes []struct {
659- Login githubv4.String
660- }
661- } `graphql:"assignees(first: 10)"`
662- } `graphql:"... on Issue"`
663- PullRequest struct {
664- Title githubv4.String
665- Assignees struct {
666- Nodes []struct {
667- Login githubv4.String
668- }
669- } `graphql:"assignees(first: 10)"`
670- } `graphql:"... on PullRequest"`
671- }
672- }
620+ Nodes []ProjectItem
673621 } `graphql:"items(first: 100)"`
674622 } `graphql:"projectV2(number: $number)"`
675- } `graphql:"organization (login: $login)"`
623+ } `graphql:"user (login: $login)"`
676624 }
677- if err := client .Query (ctx , & q , map [ string ] any { "login" : githubv4 . String ( owner ), "number" : githubv4 . Int ( number )} ); err != nil {
625+ if err := client .Query (ctx , & q , variables ); err != nil {
678626 return mcp .NewToolResultError (err .Error ()), nil
679627 }
680- return MarshalledTextResult (q ), nil
628+ return MarshalledTextResult (q .User .Project .Items ), nil
629+ }
630+
631+ // This code is now reachable and syntactically correct.
632+ var q struct {
633+ Organization struct {
634+ Project struct {
635+ Items struct {
636+ Nodes []ProjectItem
637+ } `graphql:"items(first: 100)"`
638+ } `graphql:"projectV2(number: $number)"`
639+ } `graphql:"organization(login: $login)"`
681640 }
641+ if err := client .Query (ctx , & q , variables ); err != nil {
642+ return mcp .NewToolResultError (err .Error ()), nil
643+ }
644+ return MarshalledTextResult (q .Organization .Project .Items ), nil
645+ }
682646}
683647
684648// CreateIssue creates an issue in a repository.
@@ -800,40 +764,54 @@ func UpdateProjectItemField(getClient GetGQLClientFn, t translations.Translation
800764// CreateDraftIssue creates a draft issue in a project.
801765func CreateDraftIssue (getClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
802766 return mcp .NewTool ("create_draft_issue" ,
803- mcp .WithDescription (t ("TOOL_CREATE_DRAFT_ISSUE_DESCRIPTION" , "Create a draft issue in a project" )),
804- mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_CREATE_DRAFT_ISSUE_USER_TITLE" , "Create draft issue" ), ReadOnlyHint : ToBoolPtr (false )}),
805- mcp .WithString ("project_id" , mcp .Required (), mcp .Description ("Project ID" )),
806- mcp .WithString ("title" , mcp .Required (), mcp .Description ("Issue title" )),
807- mcp .WithString ("body" , mcp .Description ("Issue body" )),
808- ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
809- projectID , err := RequiredParam [string ](req , "project_id" )
810- if err != nil {
811- return mcp .NewToolResultError (err .Error ()), nil
812- }
813- title , err := RequiredParam [string ](req , "title" )
814- if err != nil {
815- return mcp .NewToolResultError (err .Error ()), nil
816- }
817- body , err := OptionalParam [string ](req , "body" )
818- if err != nil {
819- return mcp .NewToolResultError (err .Error ()), nil
820- }
821- client , err := getClient (ctx )
822- if err != nil {
823- return mcp .NewToolResultError (err .Error ()), nil
824- }
825- input := githubv4.AddProjectV2DraftIssueInput {ProjectID : githubv4 .ID (projectID ), Title : githubv4 .String (title )}
826- if body != "" {
827- input .Body = githubv4 .NewString (githubv4 .String (body ))
828- }
829- var mut struct {
830- AddProjectV2DraftIssue struct { Item struct { ID githubv4.ID } } `graphql:"addProjectV2DraftIssue(input: $input)"`
831- }
832- if err := client .Mutate (ctx , & mut , input , nil ); err != nil {
833- return mcp .NewToolResultError (err .Error ()), nil
834- }
835- return MarshalledTextResult (mut ), nil
767+ mcp .WithDescription (t ("TOOL_CREATE_DRAFT_ISSUE_DESCRIPTION" , "Create a draft issue in a project" )),
768+ mcp .WithToolAnnotation (mcp.ToolAnnotation {Title : t ("TOOL_CREATE_DRAFT_ISSUE_USER_TITLE" , "Create draft issue" ), ReadOnlyHint : ToBoolPtr (false )}),
769+ mcp .WithString ("project_id" , mcp .Required (), mcp .Description ("Project ID" )),
770+ mcp .WithString ("title" , mcp .Required (), mcp .Description ("Issue title" )),
771+ mcp .WithString ("body" , mcp .Description ("Issue body" )),
772+ ), func (ctx context.Context , req mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
773+ projectID , err := RequiredParam [string ](req , "project_id" )
774+ if err != nil {
775+ return mcp .NewToolResultError (err .Error ()), nil
836776 }
777+ title , err := RequiredParam [string ](req , "title" )
778+ if err != nil {
779+ return mcp .NewToolResultError (err .Error ()), nil
780+ }
781+ body , err := OptionalParam [string ](req , "body" )
782+ if err != nil {
783+ return mcp .NewToolResultError (err .Error ()), nil
784+ }
785+
786+ client , err := getClient (ctx )
787+ if err != nil {
788+ return mcp .NewToolResultError (err .Error ()), nil
789+ }
790+
791+ input := githubv4.AddProjectV2DraftIssueInput {
792+ ProjectID : githubv4 .ID (projectID ),
793+ Title : githubv4 .String (title ),
794+ }
795+ if body != "" {
796+ input .Body = githubv4 .NewString (githubv4 .String (body ))
797+ }
798+
799+ // CORRECTED: The payload field is 'projectItem', not 'item'.
800+ var mut struct {
801+ AddProjectV2DraftIssue struct {
802+ ProjectItem struct {
803+ ID githubv4.ID
804+ }
805+ } `graphql:"addProjectV2DraftIssue(input: $input)"`
806+ }
807+
808+ // The library requires a pointer to the mutation struct, the input, and variables (nil in this case).
809+ if err := client .Mutate (ctx , & mut , input , nil ); err != nil {
810+ return mcp .NewToolResultError (err .Error ()), nil
811+ }
812+
813+ return MarshalledTextResult (mut .AddProjectV2DraftIssue .ProjectItem ), nil
814+ }
837815}
838816
839817// DeleteProjectItem removes an item from a project.
0 commit comments