@@ -1441,6 +1441,73 @@ func GetLatestRelease(getClient GetClientFn, t translations.TranslationHelperFun
14411441 }
14421442}
14431443
1444+ // GetReleaseByTag creates a tool to get a specific release by its tag name in a GitHub repository.
1445+ func GetReleaseByTag (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
1446+ return mcp .NewTool ("get_release_by_tag" ,
1447+ mcp .WithDescription (t ("TOOL_GET_RELEASE_BY_TAG_DESCRIPTION" , "Get a specific release by its tag name in a GitHub repository" )),
1448+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
1449+ Title : t ("TOOL_GET_RELEASE_BY_TAG_USER_TITLE" , "Get a release by tag name" ),
1450+ ReadOnlyHint : ToBoolPtr (true ),
1451+ }),
1452+ mcp .WithString ("owner" ,
1453+ mcp .Required (),
1454+ mcp .Description ("Repository owner" ),
1455+ ),
1456+ mcp .WithString ("repo" ,
1457+ mcp .Required (),
1458+ mcp .Description ("Repository name" ),
1459+ ),
1460+ mcp .WithString ("tag" ,
1461+ mcp .Required (),
1462+ mcp .Description ("Tag name (e.g., 'v1.0.0')" ),
1463+ ),
1464+ ),
1465+ func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
1466+ owner , err := RequiredParam [string ](request , "owner" )
1467+ if err != nil {
1468+ return mcp .NewToolResultError (err .Error ()), nil
1469+ }
1470+ repo , err := RequiredParam [string ](request , "repo" )
1471+ if err != nil {
1472+ return mcp .NewToolResultError (err .Error ()), nil
1473+ }
1474+ tag , err := RequiredParam [string ](request , "tag" )
1475+ if err != nil {
1476+ return mcp .NewToolResultError (err .Error ()), nil
1477+ }
1478+
1479+ client , err := getClient (ctx )
1480+ if err != nil {
1481+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
1482+ }
1483+
1484+ release , resp , err := client .Repositories .GetReleaseByTag (ctx , owner , repo , tag )
1485+ if err != nil {
1486+ return ghErrors .NewGitHubAPIErrorResponse (ctx ,
1487+ fmt .Sprintf ("failed to get release by tag: %s" , tag ),
1488+ resp ,
1489+ err ,
1490+ ), nil
1491+ }
1492+ defer func () { _ = resp .Body .Close () }()
1493+
1494+ if resp .StatusCode != http .StatusOK {
1495+ body , err := io .ReadAll (resp .Body )
1496+ if err != nil {
1497+ return nil , fmt .Errorf ("failed to read response body: %w" , err )
1498+ }
1499+ return mcp .NewToolResultError (fmt .Sprintf ("failed to get release by tag: %s" , string (body ))), nil
1500+ }
1501+
1502+ r , err := json .Marshal (release )
1503+ if err != nil {
1504+ return nil , fmt .Errorf ("failed to marshal response: %w" , err )
1505+ }
1506+
1507+ return mcp .NewToolResultText (string (r )), nil
1508+ }
1509+ }
1510+
14441511// filterPaths filters the entries in a GitHub tree to find paths that
14451512// match the given suffix.
14461513// maxResults limits the number of results returned to first maxResults entries,
0 commit comments