Hardcoding mcp__neovim__vim_* in the agent/skill prose was wrong on two counts: (1) the prefix was flat-out incorrect — a plugin-shipped .mcp.json server is namespaced mcp__plugin_<plugin>_<key>__, not mcp__<key>__; (2) hardcoding any fully-qualified MCP tool name in prose is fragile — it depends on registration method and topology (metamcp aggregation injected/removed a segment). - frontmatter tools:/allowed-tools: use the correct prefix wildcard mcp__plugin_nvim-agentic-companion_neovim__* (the allowlist needs a real pattern; one place; stable with plugin name + .mcp.json key) - all prose now names tools by leaf (vim_command, vim_health, …) and tells the agent to match those against its actual runtime toolset rather than assume a prefix
nvim-agentic-companion
A Claude Code plugin that turns the user's running Neovim into a first-class collaborator.
It assumes two things are already wired up:
mcp-neovim-serverreaching the running nvim's RPC socket (default/run/user/1000/nvim.sock, created by NixVim'sextraConfigLuaPreserverstartat editor startup). The plugin ships a.mcp.jsonthat points theneovimMCP server at themcp-session-poolover Streamable-HTTP (pool.localhost:12010/p/neovim/mcp); the pool fronts a supervised stdio→HTTP bridge. Tools surface asvim_*.coder/claudecode.nvimloaded 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.
Connection path
Claude Code session
└─ .mcp.json → http://pool.localhost:12010/p/neovim/mcp (Streamable-HTTP)
└─ mcp-session-pool (:12010, M=1 session pooler, /repin endpoint)
└─ nvim-mcp-bridge — supergateway (:12016, --stateful)
└─ mcp-neovim-server (stdio child)
└─ /run/user/1000/nvim.sock (nvim msgpack-RPC)
└─ the running Neovim
No MetaMCP in this path: nvim is ephemeral and MetaMCP never re-dials a
restarted upstream. The pool does re-establish (a fresh initialize), so
pool→bridge self-heals. Recovery is event-driven — a systemd.path watching
the nvim socket fires a oneshot that POSTs /repin to the pool when the socket
(re)appears; no polling. The pool and bridge run on emmett as systemd services
under user oleks, so the per-user socket is directly reachable. If
vim_* tools are missing: socket exists? systemctl status nvim-mcp-bridge? http://127.0.0.1:12010/pools/neovim pinned? session
restarted since the wiring landed?
Layout
nvim-agentic-companion/
├── .claude-plugin/plugin.json # manifest + userConfig (socket, config path)
├── agents/
│ └── companion.md # the nvim-companion agent identity
└── skills/
├── editor-introspect/ # read live state via the vim_* MCP tools
├── editor-act/ # drive nvim safely (open, jump, toggle, run)
└── claude-code-handoff/ # delegate buffer edits to the in-editor Claude
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.
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.
Why split it three ways
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.
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
nvim_socket— default/run/user/1000/nvim.sock. Where the running nvim listens; must matchNVIM_SOCKET_PATHin thenvim-mcp-bridgeservice thatmcp-neovim-serverruns under.config_path— default/home/oleks/projects/servers/emmett/nixos/neovim.nix. The declarative NixVim source the companion cites from.
License
MIT.