@@ -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
+ }
0 commit comments