diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index 58e4a7421..2e56c8644 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -507,6 +507,24 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t // 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. if path != "" && !strings.HasSuffix(path, "/") { + // First, get file info from Contents API to retrieve SHA + var fileSHA string + opts := &github.RepositoryContentGetOptions{Ref: ref} + fileContent, _, respContents, err := client.Repositories.GetContents(ctx, owner, repo, path, opts) + if respContents != nil { + defer func() { _ = respContents.Body.Close() }() + } + if err != nil { + return ghErrors.NewGitHubAPIErrorResponse(ctx, + "failed to get file SHA", + respContents, + err, + ), nil + } + if fileContent == nil || fileContent.SHA == nil { + return mcp.NewToolResultError("file content SHA is nil"), nil + } + fileSHA = *fileContent.SHA rawClient, err := getRawClient(ctx) if err != nil { @@ -548,18 +566,28 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t } if strings.HasPrefix(contentType, "application") || strings.HasPrefix(contentType, "text") { - return mcp.NewToolResultResource("successfully downloaded text file", mcp.TextResourceContents{ + result := mcp.TextResourceContents{ URI: resourceURI, Text: string(body), MIMEType: contentType, - }), nil + } + // Include SHA in the result metadata + if fileSHA != "" { + return mcp.NewToolResultResource(fmt.Sprintf("successfully downloaded text file (SHA: %s)", fileSHA), result), nil + } + return mcp.NewToolResultResource("successfully downloaded text file", result), nil } - return mcp.NewToolResultResource("successfully downloaded binary file", mcp.BlobResourceContents{ + result := mcp.BlobResourceContents{ URI: resourceURI, Blob: base64.StdEncoding.EncodeToString(body), MIMEType: contentType, - }), nil + } + // Include SHA in the result metadata + if fileSHA != "" { + return mcp.NewToolResultResource(fmt.Sprintf("successfully downloaded binary file (SHA: %s)", fileSHA), result), nil + } + return mcp.NewToolResultResource("successfully downloaded binary file", result), nil } } diff --git a/pkg/github/repositories_test.go b/pkg/github/repositories_test.go index 0633e2123..1572a12f4 100644 --- a/pkg/github/repositories_test.go +++ b/pkg/github/repositories_test.go @@ -76,6 +76,20 @@ func Test_GetFileContents(t *testing.T) { _, _ = w.Write([]byte(`{"ref": "refs/heads/main", "object": {"sha": ""}}`)) }), ), + mock.WithRequestMatchHandler( + mock.GetReposContentsByOwnerByRepoByPath, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + fileContent := &github.RepositoryContent{ + Name: github.Ptr("README.md"), + Path: github.Ptr("README.md"), + SHA: github.Ptr("abc123"), + Type: github.Ptr("file"), + } + contentBytes, _ := json.Marshal(fileContent) + _, _ = w.Write(contentBytes) + }), + ), mock.WithRequestMatchHandler( raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { @@ -107,6 +121,20 @@ func Test_GetFileContents(t *testing.T) { _, _ = w.Write([]byte(`{"ref": "refs/heads/main", "object": {"sha": ""}}`)) }), ), + mock.WithRequestMatchHandler( + mock.GetReposContentsByOwnerByRepoByPath, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + fileContent := &github.RepositoryContent{ + Name: github.Ptr("test.png"), + Path: github.Ptr("test.png"), + SHA: github.Ptr("def456"), + Type: github.Ptr("file"), + } + contentBytes, _ := json.Marshal(fileContent) + _, _ = w.Write(contentBytes) + }), + ), mock.WithRequestMatchHandler( raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy