@@ -292,20 +292,120 @@ function M.show_mcp_tool_prompt(params)
292292 return confirmed , cancelled
293293end
294294
295+ --- Synchronous version for RPC context (can't use async UI)
296+ --- @param params MCPHub.ParsedParams
297+ --- @return boolean confirmed
298+ --- @return boolean cancelled
299+ function M .show_mcp_tool_prompt_sync (params )
300+ local action_name = params .action
301+ local server_name = params .server_name
302+ local tool_name = params .tool_name
303+ local uri = params .uri
304+ local arguments = params .arguments or {}
305+
306+ local lines = {}
307+ local is_tool = action_name == " use_mcp_tool"
308+
309+ -- Header as a question
310+ local header_line = NuiLine ()
311+ header_line :append (Text .icons .event , Text .highlights .warn )
312+ header_line :append (" Do you want to " , Text .highlights .text )
313+ if is_tool then
314+ header_line :append (" call " , Text .highlights .text )
315+ header_line :append (tool_name , Text .highlights .warn_italic )
316+ else
317+ header_line :append (" access " , Text .highlights .text )
318+ header_line :append (uri , Text .highlights .link )
319+ end
320+ header_line :append (" on " , Text .highlights .text )
321+ header_line :append (server_name , Text .highlights .success_italic )
322+ header_line :append (" ?" , Text .highlights .text )
323+ table.insert (lines , header_line )
324+
325+ -- Parameters section
326+ if is_tool and next (arguments ) then
327+ table.insert (lines , NuiLine ():append (" " ))
328+
329+ for key , value in pairs (arguments ) do
330+ -- Parameter name
331+ local param_name_line = NuiLine ()
332+ param_name_line :append (Text .icons .param , Text .highlights .info )
333+ param_name_line :append (" " .. key .. " :" , Text .highlights .json_property )
334+ table.insert (lines , param_name_line )
335+
336+ -- Parameter value
337+ local function add_value_lines (val )
338+ if type (val ) == " string" then
339+ local value_lines = val :find (" \n " ) and vim .split (val , " \n " , { plain = true })
340+ or { ' "' .. val .. ' "' }
341+ for _ , line in ipairs (value_lines ) do
342+ local value_line = NuiLine ()
343+ value_line :append (" " .. line , Text .highlights .json_string )
344+ table.insert (lines , value_line )
345+ end
346+ elseif type (val ) == " boolean" then
347+ local value_line = NuiLine ()
348+ value_line :append (" " .. tostring (val ), Text .highlights .json_boolean )
349+ table.insert (lines , value_line )
350+ elseif type (val ) == " number" then
351+ local value_line = NuiLine ()
352+ value_line :append (" " .. tostring (val ), Text .highlights .json_number )
353+ table.insert (lines , value_line )
354+ else
355+ for _ , line in ipairs (vim .split (vim .inspect (val ), " \n " , { plain = true })) do
356+ local value_line = NuiLine ()
357+ value_line :append (" " .. line , Text .highlights .muted )
358+ table.insert (lines , value_line )
359+ end
360+ end
361+ end
362+
363+ add_value_lines (value )
364+ table.insert (lines , NuiLine ():append (" " ))
365+ end
366+ end
367+
368+ -- Fire event before showing confirmation window
369+ utils .fire (" MCPHubApprovalWindowOpened" , {
370+ action = action_name ,
371+ server_name = server_name ,
372+ tool_name = tool_name ,
373+ uri = uri ,
374+ arguments = arguments ,
375+ })
376+
377+ local confirmed , cancelled = ui_utils .confirm_sync (lines , {
378+ min_width = 70 ,
379+ max_width = 100 ,
380+ })
381+
382+ -- Fire event after user makes decision
383+ utils .fire (" MCPHubApprovalWindowClosed" , {
384+ action = action_name ,
385+ server_name = server_name ,
386+ tool_name = tool_name ,
387+ uri = uri ,
388+ arguments = arguments ,
389+ confirmed = confirmed ,
390+ cancelled = cancelled ,
391+ })
392+
393+ return confirmed , cancelled
394+ end
395+
396+ --- Check auto-approval status without showing any dialog
295397--- @param parsed_params MCPHub.ParsedParams
296398--- @return { error ?: string , approve : boolean }
297- function M .handle_auto_approval_decision (parsed_params )
399+ function M .check_auto_approval (parsed_params )
298400 local auto_approve = State .config .auto_approve or false
299401 local status = { approve = false , error = nil }
300- --- If user has a custom function that decides whether to auto-approve
301- --- call that with params + saved autoApprove state as is_auto_approved_in_server field
402+
403+ -- Check global auto_approve config (can be boolean or function)
302404 if type (auto_approve ) == " function" then
303405 local ok , res = pcall (auto_approve , parsed_params )
304406 if not ok or type (res ) == " string" then
305- --- If auto_approve function throws an error, or returns a string, treat it as an error
306407 status = { approve = false , error = res }
307408 elseif type (res ) == " boolean" then
308- --- If auto_approve function returns a boolean, use that as the decision
309409 status = { approve = res , error = nil }
310410 end
311411 elseif type (auto_approve ) == " boolean" then
@@ -317,6 +417,14 @@ function M.handle_auto_approval_decision(parsed_params)
317417 status = { approve = true , error = nil }
318418 end
319419
420+ return status
421+ end
422+
423+ --- @param parsed_params MCPHub.ParsedParams
424+ --- @return { error ?: string , approve : boolean }
425+ function M .handle_auto_approval_decision (parsed_params )
426+ local status = M .check_auto_approval (parsed_params )
427+
320428 if status .error then
321429 return { error = status .error or " Something went wrong with auto-approval" , approve = false }
322430 end
@@ -325,6 +433,25 @@ function M.handle_auto_approval_decision(parsed_params)
325433 local confirmed , _ = M .show_mcp_tool_prompt (parsed_params )
326434 return { error = not confirmed and " User cancelled the operation" , approve = confirmed }
327435 end
436+
437+ return status
438+ end
439+
440+ --- Synchronous version for RPC context (can't use async UI)
441+ --- @param parsed_params MCPHub.ParsedParams
442+ --- @return { error ?: string , approve : boolean }
443+ function M .handle_auto_approval_decision_sync (parsed_params )
444+ local status = M .check_auto_approval (parsed_params )
445+
446+ if status .error then
447+ return { error = status .error or " Something went wrong with auto-approval" , approve = false }
448+ end
449+
450+ if status .approve == false and parsed_params .needs_confirmation_window then
451+ local confirmed , _ = M .show_mcp_tool_prompt_sync (parsed_params )
452+ return { error = not confirmed and " User cancelled the operation" , approve = confirmed }
453+ end
454+
328455 return status
329456end
330457
0 commit comments