Skip to content

Commit c53d788

Browse files
committed
add support for the push_files tool
1 parent 7c772d2 commit c53d788

File tree

4 files changed

+431
-6
lines changed

4 files changed

+431
-6
lines changed

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
148148
- `branch`: Branch name (string, optional)
149149
- `sha`: File SHA if updating (string, optional)
150150

151+
- **push_files** - Push multiple files in a single commit
152+
153+
- `owner`: Repository owner (string, required)
154+
- `repo`: Repository name (string, required)
155+
- `branch`: Branch to push to (string, required)
156+
- `files`: Files to push, each with path and content (array, required)
157+
- `message`: Commit message (string, required)
158+
151159
- **search_repositories** - Search for GitHub repositories
152160

153161
- `query`: Search query (string, required)
@@ -385,12 +393,6 @@ I'd like to know more about my GitHub profile.
385393
386394
## TODO
387395
388-
Lots of things!
389-
390-
Missing tools:
391-
392-
- push_files (files array)
393-
394396
Testing
395397
396398
- Integration tests

pkg/github/repositories.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,118 @@ func createBranch(client *github.Client, t translations.TranslationHelperFunc) (
413413
return mcp.NewToolResultText(string(r)), nil
414414
}
415415
}
416+
417+
// pushFiles creates a tool to push multiple files in a single commit to a GitHub repository.
418+
func pushFiles(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
419+
return mcp.NewTool("push_files",
420+
mcp.WithDescription(t("TOOL_PUSH_FILES_DESCRIPTION", "Push multiple files to a GitHub repository in a single commit")),
421+
mcp.WithString("owner",
422+
mcp.Required(),
423+
mcp.Description("Repository owner"),
424+
),
425+
mcp.WithString("repo",
426+
mcp.Required(),
427+
mcp.Description("Repository name"),
428+
),
429+
mcp.WithString("branch",
430+
mcp.Required(),
431+
mcp.Description("Branch to push to"),
432+
),
433+
mcp.WithArray("files",
434+
mcp.Required(),
435+
mcp.Description("Array of file objects to push, each object with path (string) and content (string)"),
436+
),
437+
mcp.WithString("message",
438+
mcp.Required(),
439+
mcp.Description("Commit message"),
440+
),
441+
),
442+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
443+
owner := request.Params.Arguments["owner"].(string)
444+
repo := request.Params.Arguments["repo"].(string)
445+
branch := request.Params.Arguments["branch"].(string)
446+
message := request.Params.Arguments["message"].(string)
447+
448+
// Parse files parameter - this should be an array of objects with path and content
449+
filesObj, ok := request.Params.Arguments["files"].([]interface{})
450+
if !ok {
451+
return mcp.NewToolResultError("files parameter must be an array of objects with path and content"), nil
452+
}
453+
454+
// Get the reference for the branch
455+
ref, resp, err := client.Git.GetRef(ctx, owner, repo, "refs/heads/"+branch)
456+
if err != nil {
457+
return nil, fmt.Errorf("failed to get branch reference: %w", err)
458+
}
459+
defer func() { _ = resp.Body.Close() }()
460+
461+
// Get the commit object that the branch points to
462+
baseCommit, resp, err := client.Git.GetCommit(ctx, owner, repo, *ref.Object.SHA)
463+
if err != nil {
464+
return nil, fmt.Errorf("failed to get base commit: %w", err)
465+
}
466+
defer func() { _ = resp.Body.Close() }()
467+
468+
// Create tree entries for all files
469+
var entries []*github.TreeEntry
470+
471+
for _, file := range filesObj {
472+
fileMap, ok := file.(map[string]interface{})
473+
if !ok {
474+
return mcp.NewToolResultError("each file must be an object with path and content"), nil
475+
}
476+
477+
path, ok := fileMap["path"].(string)
478+
if !ok || path == "" {
479+
return mcp.NewToolResultError("each file must have a path"), nil
480+
}
481+
482+
content, ok := fileMap["content"].(string)
483+
if !ok {
484+
return mcp.NewToolResultError("each file must have content"), nil
485+
}
486+
487+
// Create a tree entry for the file
488+
entries = append(entries, &github.TreeEntry{
489+
Path: github.Ptr(path),
490+
Mode: github.Ptr("100644"), // Regular file mode
491+
Type: github.Ptr("blob"),
492+
Content: github.Ptr(content),
493+
})
494+
}
495+
496+
// Create a new tree with the file entries
497+
newTree, resp, err := client.Git.CreateTree(ctx, owner, repo, *baseCommit.Tree.SHA, entries)
498+
if err != nil {
499+
return nil, fmt.Errorf("failed to create tree: %w", err)
500+
}
501+
defer func() { _ = resp.Body.Close() }()
502+
503+
// Create a new commit
504+
commit := &github.Commit{
505+
Message: github.Ptr(message),
506+
Tree: newTree,
507+
Parents: []*github.Commit{{SHA: baseCommit.SHA}},
508+
}
509+
newCommit, resp, err := client.Git.CreateCommit(ctx, owner, repo, commit, nil)
510+
if err != nil {
511+
return nil, fmt.Errorf("failed to create commit: %w", err)
512+
}
513+
defer func() { _ = resp.Body.Close() }()
514+
515+
// Update the reference to point to the new commit
516+
ref.Object.SHA = newCommit.SHA
517+
updatedRef, resp, err := client.Git.UpdateRef(ctx, owner, repo, ref, false)
518+
if err != nil {
519+
return nil, fmt.Errorf("failed to update reference: %w", err)
520+
}
521+
defer func() { _ = resp.Body.Close() }()
522+
523+
r, err := json.Marshal(updatedRef)
524+
if err != nil {
525+
return nil, fmt.Errorf("failed to marshal response: %w", err)
526+
}
527+
528+
return mcp.NewToolResultText(string(r)), nil
529+
}
530+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy