Repository: github/github-mcp-server

Issue:
Enable concise responses to API requests
### Describe the feature or problem you’d like to solve

When creating a PR, the response contains hundreds of lines of text.
That's incredibly wasteful of the TCW, of I/O tokens (economics), and is a lot of noise for the LLM instance (this is an MCP server, so it's the LLM instance dealing with all of those tokens).

### Proposed solution

Providing a means to specify that a concise response will be provided would eliminate wasted tokens.

### Example prompts or workflows (for tools/toolsets only)

I pushed.  Can you create the Pull Request?  I've also updated the .profile for Git-Bash, so... hopefully that will address
  the request for authentication of ssh

● github - Open new pull request (MCP)(owner:
...
 {
       "id": 2769466452,
       "number": 2,
     … +322 lines (ctrl+r to expand)

### Additional context




Discussion:

Solution patch:
diff --git a/README.md b/README.md
index a6e740e..b9f31ee 100644
--- a/README.md
+++ b/README.md
@@ -830,6 +830,7 @@ The following sets of tools are available (all are on by default):
   - `repo`: Repository name (string, required)
 
 - **get_commit** - Get commit details
+  - `include_diff`: Whether to include file diffs and stats in the response. Default is true. (boolean, optional)
   - `owner`: Repository owner (string, required)
   - `page`: Page number for pagination (min 1) (number, optional)
   - `perPage`: Results per page for pagination (min 1, max 100) (number, optional)
@@ -898,6 +899,7 @@ The following sets of tools are available (all are on by default):
   - `sort`: Sort field ('indexed' only) (string, optional)
 
 - **search_repositories** - Search repositories
+  - `minimal_output`: Return minimal repository information (default: true). When false, returns full GitHub API repository objects. (boolean, optional)
   - `page`: Page number for pagination (min 1) (number, optional)
   - `perPage`: Results per page for pagination (min 1, max 100) (number, optional)
   - `query`: Repository search query. Examples: 'machine learning in:name stars:>1000 language:python', 'topic:react', 'user:facebook'. Supports advanced search syntax for precise filtering. (string, required)
diff --git a/pkg/github/__toolsnaps__/get_commit.snap b/pkg/github/__toolsnaps__/get_commit.snap
index af00381..1c2ecc9 100644
--- a/pkg/github/__toolsnaps__/get_commit.snap
+++ b/pkg/github/__toolsnaps__/get_commit.snap
@@ -6,6 +6,11 @@
   "description": "Get details for a commit from a GitHub repository",
   "inputSchema": {
     "properties": {
+      "include_diff": {
+        "default": true,
+        "description": "Whether to include file diffs and stats in the response. Default is true.",
+        "type": "boolean"
+      },
       "owner": {
         "description": "Repository owner",
         "type": "string"
diff --git a/pkg/github/__toolsnaps__/search_repositories.snap b/pkg/github/__toolsnaps__/search_repositories.snap
index d283a2c..f350c8e 100644
--- a/pkg/github/__toolsnaps__/search_repositories.snap
+++ b/pkg/github/__toolsnaps__/search_repositories.snap
@@ -6,6 +6,11 @@
   "description": "Find GitHub repositories by name, description, readme, topics, or other metadata. Perfect for discovering projects, finding examples, or locating specific repositories across GitHub.",
   "inputSchema": {
     "properties": {
+      "minimal_output": {
+        "default": true,
+        "description": "Return minimal repository information (default: true). When false, returns full GitHub API repository objects.",
+        "type": "boolean"
+      },
       "page": {
         "description": "Page number for pagination (min 1)",
         "minimum": 1,
diff --git a/pkg/github/gists.go b/pkg/github/gists.go
index fce34f6..3f1645f 100644
--- a/pkg/github/gists.go
+++ b/pkg/github/gists.go
@@ -165,7 +165,11 @@ func CreateGist(getClient GetClientFn, t translations.TranslationHelperFunc) (to
 				return mcp.NewToolResultError(fmt.Sprintf("failed to create gist: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(createdGist)
+			minimalResponse := MinimalResponse{
+				URL: createdGist.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -249,7 +253,11 @@ func UpdateGist(getClient GetClientFn, t translations.TranslationHelperFunc) (to
 				return mcp.NewToolResultError(fmt.Sprintf("failed to update gist: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(updatedGist)
+			minimalResponse := MinimalResponse{
+				URL: updatedGist.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
diff --git a/pkg/github/issues.go b/pkg/github/issues.go
index 89375ae..01ce7b4 100644
--- a/pkg/github/issues.go
+++ b/pkg/github/issues.go
@@ -872,7 +872,12 @@ func CreateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
 				return mcp.NewToolResultError(fmt.Sprintf("failed to create issue: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(issue)
+			// Return minimal response with just essential information
+			minimalResponse := MinimalResponse{
+				URL: issue.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -1242,7 +1247,12 @@ func UpdateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
 				return mcp.NewToolResultError(fmt.Sprintf("failed to update issue: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(updatedIssue)
+			// Return minimal response with just essential information
+			minimalResponse := MinimalResponse{
+				URL: updatedIssue.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
diff --git a/pkg/github/minimal_types.go b/pkg/github/minimal_types.go
new file mode 100644
index 0000000..0c3c220
--- /dev/null
+++ b/pkg/github/minimal_types.go
@@ -0,0 +1,204 @@
+package github
+
+import "github.com/google/go-github/v74/github"
+
+// MinimalUser is the output type for user and organization search results.
+type MinimalUser struct {
+	Login      string       `json:"login"`
+	ID         int64        `json:"id,omitempty"`
+	ProfileURL string       `json:"profile_url,omitempty"`
+	AvatarURL  string       `json:"avatar_url,omitempty"`
+	Details    *UserDetails `json:"details,omitempty"` // Optional field for additional user details
+}
+
+// MinimalSearchUsersResult is the trimmed output type for user search results.
+type MinimalSearchUsersResult struct {
+	TotalCount        int           `json:"total_count"`
+	IncompleteResults bool          `json:"incomplete_results"`
+	Items             []MinimalUser `json:"items"`
+}
+
+// MinimalRepository is the trimmed output type for repository objects to reduce verbosity.
+type MinimalRepository struct {
+	ID            int64    `json:"id"`
+	Name          string   `json:"name"`
+	FullName      string   `json:"full_name"`
+	Description   string   `json:"description,omitempty"`
+	HTMLURL       string   `json:"html_url"`
+	Language      string   `json:"language,omitempty"`
+	Stars         int      `json:"stargazers_count"`
+	Forks         int      `json:"forks_count"`
+	OpenIssues    int      `json:"open_issues_count"`
+	UpdatedAt     string   `json:"updated_at,omitempty"`
+	CreatedAt     string   `json:"created_at,omitempty"`
+	Topics        []string `json:"topics,omitempty"`
+	Private       bool     `json:"private"`
+	Fork          bool     `json:"fork"`
+	Archived      bool     `json:"archived"`
+	DefaultBranch string   `json:"default_branch,omitempty"`
+}
+
+// MinimalSearchRepositoriesResult is the trimmed output type for repository search results.
+type MinimalSearchRepositoriesResult struct {
+	TotalCount        int                 `json:"total_count"`
+	IncompleteResults bool                `json:"incomplete_results"`
+	Items             []MinimalRepository `json:"items"`
+}
+
+// MinimalCommitAuthor represents commit author information.
+type MinimalCommitAuthor struct {
+	Name  string `json:"name,omitempty"`
+	Email string `json:"email,omitempty"`
+	Date  string `json:"date,omitempty"`
+}
+
+// MinimalCommitInfo represents core commit information.
+type MinimalCommitInfo struct {
+	Message   string               `json:"message"`
+	Author    *MinimalCommitAuthor `json:"author,omitempty"`
+	Committer *MinimalCommitAuthor `json:"committer,omitempty"`
+}
+
+// MinimalCommitStats represents commit statistics.
+type MinimalCommitStats struct {
+	Additions int `json:"additions,omitempty"`
+	Deletions int `json:"deletions,omitempty"`
+	Total     int `json:"total,omitempty"`
+}
+
+// MinimalCommitFile represents a file changed in a commit.
+type MinimalCommitFile struct {
+	Filename  string `json:"filename"`
+	Status    string `json:"status,omitempty"`
+	Additions int    `json:"additions,omitempty"`
+	Deletions int    `json:"deletions,omitempty"`
+	Changes   int    `json:"changes,omitempty"`
+}
+
+// MinimalCommit is the trimmed output type for commit objects.
+type MinimalCommit struct {
+	SHA       string              `json:"sha"`
+	HTMLURL   string              `json:"html_url"`
+	Commit    *MinimalCommitInfo  `json:"commit,omitempty"`
+	Author    *MinimalUser        `json:"author,omitempty"`
+	Committer *MinimalUser        `json:"committer,omitempty"`
+	Stats     *MinimalCommitStats `json:"stats,omitempty"`
+	Files     []MinimalCommitFile `json:"files,omitempty"`
+}
+
+// MinimalRelease is the trimmed output type for release objects.
+type MinimalRelease struct {
+	ID          int64        `json:"id"`
+	TagName     string       `json:"tag_name"`
+	Name        string       `json:"name,omitempty"`
+	Body        string       `json:"body,omitempty"`
+	HTMLURL     string       `json:"html_url"`
+	PublishedAt string       `json:"published_at,omitempty"`
+	Prerelease  bool         `json:"prerelease"`
+	Draft       bool         `json:"draft"`
+	Author      *MinimalUser `json:"author,omitempty"`
+}
+
+// MinimalBranch is the trimmed output type for branch objects.
+type MinimalBranch struct {
+	Name      string `json:"name"`
+	SHA       string `json:"sha"`
+	Protected bool   `json:"protected"`
+}
+
+// MinimalResponse represents a minimal response for all CRUD operations.
+// Success is implicit in the HTTP response status, and all other information
+// can be derived from the URL or fetched separately if needed.
+type MinimalResponse struct {
+	URL string `json:"url"`
+}
+
+// Helper functions
+
+// convertToMinimalCommit converts a GitHub API RepositoryCommit to MinimalCommit
+func convertToMinimalCommit(commit *github.RepositoryCommit, includeDiffs bool) MinimalCommit {
+	minimalCommit := MinimalCommit{
+		SHA:     commit.GetSHA(),
+		HTMLURL: commit.GetHTMLURL(),
+	}
+
+	if commit.Commit != nil {
+		minimalCommit.Commit = &MinimalCommitInfo{
+			Message: commit.Commit.GetMessage(),
+		}
+
+		if commit.Commit.Author != nil {
+			minimalCommit.Commit.Author = &MinimalCommitAuthor{
+				Name:  commit.Commit.Author.GetName(),
+				Email: commit.Commit.Author.GetEmail(),
+			}
+			if commit.Commit.Author.Date != nil {
+				minimalCommit.Commit.Author.Date = commit.Commit.Author.Date.Format("2006-01-02T15:04:05Z")
+			}
+		}
+
+		if commit.Commit.Committer != nil {
+			minimalCommit.Commit.Committer = &MinimalCommitAuthor{
+				Name:  commit.Commit.Committer.GetName(),
+				Email: commit.Commit.Committer.GetEmail(),
+			}
+			if commit.Commit.Committer.Date != nil {
+				minimalCommit.Commit.Committer.Date = commit.Commit.Committer.Date.Format("2006-01-02T15:04:05Z")
+			}
+		}
+	}
+
+	if commit.Author != nil {
+		minimalCommit.Author = &MinimalUser{
+			Login:      commit.Author.GetLogin(),
+			ID:         commit.Author.GetID(),
+			ProfileURL: commit.Author.GetHTMLURL(),
+			AvatarURL:  commit.Author.GetAvatarURL(),
+		}
+	}
+
+	if commit.Committer != nil {
+		minimalCommit.Committer = &MinimalUser{
+			Login:      commit.Committer.GetLogin(),
+			ID:         commit.Committer.GetID(),
+			ProfileURL: commit.Committer.GetHTMLURL(),
+			AvatarURL:  commit.Committer.GetAvatarURL(),
+		}
+	}
+
+	// Only include stats and files if includeDiffs is true
+	if includeDiffs {
+		if commit.Stats != nil {
+			minimalCommit.Stats = &MinimalCommitStats{
+				Additions: commit.Stats.GetAdditions(),
+				Deletions: commit.Stats.GetDeletions(),
+				Total:     commit.Stats.GetTotal(),
+			}
+		}
+
+		if len(commit.Files) > 0 {
+			minimalCommit.Files = make([]MinimalCommitFile, 0, len(commit.Files))
+			for _, file := range commit.Files {
+				minimalFile := MinimalCommitFile{
+					Filename:  file.GetFilename(),
+					Status:    file.GetStatus(),
+					Additions: file.GetAdditions(),
+					Deletions: file.GetDeletions(),
+					Changes:   file.GetChanges(),
+				}
+				minimalCommit.Files = append(minimalCommit.Files, minimalFile)
+			}
+		}
+	}
+
+	return minimalCommit
+}
+
+// convertToMinimalBranch converts a GitHub API Branch to MinimalBranch
+func convertToMinimalBranch(branch *github.Branch) MinimalBranch {
+	return MinimalBranch{
+		Name:      branch.GetName(),
+		SHA:       branch.GetCommit().GetSHA(),
+		Protected: branch.GetProtected(),
+	}
+}
diff --git a/pkg/github/pullrequests.go b/pkg/github/pullrequests.go
index 63c5594..d754751 100644
--- a/pkg/github/pullrequests.go
+++ b/pkg/github/pullrequests.go
@@ -193,7 +193,12 @@ func CreatePullRequest(getClient GetClientFn, t translations.TranslationHelperFu
 				return mcp.NewToolResultError(fmt.Sprintf("failed to create pull request: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(pr)
+			// Return minimal response with just essential information
+			minimalResponse := MinimalResponse{
+				URL: pr.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -464,7 +469,12 @@ func UpdatePullRequest(getClient GetClientFn, getGQLClient GetGQLClientFn, t tra
 				}
 			}()
 
-			r, err := json.Marshal(finalPR)
+			// Return minimal response with just essential information
+			minimalResponse := MinimalResponse{
+				URL: finalPR.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return mcp.NewToolResultError(fmt.Sprintf("Failed to marshal response: %v", err)), nil
 			}
diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go
index de2c6d0..dce8501 100644
--- a/pkg/github/repositories.go
+++ b/pkg/github/repositories.go
@@ -37,6 +37,10 @@ func GetCommit(getClient GetClientFn, t translations.TranslationHelperFunc) (too
 				mcp.Required(),
 				mcp.Description("Commit SHA, branch name, or tag name"),
 			),
+			mcp.WithBoolean("include_diff",
+				mcp.Description("Whether to include file diffs and stats in the response. Default is true."),
+				mcp.DefaultBool(true),
+			),
 			WithPagination(),
 		),
 		func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
@@ -52,6 +56,10 @@ func GetCommit(getClient GetClientFn, t translations.TranslationHelperFunc) (too
 			if err != nil {
 				return mcp.NewToolResultError(err.Error()), nil
 			}
+			includeDiff, err := OptionalBoolParamWithDefault(request, "include_diff", true)
+			if err != nil {
+				return mcp.NewToolResultError(err.Error()), nil
+			}
 			pagination, err := OptionalPaginationParams(request)
 			if err != nil {
 				return mcp.NewToolResultError(err.Error()), nil
@@ -84,7 +92,10 @@ func GetCommit(getClient GetClientFn, t translations.TranslationHelperFunc) (too
 				return mcp.NewToolResultError(fmt.Sprintf("failed to get commit: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(commit)
+			// Convert to minimal commit
+			minimalCommit := convertToMinimalCommit(commit, includeDiff)
+
+			r, err := json.Marshal(minimalCommit)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -174,7 +185,13 @@ func ListCommits(getClient GetClientFn, t translations.TranslationHelperFunc) (t
 				return mcp.NewToolResultError(fmt.Sprintf("failed to list commits: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(commits)
+			// Convert to minimal commits
+			minimalCommits := make([]MinimalCommit, len(commits))
+			for i, commit := range commits {
+				minimalCommits[i] = convertToMinimalCommit(commit, false)
+			}
+
+			r, err := json.Marshal(minimalCommits)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -245,7 +262,13 @@ func ListBranches(getClient GetClientFn, t translations.TranslationHelperFunc) (
 				return mcp.NewToolResultError(fmt.Sprintf("failed to list branches: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(branches)
+			// Convert to minimal branches
+			minimalBranches := make([]MinimalBranch, 0, len(branches))
+			for _, branch := range branches {
+				minimalBranches = append(minimalBranches, convertToMinimalBranch(branch))
+			}
+
+			r, err := json.Marshal(minimalBranches)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -436,7 +459,12 @@ func CreateRepository(getClient GetClientFn, t translations.TranslationHelperFun
 				return mcp.NewToolResultError(fmt.Sprintf("failed to create repository: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(createdRepo)
+			// Return minimal response with just essential information
+			minimalResponse := MinimalResponse{
+				URL: createdRepo.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
@@ -707,7 +735,12 @@ func ForkRepository(getClient GetClientFn, t translations.TranslationHelperFunc)
 				return mcp.NewToolResultError(fmt.Sprintf("failed to fork repository: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(forkedRepo)
+			// Return minimal response with just essential information
+			minimalResponse := MinimalResponse{
+				URL: forkedRepo.GetHTMLURL(),
+			}
+
+			r, err := json.Marshal(minimalResponse)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal response: %w", err)
 			}
diff --git a/pkg/github/search.go b/pkg/github/search.go
index 248f17e..55e4cf8 100644
--- a/pkg/github/search.go
+++ b/pkg/github/search.go
@@ -26,6 +26,10 @@ func SearchRepositories(getClient GetClientFn, t translations.TranslationHelperF
 				mcp.Required(),
 				mcp.Description("Repository search query. Examples: 'machine learning in:name stars:>1000 language:python', 'topic:react', 'user:facebook'. Supports advanced search syntax for precise filtering."),
 			),
+			mcp.WithBoolean("minimal_output",
+				mcp.Description("Return minimal repository information (default: true). When false, returns full GitHub API repository objects."),
+				mcp.DefaultBool(true),
+			),
 			WithPagination(),
 		),
 		func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
@@ -37,7 +41,10 @@ func SearchRepositories(getClient GetClientFn, t translations.TranslationHelperF
 			if err != nil {
 				return mcp.NewToolResultError(err.Error()), nil
 			}
-
+			minimalOutput, err := OptionalBoolParamWithDefault(request, "minimal_output", true)
+			if err != nil {
+				return mcp.NewToolResultError(err.Error()), nil
+			}
 			opts := &github.SearchOptions{
 				ListOptions: github.ListOptions{
 					Page:    pagination.Page,
@@ -67,9 +74,55 @@ func SearchRepositories(getClient GetClientFn, t translations.TranslationHelperF
 				return mcp.NewToolResultError(fmt.Sprintf("failed to search repositories: %s", string(body))), nil
 			}
 
-			r, err := json.Marshal(result)
-			if err != nil {
-				return nil, fmt.Errorf("failed to marshal response: %w", err)
+			// Return either minimal or full response based on parameter
+			var r []byte
+			if minimalOutput {
+				minimalRepos := make([]MinimalRepository, 0, len(result.Repositories))
+				for _, repo := range result.Repositories {
+					minimalRepo := MinimalRepository{
+						ID:            repo.GetID(),
+						Name:          repo.GetName(),
+						FullName:      repo.GetFullName(),
+						Description:   repo.GetDescription(),
+						HTMLURL:       repo.GetHTMLURL(),
+						Language:      repo.GetLanguage(),
+						Stars:         repo.GetStargazersCount(),
+						Forks:         repo.GetForksCount(),
+						OpenIssues:    repo.GetOpenIssuesCount(),
+						Private:       repo.GetPrivate(),
+						Fork:          repo.GetFork(),
+						Archived:      repo.GetArchived(),
+						DefaultBranch: repo.GetDefaultBranch(),
+					}
+
+					if repo.UpdatedAt != nil {
+						minimalRepo.UpdatedAt = repo.UpdatedAt.Format("2006-01-02T15:04:05Z")
+					}
+					if repo.CreatedAt != nil {
+						minimalRepo.CreatedAt = repo.CreatedAt.Format("2006-01-02T15:04:05Z")
+					}
+					if repo.Topics != nil {
+						minimalRepo.Topics = repo.Topics
+					}
+
+					minimalRepos = append(minimalRepos, minimalRepo)
+				}
+
+				minimalResult := &MinimalSearchRepositoriesResult{
+					TotalCount:        result.GetTotal(),
+					IncompleteResults: result.GetIncompleteResults(),
+					Items:             minimalRepos,
+				}
+
+				r, err = json.Marshal(minimalResult)
+				if err != nil {
+					return nil, fmt.Errorf("failed to marshal minimal response: %w", err)
+				}
+			} else {
+				r, err = json.Marshal(result)
+				if err != nil {
+					return nil, fmt.Errorf("failed to marshal full response: %w", err)
+				}
 			}
 
 			return mcp.NewToolResultText(string(r)), nil
@@ -156,21 +209,6 @@ func SearchCode(getClient GetClientFn, t translations.TranslationHelperFunc) (to
 		}
 }
 
-// MinimalUser is the output type for user and organization search results.
-type MinimalUser struct {
-	Login      string       `json:"login"`
-	ID         int64        `json:"id,omitempty"`
-	ProfileURL string       `json:"profile_url,omitempty"`
-	AvatarURL  string       `json:"avatar_url,omitempty"`
-	Details    *UserDetails `json:"details,omitempty"` // Optional field for additional user details
-}
-
-type MinimalSearchUsersResult struct {
-	TotalCount        int           `json:"total_count"`
-	IncompleteResults bool          `json:"incomplete_results"`
-	Items             []MinimalUser `json:"items"`
-}
-
 func userOrOrgHandler(accountType string, getClient GetClientFn) server.ToolHandlerFunc {
 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
 		query, err := RequiredParam[string](request, "query")
diff --git a/pkg/github/server.go b/pkg/github/server.go
index 80a1bba..16d2864 100644
--- a/pkg/github/server.go
+++ b/pkg/github/server.go
@@ -144,6 +144,21 @@ func OptionalIntParamWithDefault(r mcp.CallToolRequest, p string, d int) (int, e
 	return v, nil
 }
 
+// OptionalBoolParamWithDefault is a helper function that can be used to fetch a requested parameter from the request
+// similar to optionalBoolParam, but it also takes a default value.
+func OptionalBoolParamWithDefault(r mcp.CallToolRequest, p string, d bool) (bool, error) {
+	args := r.GetArguments()
+	_, ok := args[p]
+	v, err := OptionalParam[bool](r, p)
+	if err != nil {
+		return false, err
+	}
+	if !ok {
+		return d, nil
+	}
+	return v, nil
+}
+
 // OptionalStringArrayParam is a helper function that can be used to fetch a requested parameter from the request.
 // It does the following checks:
 // 1. Checks if the parameter is present in the request, if not, it returns its zero-value



Test patch:
diff --git a/pkg/github/gists_test.go b/pkg/github/gists_test.go
index 49d63a2..9b8b4eb 100644
--- a/pkg/github/gists_test.go
+++ b/pkg/github/gists_test.go
@@ -321,23 +321,12 @@ func Test_CreateGist(t *testing.T) {
 			// Parse the result and get the text content
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the result
-			var gist *github.Gist
+			// Unmarshal and verify the minimal result
+			var gist MinimalResponse
 			err = json.Unmarshal([]byte(textContent.Text), &gist)
 			require.NoError(t, err)
 
-			assert.Equal(t, *tc.expectedGist.ID, *gist.ID)
-			assert.Equal(t, *tc.expectedGist.Description, *gist.Description)
-			assert.Equal(t, *tc.expectedGist.HTMLURL, *gist.HTMLURL)
-			assert.Equal(t, *tc.expectedGist.Public, *gist.Public)
-
-			// Verify file content
-			for filename, expectedFile := range tc.expectedGist.Files {
-				actualFile, exists := gist.Files[filename]
-				assert.True(t, exists)
-				assert.Equal(t, *expectedFile.Filename, *actualFile.Filename)
-				assert.Equal(t, *expectedFile.Content, *actualFile.Content)
-			}
+			assert.Equal(t, tc.expectedGist.GetHTMLURL(), gist.URL)
 		})
 	}
 }
@@ -486,22 +475,12 @@ func Test_UpdateGist(t *testing.T) {
 			// Parse the result and get the text content
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the result
-			var gist *github.Gist
-			err = json.Unmarshal([]byte(textContent.Text), &gist)
+			// Unmarshal and verify the minimal result
+			var updateResp MinimalResponse
+			err = json.Unmarshal([]byte(textContent.Text), &updateResp)
 			require.NoError(t, err)
 
-			assert.Equal(t, *tc.expectedGist.ID, *gist.ID)
-			assert.Equal(t, *tc.expectedGist.Description, *gist.Description)
-			assert.Equal(t, *tc.expectedGist.HTMLURL, *gist.HTMLURL)
-
-			// Verify file content
-			for filename, expectedFile := range tc.expectedGist.Files {
-				actualFile, exists := gist.Files[filename]
-				assert.True(t, exists)
-				assert.Equal(t, *expectedFile.Filename, *actualFile.Filename)
-				assert.Equal(t, *expectedFile.Content, *actualFile.Content)
-			}
+			assert.Equal(t, tc.expectedGist.GetHTMLURL(), updateResp.URL)
 		})
 	}
 }
diff --git a/pkg/github/issues_test.go b/pkg/github/issues_test.go
index 7c4983c..5a0d409 100644
--- a/pkg/github/issues_test.go
+++ b/pkg/github/issues_test.go
@@ -712,39 +712,12 @@ func Test_CreateIssue(t *testing.T) {
 			require.NoError(t, err)
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the result
-			var returnedIssue github.Issue
+			// Unmarshal and verify the minimal result
+			var returnedIssue MinimalResponse
 			err = json.Unmarshal([]byte(textContent.Text), &returnedIssue)
 			require.NoError(t, err)
 
-			assert.Equal(t, *tc.expectedIssue.Number, *returnedIssue.Number)
-			assert.Equal(t, *tc.expectedIssue.Title, *returnedIssue.Title)
-			assert.Equal(t, *tc.expectedIssue.State, *returnedIssue.State)
-			assert.Equal(t, *tc.expectedIssue.HTMLURL, *returnedIssue.HTMLURL)
-
-			if tc.expectedIssue.Body != nil {
-				assert.Equal(t, *tc.expectedIssue.Body, *returnedIssue.Body)
-			}
-
-			if tc.expectedIssue.Type != nil {
-				assert.Equal(t, *tc.expectedIssue.Type.Name, *returnedIssue.Type.Name)
-			}
-
-			// Check assignees if expected
-			if len(tc.expectedIssue.Assignees) > 0 {
-				assert.Equal(t, len(tc.expectedIssue.Assignees), len(returnedIssue.Assignees))
-				for i, assignee := range returnedIssue.Assignees {
-					assert.Equal(t, *tc.expectedIssue.Assignees[i].Login, *assignee.Login)
-				}
-			}
-
-			// Check labels if expected
-			if len(tc.expectedIssue.Labels) > 0 {
-				assert.Equal(t, len(tc.expectedIssue.Labels), len(returnedIssue.Labels))
-				for i, label := range returnedIssue.Labels {
-					assert.Equal(t, *tc.expectedIssue.Labels[i].Name, *label.Name)
-				}
-			}
+			assert.Equal(t, tc.expectedIssue.GetHTMLURL(), returnedIssue.URL)
 		})
 	}
 }
@@ -1233,45 +1206,12 @@ func Test_UpdateIssue(t *testing.T) {
 			// Parse the result and get the text content if no error
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the result
-			var returnedIssue github.Issue
-			err = json.Unmarshal([]byte(textContent.Text), &returnedIssue)
+			// Unmarshal and verify the minimal result
+			var updateResp MinimalResponse
+			err = json.Unmarshal([]byte(textContent.Text), &updateResp)
 			require.NoError(t, err)
 
-			assert.Equal(t, *tc.expectedIssue.Number, *returnedIssue.Number)
-			assert.Equal(t, *tc.expectedIssue.Title, *returnedIssue.Title)
-			assert.Equal(t, *tc.expectedIssue.State, *returnedIssue.State)
-			assert.Equal(t, *tc.expectedIssue.HTMLURL, *returnedIssue.HTMLURL)
-
-			if tc.expectedIssue.Body != nil {
-				assert.Equal(t, *tc.expectedIssue.Body, *returnedIssue.Body)
-			}
-
-			if tc.expectedIssue.Type != nil {
-				assert.Equal(t, *tc.expectedIssue.Type.Name, *returnedIssue.Type.Name)
-			}
-
-			// Check assignees if expected
-			if len(tc.expectedIssue.Assignees) > 0 {
-				assert.Len(t, returnedIssue.Assignees, len(tc.expectedIssue.Assignees))
-				for i, assignee := range returnedIssue.Assignees {
-					assert.Equal(t, *tc.expectedIssue.Assignees[i].Login, *assignee.Login)
-				}
-			}
-
-			// Check labels if expected
-			if len(tc.expectedIssue.Labels) > 0 {
-				assert.Len(t, returnedIssue.Labels, len(tc.expectedIssue.Labels))
-				for i, label := range returnedIssue.Labels {
-					assert.Equal(t, *tc.expectedIssue.Labels[i].Name, *label.Name)
-				}
-			}
-
-			// Check milestone if expected
-			if tc.expectedIssue.Milestone != nil {
-				assert.NotNil(t, returnedIssue.Milestone)
-				assert.Equal(t, *tc.expectedIssue.Milestone.Number, *returnedIssue.Milestone.Number)
-			}
+			assert.Equal(t, tc.expectedIssue.GetHTMLURL(), updateResp.URL)
 		})
 	}
 }
diff --git a/pkg/github/pullrequests_test.go b/pkg/github/pullrequests_test.go
index ed69214..ea2df97 100644
--- a/pkg/github/pullrequests_test.go
+++ b/pkg/github/pullrequests_test.go
@@ -381,47 +381,11 @@ func Test_UpdatePullRequest(t *testing.T) {
 			// Parse the result and get the text content
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the successful result
-			var returnedPR github.PullRequest
-			err = json.Unmarshal([]byte(textContent.Text), &returnedPR)
+			// Unmarshal and verify the minimal result
+			var updateResp MinimalResponse
+			err = json.Unmarshal([]byte(textContent.Text), &updateResp)
 			require.NoError(t, err)
-			assert.Equal(t, *tc.expectedPR.Number, *returnedPR.Number)
-			if tc.expectedPR.Title != nil {
-				assert.Equal(t, *tc.expectedPR.Title, *returnedPR.Title)
-			}
-			if tc.expectedPR.Body != nil {
-				assert.Equal(t, *tc.expectedPR.Body, *returnedPR.Body)
-			}
-			if tc.expectedPR.State != nil {
-				assert.Equal(t, *tc.expectedPR.State, *returnedPR.State)
-			}
-			if tc.expectedPR.Base != nil && tc.expectedPR.Base.Ref != nil {
-				assert.NotNil(t, returnedPR.Base)
-				assert.Equal(t, *tc.expectedPR.Base.Ref, *returnedPR.Base.Ref)
-			}
-			if tc.expectedPR.MaintainerCanModify != nil {
-				assert.Equal(t, *tc.expectedPR.MaintainerCanModify, *returnedPR.MaintainerCanModify)
-			}
-
-			// Check reviewers if they exist in the expected PR
-			if len(tc.expectedPR.RequestedReviewers) > 0 {
-				assert.NotNil(t, returnedPR.RequestedReviewers)
-				assert.Equal(t, len(tc.expectedPR.RequestedReviewers), len(returnedPR.RequestedReviewers))
-
-				// Create maps of reviewer logins for easy comparison
-				expectedReviewers := make(map[string]bool)
-				for _, reviewer := range tc.expectedPR.RequestedReviewers {
-					expectedReviewers[*reviewer.Login] = true
-				}
-
-				actualReviewers := make(map[string]bool)
-				for _, reviewer := range returnedPR.RequestedReviewers {
-					actualReviewers[*reviewer.Login] = true
-				}
-
-				// Compare the maps
-				assert.Equal(t, expectedReviewers, actualReviewers)
-			}
+			assert.Equal(t, tc.expectedPR.GetHTMLURL(), updateResp.URL)
 		})
 	}
 }
@@ -599,11 +563,11 @@ func Test_UpdatePullRequest_Draft(t *testing.T) {
 
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the successful result
-			var returnedPR github.PullRequest
-			err = json.Unmarshal([]byte(textContent.Text), &returnedPR)
+			// Unmarshal and verify the minimal result
+			var updateResp MinimalResponse
+			err = json.Unmarshal([]byte(textContent.Text), &updateResp)
 			require.NoError(t, err)
-			assert.Equal(t, *tc.expectedPR.Number, *returnedPR.Number)
+			assert.Equal(t, tc.expectedPR.GetHTMLURL(), updateResp.URL)
 		})
 	}
 }
@@ -1988,18 +1952,11 @@ func Test_CreatePullRequest(t *testing.T) {
 			// Parse the result and get the text content if no error
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the result
-			var returnedPR github.PullRequest
+			// Unmarshal and verify the minimal result
+			var returnedPR MinimalResponse
 			err = json.Unmarshal([]byte(textContent.Text), &returnedPR)
 			require.NoError(t, err)
-			assert.Equal(t, *tc.expectedPR.Number, *returnedPR.Number)
-			assert.Equal(t, *tc.expectedPR.Title, *returnedPR.Title)
-			assert.Equal(t, *tc.expectedPR.State, *returnedPR.State)
-			assert.Equal(t, *tc.expectedPR.HTMLURL, *returnedPR.HTMLURL)
-			assert.Equal(t, *tc.expectedPR.Head.SHA, *returnedPR.Head.SHA)
-			assert.Equal(t, *tc.expectedPR.Base.Ref, *returnedPR.Base.Ref)
-			assert.Equal(t, *tc.expectedPR.Body, *returnedPR.Body)
-			assert.Equal(t, *tc.expectedPR.User.Login, *returnedPR.User.Login)
+			assert.Equal(t, tc.expectedPR.GetHTMLURL(), returnedPR.URL)
 		})
 	}
 }
diff --git a/pkg/github/repositories_test.go b/pkg/github/repositories_test.go
index f5ebfd3..6db0698 100644
--- a/pkg/github/repositories_test.go
+++ b/pkg/github/repositories_test.go
@@ -737,9 +737,33 @@ func Test_ListCommits(t *testing.T) {
 				},
 			},
 			Author: &github.User{
-				Login: github.Ptr("testuser"),
+				Login:     github.Ptr("testuser"),
+				ID:        github.Ptr(int64(12345)),
+				HTMLURL:   github.Ptr("https://github.com/testuser"),
+				AvatarURL: github.Ptr("https://github.com/testuser.png"),
 			},
 			HTMLURL: github.Ptr("https://github.com/owner/repo/commit/abc123def456"),
+			Stats: &github.CommitStats{
+				Additions: github.Ptr(10),
+				Deletions: github.Ptr(5),
+				Total:     github.Ptr(15),
+			},
+			Files: []*github.CommitFile{
+				{
+					Filename:  github.Ptr("src/main.go"),
+					Status:    github.Ptr("modified"),
+					Additions: github.Ptr(8),
+					Deletions: github.Ptr(3),
+					Changes:   github.Ptr(11),
+				},
+				{
+					Filename:  github.Ptr("README.md"),
+					Status:    github.Ptr("added"),
+					Additions: github.Ptr(2),
+					Deletions: github.Ptr(2),
+					Changes:   github.Ptr(4),
+				},
+			},
 		},
 		{
 			SHA: github.Ptr("def456abc789"),
@@ -752,9 +776,26 @@ func Test_ListCommits(t *testing.T) {
 				},
 			},
 			Author: &github.User{
-				Login: github.Ptr("anotheruser"),
+				Login:     github.Ptr("anotheruser"),
+				ID:        github.Ptr(int64(67890)),
+				HTMLURL:   github.Ptr("https://github.com/anotheruser"),
+				AvatarURL: github.Ptr("https://github.com/anotheruser.png"),
 			},
 			HTMLURL: github.Ptr("https://github.com/owner/repo/commit/def456abc789"),
+			Stats: &github.CommitStats{
+				Additions: github.Ptr(20),
+				Deletions: github.Ptr(10),
+				Total:     github.Ptr(30),
+			},
+			Files: []*github.CommitFile{
+				{
+					Filename:  github.Ptr("src/utils.go"),
+					Status:    github.Ptr("added"),
+					Additions: github.Ptr(20),
+					Deletions: github.Ptr(10),
+					Changes:   github.Ptr(30),
+				},
+			},
 		},
 	}
 
@@ -875,16 +916,23 @@ func Test_ListCommits(t *testing.T) {
 			textContent := getTextResult(t, result)
 
 			// Unmarshal and verify the result
-			var returnedCommits []*github.RepositoryCommit
+			var returnedCommits []MinimalCommit
 			err = json.Unmarshal([]byte(textContent.Text), &returnedCommits)
 			require.NoError(t, err)
 			assert.Len(t, returnedCommits, len(tc.expectedCommits))
 			for i, commit := range returnedCommits {
-				assert.Equal(t, *tc.expectedCommits[i].Author, *commit.Author)
-				assert.Equal(t, *tc.expectedCommits[i].SHA, *commit.SHA)
-				assert.Equal(t, *tc.expectedCommits[i].Commit.Message, *commit.Commit.Message)
-				assert.Equal(t, *tc.expectedCommits[i].Author.Login, *commit.Author.Login)
-				assert.Equal(t, *tc.expectedCommits[i].HTMLURL, *commit.HTMLURL)
+				assert.Equal(t, tc.expectedCommits[i].GetSHA(), commit.SHA)
+				assert.Equal(t, tc.expectedCommits[i].GetHTMLURL(), commit.HTMLURL)
+				if tc.expectedCommits[i].Commit != nil {
+					assert.Equal(t, tc.expectedCommits[i].Commit.GetMessage(), commit.Commit.Message)
+				}
+				if tc.expectedCommits[i].Author != nil {
+					assert.Equal(t, tc.expectedCommits[i].Author.GetLogin(), commit.Author.Login)
+				}
+
+				// Files and stats are never included in list_commits
+				assert.Nil(t, commit.Files)
+				assert.Nil(t, commit.Stats)
 			}
 		})
 	}
@@ -1077,7 +1125,6 @@ func Test_CreateRepository(t *testing.T) {
 		Description: github.Ptr("Test repository"),
 		Private:     github.Ptr(true),
 		HTMLURL:     github.Ptr("https://github.com/testuser/test-repo"),
-		CloneURL:    github.Ptr("https://github.com/testuser/test-repo.git"),
 		CreatedAt:   &github.Timestamp{Time: time.Now()},
 		Owner: &github.User{
 			Login: github.Ptr("testuser"),
@@ -1192,17 +1239,13 @@ func Test_CreateRepository(t *testing.T) {
 			// Parse the result and get the text content if no error
 			textContent := getTextResult(t, result)
 
-			// Unmarshal and verify the result
-			var returnedRepo github.Repository
+			// Unmarshal and verify the minimal result
+			var returnedRepo MinimalResponse
 			err = json.Unmarshal([]byte(textContent.Text), &returnedRepo)
 			assert.NoError(t, err)
 
 			// Verify repository details
-			assert.Equal(t, *tc.expectedRepo.Name, *returnedRepo.Name)
-			assert.Equal(t, *tc.expectedRepo.Description, *returnedRepo.Description)
-			assert.Equal(t, *tc.expectedRepo.Private, *returnedRepo.Private)
-			assert.Equal(t, *tc.expectedRepo.HTMLURL, *returnedRepo.HTMLURL)
-			assert.Equal(t, *tc.expectedRepo.Owner.Login, *returnedRepo.Owner.Login)
+			assert.Equal(t, tc.expectedRepo.GetHTMLURL(), returnedRepo.URL)
 		})
 	}
 }
diff --git a/pkg/github/search_test.go b/pkg/github/search_test.go
index cfc87c0..91ca45a 100644
--- a/pkg/github/search_test.go
+++ b/pkg/github/search_test.go
@@ -148,23 +148,80 @@ func Test_SearchRepositories(t *testing.T) {
 			textContent := getTextResult(t, result)
 
 			// Unmarshal and verify the result
-			var returnedResult github.RepositoriesSearchResult
+			var returnedResult MinimalSearchRepositoriesResult
 			err = json.Unmarshal([]byte(textContent.Text), &returnedResult)
 			require.NoError(t, err)
-			assert.Equal(t, *tc.expectedResult.Total, *returnedResult.Total)
-			assert.Equal(t, *tc.expectedResult.IncompleteResults, *returnedResult.IncompleteResults)
-			assert.Len(t, returnedResult.Repositories, len(tc.expectedResult.Repositories))
-			for i, repo := range returnedResult.Repositories {
-				assert.Equal(t, *tc.expectedResult.Repositories[i].ID, *repo.ID)
-				assert.Equal(t, *tc.expectedResult.Repositories[i].Name, *repo.Name)
-				assert.Equal(t, *tc.expectedResult.Repositories[i].FullName, *repo.FullName)
-				assert.Equal(t, *tc.expectedResult.Repositories[i].HTMLURL, *repo.HTMLURL)
+			assert.Equal(t, *tc.expectedResult.Total, returnedResult.TotalCount)
+			assert.Equal(t, *tc.expectedResult.IncompleteResults, returnedResult.IncompleteResults)
+			assert.Len(t, returnedResult.Items, len(tc.expectedResult.Repositories))
+			for i, repo := range returnedResult.Items {
+				assert.Equal(t, *tc.expectedResult.Repositories[i].ID, repo.ID)
+				assert.Equal(t, *tc.expectedResult.Repositories[i].Name, repo.Name)
+				assert.Equal(t, *tc.expectedResult.Repositories[i].FullName, repo.FullName)
+				assert.Equal(t, *tc.expectedResult.Repositories[i].HTMLURL, repo.HTMLURL)
 			}
 
 		})
 	}
 }
 
+func Test_SearchRepositories_FullOutput(t *testing.T) {
+	mockSearchResult := &github.RepositoriesSearchResult{
+		Total:             github.Ptr(1),
+		IncompleteResults: github.Ptr(false),
+		Repositories: []*github.Repository{
+			{
+				ID:              github.Ptr(int64(12345)),
+				Name:            github.Ptr("test-repo"),
+				FullName:        github.Ptr("owner/test-repo"),
+				HTMLURL:         github.Ptr("https://github.com/owner/test-repo"),
+				Description:     github.Ptr("Test repository"),
+				StargazersCount: github.Ptr(100),
+			},
+		},
+	}
+
+	mockedClient := mock.NewMockedHTTPClient(
+		mock.WithRequestMatchHandler(
+			mock.GetSearchRepositories,
+			expectQueryParams(t, map[string]string{
+				"q":        "golang test",
+				"page":     "1",
+				"per_page": "30",
+			}).andThen(
+				mockResponse(t, http.StatusOK, mockSearchResult),
+			),
+		),
+	)
+
+	client := github.NewClient(mockedClient)
+	_, handlerTest := SearchRepositories(stubGetClientFn(client), translations.NullTranslationHelper)
+
+	request := createMCPRequest(map[string]interface{}{
+		"query":          "golang test",
+		"minimal_output": false,
+	})
+
+	result, err := handlerTest(context.Background(), request)
+
+	require.NoError(t, err)
+	require.False(t, result.IsError)
+
+	textContent := getTextResult(t, result)
+
+	// Unmarshal as full GitHub API response
+	var returnedResult github.RepositoriesSearchResult
+	err = json.Unmarshal([]byte(textContent.Text), &returnedResult)
+	require.NoError(t, err)
+
+	// Verify it's the full API response, not minimal
+	assert.Equal(t, *mockSearchResult.Total, *returnedResult.Total)
+	assert.Equal(t, *mockSearchResult.IncompleteResults, *returnedResult.IncompleteResults)
+	assert.Len(t, returnedResult.Repositories, 1)
+	assert.Equal(t, *mockSearchResult.Repositories[0].ID, *returnedResult.Repositories[0].ID)
+	assert.Equal(t, *mockSearchResult.Repositories[0].Name, *returnedResult.Repositories[0].Name)
+}
+
 func Test_SearchCode(t *testing.T) {
 	// Verify tool definition once
 	mockClient := github.NewClient(nil)