Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions pkg/errors/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package errors
import (
"context"
"fmt"
"net/http"

"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/go-github/v79/github"
Expand Down Expand Up @@ -44,10 +45,25 @@ func (e *GitHubGraphQLError) Error() string {
return fmt.Errorf("%s: %w", e.Message, e.Err).Error()
}

type GitHubRawAPIError struct {
Message string `json:"message"`
Response *http.Response `json:"-"`
Err error `json:"-"`
}

func newGitHubRawAPIError(message string, resp *http.Response, err error) *GitHubRawAPIError {
return &GitHubRawAPIError{
Message: message,
Response: resp,
Err: err,
Comment on lines +48 to +58
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHubRawAPIError type is missing an Error() string method for consistency with GitHubAPIError and GitHubGraphQLError. This method should be implemented to satisfy the error interface properly.

Add:

func (e *GitHubRawAPIError) Error() string {
	return fmt.Errorf("%s: %w", e.Message, e.Err).Error()
}

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +58
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new raw API error functionality lacks test coverage. Based on the testing patterns in error_test.go, tests should be added to cover:

  1. Adding raw API errors to context and retrieving them
  2. Accumulating multiple raw API errors
  3. The Error() method (once implemented)
  4. Integration with the existing error context system

This is important since other similar functionality (GitHubAPIError, GitHubGraphQLError) has comprehensive test coverage.

Copilot uses AI. Check for mistakes.
}
}

type GitHubErrorKey struct{}
type GitHubCtxErrors struct {
api []*GitHubAPIError
graphQL []*GitHubGraphQLError
raw []*GitHubRawAPIError
}

// ContextWithGitHubErrors updates or creates a context with a pointer to GitHub error information (to be used by middleware).
Expand Down Expand Up @@ -107,6 +123,15 @@ func addGitHubGraphQLErrorToContext(ctx context.Context, err *GitHubGraphQLError
return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
}

func addRawAPIErrorToContext(ctx context.Context, err *GitHubRawAPIError) (context.Context, error) {
if val, ok := ctx.Value(GitHubErrorKey{}).(*GitHubCtxErrors); ok {
val.raw = append(val.raw, err)
return ctx, nil
}

Comment on lines 124 to +131
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a public GetGitHubRawAPIErrors function to retrieve raw API errors from the context, for consistency with GetGitHubAPIErrors and GetGitHubGraphQLErrors. This function is needed to access the errors stored by NewGitHubRawAPIErrorResponse for metrics filtering purposes (as mentioned in the PR description).

Add after the existing getter functions:

// GetGitHubRawAPIErrors retrieves the slice of GitHubRawAPIErrors from the context.
func GetGitHubRawAPIErrors(ctx context.Context) ([]*GitHubRawAPIError, error) {
	if val, ok := ctx.Value(GitHubErrorKey{}).(*GitHubCtxErrors); ok {
		return val.raw, nil
	}
	return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
}

Copilot uses AI. Check for mistakes.
return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
}

// NewGitHubAPIErrorResponse returns an mcp.NewToolResultError and retains the error in the context for access via middleware
func NewGitHubAPIErrorResponse(ctx context.Context, message string, resp *github.Response, err error) *mcp.CallToolResult {
apiErr := newGitHubAPIError(message, resp, err)
Expand All @@ -124,3 +149,11 @@ func NewGitHubGraphQLErrorResponse(ctx context.Context, message string, err erro
}
return utils.NewToolResultErrorFromErr(message, err)
}

func NewGitHubRawAPIErrorResponse(ctx context.Context, message string, resp *http.Response, err error) *mcp.CallToolResult {
rawAPIErr := newGitHubRawAPIError(message, resp, err)
if ctx != nil {
_, _ = addRawAPIErrorToContext(ctx, rawAPIErr) // Explicitly ignore error for graceful handling
}
Comment on lines 151 to +157
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resp *http.Response parameter is accepted but never used. Unlike NewGitHubAPIErrorResponse which stores the response in the error struct, this function doesn't use it. Either:

  1. Store the response in GitHubRawAPIError (add a Response *http.Response field to the struct), or
  2. Remove the unused parameter if the response doesn't need to be stored for raw API errors

For consistency with GitHubAPIError, option 1 is recommended.

Copilot uses AI. Check for mistakes.
return utils.NewToolResultErrorFromErr(message, err)
}
2 changes: 1 addition & 1 deletion pkg/github/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
}
resp, err := rawClient.GetRawContent(ctx, owner, repo, path, rawOpts)
if err != nil {
return utils.NewToolResultError("failed to get raw repository content"), nil, nil
return ghErrors.NewGitHubRawAPIErrorResponse(ctx, "failed to get raw repository content", resp, err), nil, nil
}
defer func() {
_ = resp.Body.Close()
Expand Down