@@ -2,6 +2,7 @@ package github
22
33import (
44 "context"
5+ "encoding/base64"
56 "encoding/json"
67 "fmt"
78 "io"
@@ -715,86 +716,72 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
715716
716717 if fileContent != nil && fileContent .SHA != nil {
717718 fileSHA = * fileContent .SHA
718-
719- rawClient , err := deps .GetRawClient (ctx )
719+ fileSize := fileContent .GetSize ()
720+ // Build resource URI for the file using URI templates
721+ pathParts := strings .Split (path , "/" )
722+ resourceURI , err := expandRepoResourceURI (owner , repo , sha , ref , pathParts )
720723 if err != nil {
721- return utils .NewToolResultError ("failed to get GitHub raw content client " ), nil , nil
724+ return utils .NewToolResultError ("failed to build resource URI " ), nil , nil
722725 }
723- resp , err := rawClient .GetRawContent (ctx , owner , repo , path , rawOpts )
724- if err != nil {
725- return utils .NewToolResultError ("failed to get raw repository content" ), nil , nil
726+
727+ // main branch ref passed in ref parameter but it doesn't exist - default branch was used
728+ var successNote string
729+ if fallbackUsed {
730+ successNote = fmt .Sprintf (" Note: the provided ref '%s' does not exist, default branch '%s' was used instead." , originalRef , rawOpts .Ref )
726731 }
727- defer func () {
728- _ = resp .Body .Close ()
729- }()
730732
731- if resp .StatusCode == http .StatusOK {
732- // If the raw content is found, return it directly
733- body , err := io .ReadAll (resp .Body )
734- if err != nil {
735- return ghErrors .NewGitHubRawAPIErrorResponse (ctx , "failed to get raw repository content" , resp , err ), nil , nil
736- }
737- contentType := resp .Header .Get ("Content-Type" )
738-
739- var resourceURI string
740- switch {
741- case sha != "" :
742- resourceURI , err = url .JoinPath ("repo://" , owner , repo , "sha" , sha , "contents" , path )
743- if err != nil {
744- return nil , nil , fmt .Errorf ("failed to create resource URI: %w" , err )
745- }
746- case ref != "" :
747- resourceURI , err = url .JoinPath ("repo://" , owner , repo , ref , "contents" , path )
748- if err != nil {
749- return nil , nil , fmt .Errorf ("failed to create resource URI: %w" , err )
750- }
751- default :
752- resourceURI , err = url .JoinPath ("repo://" , owner , repo , "contents" , path )
753- if err != nil {
754- return nil , nil , fmt .Errorf ("failed to create resource URI: %w" , err )
755- }
733+ // For files >= 1MB, return a ResourceLink instead of content
734+ const maxContentSize = 1024 * 1024 // 1MB
735+ if fileSize >= maxContentSize {
736+ size := int64 (fileSize )
737+ resourceLink := & mcp.ResourceLink {
738+ URI : resourceURI ,
739+ Name : fileContent .GetName (),
740+ Title : fmt .Sprintf ("File: %s" , path ),
741+ Size : & size ,
756742 }
743+ return utils .NewToolResultResourceLink (
744+ fmt .Sprintf ("File %s is too large to display (%d bytes). Use the download URL to fetch the content: %s (SHA: %s)%s" ,
745+ path , fileSize , fileContent .GetDownloadURL (), fileSHA , successNote ),
746+ resourceLink ), nil , nil
747+ }
757748
758- // main branch ref passed in ref parameter but it doesn't exist - default branch was used
759- var successNote string
760- if fallbackUsed {
761- successNote = fmt .Sprintf (" Note: the provided ref '%s' does not exist, default branch '%s' was used instead." , originalRef , rawOpts . Ref )
762- }
749+ // For files < 1MB, get content directly from Contents API
750+ content , err := fileContent . GetContent ()
751+ if err != nil {
752+ return utils . NewToolResultError ( fmt .Sprintf ("failed to decode file content: %s" , err )), nil , nil
753+ }
763754
764- // Determine if content is text or binary
765- isTextContent := strings .HasPrefix (contentType , "text/" ) ||
766- contentType == "application/json" ||
767- contentType == "application/xml" ||
768- strings .HasSuffix (contentType , "+json" ) ||
769- strings .HasSuffix (contentType , "+xml" )
770-
771- if isTextContent {
772- result := & mcp.ResourceContents {
773- URI : resourceURI ,
774- Text : string (body ),
775- MIMEType : contentType ,
776- }
777- // Include SHA in the result metadata
778- if fileSHA != "" {
779- return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded text file (SHA: %s)" , fileSHA )+ successNote , result ), nil , nil
780- }
781- return utils .NewToolResultResource ("successfully downloaded text file" + successNote , result ), nil , nil
782- }
755+ // Detect content type from the actual content bytes,
756+ // mirroring the original approach of using the Content-Type header
757+ // from the raw API response.
758+ contentBytes := []byte (content )
759+ contentType := http .DetectContentType (contentBytes )
760+
761+ // Determine if content is text or binary based on detected content type
762+ isTextContent := strings .HasPrefix (contentType , "text/" ) ||
763+ contentType == "application/json" ||
764+ contentType == "application/xml" ||
765+ strings .HasSuffix (contentType , "+json" ) ||
766+ strings .HasSuffix (contentType , "+xml" )
783767
768+ if isTextContent {
784769 result := & mcp.ResourceContents {
785770 URI : resourceURI ,
786- Blob : body ,
771+ Text : content ,
787772 MIMEType : contentType ,
788773 }
789- // Include SHA in the result metadata
790- if fileSHA != "" {
791- return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded binary file (SHA: %s)" , fileSHA )+ successNote , result ), nil , nil
792- }
793- return utils .NewToolResultResource ("successfully downloaded binary file" + successNote , result ), nil , nil
774+ return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded text file (SHA: %s)%s" , fileSHA , successNote ), result ), nil , nil
794775 }
795776
796- // Raw API call failed
797- return matchFiles (ctx , client , owner , repo , ref , path , rawOpts , resp .StatusCode )
777+ // Binary content - encode as base64 blob
778+ blobContent := base64 .StdEncoding .EncodeToString (contentBytes )
779+ result := & mcp.ResourceContents {
780+ URI : resourceURI ,
781+ Blob : []byte (blobContent ),
782+ MIMEType : contentType ,
783+ }
784+ return utils .NewToolResultResource (fmt .Sprintf ("successfully downloaded binary file (SHA: %s)%s" , fileSHA , successNote ), result ), nil , nil
798785 } else if dirContent != nil {
799786 // file content or file SHA is nil which means it's a directory
800787 r , err := json .Marshal (dirContent )
0 commit comments