@@ -11,7 +11,6 @@ import (
1111 "github.com/github/github-mcp-server/pkg/translations"
1212 "github.com/github/github-mcp-server/pkg/utils"
1313 "github.com/google/go-github/v79/github"
14- "github.com/google/jsonschema-go/jsonschema"
1514 "github.com/modelcontextprotocol/go-sdk/mcp"
1615)
1716
@@ -114,61 +113,23 @@ func SearchRepositories(getClient GetClientFn, t translations.TranslationHelperF
114113}
115114
116115// SearchCode creates a tool to search for code across GitHub repositories.
117- func SearchCode (getClient GetClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , mcp.ToolHandlerFor [map [string ]any , any ]) {
118- schema := & jsonschema.Schema {
119- Type : "object" ,
120- Properties : map [string ]* jsonschema.Schema {
121- "query" : {
122- Type : "string" ,
123- Description : "Search query using GitHub's powerful code search syntax. Examples: 'content:Skill language:Java org:github', 'NOT is:archived language:Python OR language:go', 'repo:github/github-mcp-server'. Supports exact matching, language filters, path filters, and more." ,
124- },
125- "sort" : {
126- Type : "string" ,
127- Description : "Sort field ('indexed' only)" ,
128- },
129- "order" : {
130- Type : "string" ,
131- Description : "Sort order for results" ,
132- Enum : []any {"asc" , "desc" },
133- },
134- },
135- Required : []string {"query" },
136- }
137- WithPagination (schema )
138-
116+ func SearchCode (getClient GetClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , mcp.ToolHandlerFor [SearchCodeInput , any ]) {
139117 return mcp.Tool {
140118 Name : "search_code" ,
141119 Description : t ("TOOL_SEARCH_CODE_DESCRIPTION" , "Fast and precise code search across ALL GitHub repositories using GitHub's native search engine. Best for finding exact symbols, functions, classes, or specific code patterns." ),
142120 Annotations : & mcp.ToolAnnotations {
143121 Title : t ("TOOL_SEARCH_CODE_USER_TITLE" , "Search code" ),
144122 ReadOnlyHint : true ,
145123 },
146- InputSchema : schema ,
124+ InputSchema : SearchCodeInput {}. MCPSchema () ,
147125 },
148- func (ctx context.Context , _ * mcp.CallToolRequest , args map [string ]any ) (* mcp.CallToolResult , any , error ) {
149- query , err := RequiredParam [string ](args , "query" )
150- if err != nil {
151- return utils .NewToolResultError (err .Error ()), nil , nil
152- }
153- sort , err := OptionalParam [string ](args , "sort" )
154- if err != nil {
155- return utils .NewToolResultError (err .Error ()), nil , nil
156- }
157- order , err := OptionalParam [string ](args , "order" )
158- if err != nil {
159- return utils .NewToolResultError (err .Error ()), nil , nil
160- }
161- pagination , err := OptionalPaginationParams (args )
162- if err != nil {
163- return utils .NewToolResultError (err .Error ()), nil , nil
164- }
165-
126+ func (ctx context.Context , _ * mcp.CallToolRequest , input SearchCodeInput ) (* mcp.CallToolResult , any , error ) {
166127 opts := & github.SearchOptions {
167- Sort : sort ,
168- Order : order ,
128+ Sort : input . Sort ,
129+ Order : input . Order ,
169130 ListOptions : github.ListOptions {
170- PerPage : pagination .PerPage ,
171- Page : pagination .Page ,
131+ PerPage : input .PerPage ,
132+ Page : input .Page ,
172133 },
173134 }
174135
@@ -177,10 +138,10 @@ func SearchCode(getClient GetClientFn, t translations.TranslationHelperFunc) (mc
177138 return utils .NewToolResultErrorFromErr ("failed to get GitHub client" , err ), nil , nil
178139 }
179140
180- result , resp , err := client .Search .Code (ctx , query , opts )
141+ result , resp , err := client .Search .Code (ctx , input . Query , opts )
181142 if err != nil {
182143 return ghErrors .NewGitHubAPIErrorResponse (ctx ,
183- fmt .Sprintf ("failed to search code with query '%s'" , query ),
144+ fmt .Sprintf ("failed to search code with query '%s'" , input . Query ),
184145 resp ,
185146 err ,
186147 ), nil , nil
@@ -204,31 +165,37 @@ func SearchCode(getClient GetClientFn, t translations.TranslationHelperFunc) (mc
204165 }
205166}
206167
207- func userOrOrgHandler (accountType string , getClient GetClientFn ) mcp.ToolHandlerFor [map [string ]any , any ] {
208- return func (ctx context.Context , _ * mcp.CallToolRequest , args map [string ]any ) (* mcp.CallToolResult , any , error ) {
209- query , err := RequiredParam [string ](args , "query" )
210- if err != nil {
211- return utils .NewToolResultError (err .Error ()), nil , nil
212- }
213- sort , err := OptionalParam [string ](args , "sort" )
214- if err != nil {
215- return utils .NewToolResultError (err .Error ()), nil , nil
216- }
217- order , err := OptionalParam [string ](args , "order" )
218- if err != nil {
219- return utils .NewToolResultError (err .Error ()), nil , nil
220- }
221- pagination , err := OptionalPaginationParams (args )
222- if err != nil {
223- return utils .NewToolResultError (err .Error ()), nil , nil
224- }
168+ // userOrOrgSearchInput is a common interface for user/org search inputs
169+ type userOrOrgSearchInput interface {
170+ GetQuery () string
171+ GetSort () string
172+ GetOrder () string
173+ GetPage () int
174+ GetPerPage () int
175+ }
176+
177+ // Add getters to SearchUsersInput
178+ func (s SearchUsersInput ) GetQuery () string { return s .Query }
179+ func (s SearchUsersInput ) GetSort () string { return s .Sort }
180+ func (s SearchUsersInput ) GetOrder () string { return s .Order }
181+ func (s SearchUsersInput ) GetPage () int { return s .Page }
182+ func (s SearchUsersInput ) GetPerPage () int { return s .PerPage }
183+
184+ // Add getters to SearchOrgsInput
185+ func (s SearchOrgsInput ) GetQuery () string { return s .Query }
186+ func (s SearchOrgsInput ) GetSort () string { return s .Sort }
187+ func (s SearchOrgsInput ) GetOrder () string { return s .Order }
188+ func (s SearchOrgsInput ) GetPage () int { return s .Page }
189+ func (s SearchOrgsInput ) GetPerPage () int { return s .PerPage }
225190
191+ func userOrOrgHandlerTyped [T userOrOrgSearchInput ](accountType string , getClient GetClientFn ) mcp.ToolHandlerFor [T , any ] {
192+ return func (ctx context.Context , _ * mcp.CallToolRequest , input T ) (* mcp.CallToolResult , any , error ) {
226193 opts := & github.SearchOptions {
227- Sort : sort ,
228- Order : order ,
194+ Sort : input . GetSort () ,
195+ Order : input . GetOrder () ,
229196 ListOptions : github.ListOptions {
230- PerPage : pagination . PerPage ,
231- Page : pagination . Page ,
197+ PerPage : input . GetPerPage () ,
198+ Page : input . GetPage () ,
232199 },
233200 }
234201
@@ -237,14 +204,14 @@ func userOrOrgHandler(accountType string, getClient GetClientFn) mcp.ToolHandler
237204 return utils .NewToolResultErrorFromErr ("failed to get GitHub client" , err ), nil , nil
238205 }
239206
240- searchQuery := query
241- if ! hasTypeFilter (query ) {
242- searchQuery = "type:" + accountType + " " + query
207+ searchQuery := input . GetQuery ()
208+ if ! hasTypeFilter (searchQuery ) {
209+ searchQuery = "type:" + accountType + " " + searchQuery
243210 }
244211 result , resp , err := client .Search .Users (ctx , searchQuery , opts )
245212 if err != nil {
246213 return ghErrors .NewGitHubAPIErrorResponse (ctx ,
247- fmt .Sprintf ("failed to search %ss with query '%s'" , accountType , query ),
214+ fmt .Sprintf ("failed to search %ss with query '%s'" , accountType , input . GetQuery () ),
248215 resp ,
249216 err ,
250217 ), nil , nil
@@ -293,71 +260,27 @@ func userOrOrgHandler(accountType string, getClient GetClientFn) mcp.ToolHandler
293260}
294261
295262// SearchUsers creates a tool to search for GitHub users.
296- func SearchUsers (getClient GetClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , mcp.ToolHandlerFor [map [string ]any , any ]) {
297- schema := & jsonschema.Schema {
298- Type : "object" ,
299- Properties : map [string ]* jsonschema.Schema {
300- "query" : {
301- Type : "string" ,
302- Description : "User search query. Examples: 'john smith', 'location:seattle', 'followers:>100'. Search is automatically scoped to type:user." ,
303- },
304- "sort" : {
305- Type : "string" ,
306- Description : "Sort users by number of followers or repositories, or when the person joined GitHub." ,
307- Enum : []any {"followers" , "repositories" , "joined" },
308- },
309- "order" : {
310- Type : "string" ,
311- Description : "Sort order" ,
312- Enum : []any {"asc" , "desc" },
313- },
314- },
315- Required : []string {"query" },
316- }
317- WithPagination (schema )
318-
263+ func SearchUsers (getClient GetClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , mcp.ToolHandlerFor [SearchUsersInput , any ]) {
319264 return mcp.Tool {
320265 Name : "search_users" ,
321266 Description : t ("TOOL_SEARCH_USERS_DESCRIPTION" , "Find GitHub users by username, real name, or other profile information. Useful for locating developers, contributors, or team members." ),
322267 Annotations : & mcp.ToolAnnotations {
323268 Title : t ("TOOL_SEARCH_USERS_USER_TITLE" , "Search users" ),
324269 ReadOnlyHint : true ,
325270 },
326- InputSchema : schema ,
327- }, userOrOrgHandler ("user" , getClient )
271+ InputSchema : SearchUsersInput {}. MCPSchema () ,
272+ }, userOrOrgHandlerTyped [ SearchUsersInput ] ("user" , getClient )
328273}
329274
330275// SearchOrgs creates a tool to search for GitHub organizations.
331- func SearchOrgs (getClient GetClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , mcp.ToolHandlerFor [map [string ]any , any ]) {
332- schema := & jsonschema.Schema {
333- Type : "object" ,
334- Properties : map [string ]* jsonschema.Schema {
335- "query" : {
336- Type : "string" ,
337- Description : "Organization search query. Examples: 'microsoft', 'location:california', 'created:>=2025-01-01'. Search is automatically scoped to type:org." ,
338- },
339- "sort" : {
340- Type : "string" ,
341- Description : "Sort field by category" ,
342- Enum : []any {"followers" , "repositories" , "joined" },
343- },
344- "order" : {
345- Type : "string" ,
346- Description : "Sort order" ,
347- Enum : []any {"asc" , "desc" },
348- },
349- },
350- Required : []string {"query" },
351- }
352- WithPagination (schema )
353-
276+ func SearchOrgs (getClient GetClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , mcp.ToolHandlerFor [SearchOrgsInput , any ]) {
354277 return mcp.Tool {
355278 Name : "search_orgs" ,
356279 Description : t ("TOOL_SEARCH_ORGS_DESCRIPTION" , "Find GitHub organizations by name, location, or other organization metadata. Ideal for discovering companies, open source foundations, or teams." ),
357280 Annotations : & mcp.ToolAnnotations {
358281 Title : t ("TOOL_SEARCH_ORGS_USER_TITLE" , "Search organizations" ),
359282 ReadOnlyHint : true ,
360283 },
361- InputSchema : schema ,
362- }, userOrOrgHandler ("org" , getClient )
284+ InputSchema : SearchOrgsInput {}. MCPSchema () ,
285+ }, userOrOrgHandlerTyped [ SearchOrgsInput ] ("org" , getClient )
363286}
0 commit comments