11using NLog . Web ;
22using mcp_nexus . Tools ;
33using mcp_nexus . Helper ;
4+ using mcp_nexus . Services ;
45using System . CommandLine ;
56using System . CommandLine . Parsing ;
7+ using System . Runtime . Versioning ;
68using System . Text . Json ;
9+ using Microsoft . Extensions . Logging ;
710
811namespace mcp_nexus
912{
@@ -12,68 +15,186 @@ internal class Program
1215 private static async Task Main ( string [ ] args )
1316 {
1417 // Parse command line arguments
15- var ( customCdbPath , useHttp ) = ParseCommandLineArguments ( args ) ;
18+ var commandLineArgs = ParseCommandLineArguments ( args ) ;
19+
20+ // Handle special commands first (Windows only)
21+ if ( commandLineArgs . Install )
22+ {
23+ if ( OperatingSystem . IsWindows ( ) )
24+ {
25+ // Create a logger using NLog configuration for the installation process
26+ using var loggerFactory = LoggerFactory . Create ( builder =>
27+ {
28+ builder . ClearProviders ( ) ;
29+ builder . AddNLogWeb ( ) ;
30+ builder . SetMinimumLevel ( LogLevel . Information ) ;
31+ } ) ;
32+ var logger = loggerFactory . CreateLogger ( "MCP.Nexus.ServiceInstaller" ) ;
33+
34+ var success = await WindowsServiceInstaller . InstallServiceAsync ( logger ) ;
35+ Environment . Exit ( success ? 0 : 1 ) ;
36+ }
37+ else
38+ {
39+ Console . Error . WriteLine ( "ERROR: Service installation is only supported on Windows." ) ;
40+ Environment . Exit ( 1 ) ;
41+ }
42+ return ;
43+ }
44+
45+ if ( commandLineArgs . Uninstall )
46+ {
47+ if ( OperatingSystem . IsWindows ( ) )
48+ {
49+ // Create a logger using NLog configuration for the uninstallation process
50+ using var loggerFactory = LoggerFactory . Create ( builder =>
51+ {
52+ builder . ClearProviders ( ) ;
53+ builder . AddNLogWeb ( ) ;
54+ builder . SetMinimumLevel ( LogLevel . Information ) ;
55+ } ) ;
56+ var logger = loggerFactory . CreateLogger ( "MCP.Nexus.ServiceInstaller" ) ;
57+
58+ var success = await WindowsServiceInstaller . UninstallServiceAsync ( logger ) ;
59+ Environment . Exit ( success ? 0 : 1 ) ;
60+ }
61+ else
62+ {
63+ Console . Error . WriteLine ( "ERROR: Service uninstallation is only supported on Windows." ) ;
64+ Environment . Exit ( 1 ) ;
65+ }
66+ return ;
67+ }
68+
69+ if ( commandLineArgs . ForceUninstall )
70+ {
71+ if ( OperatingSystem . IsWindows ( ) )
72+ {
73+ // Create a logger using NLog configuration for the force uninstallation process
74+ using var loggerFactory = LoggerFactory . Create ( builder =>
75+ {
76+ builder . ClearProviders ( ) ;
77+ builder . AddNLogWeb ( ) ;
78+ builder . SetMinimumLevel ( LogLevel . Information ) ;
79+ } ) ;
80+ var logger = loggerFactory . CreateLogger ( "MCP.Nexus.ServiceInstaller" ) ;
81+
82+ var success = await WindowsServiceInstaller . ForceUninstallServiceAsync ( logger ) ;
83+ Environment . Exit ( success ? 0 : 1 ) ;
84+ }
85+ else
86+ {
87+ Console . Error . WriteLine ( "ERROR: Service uninstallation is only supported on Windows." ) ;
88+ Environment . Exit ( 1 ) ;
89+ }
90+ return ;
91+ }
92+
93+ // Determine transport mode
94+ bool useHttp = commandLineArgs . UseHttp || commandLineArgs . ServiceMode ;
95+
96+ // Validate service mode is only used on Windows
97+ if ( commandLineArgs . ServiceMode && ! OperatingSystem . IsWindows ( ) )
98+ {
99+ Console . Error . WriteLine ( "ERROR: Service mode is only supported on Windows." ) ;
100+ Environment . Exit ( 1 ) ;
101+ return ;
102+ }
16103
17104 if ( useHttp )
18105 {
19- await RunHttpServer ( args , customCdbPath ) ;
106+ await RunHttpServer ( args , commandLineArgs ) ;
20107 }
21108 else
22109 {
23- await RunStdioServer ( args , customCdbPath ) ;
110+ await RunStdioServer ( args , commandLineArgs ) ;
24111 }
25112 }
26113
27- private static ( string ? customCdbPath , bool useHttp ) ParseCommandLineArguments ( string [ ] args )
114+ private static CommandLineArguments ParseCommandLineArguments ( string [ ] args )
28115 {
29- string ? customCdbPath = null ;
30- bool useHttp = false ;
116+ var result = new CommandLineArguments ( ) ;
31117
32118 var cdbPathOption = new Option < string ? > ( "--cdb-path" , "Custom path to CDB.exe debugger executable" ) ;
33119 var httpOption = new Option < bool > ( "--http" , "Use HTTP transport instead of stdio" ) ;
34- var rootCommand = new RootCommand ( "MCP Nexus - Windows Debugging MCP Server" )
120+ var serviceOption = new Option < bool > ( "--service" , "Run in Windows service mode (implies --http)" ) ;
121+ var installOption = new Option < bool > ( "--install" , "Install MCP Nexus as Windows service" ) ;
122+ var uninstallOption = new Option < bool > ( "--uninstall" , "Uninstall MCP Nexus Windows service" ) ;
123+ var forceUninstallOption = new Option < bool > ( "--force-uninstall" , "Force uninstall MCP Nexus service (removes registry entries)" ) ;
124+
125+ var rootCommand = new RootCommand ( "MCP Nexus - Comprehensive MCP Server Platform" )
35126 {
36127 cdbPathOption ,
37- httpOption
128+ httpOption ,
129+ serviceOption ,
130+ installOption ,
131+ uninstallOption ,
132+ forceUninstallOption
38133 } ;
39134
40135 var parseResult = rootCommand . Parse ( args ) ;
41136 if ( parseResult . Errors . Count == 0 )
42137 {
43- customCdbPath = parseResult . GetValueForOption ( cdbPathOption ) ;
44- useHttp = parseResult . GetValueForOption ( httpOption ) ;
138+ result . CustomCdbPath = parseResult . GetValueForOption ( cdbPathOption ) ;
139+ result . UseHttp = parseResult . GetValueForOption ( httpOption ) ;
140+ result . ServiceMode = parseResult . GetValueForOption ( serviceOption ) ;
141+ result . Install = parseResult . GetValueForOption ( installOption ) ;
142+ result . Uninstall = parseResult . GetValueForOption ( uninstallOption ) ;
143+ result . ForceUninstall = parseResult . GetValueForOption ( forceUninstallOption ) ;
45144 }
46145
47- return ( customCdbPath , useHttp ) ;
146+ return result ;
48147 }
49148
50- private static async Task RunHttpServer ( string [ ] args , string ? customCdbPath )
149+ private class CommandLineArguments
51150 {
52- Console . WriteLine ( "Configuring for HTTP transport..." ) ;
151+ public string ? CustomCdbPath { get ; set ; }
152+ public bool UseHttp { get ; set ; }
153+ public bool ServiceMode { get ; set ; }
154+ public bool Install { get ; set ; }
155+ public bool Uninstall { get ; set ; }
156+ public bool ForceUninstall { get ; set ; }
157+ }
158+
159+ private static async Task RunHttpServer ( string [ ] args , CommandLineArguments commandLineArgs )
160+ {
161+ var logMessage = commandLineArgs . ServiceMode ?
162+ "Configuring for Windows service mode (HTTP)..." :
163+ "Configuring for HTTP transport..." ;
164+ Console . WriteLine ( logMessage ) ;
165+
53166 var webBuilder = WebApplication . CreateBuilder ( args ) ;
54167
55- ConfigureLogging ( webBuilder . Logging ) ;
56- RegisterServices ( webBuilder . Services , customCdbPath ) ;
168+ // Add Windows service support if in service mode
169+ if ( commandLineArgs . ServiceMode && OperatingSystem . IsWindows ( ) )
170+ {
171+ webBuilder . Host . UseWindowsService ( ) ;
172+ }
173+
174+ ConfigureLogging ( webBuilder . Logging , commandLineArgs . ServiceMode ) ;
175+ RegisterServices ( webBuilder . Services , commandLineArgs . CustomCdbPath ) ;
57176 ConfigureHttpServices ( webBuilder . Services ) ;
58177
59178 var app = webBuilder . Build ( ) ;
60179 ConfigureHttpPipeline ( app ) ;
61180
62- Console . WriteLine ( "Starting MCP Nexus HTTP server on {0}..." ,
63- string . Join ( ", " , app . Urls . DefaultIfEmpty ( "default URLs" ) ) ) ;
181+ var startMessage = commandLineArgs . ServiceMode ?
182+ "Starting MCP Nexus as Windows service..." :
183+ $ "Starting MCP Nexus HTTP server on { string . Join ( ", " , app . Urls . DefaultIfEmpty ( "default URLs" ) ) } ...";
184+ Console . WriteLine ( startMessage ) ;
64185
65186 await app . RunAsync ( ) ;
66187 }
67188
68- private static async Task RunStdioServer ( string [ ] args , string ? customCdbPath )
189+ private static async Task RunStdioServer ( string [ ] args , CommandLineArguments commandLineArgs )
69190 {
70191 // CRITICAL: In stdio mode, stdout is reserved for MCP protocol
71192 // All console output must go to stderr
72193 Console . Error . WriteLine ( "Configuring for stdio transport..." ) ;
73194 var builder = Host . CreateApplicationBuilder ( args ) ;
74195
75- ConfigureLogging ( builder . Logging ) ;
76- RegisterServices ( builder . Services , customCdbPath ) ;
196+ ConfigureLogging ( builder . Logging , false ) ;
197+ RegisterServices ( builder . Services , commandLineArgs . CustomCdbPath ) ;
77198 ConfigureStdioServices ( builder . Services ) ;
78199
79200 Console . Error . WriteLine ( "Building application host..." ) ;
@@ -83,13 +204,32 @@ private static async Task RunStdioServer(string[] args, string? customCdbPath)
83204 await host . RunAsync ( ) ;
84205 }
85206
86- private static void ConfigureLogging ( ILoggingBuilder logging )
207+ private static void ConfigureLogging ( ILoggingBuilder logging , bool isServiceMode )
87208 {
88209 // Note: We use Console.Error for stdio mode compatibility
89- Console . Error . WriteLine ( "Configuring logging..." ) ;
210+ var logMessage = "Configuring logging..." ;
211+ if ( isServiceMode )
212+ {
213+ // For service mode, logging will go to Windows Event Log and files
214+ Console . WriteLine ( logMessage ) ;
215+ }
216+ else
217+ {
218+ Console . Error . WriteLine ( logMessage ) ;
219+ }
220+
90221 logging . ClearProviders ( ) ;
91222 logging . AddNLogWeb ( ) ;
92- Console . Error . WriteLine ( "Logging configured with NLog" ) ;
223+
224+ var completeMessage = "Logging configured with NLog" ;
225+ if ( isServiceMode )
226+ {
227+ Console . WriteLine ( completeMessage ) ;
228+ }
229+ else
230+ {
231+ Console . Error . WriteLine ( completeMessage ) ;
232+ }
93233 }
94234
95235 private static void RegisterServices ( IServiceCollection services , string ? customCdbPath )
0 commit comments