@@ -131,6 +131,9 @@ func (h *JSHandler) handleServerCode(ctx context.Context, code string) (*mcp.Cal
131131 // Create context with custom logger
132132 ctx = js .WithLogger (ctx , logger )
133133
134+ // Channel to signal if a server was actually started
135+ serverStarted := make (chan bool , 1 )
136+
134137 // Run the server code in a goroutine
135138 go func () {
136139 // Create a custom scheduler for this server
@@ -147,33 +150,101 @@ func (h *JSHandler) handleServerCode(ctx context.Context, code string) (*mcp.Cal
147150
148151 // Override the HTTP server module if enabled
149152 if h .isModuleEnabled ("http" ) {
150- h .setupHTTPModule (vm )
153+ h .setupHTTPModuleWithCallback (vm , serverStarted )
151154 }
152155
153- // Execute the JavaScript code - this will block until server stops
156+ // Execute the JavaScript code
154157 _ , err := vm .RunString (context .Background (), code )
155158 if err != nil {
156159 // Log error but don't return it since we're in a goroutine
157160 logger .Error ("Server execution error" , "error" , err )
161+ serverStarted <- false
162+ return
163+ }
164+
165+ // If no server was started, signal false and let goroutine exit
166+ select {
167+ case serverStarted <- false :
168+ default :
169+ // Channel already has a value, meaning a server was started
158170 }
159171
160- // Keep the goroutine alive indefinitely
161- select {}
172+ // Check if we should keep the goroutine alive
173+ select {
174+ case started := <- serverStarted :
175+ if started {
176+ // Keep the goroutine alive indefinitely for HTTP servers
177+ select {}
178+ }
179+ // Otherwise, let the goroutine exit naturally
180+ default :
181+ // No signal received, let goroutine exit
182+ }
162183 }()
163184
164- // Give the server more time to start
185+ // Give the server time to start
165186 time .Sleep (500 * time .Millisecond )
166187
167188 return & mcp.CallToolResult {
168189 Content : []mcp.Content {
169190 mcp.TextContent {
170191 Type : "text" ,
171- Text : fmt .Sprintf ("Server started in background. Check console output:\n %s" , output .String ()),
192+ Text : fmt .Sprintf ("Server code executed in background. Check console output:\n %s" , output .String ()),
172193 },
173194 },
174195 }, nil
175196}
176197
198+ func (h * JSHandler ) setupHTTPModuleWithCallback (vm js.VM , serverStarted chan bool ) {
199+ // Create a custom module loader that wraps the HTTP server
200+ vm .Runtime ().Set ("__originalRequire" , vm .Runtime ().Get ("require" ))
201+ vm .Runtime ().Set ("require" , vm .Runtime ().ToValue (func (call sobek.FunctionCall ) sobek.Value {
202+ moduleName := call .Argument (0 ).String ()
203+
204+ // If requesting the HTTP server module, return our wrapped version
205+ if moduleName == "ski/http/server" {
206+ httpServer := & httpmodule.Server {}
207+ value , err := httpServer .Instantiate (vm .Runtime ())
208+ if err != nil {
209+ panic (vm .Runtime ().NewGoError (err ))
210+ }
211+
212+ // Wrap the serve function to detect when a server is actually started
213+ wrappedServe := vm .Runtime ().ToValue (func (call sobek.FunctionCall ) sobek.Value {
214+ // Call the original serve function
215+ serveFunc , ok := sobek .AssertFunction (value )
216+ if ! ok {
217+ panic (vm .Runtime ().NewTypeError ("serve is not a function" ))
218+ }
219+
220+ result , err := serveFunc (sobek .Undefined (), call .Arguments ... )
221+ if err != nil {
222+ panic (vm .Runtime ().NewGoError (err ))
223+ }
224+
225+ // Signal that a server was started
226+ select {
227+ case serverStarted <- true :
228+ default :
229+ // Channel already has a value
230+ }
231+
232+ return result
233+ })
234+
235+ return wrappedServe
236+ }
237+
238+ // For all other modules, use the original require
239+ originalRequire , _ := sobek .AssertFunction (vm .Runtime ().Get ("__originalRequire" ))
240+ result , err := originalRequire (sobek .Undefined (), call .Arguments ... )
241+ if err != nil {
242+ panic (vm .Runtime ().NewGoError (err ))
243+ }
244+ return result
245+ }))
246+ }
247+
177248func (h * JSHandler ) handleRegularCode (ctx context.Context , code string ) (* mcp.CallToolResult , error ) {
178249 // Capture console output
179250 var output bytes.Buffer
0 commit comments