v0.5.0: route the neovim MCP through MetaMCP

mcp-neovim-server no longer runs as a per-session npx stdio child.
It is now a MetaMCP namespace upstream on emmett (one persistent
process), reached over Streamable-HTTP via the mcp-session-pool:

  Claude Code -> pool.localhost:12010/p/neovim/mcp
    -> MetaMCP neovim namespace -> mcp-neovim-server -> nvim socket

- .mcp.json: stdio npx server -> streamable-http pool endpoint
- agents/companion.md + skills: tool names are now 3-segment
  (mcp__neovim__neovim__vim_*) — the MetaMCP aggregation shape; the
  surface description and unavailability runbook updated for the
  three-link path (nvim socket / MetaMCP / session)
- README: connection-path diagram

Host side (servers/emmett, deployed separately): neovim added to
services.mcp-session-pool.upstreams; metamcp.nix seeds the neovim
mcp_servers row + mapping and adds nodejs to the unit PATH.
This commit is contained in:
oleks
2026-05-21 11:18:48 +03:00
parent 222035d4fe
commit 3c5851e95e
7 changed files with 108 additions and 57 deletions
+53 -15
View File
@@ -1,17 +1,43 @@
# nvim-agentic-companion
A Claude Code plugin that turns the user's running Neovim into a first-class collaborator.
A Claude Code plugin that turns the user's running Neovim into a first-class
collaborator.
It assumes two things are already wired up:
1. **`mcp-neovim-server`** registered as an MCP server in Claude Code, pointed at the nvim RPC socket (default `/run/user/1000/nvim.sock`). NixVim's `extraConfigLuaPre` starts the server on that socket at editor startup.
2. **`coder/claudecode.nvim`** loaded inside nvim, with `<leader>a*` keymaps wired (toggle, focus, send, accept/deny diff).
1. **`mcp-neovim-server`** reaching the running nvim's RPC socket (default
`/run/user/1000/nvim.sock`, created by NixVim's `extraConfigLuaPre`
`serverstart` at editor startup). The plugin ships a `.mcp.json` that points
the `neovim` MCP server at a **MetaMCP namespace** over Streamable-HTTP
(`pool.localhost:12010/p/neovim/mcp`) rather than spawning a per-session
`npx` stdio child — one persistent server, shared across sessions. Because of
MetaMCP's aggregation, the tools surface as `mcp__neovim__neovim__vim_*`.
2. **`coder/claudecode.nvim`** loaded inside nvim, with `<leader>a*` keymaps
wired (toggle, focus, send, accept/deny diff).
This plugin doesn't ship those — it depends on them and ties them together with one agent and three skills.
This plugin doesn't ship those — it depends on them and ties them together with
one agent and three skills.
## Connection path
```text
Claude Code session
└─ .mcp.json → http://pool.localhost:12010/p/neovim/mcp (Streamable-HTTP)
└─ mcp-session-pool (:12010, M=1 session pooler)
└─ MetaMCP `neovim` namespace upstream
└─ mcp-neovim-server (one persistent stdio child on emmett)
└─ /run/user/1000/nvim.sock (nvim msgpack-RPC)
└─ the running Neovim
```
MetaMCP and the pool both run on emmett as systemd services under user `oleks`,
so the per-user socket is directly reachable. If `mcp__neovim__neovim__*` tools
are missing, walk the chain top-down: socket exists? `systemctl status metamcp`?
session restarted since the wiring landed?
## Layout
```
```text
nvim-agentic-companion/
├── .claude-plugin/plugin.json # manifest + userConfig (socket, config path)
├── agents/
@@ -24,13 +50,21 @@ nvim-agentic-companion/
## Agent
`companion` — answers questions about the *running* nvim ("what's bound to `<leader>ff`?", "is lualine actually using catppuccin-mocha?") and acts on it ("open neovim.nix at the lualine block"). It reads the declarative NixVim config as the source-of-truth for *why* things are set up the way they are, and the live editor for *what is actually loaded right now*.
`companion` — answers questions about the *running* nvim ("what's bound to
`<leader>ff`?", "is lualine actually using catppuccin-mocha?") and acts on it
("open neovim.nix at the lualine block"). It reads the declarative NixVim config
as the source-of-truth for *why* things are set up the way they are, and the
live editor for *what is actually loaded right now*.
## Skills
- **`editor-introspect`** — read-only queries against the live nvim (keymaps, buffers, options, diagnostics, plugins, messages, cursor, selection).
- **`editor-act`** — safe driving: open files, jump to definitions, trigger user keymaps, toggle UI. Does **not** edit buffer contents.
- **`claude-code-handoff`** — when the work is "change code in this buffer," hand it to the in-editor Claude Code session so the user gets a diff to accept or reject inline.
- **`editor-introspect`** — read-only queries against the live nvim (keymaps,
buffers, options, diagnostics, plugins, messages, cursor, selection).
- **`editor-act`** — safe driving: open files, jump to definitions, trigger user
keymaps, toggle UI. Does **not** edit buffer contents.
- **`claude-code-handoff`** — when the work is "change code in this buffer,"
hand it to the in-editor Claude Code session so the user gets a diff to accept
or reject inline.
## Why split it three ways
@@ -38,16 +72,20 @@ The companion's three jobs have different blast radii:
- *Reads* are free; do them eagerly.
- *Edits to navigation/UI* are cheap to undo; do them when asked.
- *Edits to code* deserve a diff and human review; route them through the inner Claude that already has the right UX for that.
- *Edits to code* deserve a diff and human review; route them through the inner
Claude that already has the right UX for that.
The skills enforce that separation so the agent doesn't drift into running `nvim_buf_set_text` directly when it should be sending to the Claude Code split.
The skills enforce that separation so the agent doesn't drift into running
`nvim_buf_set_text` directly when it should be sending to the Claude Code split.
## Configuration
| Key | Default | Purpose |
| --------------- | ------------------------------------------------------ | ----------------------------------------------------------- |
| `nvim_socket` | `/run/user/1000/nvim.sock` | Where the running nvim listens (must match the MCP server). |
| `config_path` | `/home/oleks/projects/servers/emmett/nixos/neovim.nix` | The declarative NixVim source the companion cites from. |
- **`nvim_socket`** — default `/run/user/1000/nvim.sock`. Where the
running nvim listens; must match the socket `mcp-neovim-server`
connects to (`NVIM_SOCKET_PATH` in the MetaMCP `neovim` upstream).
- **`config_path`** — default
`/home/oleks/projects/servers/emmett/nixos/neovim.nix`. The
declarative NixVim source the companion cites from.
## License