bradlives commited on
Commit
d125562
Β·
verified Β·
1 Parent(s): 4945f68

Upload ShellMcp.cs with huggingface_hub

Browse files
Files changed (1) hide show
  1. ShellMcp.cs +425 -5
ShellMcp.cs CHANGED
@@ -25,11 +25,11 @@ namespace ShellMcp
25
 
26
  var builder = Host.CreateApplicationBuilder(args);
27
 
 
 
28
  builder.Logging.ClearProviders();
29
- builder.Logging.AddConsole(options =>
30
- {
31
- options.LogToStandardErrorThreshold = LogLevel.Trace;
32
- });
33
 
34
  builder.Services
35
  .AddMcpServer()
@@ -392,7 +392,7 @@ namespace ShellMcp
392
  writer.WriteLine(command);
393
  var response = reader.ReadLine() ?? "No response";
394
  // Decode newlines
395
- return response.Replace("<<CRLF>>", "\r\n").Replace("<<LF>>", "\n");
396
  }
397
 
398
  public static string Prefill(string host, int port, string user, string? password = null)
@@ -407,6 +407,159 @@ namespace ShellMcp
407
  {
408
  return SendCommand("__CONNECT__");
409
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  }
411
 
412
  // ===============================================
@@ -600,5 +753,272 @@ namespace ShellMcp
600
  return $"❌ Error: {ex.Message}";
601
  }
602
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  }
604
  }
 
25
 
26
  var builder = Host.CreateApplicationBuilder(args);
27
 
28
+ // CRITICAL: Disable ALL console logging for MCP stdio transport
29
+ // Any stdout output will corrupt the JSON-RPC protocol and cause hangs
30
  builder.Logging.ClearProviders();
31
+ // Optionally log to a file for debugging:
32
+ // builder.Logging.AddFile("shell-mcp.log");
 
 
33
 
34
  builder.Services
35
  .AddMcpServer()
 
392
  writer.WriteLine(command);
393
  var response = reader.ReadLine() ?? "No response";
394
  // Decode newlines
395
+ return response.Replace("<<CRLF>>", "\r\n").Replace("<<LF>>", "\n").Replace("<<CR>>", "\r");
396
  }
397
 
398
  public static string Prefill(string host, int port, string user, string? password = null)
 
407
  {
408
  return SendCommand("__CONNECT__");
409
  }
410
+
411
+ public static string GetPenStatus()
412
+ {
413
+ try
414
+ {
415
+ return SendCommand("__PEN_STATUS__");
416
+ }
417
+ catch
418
+ {
419
+ return "BRIDGE_NOT_RUNNING";
420
+ }
421
+ }
422
+
423
+ public static string PutPenDown()
424
+ {
425
+ try
426
+ {
427
+ return SendCommand("__PEN_DOWN__");
428
+ }
429
+ catch
430
+ {
431
+ return "BRIDGE_NOT_RUNNING";
432
+ }
433
+ }
434
+
435
+ public static string SendAbort()
436
+ {
437
+ try
438
+ {
439
+ return SendCommand("__ABORT__");
440
+ }
441
+ catch
442
+ {
443
+ return "BRIDGE_NOT_RUNNING";
444
+ }
445
+ }
446
+
447
+ public static string IsRunning()
448
+ {
449
+ try
450
+ {
451
+ return SendCommand("__IS_RUNNING__");
452
+ }
453
+ catch
454
+ {
455
+ return "BRIDGE_NOT_RUNNING";
456
+ }
457
+ }
458
+
459
+ public static string KillPort(int port)
460
+ {
461
+ try
462
+ {
463
+ return SendCommand($"__KILL_PORT__:{port}");
464
+ }
465
+ catch
466
+ {
467
+ return "BRIDGE_NOT_RUNNING";
468
+ }
469
+ }
470
+
471
+ public static string SetTimeout(int seconds)
472
+ {
473
+ try
474
+ {
475
+ return SendCommand($"__TIMEOUT__:{seconds}");
476
+ }
477
+ catch
478
+ {
479
+ return "BRIDGE_NOT_RUNNING";
480
+ }
481
+ }
482
+
483
+ public static string GetTail()
484
+ {
485
+ try
486
+ {
487
+ return SendCommand("__TAIL__");
488
+ }
489
+ catch
490
+ {
491
+ return "BRIDGE_NOT_RUNNING";
492
+ }
493
+ }
494
+
495
+ public static string ListSpawned()
496
+ {
497
+ try
498
+ {
499
+ return SendCommand("__LIST_SPAWNED__");
500
+ }
501
+ catch
502
+ {
503
+ return "BRIDGE_NOT_RUNNING";
504
+ }
505
+ }
506
+
507
+ public static string Spawn(string name, string command)
508
+ {
509
+ try
510
+ {
511
+ return SendCommand($"__SPAWN__:{name}:{command}");
512
+ }
513
+ catch
514
+ {
515
+ return "BRIDGE_NOT_RUNNING";
516
+ }
517
+ }
518
+
519
+ public static string KillSpawned(string name)
520
+ {
521
+ try
522
+ {
523
+ return SendCommand($"__KILL_SPAWNED__:{name}");
524
+ }
525
+ catch
526
+ {
527
+ return "BRIDGE_NOT_RUNNING";
528
+ }
529
+ }
530
+
531
+ public static string WriteFile(string path, string content)
532
+ {
533
+ try
534
+ {
535
+ // Encode newlines for line-based protocol
536
+ var encoded = content
537
+ .Replace("\r\n", "<<CRLF>>")
538
+ .Replace("\n", "<<LF>>")
539
+ .Replace("\r", "<<CR>>");
540
+ return SendCommand($"__WRITE_FILE__:{path}|{encoded}");
541
+ }
542
+ catch
543
+ {
544
+ return "BRIDGE_NOT_RUNNING";
545
+ }
546
+ }
547
+
548
+ public static string AppendFile(string path, string content)
549
+ {
550
+ try
551
+ {
552
+ var encoded = content
553
+ .Replace("\r\n", "<<CRLF>>")
554
+ .Replace("\n", "<<LF>>")
555
+ .Replace("\r", "<<CR>>");
556
+ return SendCommand($"__APPEND_FILE__:{path}|{encoded}");
557
+ }
558
+ catch
559
+ {
560
+ return "BRIDGE_NOT_RUNNING";
561
+ }
562
+ }
563
  }
564
 
565
  // ===============================================
 
753
  return $"❌ Error: {ex.Message}";
754
  }
755
  }
756
+
757
+ [McpServerTool, Description("Check if user has lifted the pen (paused command execution). When pen is lifted, commands will be blocked until pen is put back down.")]
758
+ public static string SshPenStatus()
759
+ {
760
+ try
761
+ {
762
+ if (!SshBridgeClient.IsBridgeRunning())
763
+ {
764
+ return "❌ SSH Bridge not running";
765
+ }
766
+
767
+ var status = SshBridgeClient.GetPenStatus();
768
+ return status switch
769
+ {
770
+ "PEN_LIFTED" => "βœ‹ Pen is LIFTED - User has paused command execution. Wait for user or call SshPenDown to request resumption.",
771
+ "PEN_DOWN" => "✏️ Pen is DOWN - Commands will execute normally.",
772
+ _ => $"⚠️ Unknown status: {status}"
773
+ };
774
+ }
775
+ catch
776
+ {
777
+ return "❌ SSH Bridge not running";
778
+ }
779
+ }
780
+
781
+ [McpServerTool, Description("Request to put the pen back down (resume command execution). Only works if pen was lifted. User can also click the button manually.")]
782
+ public static string SshPenDown()
783
+ {
784
+ try
785
+ {
786
+ if (!SshBridgeClient.IsBridgeRunning())
787
+ {
788
+ return "❌ SSH Bridge not running";
789
+ }
790
+
791
+ var result = SshBridgeClient.PutPenDown();
792
+ return result switch
793
+ {
794
+ "PEN_LOWERED" => "✏️ Pen lowered - Command execution resumed.",
795
+ "PEN_ALREADY_DOWN" => "✏️ Pen was already down - Commands executing normally.",
796
+ _ => $"⚠️ Unexpected response: {result}"
797
+ };
798
+ }
799
+ catch
800
+ {
801
+ return "❌ SSH Bridge not running";
802
+ }
803
+ }
804
+
805
+ [McpServerTool, Description("Send Ctrl+C (abort signal) to the currently running command. Use this when a command is taking too long or appears stuck.")]
806
+ public static string SshAbort()
807
+ {
808
+ try
809
+ {
810
+ if (!SshBridgeClient.IsBridgeRunning())
811
+ {
812
+ return "❌ SSH Bridge not running";
813
+ }
814
+
815
+ var result = SshBridgeClient.SendAbort();
816
+ return result switch
817
+ {
818
+ "ABORT_SENT" => "πŸ›‘ Abort signal (Ctrl+C) sent to running command.",
819
+ "NO_COMMAND_RUNNING" => "ℹ️ No command currently running.",
820
+ _ => $"⚠️ Response: {result}"
821
+ };
822
+ }
823
+ catch
824
+ {
825
+ return "❌ SSH Bridge not running";
826
+ }
827
+ }
828
+
829
+ [McpServerTool, Description("Check if a command is currently running on the SSH connection.")]
830
+ public static string SshIsRunning()
831
+ {
832
+ try
833
+ {
834
+ if (!SshBridgeClient.IsBridgeRunning())
835
+ {
836
+ return "❌ SSH Bridge not running";
837
+ }
838
+
839
+ var result = SshBridgeClient.IsRunning();
840
+ return result switch
841
+ {
842
+ "RUNNING" => "⚑ A command is currently running.",
843
+ "IDLE" => "βœ… No command running - ready for new commands.",
844
+ _ => $"⚠️ Status: {result}"
845
+ };
846
+ }
847
+ catch
848
+ {
849
+ return "❌ SSH Bridge not running";
850
+ }
851
+ }
852
+
853
+ [McpServerTool, Description("Kill process listening on a specific port. Useful for freeing up ports or killing hung services.")]
854
+ public static string SshKillPort(
855
+ [Description("Port number to kill (1-65535)")] int port)
856
+ {
857
+ try
858
+ {
859
+ if (!SshBridgeClient.IsBridgeRunning())
860
+ {
861
+ return "❌ SSH Bridge not running";
862
+ }
863
+
864
+ if (port < 1 || port > 65535)
865
+ {
866
+ return "❌ Invalid port number. Must be 1-65535.";
867
+ }
868
+
869
+ var result = SshBridgeClient.KillPort(port);
870
+ return $"πŸ”« Kill port {port}:\n{result}";
871
+ }
872
+ catch
873
+ {
874
+ return "❌ SSH Bridge not running";
875
+ }
876
+ }
877
+
878
+ [McpServerTool, Description("Set timeout for the next SSH command. Useful for long-running operations like large downloads.")]
879
+ public static string SshSetTimeout(
880
+ [Description("Timeout in seconds (1-3600)")] int seconds)
881
+ {
882
+ try
883
+ {
884
+ if (!SshBridgeClient.IsBridgeRunning())
885
+ {
886
+ return "❌ SSH Bridge not running";
887
+ }
888
+
889
+ if (seconds < 1 || seconds > 3600)
890
+ {
891
+ return "❌ Invalid timeout. Must be 1-3600 seconds.";
892
+ }
893
+
894
+ var result = SshBridgeClient.SetTimeout(seconds);
895
+ return $"⏱️ {result}";
896
+ }
897
+ catch
898
+ {
899
+ return "❌ SSH Bridge not running";
900
+ }
901
+ }
902
+
903
+ [McpServerTool, Description("Get the last 50 lines of output from the SSH Bridge terminal. Useful for checking progress of background tasks.")]
904
+ public static string SshTail()
905
+ {
906
+ try
907
+ {
908
+ if (!SshBridgeClient.IsBridgeRunning())
909
+ {
910
+ return "❌ SSH Bridge not running";
911
+ }
912
+
913
+ var result = SshBridgeClient.GetTail();
914
+ return $"πŸ“œ Recent output:\n{result}";
915
+ }
916
+ catch
917
+ {
918
+ return "❌ SSH Bridge not running";
919
+ }
920
+ }
921
+
922
+ [McpServerTool, Description("List all tracked background processes spawned via SshSpawn.")]
923
+ public static string SshListSpawned()
924
+ {
925
+ try
926
+ {
927
+ if (!SshBridgeClient.IsBridgeRunning())
928
+ {
929
+ return "❌ SSH Bridge not running";
930
+ }
931
+
932
+ var result = SshBridgeClient.ListSpawned();
933
+ return $"πŸ“‹ Background processes:\n{result}";
934
+ }
935
+ catch
936
+ {
937
+ return "❌ SSH Bridge not running";
938
+ }
939
+ }
940
+
941
+ [McpServerTool, Description("Spawn a background process with a trackable name. Use SshListSpawned to see status and SshKillSpawned to terminate.")]
942
+ public static string SshSpawn(
943
+ [Description("Name to identify this background process")] string name,
944
+ [Description("Command to run in background")] string command)
945
+ {
946
+ try
947
+ {
948
+ if (!SshBridgeClient.IsBridgeRunning())
949
+ {
950
+ return "❌ SSH Bridge not running";
951
+ }
952
+
953
+ var result = SshBridgeClient.Spawn(name, command);
954
+ return $"πŸš€ {result}";
955
+ }
956
+ catch
957
+ {
958
+ return "❌ SSH Bridge not running";
959
+ }
960
+ }
961
+
962
+ [McpServerTool, Description("Kill a background process by name (spawned via SshSpawn or matching window title).")]
963
+ public static string SshKillSpawned(
964
+ [Description("Name of the background process to kill")] string name)
965
+ {
966
+ try
967
+ {
968
+ if (!SshBridgeClient.IsBridgeRunning())
969
+ {
970
+ return "❌ SSH Bridge not running";
971
+ }
972
+
973
+ var result = SshBridgeClient.KillSpawned(name);
974
+ return $"πŸ”« {result}";
975
+ }
976
+ catch
977
+ {
978
+ return "❌ SSH Bridge not running";
979
+ }
980
+ }
981
+
982
+ [McpServerTool, Description("Write content to a file on the remote system without shell escaping. Perfect for batch files, configs, etc.")]
983
+ public static string SshWriteFile(
984
+ [Description("Full path to file (e.g., C:\\scripts\\run.bat)")] string path,
985
+ [Description("Content to write - characters like & | < > will NOT be escaped")] string content)
986
+ {
987
+ try
988
+ {
989
+ if (!SshBridgeClient.IsBridgeRunning())
990
+ {
991
+ return "❌ SSH Bridge not running";
992
+ }
993
+
994
+ var result = SshBridgeClient.WriteFile(path, content);
995
+ return $"πŸ“ {result}";
996
+ }
997
+ catch
998
+ {
999
+ return "❌ SSH Bridge not running";
1000
+ }
1001
+ }
1002
+
1003
+ [McpServerTool, Description("Append content to a file on the remote system without shell escaping.")]
1004
+ public static string SshAppendFile(
1005
+ [Description("Full path to file")] string path,
1006
+ [Description("Content to append - characters like & | < > will NOT be escaped")] string content)
1007
+ {
1008
+ try
1009
+ {
1010
+ if (!SshBridgeClient.IsBridgeRunning())
1011
+ {
1012
+ return "❌ SSH Bridge not running";
1013
+ }
1014
+
1015
+ var result = SshBridgeClient.AppendFile(path, content);
1016
+ return $"πŸ“ {result}";
1017
+ }
1018
+ catch
1019
+ {
1020
+ return "❌ SSH Bridge not running";
1021
+ }
1022
+ }
1023
  }
1024
  }