Skip to content

get_me return concise user response #638

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 4, 2025
Merged
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
52 changes: 51 additions & 1 deletion pkg/github/context_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,36 @@ package github

import (
"context"
"time"

ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)

// UserDetails contains additional fields about a GitHub user not already
// present in MinimalUser. Used by get_me context tool but omitted from search_users.
type UserDetails struct {
Name string `json:"name,omitempty"`
Company string `json:"company,omitempty"`
Blog string `json:"blog,omitempty"`
Location string `json:"location,omitempty"`
Email string `json:"email,omitempty"`
Hireable bool `json:"hireable,omitempty"`
Bio string `json:"bio,omitempty"`
TwitterUsername string `json:"twitter_username,omitempty"`
PublicRepos int `json:"public_repos"`
PublicGists int `json:"public_gists"`
Followers int `json:"followers"`
Following int `json:"following"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PrivateGists int `json:"private_gists,omitempty"`
TotalPrivateRepos int64 `json:"total_private_repos,omitempty"`
OwnedPrivateRepos int64 `json:"owned_private_repos,omitempty"`
}

// GetMe creates a tool to get details of the authenticated user.
func GetMe(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, server.ToolHandlerFunc) {
tool := mcp.NewTool("get_me",
Expand Down Expand Up @@ -38,7 +61,34 @@ func GetMe(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Too
), nil
}

return MarshalledTextResult(user), nil
// Create minimal user representation instead of returning full user object
minimalUser := MinimalUser{
Login: user.GetLogin(),
ID: user.GetID(),
ProfileURL: user.GetHTMLURL(),
AvatarURL: user.GetAvatarURL(),
Details: &UserDetails{
Name: user.GetName(),
Company: user.GetCompany(),
Blog: user.GetBlog(),
Location: user.GetLocation(),
Email: user.GetEmail(),
Hireable: user.GetHireable(),
Bio: user.GetBio(),
TwitterUsername: user.GetTwitterUsername(),
PublicRepos: user.GetPublicRepos(),
PublicGists: user.GetPublicGists(),
Followers: user.GetFollowers(),
Following: user.GetFollowing(),
CreatedAt: user.GetCreatedAt().Time,
UpdatedAt: user.GetUpdatedAt().Time,
PrivateGists: user.GetPrivateGists(),
TotalPrivateRepos: user.GetTotalPrivateRepos(),
OwnedPrivateRepos: user.GetOwnedPrivateRepos(),
},
}

return MarshalledTextResult(minimalUser), nil
})

return tool, handler
Expand Down
40 changes: 24 additions & 16 deletions pkg/github/context_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ func Test_GetMe(t *testing.T) {

// Setup mock user response
mockUser := &github.User{
Login: github.Ptr("testuser"),
Name: github.Ptr("Test User"),
Email: github.Ptr("test@example.com"),
Bio: github.Ptr("GitHub user for testing"),
Company: github.Ptr("Test Company"),
Location: github.Ptr("Test Location"),
HTMLURL: github.Ptr("https://github.com/testuser"),
CreatedAt: &github.Timestamp{Time: time.Now().Add(-365 * 24 * time.Hour)},
Type: github.Ptr("User"),
Login: github.Ptr("testuser"),
Name: github.Ptr("Test User"),
Email: github.Ptr("test@example.com"),
Bio: github.Ptr("GitHub user for testing"),
Company: github.Ptr("Test Company"),
Location: github.Ptr("Test Location"),
HTMLURL: github.Ptr("https://github.com/testuser"),
CreatedAt: &github.Timestamp{Time: time.Now().Add(-365 * 24 * time.Hour)},
Type: github.Ptr("User"),
Hireable: github.Ptr(true),
TwitterUsername: github.Ptr("testuser_twitter"),
Plan: &github.Plan{
Name: github.Ptr("pro"),
},
Expand Down Expand Up @@ -117,17 +119,23 @@ func Test_GetMe(t *testing.T) {
}

// Unmarshal and verify the result
var returnedUser github.User
var returnedUser MinimalUser
err = json.Unmarshal([]byte(textContent.Text), &returnedUser)
require.NoError(t, err)

// Verify minimal user details
assert.Equal(t, *tc.expectedUser.Login, returnedUser.Login)
assert.Equal(t, *tc.expectedUser.HTMLURL, returnedUser.ProfileURL)

// Verify user details
assert.Equal(t, *tc.expectedUser.Login, *returnedUser.Login)
assert.Equal(t, *tc.expectedUser.Name, *returnedUser.Name)
assert.Equal(t, *tc.expectedUser.Email, *returnedUser.Email)
assert.Equal(t, *tc.expectedUser.Bio, *returnedUser.Bio)
assert.Equal(t, *tc.expectedUser.HTMLURL, *returnedUser.HTMLURL)
assert.Equal(t, *tc.expectedUser.Type, *returnedUser.Type)
require.NotNil(t, returnedUser.Details)
assert.Equal(t, *tc.expectedUser.Name, returnedUser.Details.Name)
assert.Equal(t, *tc.expectedUser.Email, returnedUser.Details.Email)
assert.Equal(t, *tc.expectedUser.Bio, returnedUser.Details.Bio)
assert.Equal(t, *tc.expectedUser.Company, returnedUser.Details.Company)
assert.Equal(t, *tc.expectedUser.Location, returnedUser.Details.Location)
assert.Equal(t, *tc.expectedUser.Hireable, returnedUser.Details.Hireable)
assert.Equal(t, *tc.expectedUser.TwitterUsername, returnedUser.Details.TwitterUsername)
})
}
}
24 changes: 11 additions & 13 deletions pkg/github/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,13 @@ 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"`
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 {
Expand Down Expand Up @@ -224,15 +226,11 @@ func userOrOrgHandler(accountType string, getClient GetClientFn) server.ToolHand

for _, user := range result.Users {
if user.Login != nil {
mu := MinimalUser{Login: *user.Login}
if user.ID != nil {
mu.ID = *user.ID
}
if user.HTMLURL != nil {
mu.ProfileURL = *user.HTMLURL
}
if user.AvatarURL != nil {
mu.AvatarURL = *user.AvatarURL
mu := MinimalUser{
Login: user.GetLogin(),
ID: user.GetID(),
ProfileURL: user.GetHTMLURL(),
AvatarURL: user.GetAvatarURL(),
}
minimalUsers = append(minimalUsers, mu)
}
Expand Down
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