6
6
"fmt"
7
7
"io"
8
8
"net/http"
9
- "strconv"
10
9
"strings"
11
10
"time"
12
11
@@ -1352,33 +1351,28 @@ type ClosingPullRequest struct {
1352
1351
// FindClosingPullRequests creates a tool to find pull requests that closed specific issues
1353
1352
func FindClosingPullRequests (getGQLClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
1354
1353
return mcp .NewTool ("find_closing_pull_requests" ,
1355
- mcp .WithDescription (t ("TOOL_FIND_CLOSING_PULL_REQUESTS_DESCRIPTION" , "Find pull requests that closed specific issues using closing references. Supports both single repository queries (owner/repo + issue_numbers array) and cross-repository queries (issue_references array) ." )),
1354
+ mcp .WithDescription (t ("TOOL_FIND_CLOSING_PULL_REQUESTS_DESCRIPTION" , "Find pull requests that closed specific issues using closing references within a repository." )),
1356
1355
mcp .WithToolAnnotation (mcp.ToolAnnotation {
1357
1356
Title : t ("TOOL_FIND_CLOSING_PULL_REQUESTS_USER_TITLE" , "Find closing pull requests" ),
1358
1357
ReadOnlyHint : ToBoolPtr (true ),
1359
1358
}),
1360
1359
mcp .WithString ("owner" ,
1361
- mcp .Description ("The owner of the repository (required if using issue_numbers)" ),
1360
+ mcp .Description ("The owner of the repository" ),
1361
+ mcp .Required (),
1362
1362
),
1363
1363
mcp .WithString ("repo" ,
1364
- mcp .Description ("The name of the repository (required if using issue_numbers)" ),
1364
+ mcp .Description ("The name of the repository" ),
1365
+ mcp .Required (),
1365
1366
),
1366
1367
mcp .WithArray ("issue_numbers" ,
1367
1368
mcp .Description ("Array of issue numbers within the specified repository" ),
1369
+ mcp .Required (),
1368
1370
mcp .Items (
1369
1371
map [string ]any {
1370
1372
"type" : "number" ,
1371
1373
},
1372
1374
),
1373
1375
),
1374
- mcp .WithArray ("issue_references" ,
1375
- mcp .Description ("Array of issue references in format 'owner/repo#number' for cross-repository queries" ),
1376
- mcp .Items (
1377
- map [string ]any {
1378
- "type" : "string" ,
1379
- },
1380
- ),
1381
- ),
1382
1376
mcp .WithNumber ("limit" ,
1383
1377
mcp .Description ("Maximum number of closing PRs to return per issue (default: 10, max: 100)" ),
1384
1378
),
@@ -1397,21 +1391,23 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
1397
1391
}
1398
1392
}
1399
1393
1400
- // Get optional parameters
1401
- owner , _ := OptionalParam [string ](request , "owner" )
1402
- repo , _ := OptionalParam [string ](request , "repo" )
1403
- issueNumbers , _ := OptionalIntArrayParam (request , "issue_numbers" )
1404
- issueReferences , _ := OptionalStringArrayParam (request , "issue_references" )
1405
-
1406
- // Validate input combinations
1407
- if len (issueNumbers ) == 0 && len (issueReferences ) == 0 {
1408
- return mcp .NewToolResultError ("either issue_numbers or issue_references must be provided" ), nil
1394
+ // Get required parameters
1395
+ owner , err := RequiredParam [string ](request , "owner" )
1396
+ if err != nil {
1397
+ return mcp .NewToolResultError (fmt .Sprintf ("owner parameter error: %s" , err .Error ())), nil
1398
+ }
1399
+ repo , err := RequiredParam [string ](request , "repo" )
1400
+ if err != nil {
1401
+ return mcp .NewToolResultError (fmt .Sprintf ("repo parameter error: %s" , err .Error ())), nil
1409
1402
}
1410
- if len (issueNumbers ) > 0 && len (issueReferences ) > 0 {
1411
- return mcp .NewToolResultError ("provide either issue_numbers OR issue_references, not both" ), nil
1403
+ issueNumbers , err := OptionalIntArrayParam (request , "issue_numbers" )
1404
+ if err != nil {
1405
+ return mcp .NewToolResultError (fmt .Sprintf ("issue_numbers parameter error: %s" , err .Error ())), nil
1412
1406
}
1413
- if len (issueNumbers ) > 0 && (owner == "" || repo == "" ) {
1414
- return mcp .NewToolResultError ("owner and repo are required when using issue_numbers" ), nil
1407
+
1408
+ // Validate that issue_numbers is not empty
1409
+ if len (issueNumbers ) == 0 {
1410
+ return mcp .NewToolResultError ("issue_numbers parameter is required and cannot be empty" ), nil
1415
1411
}
1416
1412
1417
1413
// Get GraphQL client
@@ -1420,39 +1416,16 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
1420
1416
return nil , fmt .Errorf ("failed to get GraphQL client: %w" , err )
1421
1417
}
1422
1418
1423
- var queries []IssueQuery
1424
-
1425
- // Build queries based on input type
1426
- if len (issueNumbers ) > 0 {
1427
- // Single repository, multiple issue numbers
1428
- for _ , issueNum := range issueNumbers {
1429
- queries = append (queries , IssueQuery {
1430
- Owner : owner ,
1431
- Repo : repo ,
1432
- IssueNumber : issueNum ,
1433
- })
1434
- }
1435
- } else {
1436
- // Multiple issue references
1437
- for _ , ref := range issueReferences {
1438
- parsed , err := parseIssueReference (ref )
1439
- if err != nil {
1440
- return mcp .NewToolResultError (fmt .Sprintf ("invalid issue reference '%s': %s" , ref , err .Error ())), nil
1441
- }
1442
- queries = append (queries , parsed )
1443
- }
1444
- }
1445
-
1446
- // Process each issue query
1419
+ // Process each issue number
1447
1420
var results []map [string ]interface {}
1448
- for _ , query := range queries {
1449
- result , err := queryClosingPRsForIssue (ctx , client , query . Owner , query . Repo , query . IssueNumber , limit )
1421
+ for _ , issueNum := range issueNumbers {
1422
+ result , err := queryClosingPRsForIssue (ctx , client , owner , repo , issueNum , limit )
1450
1423
if err != nil {
1451
1424
// Add error result for this issue
1452
1425
results = append (results , map [string ]interface {}{
1453
- "owner" : query . Owner ,
1454
- "repo" : query . Repo ,
1455
- "issue_number" : query . IssueNumber ,
1426
+ "owner" : owner ,
1427
+ "repo" : repo ,
1428
+ "issue_number" : issueNum ,
1456
1429
"error" : err .Error (),
1457
1430
"total_count" : 0 ,
1458
1431
"closing_pull_requests" : []ClosingPullRequest {},
@@ -1476,66 +1449,6 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
1476
1449
}
1477
1450
}
1478
1451
1479
- // IssueQuery represents a query for a specific issue
1480
- type IssueQuery struct {
1481
- Owner string
1482
- Repo string
1483
- IssueNumber int
1484
- }
1485
-
1486
- // parseIssueReference parses an issue reference in the format "owner/repo#number"
1487
- func parseIssueReference (ref string ) (IssueQuery , error ) {
1488
- if ref == "" {
1489
- return IssueQuery {}, fmt .Errorf ("invalid format, expected 'owner/repo#number'" )
1490
- }
1491
-
1492
- // Find the '#' separator
1493
- hashIndex := strings .LastIndex (ref , "#" )
1494
- if hashIndex == - 1 || hashIndex == len (ref )- 1 {
1495
- return IssueQuery {}, fmt .Errorf ("invalid format, expected 'owner/repo#number'" )
1496
- }
1497
-
1498
- // Split the repo part and issue number
1499
- repoPart := ref [:hashIndex ]
1500
- issueNumPart := ref [hashIndex + 1 :]
1501
-
1502
- // Check for multiple hash symbols (invalid case)
1503
- if strings .Count (ref , "#" ) > 1 {
1504
- return IssueQuery {}, fmt .Errorf ("invalid format, expected 'owner/repo#number'" )
1505
- }
1506
-
1507
- // Parse issue number
1508
- issueNum , err := strconv .Atoi (issueNumPart )
1509
- if err != nil {
1510
- return IssueQuery {}, fmt .Errorf ("invalid issue number: %s" , issueNumPart )
1511
- }
1512
-
1513
- // Check for negative or zero issue numbers (GitHub issue numbers are positive)
1514
- if issueNum <= 0 {
1515
- return IssueQuery {}, fmt .Errorf ("invalid issue number: %s" , issueNumPart )
1516
- }
1517
-
1518
- // Find the '/' separator in repo part
1519
- slashIndex := strings .Index (repoPart , "/" )
1520
- if slashIndex == - 1 || slashIndex == 0 || slashIndex == len (repoPart )- 1 {
1521
- return IssueQuery {}, fmt .Errorf ("invalid format, expected 'owner/repo#number'" )
1522
- }
1523
-
1524
- // Check for multiple slashes in repo part (invalid case like "owner/repo/extra")
1525
- if strings .Count (repoPart , "/" ) > 1 {
1526
- return IssueQuery {}, fmt .Errorf ("invalid format, expected 'owner/repo#number'" )
1527
- }
1528
-
1529
- owner := repoPart [:slashIndex ]
1530
- repo := repoPart [slashIndex + 1 :]
1531
-
1532
- return IssueQuery {
1533
- Owner : owner ,
1534
- Repo : repo ,
1535
- IssueNumber : issueNum ,
1536
- }, nil
1537
- }
1538
-
1539
1452
// queryClosingPRsForIssue queries closing PRs for a single issue
1540
1453
func queryClosingPRsForIssue (ctx context.Context , client * githubv4.Client , owner , repo string , issueNumber , limit int ) (map [string ]interface {}, error ) {
1541
1454
// Define the GraphQL query for this specific issue
0 commit comments