Skip to content

Commit d9ea432

Browse files
committed
fix: minor UI improvements
1 parent da53d9f commit d9ea432

3 files changed

Lines changed: 103 additions & 88 deletions

File tree

doc/mcp/servers_json.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@ Adding, editing, deleting and securing MCP servers in easy and intuitive with MC
1515

1616
![Image](https://github.com/user-attachments/assets/f5c8adfa-601e-4d03-8745-75180a9d3648)
1717

18-
#### One click AI install with Avante and CodeCompanion
19-
![Image](https://github.com/user-attachments/assets/2d0a0d8b-18ca-4ac8-a207-4758d09d359d)
18+
#### One Click Install/Uninstall
2019

21-
#### Or Simple copy paste `mcpServers` json block in the README
20+
Choose from different install options:
2221

23-
![Image](https://github.com/user-attachments/assets/359bc81e-d6fe-47bb-a25b-572bf280851e)
24-
<!-- ![Image](https://github.com/user-attachments/assets/f58fcba3-8670-4b4e-998b-cd70b9e6c7ec) -->
22+
![Image](https://github.com/user-attachments/assets/560bddda-e48d-488b-a9f8-7b188178914c)
2523

2624

2725
### From Hub View

lua/mcphub/ui/views/marketplace.lua

Lines changed: 98 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,74 @@ function MarketplaceView:before_leave()
210210
end
211211

212212
function MarketplaceView:setup_active_mode()
213+
local function enter_detail_mode()
214+
local cursor = vim.api.nvim_win_get_cursor(0)
215+
local server = self:get_server_at_line(cursor[1])
216+
if server then
217+
self.cursor_positions.browse_mode = cursor
218+
self.selected_server = server
219+
self.active_mode = "details"
220+
self.active_installation_index = 1
221+
self:setup_active_mode()
222+
self:draw()
223+
local install_line = self.interactive_lines[1]
224+
vim.api.nvim_win_set_cursor(0, { install_line and install_line.line or 7, 0 })
225+
end
226+
end
227+
local function go_to_browse_mode()
228+
self.cursor_positions.details_mode = vim.api.nvim_win_get_cursor(0)
229+
self.active_mode = "browse"
230+
self.selected_server = nil
231+
self:setup_active_mode()
232+
self:draw()
233+
-- Restore browse mode position
234+
if self.cursor_positions.browse_mode then
235+
vim.api.nvim_win_set_cursor(0, self.cursor_positions.browse_mode)
236+
end
237+
end
238+
local function install_server()
239+
local cursor = vim.api.nvim_win_get_cursor(0)
240+
local type, context = self:get_line_info(cursor[1])
241+
242+
if type == "install_with_method" and not State:is_server_installed(self.selected_server.id) then
243+
-- Open installation editor directly
244+
self:handle_installation_selection(
245+
context --[[@as { server: MarketplaceItem, installation: MarketplaceInstallation }]]
246+
)
247+
elseif type == "uninstall_server" and State:is_server_installed(self.selected_server.id) then
248+
-- Show confirmation and uninstall
249+
if context then
250+
local server_id = context.server.id --[[@as string]]
251+
utils.confirm_and_delete_server(server_id)
252+
end
253+
end
254+
end
255+
local function cycle_method(forward)
256+
if self.selected_server and self.selected_server.installations then
257+
local num_installations = #self.selected_server.installations
258+
if num_installations >= 1 then
259+
local is_installed = State:is_server_installed(self.selected_server.id)
260+
local max_index = is_installed and num_installations + 1 or num_installations
261+
262+
if forward then
263+
self.active_installation_index = (self.active_installation_index % max_index) + 1
264+
else
265+
self.active_installation_index = ((self.active_installation_index - 2) % max_index) + 1
266+
end
267+
268+
self:draw()
269+
-- Keep cursor on install/uninstall line
270+
if self.interactive_lines and #self.interactive_lines > 0 then
271+
for _, line_info in ipairs(self.interactive_lines) do
272+
if line_info.type == "install_with_method" or line_info.type == "uninstall_server" then
273+
vim.api.nvim_win_set_cursor(0, { line_info.line, 0 })
274+
break
275+
end
276+
end
277+
end
278+
end
279+
end
280+
end
213281
if self.active_mode == "browse" then
214282
self.keymaps = {
215283
["/"] = {
@@ -308,89 +376,34 @@ function MarketplaceView:setup_active_mode()
308376
desc = "Clear filters",
309377
},
310378
["l"] = {
311-
action = function()
312-
local cursor = vim.api.nvim_win_get_cursor(0)
313-
local server = self:get_server_at_line(cursor[1])
314-
if server then
315-
self.cursor_positions.browse_mode = cursor
316-
self.selected_server = server
317-
self.active_mode = "details"
318-
self.active_installation_index = 1
319-
self:setup_active_mode()
320-
self:draw()
321-
local install_line = self.interactive_lines[1]
322-
vim.api.nvim_win_set_cursor(0, { install_line and install_line.line or 7, 0 })
323-
end
324-
end,
379+
action = enter_detail_mode,
380+
desc = "View details",
381+
},
382+
["<Cr>"] = {
383+
action = enter_detail_mode,
325384
desc = "View details",
326385
},
327386
}
328387
else
329388
self.keymaps = {
330-
["h"] = {
331-
action = function()
332-
self.cursor_positions.details_mode = vim.api.nvim_win_get_cursor(0)
333-
self.active_mode = "browse"
334-
self.selected_server = nil
335-
self:setup_active_mode()
336-
self:draw()
337-
-- Restore browse mode position
338-
if self.cursor_positions.browse_mode then
339-
vim.api.nvim_win_set_cursor(0, self.cursor_positions.browse_mode)
340-
end
341-
end,
389+
["<Esc>"] = {
390+
action = go_to_browse_mode,
342391
desc = "Back to list",
343392
},
344-
["<Tab>"] = {
393+
["l"] = {
345394
action = function()
346-
if self.selected_server and self.selected_server.installations then
347-
local num_installations = #self.selected_server.installations
348-
if num_installations >= 1 then
349-
local is_installed = State:is_server_installed(self.selected_server.id)
350-
-- For installed servers, we have 1 extra "Current" tab
351-
self.active_installation_index = (
352-
self.active_installation_index
353-
% (is_installed and num_installations + 1 or num_installations)
354-
) + 1
355-
self:draw()
356-
-- Keep cursor on install/uninstall line
357-
if self.interactive_lines and #self.interactive_lines > 0 then
358-
for _, line_info in ipairs(self.interactive_lines) do
359-
if
360-
line_info.type == "install_with_method"
361-
or line_info.type == "uninstall_server"
362-
then
363-
vim.api.nvim_win_set_cursor(0, { line_info.line, 0 })
364-
break
365-
end
366-
end
367-
end
368-
end
369-
end
395+
cycle_method(true)
370396
end,
371-
desc = "Switch installation method",
397+
desc = "Switch method",
372398
},
373-
["l"] = {
399+
["h"] = {
374400
action = function()
375-
local cursor = vim.api.nvim_win_get_cursor(0)
376-
local type, context = self:get_line_info(cursor[1])
377-
378-
if type == "install_with_method" and not State:is_server_installed(self.selected_server.id) then
379-
-- Open installation editor directly
380-
self:handle_installation_selection(
381-
context --[[@as { server: MarketplaceItem, installation: MarketplaceInstallation }]]
382-
)
383-
elseif type == "uninstall_server" and State:is_server_installed(self.selected_server.id) then
384-
-- Show confirmation and uninstall
385-
if context then
386-
local server_id = context.server.id --[[@as string]]
387-
utils.confirm_and_delete_server(server_id)
388-
end
389-
else
390-
-- Normal vim movement: move cursor right
391-
vim.cmd("normal! l")
392-
end
401+
cycle_method(false)
393402
end,
403+
desc = "Switch method",
404+
},
405+
["<Cr>"] = {
406+
action = install_server,
394407
desc = "Install/Uninstall",
395408
},
396409
}
@@ -416,8 +429,8 @@ function MarketplaceView:handle_installation_selection(context)
416429
start_insert = false,
417430
go_to_placeholder = true, -- Position cursor at first ${} placeholder
418431
virtual_lines = {
419-
{ Text.icons.hint .. " ${VARIABLES} will be resolved from environment if not replaced", "DiagnosticHint" },
420-
{ Text.icons.hint .. " ${cmd: echo 'secret'} will run command and replace ${}", "DiagnosticHint" },
432+
{ Text.icons.hint .. " ${VARIABLES} will be resolved from environment if not replaced", "Comment" },
433+
{ Text.icons.hint .. " ${cmd: echo 'secret'} will run command and replace ${}", "Comment" },
421434
},
422435
on_success = function()
423436
-- Switch to main view and browse mode after successful installation
@@ -666,6 +679,10 @@ function MarketplaceView:render_browse_mode(line_offset)
666679
end
667680
end
668681

682+
local info_line = NuiLine()
683+
info_line:append(Text.icons.bug .. " Report issues or suggest changes: ", Text.highlights.title)
684+
info_line:append("https://github.com/ravitemer/mcp-registry", Text.highlights.link)
685+
table.insert(lines, Text.pad_line(info_line))
669686
return lines
670687
end
671688

@@ -772,13 +789,13 @@ function MarketplaceView:render_details_mode(line_offset)
772789
self:track_line(#lines + line_offset, "uninstall_server", {
773790
type = "uninstall_server",
774791
server = server,
775-
hint = "[<l> Uninstall, <Tab> Switch Installation]",
792+
hint = "[<Cr> Uninstall, <l> Switch Method]",
776793
})
777794

778795
table.insert(lines, Text.pad_line(NuiLine()))
779-
local prereq_line = NuiLine()
780-
prereq_line:append("PREVIEW ", Text.highlights.muted)
781-
table.insert(lines, Text.pad_line(prereq_line))
796+
-- local prereq_line = NuiLine()
797+
-- prereq_line:append("PREVIEW ", Text.highlights.muted)
798+
-- table.insert(lines, Text.pad_line(prereq_line))
782799
table.insert(lines, self:divider())
783800

784801
-- Show details based on active tab
@@ -821,7 +838,7 @@ function MarketplaceView:render_details_mode(line_offset)
821838
type = "install_with_method",
822839
server = server,
823840
installation = active_installation,
824-
hint = "[<l> Install, <Tab> Switch Method]",
841+
hint = "[<Cr> Install, <l> Switch Method]",
825842
})
826843

827844
table.insert(lines, Text.pad_line(NuiLine()))
@@ -834,9 +851,9 @@ function MarketplaceView:render_details_mode(line_offset)
834851
-- table.insert(lines, Text.pad_line(prereq_line))
835852
-- end
836853

837-
local prereq_line = NuiLine()
838-
prereq_line:append("PREVIEW ", Text.highlights.muted)
839-
table.insert(lines, Text.pad_line(prereq_line))
854+
-- local prereq_line = NuiLine()
855+
-- prereq_line:append("PREVIEW ", Text.highlights.muted)
856+
-- table.insert(lines, Text.pad_line(prereq_line))
840857
table.insert(lines, self:divider())
841858

842859
-- Show active installation details

lua/mcphub/utils/ui.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ function M.multiline_input(title, content, on_save, opts)
8686
local cursor = vim.api.nvim_win_get_cursor(0)
8787
local row = cursor[1] - 1
8888
vim.api.nvim_buf_set_extmark(bufnr, ns, row, 0, {
89-
virt_text = { { "Press <CR> to save", "Comment" } },
90-
virt_text_pos = "eol",
89+
virt_text = { { "[<i> Edit, <Cr> Save]", "Comment" } },
90+
virt_text_pos = "right_align",
9191
})
9292
end
9393
end

0 commit comments

Comments
 (0)