diff --git a/README.md b/README.md index d40d8aab..a8b7bbb8 100644 --- a/README.md +++ b/README.md @@ -642,6 +642,13 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `private`: Whether the repository is private (boolean, optional) - `autoInit`: Auto-initialize with README (boolean, optional) +- **create_repository_from_template** - Create a new GitHub repository from a template + - `template_owner`: The account owner of the template repository + - `template_repo` : The name of the template repository + - `name`: Repository name (string, required) + - `description`: Repository description (string, optional) + - `private`: Whether the repository is private (boolean, optional) + - **get_file_contents** - Get contents of a file or directory - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index 3475167b..6306368e 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -390,6 +390,90 @@ func CreateRepository(getClient GetClientFn, t translations.TranslationHelperFun return nil, fmt.Errorf("failed to get GitHub client: %w", err) } createdRepo, resp, err := client.Repositories.Create(ctx, "", repo) + + if err != nil { + return nil, fmt.Errorf("failed to create repository: %w", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusCreated { + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + return mcp.NewToolResultError(fmt.Sprintf("failed to create repository: %s", string(body))), nil + } + + r, err := json.Marshal(createdRepo) + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + + return mcp.NewToolResultText(string(r)), nil + } +} + +// CreateRepositoryFromTemplate creates a tool to create a new GitHub repository from a template. +func CreateRepositoryFromTemplate(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) { + return mcp.NewTool("create_repository_from_template", + mcp.WithDescription(t("TOOL_CREATE_REPOSITORY_FROM_TEMPLATE_DESCRIPTION", "Create a new GitHub repository from template in your account")), + mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: t("TOOL_CREATE_REPOSITORY_FROM_TEMPLATE_USER_TITLE", "Create repository from template"), + ReadOnlyHint: ToBoolPtr(false), + }), + mcp.WithString("template_owner", + mcp.Required(), + mcp.Description("template owner"), + ), + mcp.WithString("template_repo", + mcp.Required(), + mcp.Description("The name of the template repository"), + ), + mcp.WithString("name", + mcp.Required(), + mcp.Description("Repository name"), + ), + mcp.WithString("description", + mcp.Description("Repository description"), + ), + mcp.WithBoolean("private", + mcp.Description("Whether repo should be private"), + ), + ), + func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + template_owner, err := RequiredParam[string](request, "template_owner") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + template_repo, err := RequiredParam[string](request, "template_repo") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + name, err := RequiredParam[string](request, "name") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + description, err := OptionalParam[string](request, "description") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + private, err := OptionalParam[bool](request, "private") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + + repo := &github.TemplateRepoRequest{ + Name: github.Ptr(name), + Description: github.Ptr(description), + Private: github.Ptr(private), + } + + client, err := getClient(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get GitHub client: %w", err) + } + createdRepo, resp, err := client.Repositories.CreateFromTemplate(ctx, template_owner, template_repo, repo) + if err != nil { return nil, fmt.Errorf("failed to create repository: %w", err) } diff --git a/pkg/github/tools.go b/pkg/github/tools.go index 9569c439..cc11e3a5 100644 --- a/pkg/github/tools.go +++ b/pkg/github/tools.go @@ -35,6 +35,7 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG AddWriteTools( toolsets.NewServerTool(CreateOrUpdateFile(getClient, t)), toolsets.NewServerTool(CreateRepository(getClient, t)), + toolsets.NewServerTool(CreateRepositoryFromTemplate(getClient, t)), toolsets.NewServerTool(ForkRepository(getClient, t)), toolsets.NewServerTool(CreateBranch(getClient, t)), toolsets.NewServerTool(PushFiles(getClient, t)),