@@ -266,6 +266,104 @@ func AddSubIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
266
266
}
267
267
}
268
268
269
+ // ListSubIssues creates a tool to list sub-issues for a GitHub issue.
270
+ func ListSubIssues (getClient GetClientFn ,t translations.TranslationHelperFunc ) (tool mcp.Tool ,handler server.ToolHandlerFunc ) {
271
+ return mcp .NewTool ("list_sub_issues" ,
272
+ mcp .WithDescription (t ("TOOL_LIST_SUB_ISSUES_DESCRIPTION" ,"List sub-issues for a specific issue in a GitHub repository." )),
273
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
274
+ Title :t ("TOOL_LIST_SUB_ISSUES_USER_TITLE" ,"List sub-issues" ),
275
+ ReadOnlyHint :toBoolPtr (true ),
276
+ }),
277
+ mcp .WithString ("owner" ,
278
+ mcp .Required (),
279
+ mcp .Description ("Repository owner" ),
280
+ ),
281
+ mcp .WithString ("repo" ,
282
+ mcp .Required (),
283
+ mcp .Description ("Repository name" ),
284
+ ),
285
+ mcp .WithNumber ("issue_number" ,
286
+ mcp .Required (),
287
+ mcp .Description ("Issue number" ),
288
+ ),
289
+ mcp .WithNumber ("page" ,
290
+ mcp .Description ("Page number for pagination (default: 1)" ),
291
+ ),
292
+ mcp .WithNumber ("per_page" ,
293
+ mcp .Description ("Number of results per page (max 100, default: 30)" ),
294
+ ),
295
+ ),
296
+ func (ctx context.Context ,request mcp.CallToolRequest ) (* mcp.CallToolResult ,error ) {
297
+ owner ,err := requiredParam [string ](request ,"owner" )
298
+ if err != nil {
299
+ return mcp .NewToolResultError (err .Error ()),nil
300
+ }
301
+ repo ,err := requiredParam [string ](request ,"repo" )
302
+ if err != nil {
303
+ return mcp .NewToolResultError (err .Error ()),nil
304
+ }
305
+ issueNumber ,err := RequiredInt (request ,"issue_number" )
306
+ if err != nil {
307
+ return mcp .NewToolResultError (err .Error ()),nil
308
+ }
309
+ page ,err := OptionalIntParamWithDefault (request ,"page" ,1 )
310
+ if err != nil {
311
+ return mcp .NewToolResultError (err .Error ()),nil
312
+ }
313
+ perPage ,err := OptionalIntParamWithDefault (request ,"per_page" ,30 )
314
+ if err != nil {
315
+ return mcp .NewToolResultError (err .Error ()),nil
316
+ }
317
+
318
+ client ,err := getClient (ctx )
319
+ if err != nil {
320
+ return nil ,fmt .Errorf ("failed to get GitHub client: %w" ,err )
321
+ }
322
+
323
+ // Since the go-github library might not have sub-issues support yet,
324
+ // we'll make a direct HTTP request using the client's HTTP client
325
+ url := fmt .Sprintf ("%srepos/%s/%s/issues/%d/sub_issues?page=%d&per_page=%d" ,
326
+ client .BaseURL .String (),owner ,repo ,issueNumber ,page ,perPage )
327
+ req ,err := http .NewRequestWithContext (ctx ,"GET" ,url ,nil )
328
+ if err != nil {
329
+ return nil ,fmt .Errorf ("failed to create request: %w" ,err )
330
+ }
331
+
332
+ req .Header .Set ("Accept" ,"application/vnd.github+json" )
333
+ req .Header .Set ("X-GitHub-Api-Version" ,"2022-11-28" )
334
+
335
+ // Use the same authentication as the GitHub client
336
+ httpClient := client .Client ()
337
+ resp ,err := httpClient .Do (req )
338
+ if err != nil {
339
+ return nil ,fmt .Errorf ("failed to list sub-issues: %w" ,err )
340
+ }
341
+ defer func () {_ = resp .Body .Close () }()
342
+
343
+ body ,err := io .ReadAll (resp .Body )
344
+ if err != nil {
345
+ return nil ,fmt .Errorf ("failed to read response body: %w" ,err )
346
+ }
347
+
348
+ if resp .StatusCode != http .StatusOK {
349
+ return mcp .NewToolResultError (fmt .Sprintf ("failed to list sub-issues: %s" ,string (body ))),nil
350
+ }
351
+
352
+ // Parse and re-marshal to ensure consistent formatting
353
+ var result interface {}
354
+ if err := json .Unmarshal (body ,& result );err != nil {
355
+ return nil ,fmt .Errorf ("failed to unmarshal response: %w" ,err )
356
+ }
357
+
358
+ r ,err := json .Marshal (result )
359
+ if err != nil {
360
+ return nil ,fmt .Errorf ("failed to marshal response: %w" ,err )
361
+ }
362
+
363
+ return mcp .NewToolResultText (string (r )),nil
364
+ }
365
+ }
366
+
269
367
// SearchIssues creates a tool to search for issues and pull requests.
270
368
func SearchIssues (getClient GetClientFn ,t translations.TranslationHelperFunc ) (tool mcp.Tool ,handler server.ToolHandlerFunc ) {
271
369
return mcp .NewTool ("search_issues" ,