@@ -160,94 +160,134 @@ type MinimalSearchUsersResult struct {
160160}
161161
162162// 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- }
163+ func userOrOrgHandler (accountType string , getClient GetClientFn ) server.ToolHandlerFunc {
164+ return func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
165+ query , err := requiredParam [string ](request , "q" )
166+ if err != nil {
167+ return mcp .NewToolResultError (err .Error ()), nil
168+ }
169+ sort , err := OptionalParam [string ](request , "sort" )
170+ if err != nil {
171+ return mcp .NewToolResultError (err .Error ()), nil
172+ }
173+ order , err := OptionalParam [string ](request , "order" )
174+ if err != nil {
175+ return mcp .NewToolResultError (err .Error ()), nil
176+ }
177+ pagination , err := OptionalPaginationParams (request )
178+ if err != nil {
179+ return mcp .NewToolResultError (err .Error ()), nil
180+ }
201181
202- opts := & github.SearchOptions {
203- Sort : sort ,
204- Order : order ,
205- ListOptions : github.ListOptions {
206- PerPage : pagination .perPage ,
207- Page : pagination .page ,
208- },
209- }
182+ opts := & github.SearchOptions {
183+ Sort : sort ,
184+ Order : order ,
185+ ListOptions : github.ListOptions {
186+ PerPage : pagination .perPage ,
187+ Page : pagination .page ,
188+ },
189+ }
210190
211- client , err := getClient (ctx )
212- if err != nil {
213- return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
214- }
191+ client , err := getClient (ctx )
192+ if err != nil {
193+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
194+ }
215195
216- result , resp , err := client .Search .Users (ctx , "type:user " + query , opts )
196+ searchQuery := "type:" + accountType + " " + query
197+ result , resp , err := client .Search .Users (ctx , searchQuery , opts )
198+ if err != nil {
199+ return nil , fmt .Errorf ("failed to search %ss: %w" , accountType , err )
200+ }
201+ defer func () { _ = resp .Body .Close () }()
202+
203+ if resp .StatusCode != 200 {
204+ body , err := io .ReadAll (resp .Body )
217205 if err != nil {
218- return nil , fmt .Errorf ("failed to search users : %w" , err )
206+ return nil , fmt .Errorf ("failed to read response body : %w" , err )
219207 }
220- defer func () { _ = resp .Body .Close () }()
208+ return mcp .NewToolResultError (fmt .Sprintf ("failed to search %ss: %s" , accountType , string (body ))), nil
209+ }
221210
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- }
211+ minimalUsers := make ([]MinimalUser , 0 , len (result .Users ))
229212
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 (),
213+ for _ , user := range result .Users {
214+ if user .Login != nil {
215+ mu := MinimalUser {Login : * user .Login }
216+ if user .ID != nil {
217+ mu .ID = * user .ID
218+ }
219+ if user .HTMLURL != nil {
220+ mu .ProfileURL = * user .HTMLURL
221+ }
222+ if user .AvatarURL != nil {
223+ mu .AvatarURL = * user .AvatarURL
237224 }
238-
239225 minimalUsers = append (minimalUsers , mu )
240226 }
227+ }
228+ minimalResp := & MinimalSearchUsersResult {
229+ TotalCount : result .GetTotal (),
230+ IncompleteResults : result .GetIncompleteResults (),
231+ Items : minimalUsers ,
232+ }
233+ if result .Total != nil {
234+ minimalResp .TotalCount = * result .Total
235+ }
236+ if result .IncompleteResults != nil {
237+ minimalResp .IncompleteResults = * result .IncompleteResults
238+ }
241239
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
240+ r , err := json .Marshal (minimalResp )
241+ if err != nil {
242+ return nil , fmt .Errorf ("failed to marshal response: %w" , err )
252243 }
244+ return mcp .NewToolResultText (string (r )), nil
245+ }
246+ }
247+
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