From 3f52d21e286c985348d714d1e1c3bbd114861ea8 Mon Sep 17 00:00:00 2001 From: Ksenia Bobrova Date: Fri, 12 Dec 2025 11:47:37 +0100 Subject: [PATCH 1/5] Improvements & refactoring of get_file_contents --- .../__toolsnaps__/get_file_contents.snap | 2 +- pkg/github/repositories.go | 174 +++++++++--------- 2 files changed, 85 insertions(+), 91 deletions(-) diff --git a/pkg/github/__toolsnaps__/get_file_contents.snap b/pkg/github/__toolsnaps__/get_file_contents.snap index 767466dd3..638452fe7 100644 --- a/pkg/github/__toolsnaps__/get_file_contents.snap +++ b/pkg/github/__toolsnaps__/get_file_contents.snap @@ -17,7 +17,7 @@ }, "path": { "type": "string", - "description": "Path to file/directory (directories must end with a slash '/')", + "description": "Path to file/directory", "default": "/" }, "ref": { diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index ff81484f2..eebc496ca 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -560,7 +560,7 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t }, "path": { Type: "string", - Description: "Path to file/directory (directories must end with a slash '/')", + Description: "Path to file/directory", Default: json.RawMessage(`"/"`), }, "ref": { @@ -608,132 +608,126 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t return utils.NewToolResultError(fmt.Sprintf("failed to resolve git reference: %s", err)), nil, nil } + if rawOpts.SHA != "" { + ref = rawOpts.SHA + } + // 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. var rawAPIResponseCode int - 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, nil - } - if fileContent == nil || fileContent.SHA == nil { - return utils.NewToolResultError("file content SHA is nil, if a directory was requested, path parameters should end with a trailing slash '/'"), nil, nil - } - fileSHA = *fileContent.SHA + // First, get file info from Contents API to retrieve SHA + var fileSHA string + opts := &github.RepositoryContentGetOptions{Ref: ref} + fileContent, dirContent, 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, nil + } - rawClient, err := getRawClient(ctx) + // file content or file SHA is nil which means it's a directory + if fileContent == nil || fileContent.SHA == nil { + defer func() { _ = respContents.Body.Close() }() + r, err := json.Marshal(dirContent) if err != nil { - return utils.NewToolResultError("failed to get GitHub raw content client"), nil, nil + return utils.NewToolResultError("failed to marshal response"), nil, nil } - resp, err := rawClient.GetRawContent(ctx, owner, repo, path, rawOpts) + return utils.NewToolResultText(string(r)), nil, nil + } + + fileSHA = *fileContent.SHA + + rawClient, err := getRawClient(ctx) + if err != nil { + return utils.NewToolResultError("failed to get GitHub raw content client"), nil, nil + } + resp, err := rawClient.GetRawContent(ctx, owner, repo, path, rawOpts) + if err != nil { + return utils.NewToolResultError("failed to get raw repository content"), nil, nil + } + defer func() { + _ = resp.Body.Close() + }() + + if resp.StatusCode == http.StatusOK { + // If the raw content is found, return it directly + body, err := io.ReadAll(resp.Body) if err != nil { - return utils.NewToolResultError("failed to get raw repository content"), nil, nil + return utils.NewToolResultError("failed to read response body"), nil, nil } - defer func() { - _ = resp.Body.Close() - }() + contentType := resp.Header.Get("Content-Type") - if resp.StatusCode == http.StatusOK { - // If the raw content is found, return it directly - body, err := io.ReadAll(resp.Body) + var resourceURI string + switch { + case sha != "": + resourceURI, err = url.JoinPath("repo://", owner, repo, "sha", sha, "contents", path) if err != nil { - return utils.NewToolResultError("failed to read response body"), nil, nil + return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) } - contentType := resp.Header.Get("Content-Type") - - var resourceURI string - switch { - case sha != "": - resourceURI, err = url.JoinPath("repo://", owner, repo, "sha", sha, "contents", path) - if err != nil { - return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) - } - case ref != "": - resourceURI, err = url.JoinPath("repo://", owner, repo, ref, "contents", path) - if err != nil { - return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) - } - default: - resourceURI, err = url.JoinPath("repo://", owner, repo, "contents", path) - if err != nil { - return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) - } + case ref != "": + resourceURI, err = url.JoinPath("repo://", owner, repo, ref, "contents", path) + if err != nil { + return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) } - - // Determine if content is text or binary - isTextContent := strings.HasPrefix(contentType, "text/") || - contentType == "application/json" || - contentType == "application/xml" || - strings.HasSuffix(contentType, "+json") || - strings.HasSuffix(contentType, "+xml") - - if isTextContent { - result := &mcp.ResourceContents{ - URI: resourceURI, - Text: string(body), - MIMEType: contentType, - } - // Include SHA in the result metadata - if fileSHA != "" { - return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded text file (SHA: %s)", fileSHA), result), nil, nil - } - return utils.NewToolResultResource("successfully downloaded text file", result), nil, nil + default: + resourceURI, err = url.JoinPath("repo://", owner, repo, "contents", path) + if err != nil { + return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) } + } + + // Determine if content is text or binary + isTextContent := strings.HasPrefix(contentType, "text/") || + contentType == "application/json" || + contentType == "application/xml" || + strings.HasSuffix(contentType, "+json") || + strings.HasSuffix(contentType, "+xml") + if isTextContent { result := &mcp.ResourceContents{ URI: resourceURI, - Blob: body, + Text: string(body), MIMEType: contentType, } // Include SHA in the result metadata if fileSHA != "" { - return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded binary file (SHA: %s)", fileSHA), result), nil, nil + return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded text file (SHA: %s)", fileSHA), result), nil, nil } - return utils.NewToolResultResource("successfully downloaded binary file", result), nil, nil + return utils.NewToolResultResource("successfully downloaded text file", result), nil, nil } - rawAPIResponseCode = resp.StatusCode - } - if rawOpts.SHA != "" { - ref = rawOpts.SHA - } - if strings.HasSuffix(path, "/") { - opts := &github.RepositoryContentGetOptions{Ref: ref} - _, dirContent, resp, err := client.Repositories.GetContents(ctx, owner, repo, path, opts) - if err == nil && resp.StatusCode == http.StatusOK { - defer func() { _ = resp.Body.Close() }() - r, err := json.Marshal(dirContent) - if err != nil { - return utils.NewToolResultError("failed to marshal response"), nil, nil - } - return utils.NewToolResultText(string(r)), nil, nil + result := &mcp.ResourceContents{ + URI: resourceURI, + Blob: body, + MIMEType: contentType, + } + // Include SHA in the result metadata + if fileSHA != "" { + return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded binary file (SHA: %s)", fileSHA), result), nil, nil } + return utils.NewToolResultResource("successfully downloaded binary file", result), nil, nil } + rawAPIResponseCode = resp.StatusCode // The path does not point to a file or directory. // Instead let's try to find it in the Git Tree by matching the end of the path. // Step 1: Get Git Tree recursively - tree, resp, err := client.Git.GetTree(ctx, owner, repo, ref, true) + tree, response, err := client.Git.GetTree(ctx, owner, repo, ref, true) if err != nil { return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to get git tree", - resp, + response, err, ), nil, nil } - defer func() { _ = resp.Body.Close() }() + defer func() { _ = response.Body.Close() }() // Step 2: Filter tree for matching paths const maxMatchingFiles = 3 From ba2d7ce9638c26dec6457aff5e5dae9efcc59672 Mon Sep 17 00:00:00 2001 From: Ksenia Bobrova Date: Fri, 12 Dec 2025 12:28:01 +0100 Subject: [PATCH 2/5] Fix logical path when file or directory not found --- pkg/github/repositories.go | 185 ++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 96 deletions(-) diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index eebc496ca..6b5354024 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -623,128 +623,121 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t if respContents != nil { defer func() { _ = respContents.Body.Close() }() } - if err != nil { - return ghErrors.NewGitHubAPIErrorResponse(ctx, - "failed to get file SHA", - respContents, - err, - ), nil, nil - } - // file content or file SHA is nil which means it's a directory - if fileContent == nil || fileContent.SHA == nil { - defer func() { _ = respContents.Body.Close() }() - r, err := json.Marshal(dirContent) + // The path does not point to a file or directory. + // Instead let's try to find it in the Git Tree by matching the end of the path. + if err != nil || (fileContent == nil && dirContent == nil) { + // Step 1: Get Git Tree recursively + tree, response, err := client.Git.GetTree(ctx, owner, repo, ref, true) if err != nil { - return utils.NewToolResultError("failed to marshal response"), nil, nil + return ghErrors.NewGitHubAPIErrorResponse(ctx, + "failed to get git tree", + response, + err, + ), nil, nil } - return utils.NewToolResultText(string(r)), nil, nil - } + defer func() { _ = response.Body.Close() }() - fileSHA = *fileContent.SHA - - rawClient, err := getRawClient(ctx) - if err != nil { - return utils.NewToolResultError("failed to get GitHub raw content client"), nil, nil - } - resp, err := rawClient.GetRawContent(ctx, owner, repo, path, rawOpts) - if err != nil { - return utils.NewToolResultError("failed to get raw repository content"), nil, nil + // Step 2: Filter tree for matching paths + const maxMatchingFiles = 3 + matchingFiles := filterPaths(tree.Entries, path, maxMatchingFiles) + if len(matchingFiles) > 0 { + matchingFilesJSON, err := json.Marshal(matchingFiles) + if err != nil { + return utils.NewToolResultError(fmt.Sprintf("failed to marshal matching files: %s", err)), nil, nil + } + resolvedRefs, err := json.Marshal(rawOpts) + if err != nil { + return utils.NewToolResultError(fmt.Sprintf("failed to marshal resolved refs: %s", err)), nil, nil + } + return utils.NewToolResultError(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s), but the raw content API returned an unexpected status code %d.", string(resolvedRefs), string(matchingFilesJSON), rawAPIResponseCode)), nil, nil + } + return utils.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."), nil, nil } - defer func() { - _ = resp.Body.Close() - }() - if resp.StatusCode == http.StatusOK { - // If the raw content is found, return it directly - body, err := io.ReadAll(resp.Body) + if fileContent != nil && fileContent.SHA != nil { + fileSHA = *fileContent.SHA + + rawClient, err := getRawClient(ctx) if err != nil { - return utils.NewToolResultError("failed to read response body"), nil, nil + return utils.NewToolResultError("failed to get GitHub raw content client"), nil, nil } - contentType := resp.Header.Get("Content-Type") + resp, err := rawClient.GetRawContent(ctx, owner, repo, path, rawOpts) + if err != nil { + return utils.NewToolResultError("failed to get raw repository content"), nil, nil + } + defer func() { + _ = resp.Body.Close() + }() - var resourceURI string - switch { - case sha != "": - resourceURI, err = url.JoinPath("repo://", owner, repo, "sha", sha, "contents", path) + if resp.StatusCode == http.StatusOK { + // If the raw content is found, return it directly + body, err := io.ReadAll(resp.Body) if err != nil { - return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) + return utils.NewToolResultError("failed to read response body"), nil, nil } - case ref != "": - resourceURI, err = url.JoinPath("repo://", owner, repo, ref, "contents", path) - if err != nil { - return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) - } - default: - resourceURI, err = url.JoinPath("repo://", owner, repo, "contents", path) - if err != nil { - return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) + contentType := resp.Header.Get("Content-Type") + + var resourceURI string + switch { + case sha != "": + resourceURI, err = url.JoinPath("repo://", owner, repo, "sha", sha, "contents", path) + if err != nil { + return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) + } + case ref != "": + resourceURI, err = url.JoinPath("repo://", owner, repo, ref, "contents", path) + if err != nil { + return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) + } + default: + resourceURI, err = url.JoinPath("repo://", owner, repo, "contents", path) + if err != nil { + return nil, nil, fmt.Errorf("failed to create resource URI: %w", err) + } } - } - // Determine if content is text or binary - isTextContent := strings.HasPrefix(contentType, "text/") || - contentType == "application/json" || - contentType == "application/xml" || - strings.HasSuffix(contentType, "+json") || - strings.HasSuffix(contentType, "+xml") + // Determine if content is text or binary + isTextContent := strings.HasPrefix(contentType, "text/") || + contentType == "application/json" || + contentType == "application/xml" || + strings.HasSuffix(contentType, "+json") || + strings.HasSuffix(contentType, "+xml") + + if isTextContent { + result := &mcp.ResourceContents{ + URI: resourceURI, + Text: string(body), + MIMEType: contentType, + } + // Include SHA in the result metadata + if fileSHA != "" { + return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded text file (SHA: %s)", fileSHA), result), nil, nil + } + return utils.NewToolResultResource("successfully downloaded text file", result), nil, nil + } - if isTextContent { result := &mcp.ResourceContents{ URI: resourceURI, - Text: string(body), + Blob: body, MIMEType: contentType, } // Include SHA in the result metadata if fileSHA != "" { - return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded text file (SHA: %s)", fileSHA), result), nil, nil + return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded binary file (SHA: %s)", fileSHA), result), nil, nil } - return utils.NewToolResultResource("successfully downloaded text file", result), nil, nil - } - - result := &mcp.ResourceContents{ - URI: resourceURI, - Blob: body, - MIMEType: contentType, - } - // Include SHA in the result metadata - if fileSHA != "" { - return utils.NewToolResultResource(fmt.Sprintf("successfully downloaded binary file (SHA: %s)", fileSHA), result), nil, nil - } - return utils.NewToolResultResource("successfully downloaded binary file", result), nil, nil - } - rawAPIResponseCode = resp.StatusCode - - // The path does not point to a file or directory. - // Instead let's try to find it in the Git Tree by matching the end of the path. - - // Step 1: Get Git Tree recursively - tree, response, err := client.Git.GetTree(ctx, owner, repo, ref, true) - if err != nil { - return ghErrors.NewGitHubAPIErrorResponse(ctx, - "failed to get git tree", - response, - err, - ), nil, nil - } - defer func() { _ = response.Body.Close() }() - - // Step 2: Filter tree for matching paths - const maxMatchingFiles = 3 - matchingFiles := filterPaths(tree.Entries, path, maxMatchingFiles) - if len(matchingFiles) > 0 { - matchingFilesJSON, err := json.Marshal(matchingFiles) - if err != nil { - return utils.NewToolResultError(fmt.Sprintf("failed to marshal matching files: %s", err)), nil, nil + return utils.NewToolResultResource("successfully downloaded binary file", result), nil, nil } - resolvedRefs, err := json.Marshal(rawOpts) + } else if dirContent != nil { + // file content or file SHA is nil which means it's a directory + r, err := json.Marshal(dirContent) if err != nil { - return utils.NewToolResultError(fmt.Sprintf("failed to marshal resolved refs: %s", err)), nil, nil + return utils.NewToolResultError("failed to marshal response"), nil, nil } - return utils.NewToolResultError(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s), but the raw content API returned an unexpected status code %d.", string(resolvedRefs), string(matchingFilesJSON), rawAPIResponseCode)), nil, nil + return utils.NewToolResultText(string(r)), nil, nil } - return utils.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."), nil, nil + return utils.NewToolResultError("failed to get file contents"), nil, nil }) return tool, handler From 3e01bb1def37e663caeeef7188660e0472d01f4b Mon Sep 17 00:00:00 2001 From: Ksenia Bobrova Date: Fri, 12 Dec 2025 12:38:59 +0100 Subject: [PATCH 3/5] Fix comment --- pkg/github/repositories.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index 6b5354024..58ecaf5a9 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -612,13 +612,11 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t ref = rawOpts.SHA } - // 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. - var rawAPIResponseCode int - // First, get file info from Contents API to retrieve SHA var fileSHA string opts := &github.RepositoryContentGetOptions{Ref: ref} + + // Always call GitHub Contents API first to get metadata including SHA and determine if it's a file or directory fileContent, dirContent, respContents, err := client.Repositories.GetContents(ctx, owner, repo, path, opts) if respContents != nil { defer func() { _ = respContents.Body.Close() }() From f6632149539d9be8512231e9bc8ab8f1345e2a9f Mon Sep 17 00:00:00 2001 From: Ksenia Bobrova Date: Fri, 12 Dec 2025 12:44:56 +0100 Subject: [PATCH 4/5] Docs update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7243033b..f0d31f0be 100644 --- a/README.md +++ b/README.md @@ -1092,7 +1092,7 @@ Possible options: - **get_file_contents** - Get file or directory contents - `owner`: Repository owner (username or organization) (string, required) - - `path`: Path to file/directory (directories must end with a slash '/') (string, optional) + - `path`: Path to file/directory (string, optional) - `ref`: Accepts optional git refs such as `refs/tags/{tag}`, `refs/heads/{branch}` or `refs/pull/{pr_number}/head` (string, optional) - `repo`: Repository name (string, required) - `sha`: Accepts optional commit SHA. If specified, it will be used instead of ref (string, optional) From a3460a96889f00325927937d612bf7372de1e641 Mon Sep 17 00:00:00 2001 From: Ksenia Bobrova Date: Fri, 12 Dec 2025 17:25:34 +0100 Subject: [PATCH 5/5] Do file matching when raw API returns error --- pkg/github/repositories.go | 63 ++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index 58ecaf5a9..e5f6ec0c1 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -612,7 +612,6 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t ref = rawOpts.SHA } - var rawAPIResponseCode int var fileSHA string opts := &github.RepositoryContentGetOptions{Ref: ref} @@ -625,32 +624,7 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t // The path does not point to a file or directory. // Instead let's try to find it in the Git Tree by matching the end of the path. if err != nil || (fileContent == nil && dirContent == nil) { - // Step 1: Get Git Tree recursively - tree, response, err := client.Git.GetTree(ctx, owner, repo, ref, true) - if err != nil { - return ghErrors.NewGitHubAPIErrorResponse(ctx, - "failed to get git tree", - response, - err, - ), nil, nil - } - defer func() { _ = response.Body.Close() }() - - // Step 2: Filter tree for matching paths - const maxMatchingFiles = 3 - matchingFiles := filterPaths(tree.Entries, path, maxMatchingFiles) - if len(matchingFiles) > 0 { - matchingFilesJSON, err := json.Marshal(matchingFiles) - if err != nil { - return utils.NewToolResultError(fmt.Sprintf("failed to marshal matching files: %s", err)), nil, nil - } - resolvedRefs, err := json.Marshal(rawOpts) - if err != nil { - return utils.NewToolResultError(fmt.Sprintf("failed to marshal resolved refs: %s", err)), nil, nil - } - return utils.NewToolResultError(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s), but the raw content API returned an unexpected status code %d.", string(resolvedRefs), string(matchingFilesJSON), rawAPIResponseCode)), nil, nil - } - return utils.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."), nil, nil + return matchFiles(ctx, client, owner, repo, ref, path, rawOpts, 0) } if fileContent != nil && fileContent.SHA != nil { @@ -726,6 +700,9 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t } return utils.NewToolResultResource("successfully downloaded binary file", result), nil, nil } + + // Raw API call failed + return matchFiles(ctx, client, owner, repo, ref, path, rawOpts, resp.StatusCode) } else if dirContent != nil { // file content or file SHA is nil which means it's a directory r, err := json.Marshal(dirContent) @@ -2100,3 +2077,35 @@ func UnstarRepository(getClient GetClientFn, t translations.TranslationHelperFun return tool, handler } + +func matchFiles(ctx context.Context, client *github.Client, owner, repo, ref, path string, rawOpts *raw.ContentOpts, rawAPIResponseCode int) (*mcp.CallToolResult, any, error) { + // Step 1: Get Git Tree recursively + tree, response, err := client.Git.GetTree(ctx, owner, repo, ref, true) + if err != nil { + return ghErrors.NewGitHubAPIErrorResponse(ctx, + "failed to get git tree", + response, + err, + ), nil, nil + } + defer func() { _ = response.Body.Close() }() + + // Step 2: Filter tree for matching paths + const maxMatchingFiles = 3 + matchingFiles := filterPaths(tree.Entries, path, maxMatchingFiles) + if len(matchingFiles) > 0 { + matchingFilesJSON, err := json.Marshal(matchingFiles) + if err != nil { + return utils.NewToolResultError(fmt.Sprintf("failed to marshal matching files: %s", err)), nil, nil + } + resolvedRefs, err := json.Marshal(rawOpts) + if err != nil { + return utils.NewToolResultError(fmt.Sprintf("failed to marshal resolved refs: %s", err)), nil, nil + } + if rawAPIResponseCode > 0 { + return utils.NewToolResultText(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s), but the content API returned an unexpected status code %d.", string(resolvedRefs), string(matchingFilesJSON), rawAPIResponseCode)), nil, nil + } + return utils.NewToolResultText(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s).", string(resolvedRefs), string(matchingFilesJSON))), nil, nil + } + return utils.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."), nil, nil +}