@@ -467,6 +467,139 @@ func RemoveSubIssue(getClient GetClientFn, t translations.TranslationHelperFunc)
467
467
}
468
468
}
469
469
470
+ // ReprioritizeSubIssue creates a tool to reprioritize a sub-issue to a different position in the parent list.
471
+ func ReprioritizeSubIssue (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
472
+ return mcp .NewTool ("reprioritize_sub_issue" ,
473
+ mcp .WithDescription (t ("TOOL_REPRIORITIZE_SUB_ISSUE_DESCRIPTION" , "Reprioritize a sub-issue to a different position in the parent issue's sub-issue list." )),
474
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
475
+ Title : t ("TOOL_REPRIORITIZE_SUB_ISSUE_USER_TITLE" , "Reprioritize sub-issue" ),
476
+ ReadOnlyHint : toBoolPtr (false ),
477
+ }),
478
+ mcp .WithString ("owner" ,
479
+ mcp .Required (),
480
+ mcp .Description ("Repository owner" ),
481
+ ),
482
+ mcp .WithString ("repo" ,
483
+ mcp .Required (),
484
+ mcp .Description ("Repository name" ),
485
+ ),
486
+ mcp .WithNumber ("issue_number" ,
487
+ mcp .Required (),
488
+ mcp .Description ("The number of the parent issue" ),
489
+ ),
490
+ mcp .WithNumber ("sub_issue_id" ,
491
+ mcp .Required (),
492
+ mcp .Description ("The ID of the sub-issue to reprioritize" ),
493
+ ),
494
+ mcp .WithNumber ("after_id" ,
495
+ mcp .Description ("The ID of the sub-issue to be prioritized after (either after_id OR before_id should be specified)" ),
496
+ ),
497
+ mcp .WithNumber ("before_id" ,
498
+ mcp .Description ("The ID of the sub-issue to be prioritized before (either after_id OR before_id should be specified)" ),
499
+ ),
500
+ ),
501
+ func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
502
+ owner , err := requiredParam [string ](request , "owner" )
503
+ if err != nil {
504
+ return mcp .NewToolResultError (err .Error ()), nil
505
+ }
506
+ repo , err := requiredParam [string ](request , "repo" )
507
+ if err != nil {
508
+ return mcp .NewToolResultError (err .Error ()), nil
509
+ }
510
+ issueNumber , err := RequiredInt (request , "issue_number" )
511
+ if err != nil {
512
+ return mcp .NewToolResultError (err .Error ()), nil
513
+ }
514
+ subIssueID , err := RequiredInt (request , "sub_issue_id" )
515
+ if err != nil {
516
+ return mcp .NewToolResultError (err .Error ()), nil
517
+ }
518
+
519
+ // Handle optional positioning parameters
520
+ afterID , err := OptionalIntParam (request , "after_id" )
521
+ if err != nil {
522
+ return mcp .NewToolResultError (err .Error ()), nil
523
+ }
524
+ beforeID , err := OptionalIntParam (request , "before_id" )
525
+ if err != nil {
526
+ return mcp .NewToolResultError (err .Error ()), nil
527
+ }
528
+
529
+ // Validate that either after_id or before_id is specified, but not both
530
+ if afterID == 0 && beforeID == 0 {
531
+ return mcp .NewToolResultError ("either after_id or before_id must be specified" ), nil
532
+ }
533
+ if afterID != 0 && beforeID != 0 {
534
+ return mcp .NewToolResultError ("only one of after_id or before_id should be specified, not both" ), nil
535
+ }
536
+
537
+ client , err := getClient (ctx )
538
+ if err != nil {
539
+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
540
+ }
541
+
542
+ // Create the request body
543
+ requestBody := map [string ]interface {}{
544
+ "sub_issue_id" : subIssueID ,
545
+ }
546
+ if afterID != 0 {
547
+ requestBody ["after_id" ] = afterID
548
+ }
549
+ if beforeID != 0 {
550
+ requestBody ["before_id" ] = beforeID
551
+ }
552
+
553
+ // Since the go-github library might not have sub-issues support yet,
554
+ // we'll make a direct HTTP request using the client's HTTP client
555
+ reqBodyBytes , err := json .Marshal (requestBody )
556
+ if err != nil {
557
+ return nil , fmt .Errorf ("failed to marshal request body: %w" , err )
558
+ }
559
+
560
+ url := fmt .Sprintf ("%srepos/%s/%s/issues/%d/sub_issues/priority" ,
561
+ client .BaseURL .String (), owner , repo , issueNumber )
562
+ req , err := http .NewRequestWithContext (ctx , "PATCH" , url , strings .NewReader (string (reqBodyBytes )))
563
+ if err != nil {
564
+ return nil , fmt .Errorf ("failed to create request: %w" , err )
565
+ }
566
+
567
+ req .Header .Set ("Accept" , "application/vnd.github+json" )
568
+ req .Header .Set ("Content-Type" , "application/json" )
569
+ req .Header .Set ("X-GitHub-Api-Version" , "2022-11-28" )
570
+
571
+ // Use the same authentication as the GitHub client
572
+ httpClient := client .Client ()
573
+ resp , err := httpClient .Do (req )
574
+ if err != nil {
575
+ return nil , fmt .Errorf ("failed to reprioritize sub-issue: %w" , err )
576
+ }
577
+ defer func () { _ = resp .Body .Close () }()
578
+
579
+ body , err := io .ReadAll (resp .Body )
580
+ if err != nil {
581
+ return nil , fmt .Errorf ("failed to read response body: %w" , err )
582
+ }
583
+
584
+ if resp .StatusCode != http .StatusOK {
585
+ return mcp .NewToolResultError (fmt .Sprintf ("failed to reprioritize sub-issue: %s" , string (body ))), nil
586
+ }
587
+
588
+ // Parse and re-marshal to ensure consistent formatting
589
+ var result interface {}
590
+ if err := json .Unmarshal (body , & result ); err != nil {
591
+ return nil , fmt .Errorf ("failed to unmarshal response: %w" , err )
592
+ }
593
+
594
+ r , err := json .Marshal (result )
595
+ if err != nil {
596
+ return nil , fmt .Errorf ("failed to marshal response: %w" , err )
597
+ }
598
+
599
+ return mcp .NewToolResultText (string (r )), nil
600
+ }
601
+ }
602
+
470
603
// SearchIssues creates a tool to search for issues and pull requests.
471
604
func SearchIssues (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
472
605
return mcp .NewTool ("search_issues" ,
0 commit comments