88 "io"
99 "net/http"
1010 "net/url"
11+ "strconv"
1112 "strings"
1213
1314 "github.com/github/github-mcp-server/pkg/raw"
@@ -432,8 +433,11 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
432433 mcp .Required (),
433434 mcp .Description ("Path to file/directory (directories must end with a slash '/')" ),
434435 ),
435- mcp .WithString ("branch" ,
436- mcp .Description ("Branch to get contents from" ),
436+ mcp .WithString ("ref" ,
437+ mcp .Description ("Accepts optional git refs such as `refs/tags/<tag>`, `refs/heads/<branch>` or `refs/pull/<pr_number>/head`" ),
438+ ),
439+ mcp .WithString ("sha" ,
440+ mcp .Description ("Accepts optional git sha, if sha is specified it will be used instead of ref" ),
437441 ),
438442 ),
439443 func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
@@ -449,17 +453,44 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
449453 if err != nil {
450454 return mcp .NewToolResultError (err .Error ()), nil
451455 }
452- branch , err := OptionalParam [string ](request , "branch" )
456+ ref , err := OptionalParam [string ](request , "ref" )
457+ if err != nil {
458+ return mcp .NewToolResultError (err .Error ()), nil
459+ }
460+ sha , err := OptionalParam [string ](request , "sha" )
453461 if err != nil {
454462 return mcp .NewToolResultError (err .Error ()), nil
455463 }
456464
465+ rawOpts := & raw.RawContentOpts {}
466+
467+ if strings .HasPrefix (path , "refs/pull/" ) {
468+ prNumber , ok := strings .CutPrefix (path , "refs/pull/" )
469+ if ok && len (prNumber ) > 0 {
470+ // fetch the PR from the API to get the latest commit and use SHA
471+ githubClient , err := getClient (ctx )
472+ if err != nil {
473+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
474+ }
475+ prNum , err := strconv .Atoi (prNumber )
476+ if err != nil {
477+ return nil , fmt .Errorf ("invalid pull request number: %w" , err )
478+ }
479+ pr , _ , err := githubClient .PullRequests .Get (ctx , owner , repo , prNum )
480+ if err != nil {
481+ return nil , fmt .Errorf ("failed to get pull request: %w" , err )
482+ }
483+ sha = pr .GetHead ().GetSHA ()
484+ ref = ""
485+ }
486+ }
487+
488+ rawOpts .SHA = sha
489+ rawOpts .Ref = ref
490+
457491 // If the path is (most likely) not to be a directory, we will first try to get the raw content from the GitHub raw content API.
458492 if path != "" && ! strings .HasSuffix (path , "/" ) {
459- rawOpts := & raw.RawContentOpts {}
460- if branch != "" {
461- rawOpts .Ref = "refs/heads/" + branch
462- }
493+
463494 rawClient , err := getRawClient (ctx )
464495 if err != nil {
465496 return mcp .NewToolResultError ("failed to get GitHub raw content client" ), nil
@@ -483,14 +514,19 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
483514 contentType := resp .Header .Get ("Content-Type" )
484515
485516 var resourceURI string
486- if branch = = "" {
517+ if sha ! = "" {
487518 // do a safe url join
488- resourceURI , err = url .JoinPath ("repo://" , owner , repo , "contents" , path )
519+ resourceURI , err = url .JoinPath ("repo://" , owner , repo , "sha" , sha , "contents" , path )
520+ if err != nil {
521+ return nil , fmt .Errorf ("failed to create resource URI: %w" , err )
522+ }
523+ } else if ref != "" {
524+ resourceURI , err = url .JoinPath ("repo://" , owner , repo , ref , "contents" , path )
489525 if err != nil {
490526 return nil , fmt .Errorf ("failed to create resource URI: %w" , err )
491527 }
492528 } else {
493- resourceURI , err = url .JoinPath ("repo://" , owner , repo , "refs" , "heads" , branch , " contents" , path )
529+ resourceURI , err = url .JoinPath ("repo://" , owner , repo , "contents" , path )
494530 if err != nil {
495531 return nil , fmt .Errorf ("failed to create resource URI: %w" , err )
496532 }
@@ -517,8 +553,11 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
517553 return mcp .NewToolResultError ("failed to get GitHub client" ), nil
518554 }
519555
556+ if sha != "" {
557+ ref = sha
558+ }
520559 if strings .HasSuffix (path , "/" ) {
521- opts := & github.RepositoryContentGetOptions {Ref : branch }
560+ opts := & github.RepositoryContentGetOptions {Ref : ref }
522561 _ , dirContent , resp , err := client .Repositories .GetContents (ctx , owner , repo , path , opts )
523562 if err != nil {
524563 return mcp .NewToolResultError ("failed to get file contents" ), nil
0 commit comments