@@ -159,95 +159,135 @@ type MinimalSearchUsersResult struct {
159159 Items []MinimalUser `json:"items"`
160160}
161161
162- // SearchUsers creates a tool to search for GitHub users.
163- func SearchUsers (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
164- return mcp .NewTool ("search_users" ,
165- mcp .WithDescription (t ("TOOL_SEARCH_USERS_DESCRIPTION" , "Search for GitHub users" )),
166- mcp .WithToolAnnotation (mcp.ToolAnnotation {
167- Title : t ("TOOL_SEARCH_USERS_USER_TITLE" , "Search users" ),
168- ReadOnlyHint : toBoolPtr (true ),
169- }),
170- mcp .WithString ("q" ,
171- mcp .Required (),
172- mcp .Description ("Search query using GitHub users search syntax" ),
173- ),
174- mcp .WithString ("sort" ,
175- mcp .Description ("Sort field by category" ),
176- mcp .Enum ("followers" , "repositories" , "joined" ),
177- ),
178- mcp .WithString ("order" ,
179- mcp .Description ("Sort order" ),
180- mcp .Enum ("asc" , "desc" ),
181- ),
182- WithPagination (),
183- ),
184- func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
185- query , err := requiredParam [string ](request , "q" )
186- if err != nil {
187- return mcp .NewToolResultError (err .Error ()), nil
188- }
189- sort , err := OptionalParam [string ](request , "sort" )
190- if err != nil {
191- return mcp .NewToolResultError (err .Error ()), nil
192- }
193- order , err := OptionalParam [string ](request , "order" )
194- if err != nil {
195- return mcp .NewToolResultError (err .Error ()), nil
196- }
197- pagination , err := OptionalPaginationParams (request )
198- if err != nil {
199- return mcp .NewToolResultError (err .Error ()), nil
200- }
162+ func userOrOrgHandler (accountType string , getClient GetClientFn ) server.ToolHandlerFunc {
163+ return func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
164+ query , err := requiredParam [string ](request , "q" )
165+ if err != nil {
166+ return mcp .NewToolResultError (err .Error ()), nil
167+ }
168+ sort , err := OptionalParam [string ](request , "sort" )
169+ if err != nil {
170+ return mcp .NewToolResultError (err .Error ()), nil
171+ }
172+ order , err := OptionalParam [string ](request , "order" )
173+ if err != nil {
174+ return mcp .NewToolResultError (err .Error ()), nil
175+ }
176+ pagination , err := OptionalPaginationParams (request )
177+ if err != nil {
178+ return mcp .NewToolResultError (err .Error ()), nil
179+ }
201180
202- opts := & github.SearchOptions {
203- Sort : sort ,
204- Order : order ,
205- ListOptions : github.ListOptions {
206- PerPage : pagination .perPage ,
207- Page : pagination .page ,
208- },
209- }
181+ opts := & github.SearchOptions {
182+ Sort : sort ,
183+ Order : order ,
184+ ListOptions : github.ListOptions {
185+ PerPage : pagination .perPage ,
186+ Page : pagination .page ,
187+ },
188+ }
210189
211- client , err := getClient (ctx )
212- if err != nil {
213- return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
214- }
190+ client , err := getClient (ctx )
191+ if err != nil {
192+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
193+ }
215194
216- result , resp , err := client .Search .Users (ctx , "type:user " + query , opts )
195+ searchQuery := "type:" + accountType + " " + query
196+ result , resp , err := client .Search .Users (ctx , searchQuery , opts )
197+ if err != nil {
198+ return nil , fmt .Errorf ("failed to search %ss: %w" , accountType , err )
199+ }
200+ defer func () { _ = resp .Body .Close () }()
201+
202+ if resp .StatusCode != 200 {
203+ body , err := io .ReadAll (resp .Body )
217204 if err != nil {
218- return nil , fmt .Errorf ("failed to search users : %w" , err )
205+ return nil , fmt .Errorf ("failed to read response body : %w" , err )
219206 }
220- defer func () { _ = resp .Body .Close () }()
207+ return mcp .NewToolResultError (fmt .Sprintf ("failed to search %ss: %s" , accountType , string (body ))), nil
208+ }
221209
222- if resp .StatusCode != 200 {
223- body , err := io .ReadAll (resp .Body )
224- if err != nil {
225- return nil , fmt .Errorf ("failed to read response body: %w" , err )
226- }
227- return mcp .NewToolResultError (fmt .Sprintf ("failed to search users: %s" , string (body ))), nil
228- }
210+ minimalUsers := make ([]MinimalUser , 0 , len (result .Users ))
229211
230- minimalUsers := make ([]MinimalUser , 0 , len (result .Users ))
231- for _ , user := range result .Users {
232- mu := MinimalUser {
233- Login : user .GetLogin (),
234- ID : user .GetID (),
235- ProfileURL : user .GetHTMLURL (),
236- AvatarURL : user .GetAvatarURL (),
212+ for _ , user := range result .Users {
213+ if user .Login != nil {
214+ mu := MinimalUser {Login : * user .Login }
215+ if user .ID != nil {
216+ mu .ID = * user .ID
217+ }
218+ if user .HTMLURL != nil {
219+ mu .ProfileURL = * user .HTMLURL
220+ }
221+ if user .AvatarURL != nil {
222+ mu .AvatarURL = * user .AvatarURL
237223 }
238-
239224 minimalUsers = append (minimalUsers , mu )
240225 }
226+ }
227+ minimalResp := & MinimalSearchUsersResult {
228+ TotalCount : result .GetTotal (),
229+ IncompleteResults : result .GetIncompleteResults (),
230+ Items : minimalUsers ,
231+ }
232+ if result .Total != nil {
233+ minimalResp .TotalCount = * result .Total
234+ }
235+ if result .IncompleteResults != nil {
236+ minimalResp .IncompleteResults = * result .IncompleteResults
237+ }
241238
242- minimalResp := MinimalSearchUsersResult {
243- TotalCount : result .GetTotal (),
244- IncompleteResults : result .GetIncompleteResults (),
245- Items : minimalUsers ,
246- }
247- r , err := json .Marshal (minimalResp )
248- if err != nil {
249- return nil , fmt .Errorf ("failed to marshal response: %w" , err )
250- }
251- return mcp .NewToolResultText (string (r )), nil
239+ r , err := json .Marshal (minimalResp )
240+ if err != nil {
241+ return nil , fmt .Errorf ("failed to marshal response: %w" , err )
252242 }
243+ return mcp .NewToolResultText (string (r )), nil
244+ }
245+ }
246+
247+ // SearchUsers creates a tool to search for GitHub users.
248+ func SearchUsers (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
249+ return mcp .NewTool ("search_users" ,
250+ mcp .WithDescription (t ("TOOL_SEARCH_USERS_DESCRIPTION" , "Search for GitHub users exclusively" )),
251+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
252+ Title : t ("TOOL_SEARCH_USERS_USER_TITLE" , "Search users" ),
253+ ReadOnlyHint : toBoolPtr (true ),
254+ }),
255+ mcp .WithString ("q" ,
256+ mcp .Required (),
257+ mcp .Description ("Search query using GitHub users search syntax scoped to type:user" ),
258+ ),
259+ mcp .WithString ("sort" ,
260+ mcp .Description ("Sort field by category" ),
261+ mcp .Enum ("followers" , "repositories" , "joined" ),
262+ ),
263+ mcp .WithString ("order" ,
264+ mcp .Description ("Sort order" ),
265+ mcp .Enum ("asc" , "desc" ),
266+ ),
267+ WithPagination (),
268+ ), userOrOrgHandler ("user" , getClient )
269+ }
270+
271+ // SearchOrgs creates a tool to search for GitHub organizations.
272+ func SearchOrgs (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
273+ return mcp .NewTool ("search_orgs" ,
274+ mcp .WithDescription (t ("TOOL_SEARCH_ORGS_DESCRIPTION" , "Search for GitHub organizations exclusively" )),
275+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
276+ Title : t ("TOOL_SEARCH_ORGS_USER_TITLE" , "Search organizations" ),
277+ ReadOnlyHint : toBoolPtr (true ),
278+ }),
279+ mcp .WithString ("q" ,
280+ mcp .Required (),
281+ mcp .Description ("Search query using GitHub organizations search syntax scoped to type:org" ),
282+ ),
283+ mcp .WithString ("sort" ,
284+ mcp .Description ("Sort field by category" ),
285+ mcp .Enum ("followers" , "repositories" , "joined" ),
286+ ),
287+ mcp .WithString ("order" ,
288+ mcp .Description ("Sort order" ),
289+ mcp .Enum ("asc" , "desc" ),
290+ ),
291+ WithPagination (),
292+ ), userOrOrgHandler ("org" , getClient )
253293}
0 commit comments