@@ -153,6 +153,118 @@ func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc
153153 }
154154}
155155
156+ // AddSubIssue creates a tool to add a sub-issue to a parent issue.
157+ func AddSubIssue (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
158+ return mcp .NewTool ("add_sub_issue" ,
159+ mcp .WithDescription (t ("TOOL_ADD_SUB_ISSUE_DESCRIPTION" , "Add a sub-issue to a parent issue in a GitHub repository." )),
160+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
161+ Title : t ("TOOL_ADD_SUB_ISSUE_USER_TITLE" , "Add sub-issue" ),
162+ ReadOnlyHint : toBoolPtr (false ),
163+ }),
164+ mcp .WithString ("owner" ,
165+ mcp .Required (),
166+ mcp .Description ("Repository owner" ),
167+ ),
168+ mcp .WithString ("repo" ,
169+ mcp .Required (),
170+ mcp .Description ("Repository name" ),
171+ ),
172+ mcp .WithNumber ("issue_number" ,
173+ mcp .Required (),
174+ mcp .Description ("The number of the parent issue" ),
175+ ),
176+ mcp .WithNumber ("sub_issue_id" ,
177+ mcp .Required (),
178+ mcp .Description ("The ID of the sub-issue to add" ),
179+ ),
180+ mcp .WithBoolean ("replace_parent" ,
181+ mcp .Description ("When true, replaces the sub-issue's current parent issue" ),
182+ ),
183+ ),
184+ func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
185+ owner , err := requiredParam [string ](request , "owner" )
186+ if err != nil {
187+ return mcp .NewToolResultError (err .Error ()), nil
188+ }
189+ repo , err := requiredParam [string ](request , "repo" )
190+ if err != nil {
191+ return mcp .NewToolResultError (err .Error ()), nil
192+ }
193+ issueNumber , err := RequiredInt (request , "issue_number" )
194+ if err != nil {
195+ return mcp .NewToolResultError (err .Error ()), nil
196+ }
197+ subIssueID , err := RequiredInt (request , "sub_issue_id" )
198+ if err != nil {
199+ return mcp .NewToolResultError (err .Error ()), nil
200+ }
201+ replaceParent , err := OptionalParam [bool ](request , "replace_parent" )
202+ if err != nil {
203+ return mcp .NewToolResultError (err .Error ()), nil
204+ }
205+
206+ client , err := getClient (ctx )
207+ if err != nil {
208+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
209+ }
210+
211+ // Create the request body
212+ requestBody := map [string ]interface {}{
213+ "sub_issue_id" : subIssueID ,
214+ }
215+ if replaceParent {
216+ requestBody ["replace_parent" ] = replaceParent
217+ }
218+
219+ // Since the go-github library might not have sub-issues support yet,
220+ // we'll make a direct HTTP request using the client's HTTP client
221+ reqBodyBytes , err := json .Marshal (requestBody )
222+ if err != nil {
223+ return nil , fmt .Errorf ("failed to marshal request body: %w" , err )
224+ }
225+
226+ url := fmt .Sprintf ("https://api.github.com/repos/%s/%s/issues/%d/sub_issues" , owner , repo , issueNumber )
227+ req , err := http .NewRequestWithContext (ctx , "POST" , url , strings .NewReader (string (reqBodyBytes )))
228+ if err != nil {
229+ return nil , fmt .Errorf ("failed to create request: %w" , err )
230+ }
231+
232+ req .Header .Set ("Accept" , "application/vnd.github+json" )
233+ req .Header .Set ("Content-Type" , "application/json" )
234+ req .Header .Set ("X-GitHub-Api-Version" , "2022-11-28" )
235+
236+ // Use the same authentication as the GitHub client
237+ httpClient := client .Client ()
238+ resp , err := httpClient .Do (req )
239+ if err != nil {
240+ return nil , fmt .Errorf ("failed to add sub-issue: %w" , err )
241+ }
242+ defer func () { _ = resp .Body .Close () }()
243+
244+ body , err := io .ReadAll (resp .Body )
245+ if err != nil {
246+ return nil , fmt .Errorf ("failed to read response body: %w" , err )
247+ }
248+
249+ if resp .StatusCode != http .StatusCreated {
250+ return mcp .NewToolResultError (fmt .Sprintf ("failed to add sub-issue: %s" , string (body ))), nil
251+ }
252+
253+ // Parse and re-marshal to ensure consistent formatting
254+ var result interface {}
255+ if err := json .Unmarshal (body , & result ); err != nil {
256+ return nil , fmt .Errorf ("failed to unmarshal response: %w" , err )
257+ }
258+
259+ r , err := json .Marshal (result )
260+ if err != nil {
261+ return nil , fmt .Errorf ("failed to marshal response: %w" , err )
262+ }
263+
264+ return mcp .NewToolResultText (string (r )), nil
265+ }
266+ }
267+
156268// SearchIssues creates a tool to search for issues and pull requests.
157269func SearchIssues (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
158270 return mcp .NewTool ("search_issues" ,
0 commit comments