@@ -413,3 +413,118 @@ func createBranch(client *github.Client, t translations.TranslationHelperFunc) (
413
413
return mcp .NewToolResultText (string (r )),nil
414
414
}
415
415
}
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
+ }