Skip to content

feat: add get_user tool to fetch user by username (#1970)#2246

Open
sierikov wants to merge 1 commit intogithub:mainfrom
sierikov:feat/1970-add-get-user-tool
Open

feat: add get_user tool to fetch user by username (#1970)#2246
sierikov wants to merge 1 commit intogithub:mainfrom
sierikov:feat/1970-add-get-user-tool

Conversation

@sierikov
Copy link

Summary

Add a new get_user MCP tool that retrieves a GitHub user's profile by username using the public GET /users/{username} endpoint. Returns a MinimalUser with UserDetails to keep responses token-efficient for LLM consumers.

Why

Fixes #1970

What changed

  • Added pkg/github/users.go with GetUser tool definition and getUserHandler implementation
  • Added pkg/github/users_test.go with tests for successful lookup, user not found, and API error cases
  • Registered GetUser in the users toolset in pkg/github/tools.go
  • Renamed GetUser test constant to GetAuthenticatedUser in pkg/github/helper_test.go to avoid conflict with the new function name, and added GetUserByUsername constant
  • Updated 5 references in pkg/github/context_tools_test.go to use renamed constant
  • Auto-generated pkg/github/__toolsnaps__/get_user.snap and updated README.md via script/generate-docs

MCP impact

  • No tool or API changes
  • Tool schema or behavior changed
  • New tool added — get_user accepts a required username string parameter and returns the user's profile as a MinimalUser with UserDetails. Annotated with ReadOnlyHint: true. Registered under the users toolset.

Prompts tested (tool changes only)

  • "Get the profile of user octocat"
  • "Who is SamMorrowDrums on GitHub?"
  • "use the get_user tool for torvalds"

Security / limits

  • Auth / permissions considered — Uses the public GET /users/{username} endpoint. Scopes are nil since GitHub returns data based on the token's existing permissions without requiring additional scopes.
  • Data exposure, filtering, or token/size limits considered — Returns MinimalUser with UserDetail rather than the full github.User` object.

Tool renaming

  • I am not renaming tools as part of this PR

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Docs

  • Updated (README / docs / examples) — README.md regenerated via script/generate-docs

Add a new `get_user` MCP tool that retrieves a GitHub user's profile
by username using the public `GET /users/{username}` endpoint. Returns
a MinimalUser with UserDetails.
@sierikov sierikov requested a review from a team as a code owner March 21, 2026 13:46
Copilot AI review requested due to automatic review settings March 21, 2026 13:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new MCP tool (get_user) to fetch a GitHub user profile by username via GET /users/{username}, returning the existing token-efficient MinimalUser shape with UserDetails.

Changes:

  • Added get_user tool implementation and tool snapshot.
  • Added unit tests covering success and error paths for get_user.
  • Registered the tool in the users toolset and updated docs/README generation output.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/github/users.go Introduces the get_user tool definition and handler that calls client.Users.Get(ctx, username) and returns MinimalUser + UserDetails.
pkg/github/users_test.go Adds tests validating the tool schema snapshot and handler behavior across success/error scenarios.
pkg/github/tools.go Registers GetUser in AllTools under the users tools grouping.
pkg/github/helper_test.go Renames the existing /user endpoint constant to avoid naming conflict; adds /users/{username} endpoint constant.
pkg/github/context_tools_test.go Updates references to the renamed authenticated-user endpoint constant.
pkg/github/toolsnaps/get_user.snap Adds the generated schema snapshot for the new tool.
README.md Updates tool documentation list to include get_user.

ToolsetMetadataUsers,
mcp.Tool{
Name: "get_user",
Description: t("TOOL_GET_USER_DESCRIPTION", "Get user by username. Use this when you need information about specific GitHub user."),
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

Tool description has grammatical issues (missing article) and reads a bit awkwardly. Consider updating it to something like “Get a user by username. Use this when you need information about a specific GitHub user.” so the generated docs/tooling text is clearer.

Suggested change
Description: t("TOOL_GET_USER_DESCRIPTION", "Get user by username. Use this when you need information about specific GitHub user."),
Description: t("TOOL_GET_USER_DESCRIPTION", "Get a user by username. Use this when you need information about a specific GitHub user."),

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +88
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(),
},
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The MinimalUser/UserDetails mapping here duplicates the same field-by-field conversion logic in GetMe (context_tools.go). Since this is now shared behavior across multiple tools, consider extracting a small helper (e.g., buildMinimalUserWithDetails(*github.User)) to avoid future divergence when the shape changes.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +84
name: "user not found",
mockedClient: MockHTTPClientWithHandler(badRequestHandler("user not found")),
requestArgs: map[string]any{
"username": "other-non-existent-john-doe",
},
expectError: true,
expectedErrMsg: "failed to get user",
},
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The “user not found” test case currently uses badRequestHandler(), which returns HTTP 400. The real GET /users/{username} not-found path is a 404, and error formatting can differ by status code. Adjust this test to return http.StatusNotFound (with a typical {"message":"Not Found"} body) so the not-found behavior is actually covered.

Copilot generated this review using guidance from repository custom instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add get_user tool to fetch a user profile by username

2 participants