@@ -159,105 +159,194 @@ type MinimalSearchUsersResult struct {
159
159
Items []MinimalUser `json:"items"`
160
160
}
161
161
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
162
+ // shared handler for user/org search
163
+ func minimalAccountSearchHandler (accountType string , query string , getClient GetClientFn , ctx context.Context , sort , order string , pagination PaginationParams ) (* MinimalSearchUsersResult , error ) {
164
+ opts := & github.SearchOptions {
165
+ Sort : sort ,
166
+ Order : order ,
167
+ ListOptions : github.ListOptions {
168
+ PerPage : pagination .perPage ,
169
+ Page : pagination .page ,
170
+ },
171
+ }
172
+
173
+ client , err := getClient (ctx )
174
+ if err != nil {
175
+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
176
+ }
177
+
178
+ searchQuery := "type:" + accountType + " " + query
179
+ result , resp , err := client .Search .Users (ctx , searchQuery , opts )
180
+ if err != nil {
181
+ return nil , fmt .Errorf ("failed to search %ss: %w" , accountType , err )
182
+ }
183
+ defer func () { _ = resp .Body .Close () }()
184
+
185
+ if resp .StatusCode != 200 {
186
+ body , err := io .ReadAll (resp .Body )
187
+ if err != nil {
188
+ return nil , fmt .Errorf ("failed to read response body: %w" , err )
189
+ }
190
+ return nil , fmt .Errorf ("failed to search %ss: %s" , accountType , string (body ))
191
+ }
192
+
193
+ minimalUsers := make ([]MinimalUser , 0 , len (result .Users ))
194
+ for _ , user := range result .Users {
195
+ if user .Login != nil {
196
+ mu := MinimalUser {Login : * user .Login }
197
+ if user .ID != nil {
198
+ mu .ID = * user .ID
192
199
}
193
- order , err := OptionalParam [string ](request , "order" )
194
- if err != nil {
195
- return mcp .NewToolResultError (err .Error ()), nil
200
+ if user .HTMLURL != nil {
201
+ mu .ProfileURL = * user .HTMLURL
196
202
}
197
- pagination , err := OptionalPaginationParams (request )
198
- if err != nil {
199
- return mcp .NewToolResultError (err .Error ()), nil
203
+ if user .AvatarURL != nil {
204
+ mu .AvatarURL = * user .AvatarURL
200
205
}
206
+ minimalUsers = append (minimalUsers , mu )
207
+ }
208
+ }
209
+ minimalResp := & MinimalSearchUsersResult {
210
+ TotalCount : result .GetTotal (),
211
+ IncompleteResults : result .GetIncompleteResults (),
212
+ Items : minimalUsers ,
213
+ }
214
+ if result .Total != nil {
215
+ minimalResp .TotalCount = * result .Total
216
+ }
217
+ if result .IncompleteResults != nil {
218
+ minimalResp .IncompleteResults = * result .IncompleteResults
219
+ }
220
+ return minimalResp , nil
221
+ }
201
222
202
- opts := & github.SearchOptions {
203
- Sort : sort ,
204
- Order : order ,
205
- ListOptions : github.ListOptions {
206
- PerPage : pagination .perPage ,
207
- Page : pagination .page ,
208
- },
209
- }
223
+ // SearchUsers creates a tool to search for GitHub users.
224
+ func userOrOrgHandler (accountType string , getClient GetClientFn ) server.ToolHandlerFunc {
225
+ return func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
226
+ query , err := requiredParam [string ](request , "q" )
227
+ if err != nil {
228
+ return mcp .NewToolResultError (err .Error ()), nil
229
+ }
230
+ sort , err := OptionalParam [string ](request , "sort" )
231
+ if err != nil {
232
+ return mcp .NewToolResultError (err .Error ()), nil
233
+ }
234
+ order , err := OptionalParam [string ](request , "order" )
235
+ if err != nil {
236
+ return mcp .NewToolResultError (err .Error ()), nil
237
+ }
238
+ pagination , err := OptionalPaginationParams (request )
239
+ if err != nil {
240
+ return mcp .NewToolResultError (err .Error ()), nil
241
+ }
210
242
211
- client , err := getClient (ctx )
212
- if err != nil {
213
- return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
214
- }
243
+ opts := & github.SearchOptions {
244
+ Sort : sort ,
245
+ Order : order ,
246
+ ListOptions : github.ListOptions {
247
+ PerPage : pagination .perPage ,
248
+ Page : pagination .page ,
249
+ },
250
+ }
251
+
252
+ client , err := getClient (ctx )
253
+ if err != nil {
254
+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
255
+ }
215
256
216
- result , resp , err := client .Search .Users (ctx , "type:user " + query , opts )
257
+ searchQuery := "type:" + accountType + " " + query
258
+ result , resp , err := client .Search .Users (ctx , searchQuery , opts )
259
+ if err != nil {
260
+ return nil , fmt .Errorf ("failed to search %ss: %w" , accountType , err )
261
+ }
262
+ defer func () { _ = resp .Body .Close () }()
263
+
264
+ if resp .StatusCode != 200 {
265
+ body , err := io .ReadAll (resp .Body )
217
266
if err != nil {
218
- return nil , fmt .Errorf ("failed to search users : %w" , err )
267
+ return nil , fmt .Errorf ("failed to read response body : %w" , err )
219
268
}
220
- defer func () { _ = resp .Body .Close () }()
269
+ return mcp .NewToolResultError (fmt .Sprintf ("failed to search %ss: %s" , accountType , string (body ))), nil
270
+ }
221
271
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 )
272
+ minimalUsers := make ([]MinimalUser , 0 , len (result .Users ))
273
+ for _ , user := range result .Users {
274
+ if user .Login != nil {
275
+ mu := MinimalUser {Login : * user .Login }
276
+ if user .ID != nil {
277
+ mu .ID = * user .ID
226
278
}
227
- return mcp .NewToolResultError (fmt .Sprintf ("failed to search users: %s" , string (body ))), nil
228
- }
229
-
230
- minimalUsers := make ([]MinimalUser , 0 , len (result .Users ))
231
- for _ , user := range result .Users {
232
- if user .Login != nil {
233
- mu := MinimalUser {Login : * user .Login }
234
- if user .ID != nil {
235
- mu .ID = * user .ID
236
- }
237
- if user .HTMLURL != nil {
238
- mu .ProfileURL = * user .HTMLURL
239
- }
240
- if user .AvatarURL != nil {
241
- mu .AvatarURL = * user .AvatarURL
242
- }
243
- minimalUsers = append (minimalUsers , mu )
279
+ if user .HTMLURL != nil {
280
+ mu .ProfileURL = * user .HTMLURL
244
281
}
282
+ if user .AvatarURL != nil {
283
+ mu .AvatarURL = * user .AvatarURL
284
+ }
285
+ minimalUsers = append (minimalUsers , mu )
245
286
}
246
- minimalResp := MinimalSearchUsersResult {
247
- TotalCount : result .GetTotal (),
248
- IncompleteResults : result .GetIncompleteResults (),
249
- Items : minimalUsers ,
250
- }
251
- if result .Total != nil {
252
- minimalResp .TotalCount = * result .Total
253
- }
254
- if result .IncompleteResults != nil {
255
- minimalResp .IncompleteResults = * result .IncompleteResults
256
- }
257
- r , err := json .Marshal (minimalResp )
258
- if err != nil {
259
- return nil , fmt .Errorf ("failed to marshal response: %w" , err )
260
- }
261
- return mcp .NewToolResultText (string (r )), nil
262
287
}
288
+ minimalResp := & MinimalSearchUsersResult {
289
+ TotalCount : result .GetTotal (),
290
+ IncompleteResults : result .GetIncompleteResults (),
291
+ Items : minimalUsers ,
292
+ }
293
+ if result .Total != nil {
294
+ minimalResp .TotalCount = * result .Total
295
+ }
296
+ if result .IncompleteResults != nil {
297
+ minimalResp .IncompleteResults = * result .IncompleteResults
298
+ }
299
+ r , err := json .Marshal (minimalResp )
300
+ if err != nil {
301
+ return nil , fmt .Errorf ("failed to marshal response: %w" , err )
302
+ }
303
+ return mcp .NewToolResultText (string (r )), nil
304
+ }
305
+ }
306
+
307
+ func SearchUsers (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
308
+ return mcp .NewTool ("search_users" ,
309
+ mcp .WithDescription (t ("TOOL_SEARCH_USERS_DESCRIPTION" , "Search for GitHub users exlusively" )),
310
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
311
+ Title : t ("TOOL_SEARCH_USERS_USER_TITLE" , "Search users" ),
312
+ ReadOnlyHint : toBoolPtr (true ),
313
+ }),
314
+ mcp .WithString ("q" ,
315
+ mcp .Required (),
316
+ mcp .Description ("Search query using GitHub users search syntax scoped to type:user" ),
317
+ ),
318
+ mcp .WithString ("sort" ,
319
+ mcp .Description ("Sort field by category" ),
320
+ mcp .Enum ("followers" , "repositories" , "joined" ),
321
+ ),
322
+ mcp .WithString ("order" ,
323
+ mcp .Description ("Sort order" ),
324
+ mcp .Enum ("asc" , "desc" ),
325
+ ),
326
+ WithPagination (),
327
+ ), userOrOrgHandler ("user" , getClient )
328
+ }
329
+
330
+ // SearchOrgs creates a tool to search for GitHub organizations.
331
+ func SearchOrgs (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
332
+ return mcp .NewTool ("search_orgs" ,
333
+ mcp .WithDescription (t ("TOOL_SEARCH_ORGS_DESCRIPTION" , "Search for GitHub organizations exclusively" )),
334
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
335
+ Title : t ("TOOL_SEARCH_ORGS_USER_TITLE" , "Search organizations" ),
336
+ ReadOnlyHint : toBoolPtr (true ),
337
+ }),
338
+ mcp .WithString ("q" ,
339
+ mcp .Required (),
340
+ mcp .Description ("Search query using GitHub organizations search syntax scoped to type:org" ),
341
+ ),
342
+ mcp .WithString ("sort" ,
343
+ mcp .Description ("Sort field by category" ),
344
+ mcp .Enum ("followers" , "repositories" , "joined" ),
345
+ ),
346
+ mcp .WithString ("order" ,
347
+ mcp .Description ("Sort order" ),
348
+ mcp .Enum ("asc" , "desc" ),
349
+ ),
350
+ WithPagination (),
351
+ ), userOrOrgHandler ("org" , getClient )
263
352
}
0 commit comments