@@ -413,3 +413,118 @@ func createBranch(client *github.Client, t translations.TranslationHelperFunc) (
413413return 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+ }