@@ -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