Compare commits

...
2 Commits
7 changed files with 132 additions and 189 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# Neovim UX Protocol & Live Editing # Neovim UX Protocol & Live Editing
Whenever you need to actively interact with the user's Neovim UI or dynamically inject code edits into their live buffers, use the nvim_execute_lua tool (the "God Mode" escape hatch). Whenever you need to actively interact with the user's Neovim UI or dynamically inject code edits into their live buffers, use the nvim_exec tool (with action 'lua') (the "God Mode" escape hatch).
## 1. Showing UI Feedback (Agent Notifications) ## 1. Showing UI Feedback (Agent Notifications)
The user has a global Lua table _G.gemini loaded in their Neovim environment. You can use it to pop up a floating notification window when you are starting a background task. The user has a global Lua table _G.gemini loaded in their Neovim environment. You can use it to pop up a floating notification window when you are starting a background task.
+7 -9
View File
@@ -21,7 +21,7 @@ The Antigravity CLI (`agy`) acts as the MCP Client and automatically manages the
When `agy` starts up, it reads `mcp_config.json`. If it finds `"win-nvim": { "command": "C:\\Users\\reazul.ashraf\\.local\\bin\\mcp-memory-nvim.exe" }`, it will spawn that binary as a background subprocess using standard `stdio`. When `agy` starts up, it reads `mcp_config.json`. If it finds `"win-nvim": { "command": "C:\\Users\\reazul.ashraf\\.local\\bin\\mcp-memory-nvim.exe" }`, it will spawn that binary as a background subprocess using standard `stdio`.
3. **Communication:** 3. **Communication:**
- The LLM requests to use a consolidated tool (e.g., `nvim_view` with action `goto_line`, or `nvim_execute_lua`). - The LLM requests to use a consolidated tool (e.g., `nvim_workspace` with action `focus`, or `nvim_exec`).
- The `agy` CLI sends a JSON-RPC request to the `mcp-memory-nvim` subprocess via its `stdin`. - The `agy` CLI sends a JSON-RPC request to the `mcp-memory-nvim` subprocess via its `stdin`.
- The Rust MCP Server receives the request, connects to the Neovim active socket/pipe (`~/.gemini/active_nvim.txt` or `\\.\pipe\nvim.*`), sends the Msgpack-RPC command, and writes the JSON-RPC response back to `stdout`. - The Rust MCP Server receives the request, connects to the Neovim active socket/pipe (`~/.gemini/active_nvim.txt` or `\\.\pipe\nvim.*`), sends the Msgpack-RPC command, and writes the JSON-RPC response back to `stdout`.
- The `agy` CLI reads the response from `stdout` and returns it to the LLM context. - The `agy` CLI reads the response from `stdout` and returns it to the LLM context.
@@ -29,12 +29,10 @@ The Antigravity CLI (`agy`) acts as the MCP Client and automatically manages the
## Capabilities & Requirements ## Capabilities & Requirements
To use this architecture, Neovim must run the `gemini-integration.lua` script to broadcast its active socket to `~/.gemini/active_nvim.txt`. To use this architecture, Neovim must run the `gemini-integration.lua` script to broadcast its active socket to `~/.gemini/active_nvim.txt`.
The MCP server provides 7 cohesive domain tools: The MCP server provides 5 cohesive mega-tools:
1. **`nvim_buffer`** (actions: `get_active`, `read`, `open`, `create_scratch`, `save`, `reload`, `close`, `list`, `search`) 1. **`nvim_buffer`** (actions: `read`, `replace`, `save`, `undo`, `redo`, `create_scratch`)
2. **`nvim_window`** (actions: `list`, `get_active`, `focus`, `split`, `close`) 2. **`nvim_workspace`** (actions: `list_buffers`, `list_windows`, `focus`, `split`, `cwd`)
3. **`nvim_view`** (actions: `goto_line`, `get_cursor`, `get_viewport`, `get_selection`) 3. **`nvim_intelligence`** (actions: `hover`, `definition`, `references`, `outline`, `query`, `diagnostics`, `rename`, `code_action`)
4. **`nvim_diagnostics`** (actions: `get`, `set`, `set_quickfix`) 4. **`nvim_ui`** (actions: `highlight`, `ghost_text`, `clear`)
5. **`nvim_visual`** (actions: `preview`, `extmark`, `highlight`, `clear_highlight`) 5. **`nvim_exec`** (actions: `lua`, `vimscript`, `terminal`)
6. **`nvim_execute_lua`** (direct Lua execution escape hatch)
7. **`nvim_system`** (actions: `get_info`, `get_messages`, `send_to_terminal`)
+4 -4
View File
@@ -16,9 +16,9 @@ File edits must use EXACTLY one of two paths:
## 2. Strict Tool Adherence (No Raw Lua RCE) ## 2. Strict Tool Adherence (No Raw Lua RCE)
You must strictly use the specialized, sandboxed Neovim MCP tools: You must strictly use the specialized, sandboxed Neovim MCP tools:
- `nvim_buffer`: For reading, writing, saving, and creating scratch buffers. - `nvim_buffer`: For reading, writing, saving, and creating scratch buffers.
- `nvim_window`: For creating splits and focusing panes. - `nvim_workspace`: For creating splits and focusing panes.
- `nvim_visual`: For highlighting diffs, adding ghost text, and showing previews. - `nvim_ui`: For highlighting diffs, adding ghost text, and showing previews.
**DO NOT** use `nvim_execute_lua` to mutate editor state. It is restricted to **READ-ONLY** queries. **DO NOT** use `nvim_exec` (action `lua`) to mutate editor state. It is restricted to **READ-ONLY** queries.
## 3. Headless Quarantine ## 3. Headless Quarantine
Headless mode (`nvim --headless`) is strictly banned for interactive edits. Headless mode (`nvim --headless`) is strictly banned for interactive edits.
@@ -26,7 +26,7 @@ Headless mode (`nvim --headless`) is strictly banned for interactive edits.
Headless instances are allowed ONLY for non-interactive background batch processing (e.g., project-wide formatting or linting). Headless instances are allowed ONLY for non-interactive background batch processing (e.g., project-wide formatting or linting).
## 4. UI Presentation & Chat Console Minimization ## 4. UI Presentation & Chat Console Minimization
Never output large plans, context blocks, or architectural discussions to the chat console if Neovim is running. You MUST use the `nvim_buffer` and `nvim_window` tools to open a vertical split (e.g., `Antigravity_Plan.md` scratch buffer) and present the markdown natively. Reserve the chat console strictly for brief confirmations. Never output large plans, context blocks, or architectural discussions to the chat console if Neovim is running. You MUST use the `nvim_buffer` and `nvim_workspace` tools to open a vertical split (e.g., `Antigravity_Plan.md` scratch buffer) and present the markdown natively. Reserve the chat console strictly for brief confirmations.
## 5. Visual Cues & Auto-Save ## 5. Visual Cues & Auto-Save
When manipulating buffers via MCP: When manipulating buffers via MCP:
+1 -1
View File
@@ -3,6 +3,6 @@
When interacting with the user's Neovim editor (e.g., opening a file, moving the cursor, reading the active buffer, setting diagnostics), you MUST ALWAYS use the MCP tools provided by the `win-nvim` (Neovim) MCP server. When interacting with the user's Neovim editor (e.g., opening a file, moving the cursor, reading the active buffer, setting diagnostics), you MUST ALWAYS use the MCP tools provided by the `win-nvim` (Neovim) MCP server.
- You are strictly forbidden from using bash scripts, `nvim --server`, or other raw terminal/shell hacks to remote-control Neovim. - You are strictly forbidden from using bash scripts, `nvim --server`, or other raw terminal/shell hacks to remote-control Neovim.
- You must rely entirely on the consolidated MCP tool registry (`nvim_buffer`, `nvim_window`, `nvim_view`, `nvim_diagnostics`, `nvim_visual`, `nvim_execute_lua`, `nvim_system`). - You must rely entirely on the consolidated MCP tool registry (`nvim_buffer`, `nvim_workspace`, `nvim_intelligence`, `nvim_ui`, `nvim_exec`).
- If the tool is eagerly loaded, use it natively as an agent tool. If lazy-loaded, invoke it via the `call_mcp_tool` mechanism. - If the tool is eagerly loaded, use it natively as an agent tool. If lazy-loaded, invoke it via the `call_mcp_tool` mechanism.
+2 -2
View File
@@ -10,7 +10,7 @@ Our current MCP ecosystem is highly advanced, utilizing a **Dual-Transport Leade
* `process_logs`: Direct file seeking and daemon log management (`watch`, `get`, `clear`). Prevents LLMs from reading multi-megabyte log files. **Score: A** * `process_logs`: Direct file seeking and daemon log management (`watch`, `get`, `clear`). Prevents LLMs from reading multi-megabyte log files. **Score: A**
### 2. Neovim IDE Integration (nvim-core) ### 2. Neovim IDE Integration (nvim-core)
* `nvim_buffer`, `nvim_window`, `nvim_view`, `nvim_diagnostics`, `nvim_visual`, `nvim_execute_lua`, `nvim_system`. * `nvim_buffer`, `nvim_workspace`, `nvim_intelligence`, `nvim_ui`, `nvim_exec`.
* **Review:** Exceptional human QoL. The agent interacts with the code where the human's eyes actually are. Ghost text and diagnostic extmarks provide an IDE-like experience usually reserved for closed-source tools like Cursor. **Score: S-Tier** * **Review:** Exceptional human QoL. The agent interacts with the code where the human's eyes actually are. Ghost text and diagnostic extmarks provide an IDE-like experience usually reserved for closed-source tools like Cursor. **Score: S-Tier**
### 3. Clipboard & Workflow ### 3. Clipboard & Workflow
@@ -37,7 +37,7 @@ To push the system to the absolute bleeding edge of autonomous coding, I propose
* **The Solution:** Using Tantivy and BERT embeddings in our backend. We index the AST blocks of the codebase in the background. The LLM can query *"Where is the auth token validated?"* and get the exact 3 relevant functions instantly. * **The Solution:** Using Tantivy and BERT embeddings in our backend. We index the AST blocks of the codebase in the background. The LLM can query *"Where is the auth token validated?"* and get the exact 3 relevant functions instantly.
* **Impact:** Massive token cost reduction (no blind file reading). Instant T2R for codebase exploration. * **Impact:** Massive token cost reduction (no blind file reading). Instant T2R for codebase exploration.
### 3. `nvim_system` terminal execution (Interactive Execution QoL) ### 3. `nvim_exec` terminal execution (Interactive Execution QoL)
* **The Problem:** When the agent runs a background terminal command (`cargo build`, `npm run dev`), the output is hidden from the human, and interactive prompts cause the background task to hang indefinitely. * **The Problem:** When the agent runs a background terminal command (`cargo build`, `npm run dev`), the output is hidden from the human, and interactive prompts cause the background task to hang indefinitely.
* **The Solution:** Dispatch to Neovim terminal splits where the human can watch the tests run natively, interact with prompts, see ANSI colors, and interact seamlessly. * **The Solution:** Dispatch to Neovim terminal splits where the human can watch the tests run natively, interact with prompts, see ANSI colors, and interact seamlessly.
* **Impact:** Massive Human QoL. * **Impact:** Massive Human QoL.
+12 -39
View File
@@ -2,48 +2,22 @@
When connected to this Neovim MCP server (`win-nvim`), you have powerful tools to interact directly with the active Neovim editor. When connected to this Neovim MCP server (`win-nvim`), you have powerful tools to interact directly with the active Neovim editor.
## The Consolidated Tool Arsenal (v2) ## The Consolidated Tool Arsenal (v3)
The server consolidates granular Neovim operations into 7 smart domain tools: The server consolidates granular Neovim operations into 5 smart mega-tools:
- **`nvim_buffer`**: Buffer and file management. - **`nvim_buffer`**: Buffer and file management. Actions: `read`, `replace`, `save`, `undo`, `redo`, `create_scratch`.
- `action: "open_file"`: Open file in buffer (args: `file`, `line`, `col`). - **`nvim_workspace`**: Window split and focus management. Actions: `list_buffers`, `list_windows`, `focus`, `split`, `cwd`.
- `action: "open"`: Open buffer (args: `bufnr`). - **`nvim_intelligence`**: Code intelligence and LSP. Actions: `hover`, `definition`, `references`, `outline`, `query`, `diagnostics`, `rename`, `code_action`.
- `action: "close"`: Close buffer (args: `bufnr`, `force`). - **`nvim_ui`**: Visual highlighting, diff previews, and ghost text. Actions: `highlight`, `ghost_text`, `clear`.
- `action: "reload"`: Reload buffer from disk (args: `bufnr`). - **`nvim_exec`**: Escape hatch for raw evaluation. Actions: `lua`, `vimscript`, `terminal`.
- `action: "save"`: Save buffer to disk (args: `bufnr`).
- `action: "list"`: List all loaded buffers.
- **`nvim_window`**: Window split and focus management.
- `action: "split"`: Split window (args: `direction: "horizontal" | "vertical"`, `file`).
- `action: "close"`: Close window (args: `winnr`).
- `action: "list"`: List open windows.
- `action: "get_active"`: Get active window details.
- `action: "set_active"`: Set active window focus (args: `winnr`).
- **`nvim_view`**: Editor viewport and navigation.
- `action: "get_active_buffer"`: Get active buffer details.
- `action: "get_cursor"`: Get current cursor line/col.
- `action: "goto_line"`: Jump cursor to line (args: `line`, `col`).
- `action: "get_viewport"`: Get visible line range in viewport.
- `action: "get_messages"`: Get Neovim command-line messages.
- **`nvim_diagnostics`**: LSP diagnostics querying and publishing.
- `action: "get"`: Get diagnostics (args: `bufnr`, `severity`).
- `action: "set"`: Set buffer diagnostics (args: `bufnr`, `diagnostics`).
- **`nvim_visual`**: Visual highlighting, extmarks, and quickfix.
- `action: "get_selection"`: Get current visual selection text and range.
- `action: "highlight_lines"`: Highlight line ranges (args: `bufnr`, `hl_group`, `start_line`, `end_line`).
- `action: "set_extmark"`: Place virtual text or sign extmarks (args: `bufnr`, `ns_id`, `line`, `col`, `opts`).
- `action: "set_quickfix"`: Populate quickfix list (args: `items`, `title`).
- **`nvim_execute_lua`**: God Mode arbitrary Lua evaluation.
- Arguments: `code: String`.
- **`nvim_system`**: System diagnostics and connection heartbeat.
- `action: "ping"`: Heartbeat test.
- `action: "status"`: Server and socket bridge health status.
## 1. Using Consolidated Domain Tools First ## 1. Using Consolidated Domain Tools First
Always prefer the specific consolidated tools (like `nvim_buffer`, `nvim_window`, `nvim_visual`, etc.) over writing raw Lua scripts. These tools are strongly typed, tested, and safe. Always prefer the specific consolidated tools (like `nvim_buffer`, `nvim_workspace`, `nvim_ui`, etc.) over writing raw Lua scripts. These tools are strongly typed, tested, and safe.
## 2. Lua God Mode (`nvim_execute_lua`) ## 2. Lua God Mode (`nvim_exec` with action `lua`)
If you need to access *any* Neovim API that does not have a dedicated tool (e.g., complex buffer edits, changing options, custom LSP interactions), you MUST use `nvim_execute_lua` as your escape hatch. If you need to access *any* Neovim API that does not have a dedicated tool (e.g., changing options, setting autocmds), you MUST use `nvim_exec` with action `lua` as your escape hatch.
**CRITICAL**: `nvim_exec` is restricted to **READ-ONLY** queries. Do NOT use it to mutate editor state.
### CRITICAL RULES for `nvim_execute_lua`: ### CRITICAL RULES for `nvim_exec` (`lua`):
1. **Never Block:** Never use interactive prompt functions or interactive confirmation flags in substitutions (e.g., `%s/old/new/gc`). This will cause the headless MCP bridge to deadlock forever. 1. **Never Block:** Never use interactive prompt functions or interactive confirmation flags in substitutions (e.g., `%s/old/new/gc`). This will cause the headless MCP bridge to deadlock forever.
2. **Visual Feedback:** Always trigger a notification using `require("notify")("Antigravity: [Action]", "info", { title = "Antigravity" })`. 2. **Visual Feedback:** Always trigger a notification using `require("notify")("Antigravity: [Action]", "info", { title = "Antigravity" })`.
3. **Auto-Save:** If you modify a file buffer, always save it using `vim.cmd('write')` within the same Lua script so external tools can see the changes, unless you explicitly want to pause for manual human review. 3. **Auto-Save:** If you modify a file buffer, always save it using `vim.cmd('write')` within the same Lua script so external tools can see the changes, unless you explicitly want to pause for manual human review.
@@ -57,4 +31,3 @@ While the headless background instance is great for autonomous, routine tasks, i
## 4. Tool Schema Discovery ## 4. Tool Schema Discovery
Do **NOT** grep or search the Rust source code to find tool schemas or arguments. All lazy-loaded MCP tool schemas are automatically cached as JSON files on your disk. To understand a tool's arguments, directly read `~/.gemini/antigravity-cli/mcp/win-nvim/<tool_name>.json` (or linux-nvim). Do **NOT** grep or search the Rust source code to find tool schemas or arguments. All lazy-loaded MCP tool schemas are automatically cached as JSON files on your disk. To understand a tool's arguments, directly read `~/.gemini/antigravity-cli/mcp/win-nvim/<tool_name>.json` (or linux-nvim).
+105 -133
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,