66 "fmt"
77 "io"
88 "net/http"
9- "strconv"
109 "strings"
1110 "time"
1211
@@ -1352,33 +1351,28 @@ type ClosingPullRequest struct {
13521351// FindClosingPullRequests creates a tool to find pull requests that closed specific issues
13531352func FindClosingPullRequests (getGQLClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
13541353 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." )),
13561355 mcp .WithToolAnnotation (mcp.ToolAnnotation {
13571356 Title : t ("TOOL_FIND_CLOSING_PULL_REQUESTS_USER_TITLE" , "Find closing pull requests" ),
13581357 ReadOnlyHint : ToBoolPtr (true ),
13591358 }),
13601359 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 (),
13621362 ),
13631363 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 (),
13651366 ),
13661367 mcp .WithArray ("issue_numbers" ,
13671368 mcp .Description ("Array of issue numbers within the specified repository" ),
1369+ mcp .Required (),
13681370 mcp .Items (
13691371 map [string ]any {
13701372 "type" : "number" ,
13711373 },
13721374 ),
13731375 ),
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- ),
13821376 mcp .WithNumber ("limit" ,
13831377 mcp .Description ("Maximum number of closing PRs to return per issue (default: 10, max: 100)" ),
13841378 ),
@@ -1397,21 +1391,23 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
13971391 }
13981392 }
13991393
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
14091402 }
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
14121406 }
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
14151411 }
14161412
14171413 // Get GraphQL client
@@ -1420,39 +1416,16 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
14201416 return nil , fmt .Errorf ("failed to get GraphQL client: %w" , err )
14211417 }
14221418
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
14471420 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 )
14501423 if err != nil {
14511424 // Add error result for this issue
14521425 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 ,
14561429 "error" : err .Error (),
14571430 "total_count" : 0 ,
14581431 "closing_pull_requests" : []ClosingPullRequest {},
@@ -1476,66 +1449,6 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
14761449 }
14771450}
14781451
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-
15391452// queryClosingPRsForIssue queries closing PRs for a single issue
15401453func queryClosingPRsForIssue (ctx context.Context , client * githubv4.Client , owner , repo string , issueNumber , limit int ) (map [string ]interface {}, error ) {
15411454 // Define the GraphQL query for this specific issue
0 commit comments