feat(nvim-core): consolidate nvim tools into 5 mega-tools

This commit is contained in:
Riz Ashraf committed 2026-10-09 06:08:08 +01:00
1 parent 03f8786d24
commit bce9b82b66
1 file changed
+104 -132
+104 -132
View File
@@ -1083,39 +1083,36 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
jsonrpc: "2.0".to_string(), jsonrpc: "2.0".to_string(),
id, id,
result: Some(json!({ result: Some(json!({
"tools": [ "tools":
[
{ {
"name": "nvim_buffer", "name": "nvim_buffer",
"description": "Unified buffer management: inspect, open, read, search, save, reload, or close Neovim buffers.", "description": "Core Text Editing: read, replace, save, and manipulate Neovim buffers in memory.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
"action": { "action": {
"type": "string", "type": "string",
"enum": ["get_active", "read", "open", "create_scratch", "save", "reload", "close", "list", "search", "edit", "undo", "redo"], "enum": ["read", "replace", "save", "undo", "redo", "create_scratch"],
"description": "Action to perform on the buffer" "description": "Action to perform on the buffer"
}, },
"file": { "type": "string", "description": "Target file path (for open, read, search)" }, "file": { "type": "string", "description": "Target file path (for read, replace, save)" },
"buf_id": { "type": "integer", "description": "Buffer ID (for close, reload, or split)" },
"steps": { "type": "integer", "description": "Number of undo/redo steps to apply (default: 1)" },
"content": { "type": "string", "description": "Initial text content (for create_scratch)" },
"name": { "type": "string", "description": "Buffer display name (for create_scratch)" },
"filetype": { "type": "string", "description": "Filetype syntax (for open, create_scratch)" },
"start_line": { "type": "integer", "description": "1-indexed start line (for read)" }, "start_line": { "type": "integer", "description": "1-indexed start line (for read)" },
"end_line": { "type": "integer", "description": "1-indexed end line (for read)" }, "end_line": { "type": "integer", "description": "1-indexed end line (for read)" },
"pattern": { "type": "string", "description": "Regex or substring pattern to search for (for search)" }, "content": { "type": "string", "description": "Initial text content (for create_scratch)" },
"force": { "type": "boolean", "description": "Force reload or close (for reload, close)" }, "name": { "type": "string", "description": "Buffer display name (for create_scratch)" },
"steps": { "type": "integer", "description": "Number of undo/redo steps to apply (default: 1)" },
"edits": { "edits": {
"type": "array", "type": "array",
"description": "Array of edits to apply sequentially (for edit). Grouped by file, applied in descending order.", "description": "Array of edits to apply sequentially (for replace). Grouped by file, applied in descending order.",
"items": { "items": {
"type": "object", "type": "object",
"properties": { "properties": {
"file": { "type": "string", "description": "Target file path" }, "file": { "type": "string" },
"start_line": { "type": "integer", "description": "1-indexed start line" }, "start_line": { "type": "integer" },
"end_line": { "type": "integer", "description": "1-indexed end line" }, "end_line": { "type": "integer" },
"replacement_content": { "type": "string", "description": "New content" }, "replacement_content": { "type": "string" },
"expected_content": { "type": "string", "description": "Optional: exact content expected in the replacement range to prevent line drift corruption" } "expected_content": { "type": "string" }
}, },
"required": ["file", "start_line", "end_line", "replacement_content"] "required": ["file", "start_line", "end_line", "replacement_content"]
} }
@@ -1125,166 +1122,86 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
}, },
{ {
"name": "nvim_window", "name": "nvim_workspace",
"description": "Manage Neovim windows and splits: list open windows, query or focus active window, create splits, or close windows.", "description": "Window & Editor State: list buffers, windows, focus splits, and manage cwd.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
"action": { "action": {
"type": "string", "type": "string",
"enum": ["list", "get_active", "focus", "split", "close"], "enum": ["list_buffers", "list_windows", "focus", "split", "cwd"],
"description": "Window operation to perform" "description": "Workspace operation to perform"
}, },
"win_id": { "type": "integer", "description": "Window ID to focus or close" }, "win_id": { "type": "integer", "description": "Window ID to focus" },
"file": { "type": "string", "description": "File to open in split" }, "file": { "type": "string", "description": "File to open in split" },
"buf_id": { "type": "integer", "description": "Buffer ID to attach to split" },
"direction": { "type": "string", "enum": ["vertical", "horizontal"], "description": "Split orientation (default: vertical)" }, "direction": { "type": "string", "enum": ["vertical", "horizontal"], "description": "Split orientation (default: vertical)" },
"force": { "type": "boolean", "description": "Force close window" } "path": { "type": "string", "description": "Target directory (for cwd action)" }
}, },
"required": ["action"] "required": ["action"]
} }
}, },
{ {
"name": "nvim_view", "name": "nvim_intelligence",
"description": "Editor navigation and viewport introspection: jump to line, query cursor position, get visible viewport lines, or get visual selection.", "description": "Code Semantics: LSP queries (hover, definition, references, code_action, rename, diagnostics) and AST outlining/queries.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
"action": { "action": {
"type": "string", "type": "string",
"enum": ["goto_line", "get_cursor", "get_viewport", "get_selection"], "enum": ["hover", "definition", "references", "outline", "query", "diagnostics", "rename", "code_action"],
"description": "Navigation/inspection action to perform" "description": "Intelligence action to perform"
}, },
"file": { "type": "string", "description": "File path (for goto_line)" }, "file": { "type": "string", "description": "Target file path" },
"line": { "type": "integer", "description": "Target line number (1-indexed, for goto_line)" } "line": { "type": "integer", "description": "1-indexed line number (for LSP)" },
"col": { "type": "integer", "description": "0-indexed column number (for LSP)" },
"new_name": { "type": "string", "description": "New name (for rename action)" },
"query": { "type": "string", "description": "Tree-sitter query string (for AST query)" },
"preset": { "type": "string", "description": "Query preset (e.g., 'functions', 'classes' for AST query)" }
}, },
"required": ["action"] "required": ["action"]
} }
}, },
{ {
"name": "nvim_diagnostics", "name": "nvim_ui",
"description": "LSP diagnostics and quickfix integration: fetch current diagnostics, inject LSP diagnostic markers, or populate the quickfix list.", "description": "Visual Feedback: communicating visually with the human user via highlights and ghost text.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
"action": { "action": {
"type": "string", "type": "string",
"enum": ["get", "set", "set_quickfix"], "enum": ["highlight", "ghost_text", "clear"],
"description": "Diagnostic action to perform" "description": "UI action"
}, },
"line": { "type": "integer", "description": "Line number (1-indexed, for set)" }, "buf_id": { "type": "integer", "description": "Buffer ID to apply to" },
"message": { "type": "string", "description": "Diagnostic warning/error message (for set)" }, "start_line": { "type": "integer", "description": "1-indexed start line (for highlight)" },
"items": { "end_line": { "type": "integer", "description": "1-indexed end line (for highlight)" },
"type": "array", "line": { "type": "integer", "description": "1-indexed line number (for ghost_text)" },
"description": "Quickfix entries (for set_quickfix)", "text": { "type": "string", "description": "Virtual text to display (for ghost_text)" },
"items": { "highlight_group": { "type": "string", "description": "Highlight group (e.g. 'Comment', 'IncSearch')" },
"type": "object",
"properties": {
"filename": { "type": "string" },
"lnum": { "type": "integer" },
"text": { "type": "string" }
},
"required": ["filename", "lnum", "text"]
}
},
"qf_action": { "type": "string", "enum": ["replace", "append", "prepend"], "description": "Quickfix list modification action (for set_quickfix)" }
},
"required": ["action"]
}
},
{
"name": "nvim_visual",
"description": "Visual feedback, syntax highlighting, ghost text extmarks, and diff preview overlays.",
"inputSchema": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["preview", "extmark", "highlight", "clear_highlight"],
"description": "Visual feedback action"
},
"file_path": { "type": "string", "description": "File path (for preview)" },
"start_line": { "type": "integer", "description": "Start line (1-indexed, for preview, highlight)" },
"end_line": { "type": "integer", "description": "End line (1-indexed, for preview, highlight)" },
"preview_content": { "type": "string", "description": "Proposed replacement code (for preview)" },
"line": { "type": "integer", "description": "Line number (1-indexed, for extmark)" },
"text": { "type": "string", "description": "Virtual ghost text to display (for extmark)" },
"highlight_group": { "type": "string", "description": "Highlight group (for extmark, highlight, e.g. 'Comment', 'IncSearch')" },
"buf_id": { "type": "integer", "description": "Buffer ID (for highlight, clear_highlight)" },
"duration_ms": { "type": "integer", "description": "Auto-clear duration in ms (for highlight, default: 5000)" } "duration_ms": { "type": "integer", "description": "Auto-clear duration in ms (for highlight, default: 5000)" }
}, },
"required": ["action"] "required": ["action"]
} }
}, },
{ {
"name": "nvim_execute_lua", "name": "nvim_exec",
"description": "Execute arbitrary Lua code directly in the active Neovim session. Primary tool for editing files via vim.api.nvim_buf_set_lines, querying editor state, and triggering notifications.", "description": "The Escape Hatch: execute lua read-only queries, run vimscript commands, or send commands to the terminal.",
"inputSchema": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "The Lua code string to execute in Neovim"
}
},
"required": ["code"]
}
},
{
"name": "nvim_system",
"description": "System diagnostics, terminal interaction, and editor notification messages.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
"action": { "action": {
"type": "string", "type": "string",
"enum": ["get_info", "get_messages", "send_to_terminal"], "enum": ["lua", "vimscript", "terminal"],
"description": "System action to perform" "description": "Execution action"
}, },
"command": { "type": "string", "description": "Shell command to send (for send_to_terminal)" }, "code": { "type": "string", "description": "Lua code or Vimscript command to execute" },
"tail": { "type": "integer", "description": "Number of message lines to return (for get_messages)" } "command": { "type": "string", "description": "Shell command to send (for terminal)" }
},
"required": ["action"]
}
},
{
"name": "nvim_lsp",
"description": "Language Server Protocol integration for semantic queries and safe workspace-wide refactoring.",
"inputSchema": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["rename", "definition", "references", "hover", "code_action"],
"description": "LSP action to perform"
},
"file": { "type": "string", "description": "Target file path" },
"line": { "type": "integer", "description": "1-indexed line number" },
"col": { "type": "integer", "description": "0-indexed column number" },
"new_name": { "type": "string", "description": "New name for rename action" }
},
"required": ["action"]
}
},
{
"name": "nvim_ast",
"description": "Tree-sitter AST queries for semantic code exploration and outlining.",
"inputSchema": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["query", "outline"],
"description": "AST action to perform"
},
"file": { "type": "string", "description": "Target file path" },
"query": { "type": "string", "description": "Tree-sitter query string" },
"preset": { "type": "string", "description": "Query preset (e.g., 'functions', 'classes')" }
}, },
"required": ["action"] "required": ["action"]
} }
} }
] ]
})), })),
error: None, error: None,
}).await; }).await;
@@ -1297,8 +1214,42 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
let action = args.get("action").and_then(|v| v.as_str()).unwrap_or(""); let action = args.get("action").and_then(|v| v.as_str()).unwrap_or("");
match name { let (mapped_name, mapped_action) = match (name, action) {
"nvim_buffer" => match action { ("nvim_buffer", "read") => ("nvim_buffer", "read"),
("nvim_buffer", "replace") => ("nvim_buffer", "edit"),
("nvim_buffer", "save") => ("nvim_buffer", "save"),
("nvim_buffer", "undo") => ("nvim_buffer", "undo"),
("nvim_buffer", "redo") => ("nvim_buffer", "redo"),
("nvim_buffer", "create_scratch") => ("nvim_buffer", "create_scratch"),
("nvim_workspace", "list_buffers") => ("nvim_buffer", "list"),
("nvim_workspace", "list_windows") => ("nvim_window", "list"),
("nvim_workspace", "focus") => ("nvim_window", "focus"),
("nvim_workspace", "split") => ("nvim_window", "split"),
("nvim_workspace", "cwd") => ("nvim_system", "cwd"),
("nvim_intelligence", "hover") => ("nvim_lsp", "hover"),
("nvim_intelligence", "definition") => ("nvim_lsp", "definition"),
("nvim_intelligence", "references") => ("nvim_lsp", "references"),
("nvim_intelligence", "rename") => ("nvim_lsp", "rename"),
("nvim_intelligence", "code_action") => ("nvim_lsp", "code_action"),
("nvim_intelligence", "outline") => ("nvim_ast", "outline"),
("nvim_intelligence", "query") => ("nvim_ast", "query"),
("nvim_intelligence", "diagnostics") => ("nvim_diagnostics", "get"),
("nvim_ui", "highlight") => ("nvim_visual", "highlight"),
("nvim_ui", "ghost_text") => ("nvim_visual", "extmark"),
("nvim_ui", "clear") => ("nvim_visual", "clear_highlight"),
("nvim_exec", "lua") => ("nvim_execute_lua", ""),
("nvim_exec", "vimscript") => ("nvim_system", "vimscript"),
("nvim_exec", "terminal") => ("nvim_system", "send_to_terminal"),
(n, a) => (n, a),
};
match mapped_name {
"nvim_buffer" => match mapped_action {
"get_active" => match get_nvim_active_buffer().await { "get_active" => match get_nvim_active_buffer().await {
Ok(content) => { Ok(content) => {
send_text_result!(id.clone(), content); send_text_result!(id.clone(), content);
@@ -2147,6 +2098,27 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
send_error(id, -32602, "Missing 'command'").await; send_error(id, -32602, "Missing 'command'").await;
} }
} }
"cwd" => {
let lua_code =
if let Some(path) = args.get("path").and_then(|v| v.as_str()) {
format!(
"vim.cmd('cd {}'); return vim.fn.getcwd()",
path.replace("\\", "\\\\").replace("'", "\\'")
)
} else {
"return vim.fn.getcwd()".to_string()
};
handle_lua_result!(id, execute_nvim_lua(&lua_code));
}
"vimscript" => {
if let Some(code) = args.get("code").and_then(|v| v.as_str()) {
let lua_code =
format!("vim.cmd([=[{}]=]); return 'Success'", code);
handle_lua_result!(id, execute_nvim_lua(&lua_code));
} else {
send_error(id, -32602, "Missing 'code'").await;
}
}
_ => { _ => {
send_error( send_error(
id, id,