Skip to content

Commit c3128b7

Browse files
committed
feat: add tool to create GitHub repository from template
Introduced a new tool 'create_repository_from_template' to allow users to create repositories from a given repository template. Signed-off-by: Eran Cohen <eranco@redhat.com>
1 parent e9926b9 commit c3128b7

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,13 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
642642
- `private`: Whether the repository is private (boolean, optional)
643643
- `autoInit`: Auto-initialize with README (boolean, optional)
644644

645+
- **create_repository_from_template** - Create a new GitHub repository from a template
646+
- `template_owner`: The account owner of the template repository
647+
- `template_repo` : The name of the template repository
648+
- `name`: Repository name (string, required)
649+
- `description`: Repository description (string, optional)
650+
- `private`: Whether the repository is private (boolean, optional)
651+
645652
- **get_file_contents** - Get contents of a file or directory
646653
- `owner`: Repository owner (string, required)
647654
- `repo`: Repository name (string, required)

pkg/github/repositories.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,90 @@ func CreateRepository(getClient GetClientFn, t translations.TranslationHelperFun
390390
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
391391
}
392392
createdRepo, resp, err := client.Repositories.Create(ctx, "", repo)
393+
394+
if err != nil {
395+
return nil, fmt.Errorf("failed to create repository: %w", err)
396+
}
397+
defer func() { _ = resp.Body.Close() }()
398+
399+
if resp.StatusCode != http.StatusCreated {
400+
body, err := io.ReadAll(resp.Body)
401+
if err != nil {
402+
return nil, fmt.Errorf("failed to read response body: %w", err)
403+
}
404+
return mcp.NewToolResultError(fmt.Sprintf("failed to create repository: %s", string(body))), nil
405+
}
406+
407+
r, err := json.Marshal(createdRepo)
408+
if err != nil {
409+
return nil, fmt.Errorf("failed to marshal response: %w", err)
410+
}
411+
412+
return mcp.NewToolResultText(string(r)), nil
413+
}
414+
}
415+
416+
// CreateRepositoryFromTemplate creates a tool to create a new GitHub repository from a template.
417+
func CreateRepositoryFromTemplate(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
418+
return mcp.NewTool("create_repository_from_template",
419+
mcp.WithDescription(t("TOOL_CREATE_REPOSITORY_FROM_TEMPLATE_DESCRIPTION", "Create a new GitHub repository from template in your account")),
420+
mcp.WithToolAnnotation(mcp.ToolAnnotation{
421+
Title: t("TOOL_CREATE_REPOSITORY_FROM_TEMPLATE_USER_TITLE", "Create repository from template"),
422+
ReadOnlyHint: ToBoolPtr(false),
423+
}),
424+
mcp.WithString("template_owner",
425+
mcp.Required(),
426+
mcp.Description("template owner"),
427+
),
428+
mcp.WithString("template_repo",
429+
mcp.Required(),
430+
mcp.Description("The name of the template repository"),
431+
),
432+
mcp.WithString("name",
433+
mcp.Required(),
434+
mcp.Description("Repository name"),
435+
),
436+
mcp.WithString("description",
437+
mcp.Description("Repository description"),
438+
),
439+
mcp.WithBoolean("private",
440+
mcp.Description("Whether repo should be private"),
441+
),
442+
),
443+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
444+
template_owner, err := RequiredParam[string](request, "template_owner")
445+
if err != nil {
446+
return mcp.NewToolResultError(err.Error()), nil
447+
}
448+
template_repo, err := RequiredParam[string](request, "template_repo")
449+
if err != nil {
450+
return mcp.NewToolResultError(err.Error()), nil
451+
}
452+
name, err := RequiredParam[string](request, "name")
453+
if err != nil {
454+
return mcp.NewToolResultError(err.Error()), nil
455+
}
456+
description, err := OptionalParam[string](request, "description")
457+
if err != nil {
458+
return mcp.NewToolResultError(err.Error()), nil
459+
}
460+
private, err := OptionalParam[bool](request, "private")
461+
if err != nil {
462+
return mcp.NewToolResultError(err.Error()), nil
463+
}
464+
465+
repo := &github.TemplateRepoRequest{
466+
Name: github.Ptr(name),
467+
Description: github.Ptr(description),
468+
Private: github.Ptr(private),
469+
}
470+
471+
client, err := getClient(ctx)
472+
if err != nil {
473+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
474+
}
475+
createdRepo, resp, err := client.Repositories.CreateFromTemplate(ctx, template_owner, template_repo, repo)
476+
393477
if err != nil {
394478
return nil, fmt.Errorf("failed to create repository: %w", err)
395479
}

pkg/github/tools.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
3535
AddWriteTools(
3636
toolsets.NewServerTool(CreateOrUpdateFile(getClient, t)),
3737
toolsets.NewServerTool(CreateRepository(getClient, t)),
38+
toolsets.NewServerTool(CreateRepositoryFromTemplate(getClient, t)),
3839
toolsets.NewServerTool(ForkRepository(getClient, t)),
3940
toolsets.NewServerTool(CreateBranch(getClient, t)),
4041
toolsets.NewServerTool(PushFiles(getClient, t)),

0 commit comments

Comments
 (0)