@@ -671,6 +671,8 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
671671 if err != nil {
672672 return utils .NewToolResultError (err .Error ()), nil , nil
673673 }
674+ originalRef := ref
675+
674676 sha , err := OptionalParam [string ](args , "sha" )
675677 if err != nil {
676678 return utils .NewToolResultError (err .Error ()), nil , nil
@@ -681,7 +683,7 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
681683 return utils .NewToolResultError ("failed to get GitHub client" ), nil , nil
682684 }
683685
684- rawOpts , err := resolveGitReference (ctx , client , owner , repo , ref , sha )
686+ rawOpts , fallbackUsed , err := resolveGitReference (ctx , client , owner , repo , ref , sha )
685687 if err != nil {
686688 return utils .NewToolResultError (fmt .Sprintf ("failed to resolve git reference: %s" , err )), nil , nil
687689 }
@@ -747,6 +749,12 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
747749 }
748750 }
749751
752+ // main branch ref passed in ref parameter but it doesn't exist - default branch was used
753+ var successNote string
754+ if fallbackUsed {
755+ successNote = fmt .Sprintf (" Note: the provided ref '%s' does not exist, default branch '%s' was used instead." , originalRef , rawOpts .Ref )
756+ }
757+
750758 // Determine if content is text or binary
751759 isTextContent := strings .HasPrefix (contentType , "text/" ) ||
752760 contentType == "application/json" ||
@@ -762,9 +770,9 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
762770 }
763771 // Include SHA in the result metadata
764772 if fileSHA != "" {
765- return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded text file (SHA: %s)" , fileSHA ), result ), nil , nil
773+ return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded text file (SHA: %s)" , fileSHA )+ successNote , result ), nil , nil
766774 }
767- return utils .NewToolResultResource ("successfully downloaded text file" , result ), nil , nil
775+ return utils .NewToolResultResource ("successfully downloaded text file" + successNote , result ), nil , nil
768776 }
769777
770778 result := & mcp.ResourceContents {
@@ -774,9 +782,9 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
774782 }
775783 // Include SHA in the result metadata
776784 if fileSHA != "" {
777- return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded binary file (SHA: %s)" , fileSHA ), result ), nil , nil
785+ return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded binary file (SHA: %s)" , fileSHA )+ successNote , result ), nil , nil
778786 }
779- return utils .NewToolResultResource ("successfully downloaded binary file" , result ), nil , nil
787+ return utils .NewToolResultResource ("successfully downloaded binary file" + successNote , result ), nil , nil
780788 }
781789
782790 // Raw API call failed
@@ -1876,15 +1884,15 @@ func looksLikeSHA(s string) bool {
18761884//
18771885// Any unexpected (non-404) errors during the resolution process are returned
18781886// immediately. All API errors are logged with rich context to aid diagnostics.
1879- func resolveGitReference (ctx context.Context , githubClient * github.Client , owner , repo , ref , sha string ) (* raw.ContentOpts , error ) {
1887+ func resolveGitReference (ctx context.Context , githubClient * github.Client , owner , repo , ref , sha string ) (* raw.ContentOpts , bool , error ) {
18801888 // 1) If SHA explicitly provided, it's the highest priority.
18811889 if sha != "" {
1882- return & raw.ContentOpts {Ref : "" , SHA : sha }, nil
1890+ return & raw.ContentOpts {Ref : "" , SHA : sha }, false , nil
18831891 }
18841892
18851893 // 1a) If sha is empty but ref looks like a SHA, return it without changes
18861894 if looksLikeSHA (ref ) {
1887- return & raw.ContentOpts {Ref : "" , SHA : ref }, nil
1895+ return & raw.ContentOpts {Ref : "" , SHA : ref }, false , nil
18881896 }
18891897
18901898 originalRef := ref // Keep original ref for clearer error messages down the line.
@@ -1893,16 +1901,16 @@ func resolveGitReference(ctx context.Context, githubClient *github.Client, owner
18931901 var reference * github.Reference
18941902 var resp * github.Response
18951903 var err error
1904+ var fallbackUsed bool
18961905
18971906 switch {
18981907 case originalRef == "" :
18991908 // 2a) If ref is empty, determine the default branch.
1900- repoInfo , resp , err := githubClient . Repositories . Get (ctx , owner , repo )
1909+ reference , err = resolveDefaultBranch (ctx , githubClient , owner , repo )
19011910 if err != nil {
1902- _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get repository info" , resp , err )
1903- return nil , fmt .Errorf ("failed to get repository info: %w" , err )
1911+ return nil , false , err // Error is already wrapped in resolveDefaultBranch.
19041912 }
1905- ref = fmt . Sprintf ( "refs/heads/%s" , repoInfo . GetDefaultBranch () )
1913+ ref = reference . GetRef ( )
19061914 case strings .HasPrefix (originalRef , "refs/" ):
19071915 // 2b) Already fully qualified. The reference will be fetched at the end.
19081916 case strings .HasPrefix (originalRef , "heads/" ) || strings .HasPrefix (originalRef , "tags/" ):
@@ -1928,19 +1936,26 @@ func resolveGitReference(ctx context.Context, githubClient *github.Client, owner
19281936 ghErr2 , isGhErr2 := err .(* github.ErrorResponse )
19291937 if isGhErr2 && ghErr2 .Response .StatusCode == http .StatusNotFound {
19301938 if originalRef == "main" {
1931- return nil , fmt .Errorf ("could not find branch or tag 'main'. Some repositories use 'master' as the default branch name" )
1939+ reference , err = resolveDefaultBranch (ctx , githubClient , owner , repo )
1940+ if err != nil {
1941+ return nil , false , err // Error is already wrapped in resolveDefaultBranch.
1942+ }
1943+ // Update ref to the actual default branch ref so the note can be generated
1944+ ref = reference .GetRef ()
1945+ fallbackUsed = true
1946+ break
19321947 }
1933- return nil , fmt .Errorf ("could not resolve ref %q as a branch or a tag" , originalRef )
1948+ return nil , false , fmt .Errorf ("could not resolve ref %q as a branch or a tag" , originalRef )
19341949 }
19351950
19361951 // The tag lookup failed for a different reason.
19371952 _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get reference (tag)" , resp , err )
1938- return nil , fmt .Errorf ("failed to get reference for tag '%s': %w" , originalRef , err )
1953+ return nil , false , fmt .Errorf ("failed to get reference for tag '%s': %w" , originalRef , err )
19391954 }
19401955 } else {
19411956 // The branch lookup failed for a different reason.
19421957 _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get reference (branch)" , resp , err )
1943- return nil , fmt .Errorf ("failed to get reference for branch '%s': %w" , originalRef , err )
1958+ return nil , false , fmt .Errorf ("failed to get reference for branch '%s': %w" , originalRef , err )
19441959 }
19451960 }
19461961 }
@@ -1949,15 +1964,48 @@ func resolveGitReference(ctx context.Context, githubClient *github.Client, owner
19491964 reference , resp , err = githubClient .Git .GetRef (ctx , owner , repo , ref )
19501965 if err != nil {
19511966 if ref == "refs/heads/main" {
1952- return nil , fmt .Errorf ("could not find branch 'main'. Some repositories use 'master' as the default branch name" )
1967+ reference , err = resolveDefaultBranch (ctx , githubClient , owner , repo )
1968+ if err != nil {
1969+ return nil , false , err // Error is already wrapped in resolveDefaultBranch.
1970+ }
1971+ // Update ref to the actual default branch ref so the note can be generated
1972+ ref = reference .GetRef ()
1973+ fallbackUsed = true
1974+ } else {
1975+ _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get final reference" , resp , err )
1976+ return nil , false , fmt .Errorf ("failed to get final reference for %q: %w" , ref , err )
19531977 }
1954- _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get final reference" , resp , err )
1955- return nil , fmt .Errorf ("failed to get final reference for %q: %w" , ref , err )
19561978 }
19571979 }
19581980
19591981 sha = reference .GetObject ().GetSHA ()
1960- return & raw.ContentOpts {Ref : ref , SHA : sha }, nil
1982+ return & raw.ContentOpts {Ref : ref , SHA : sha }, fallbackUsed , nil
1983+ }
1984+
1985+ func resolveDefaultBranch (ctx context.Context , githubClient * github.Client , owner , repo string ) (* github.Reference , error ) {
1986+ repoInfo , resp , err := githubClient .Repositories .Get (ctx , owner , repo )
1987+ if err != nil {
1988+ _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get repository info" , resp , err )
1989+ return nil , fmt .Errorf ("failed to get repository info: %w" , err )
1990+ }
1991+
1992+ if resp != nil && resp .Body != nil {
1993+ _ = resp .Body .Close ()
1994+ }
1995+
1996+ defaultBranch := repoInfo .GetDefaultBranch ()
1997+
1998+ defaultRef , resp , err := githubClient .Git .GetRef (ctx , owner , repo , "heads/" + defaultBranch )
1999+ if err != nil {
2000+ _ , _ = ghErrors .NewGitHubAPIErrorToCtx (ctx , "failed to get default branch reference" , resp , err )
2001+ return nil , fmt .Errorf ("failed to get default branch reference: %w" , err )
2002+ }
2003+
2004+ if resp != nil && resp .Body != nil {
2005+ defer func () { _ = resp .Body .Close () }()
2006+ }
2007+
2008+ return defaultRef , nil
19612009}
19622010
19632011// ListStarredRepositories creates a tool to list starred repositories for the authenticated user or a specified user.
0 commit comments