Neovim MCP工具插件

buddy.nvim是一个Neovim插件,通过MCP协议实现AI工具与编辑器的交互控制,支持Lua编写工具并同时作为键映射和命令使用。

  • by arismoko
  • Lua
  • 本地部署
  • 22 星标
  • 更新于
在 GitHub 查看 arismoko/buddy.nvim

使用说明

buddy.nvim

Lua工具既可以作为键映射,也可以作为MCP工具。


我想在Neovim中使用AI工具,而不用去找另一个编辑器。所以我建造了这个。

buddy.nvim经营着一家 MCP服务器 Neovim内部。Claude、OpenCode或任何MCP客户端都可以连接并实际控制您的编辑器:读取缓冲区、编辑文件、运行命令、导航。不只是聊天。

你用Lua编写工具。它们充当MCP工具(AI称之为MCP工具) 和 作为常规的Neovim插件(键盘映射、命令、autocmds)。相同的代码,两个接口。


安装

lazy.nvim

{
  "arismoko/buddy.nvim",
  dependencies = {
    "nvim-mini/mini.nvim",
    "nvim-neotest/nvim-nio",
  },
  lazy = false,
  config = function()
    require("buddy").setup({
      auto_start = true,
      port = 7234,
    })
  end,
}

包装商nvim

use {
  "arismoko/buddy.nvim",
  requires = {
    "nvim-mini/mini.nvim",
    "nvim-neotest/nvim-nio",
  },
  config = function()
    require("buddy").setup({
      auto_start = true,
      port = 7234,
    })
  end,
}

手册

克隆到您的Neovim包目录:

git clone https://github.com/arismoko/buddy.nvim ~/.local/share/nvim/site/pack/plugins/start/buddy.nvim

连接MCP客户端

buddy.nvim使用 HTTP+服务器发送事件(SSE) 与现代MCP客户端兼容。

有两种连接方式:

选项A:通过代理(推荐)

这 buddy-mcp-proxy 自动发现正在运行的Neovim会话,为您转发身份验证令牌,并支持在多个实例之间切换。不需要端口配置。需要 Node.js 20+.

npm install -g buddy-mcp-proxy

OpenCode

添加 ~/.config/opencode/opencode.jsonc:

{
  "mcp": {
    "vim": {
      "type": "local",
      "command": ["npx", "buddy-mcp-proxy"]
    }
  }
}

克劳德桌面版

添加到您的Claude Desktop配置中:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • 视窗: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "vim": {
      "command": "npx",
      "args": ["buddy-mcp-proxy"]
    }
  }
}

选项B:直接SSE连接

通过URL直接连接到特定的Neovim实例。更简单,但您必须知道端口,并且只能连接到一个会话。

备注:启用身份验证(默认)后,客户端必须发送 Authorization: Bearer <token> 头球代理自动处理此问题;对于直接连接,可以配置客户端的auth标头,也可以在受信任的本地设置中禁用auth。

小贴士:buddy.nvim工具仅在启用好友的Neovim会话实际运行时显示。如果您的客户端在Neovim之前启动,请先启动Neovim或使用 buddy-mcp-proxy,当会话联机时,它将自动连接。

OpenCode

{
  "mcp": {
    "vim": {
      "type": "remote",
      "url": "http://127.0.0.1:7234/sse"
    }
  }
}

克劳德桌面版

{
  "mcpServers": {
    "vim": {
      "url": "http://127.0.0.1:7234/sse"
    }
  }
}

安全

默认情况下,buddy.nvim绑定到 127.0.0.1 (仅限本地主机)。这意味着只有本地进程可以连接。

在局域网上曝光 (例如,对于远程AI客户端):

require("buddy").setup({
  host = "0.0.0.0",  -- Listen on all interfaces
})

备注:默认情况下启用承载令牌身份验证(auth = true)但是没有TLS。如果你绑定到 0.0.0.0,令牌以明文形式发送。考虑:

  • 使用防火墙限制访问
  • 用于远程访问的SSH隧道
  • 仅在受信任的网络上启用

内置工具

工具 说明
buffer 读取、列出和获取缓冲区信息
edit 插入、替换、删除缓冲区中的文本
command 执行Ex命令
navigation 跳转到文件、行、标记
search 在当前缓冲区中查找并替换
grep 使用vimgrep进行项目范围内的搜索
diagnostics 从Neovim获取LSP诊断
window 管理拆分和窗口布局
tab 管理选项卡
fold 控制码折叠
visual 创建视觉选择
macro 录制和播放宏
register 访问Neovim注册表
status 获取光标、模式、标记、寄存器
init 脚手架新用户工具

看 docs/tools.md 有关MCP JSON示例的完整参考。


创建工具

工具已上线 lua/{plugin}/buddy.lua 文件夹。buddy.nvim会自动从运行时路径中发现它们。

格式1:工具列表

对于具有一个或多个独立工具的插件:

-- lua/my-plugin/buddy.lua
return {
  tools = {
    {
      name = "greet",
      description = "Say hello",
      input_schema = {
        type = "object",
        properties = {
          name = { type = "string", description = "Name to greet" },
        },
        required = { "name" },
      },
      run = function(args)
        return "Hello, " .. args.name
      end,
    },
    {
      name = "farewell",
      description = "Say goodbye",
      input_schema = {
        type = "object",
        properties = {
          name = { type = "string", description = "Name to farewell" },
        },
        required = { "name" },
      },
      run = function(args)
        return "Goodbye, " .. args.name
      end,
    },
  }
}

格式2:单工具

对于只公开一个工具的插件:

-- lua/my-plugin/buddy.lua
return {
  name = "my_tool",
  description = "Does a thing",
  input_schema = {
    type = "object",
    properties = {
      message = { type = "string", description = "Message to show" },
    },
    required = {},
  },
  run = function(args)
    vim.notify("Did the thing with: " .. (args.message or "nothing"))
    return { success = true }
  end,
}

返回结果

工具归还 原始Lua值.buddy.nvim会自动将它们包装成MCP响应:

-- String → text content block
return "Hello, world!"

-- Table → JSON-encoded text content block
return { success = true, data = "result" }

-- nil → text content block with "nil"
return nil

常见错误:不要像这样退回MCP信封 { content = { { type = "text", text = "..." } } } 从你的工具。只需返回原始值。buddy.nvim为你包装好了。

添加关键点映射、命令、Autocmd

添加一个 setup block,你的工具就变成了一个合适的Neovim插件:

local function do_thing(args)
  vim.notify("Did the thing with: " .. (args.message or "nothing"))
  return { success = true }
end

return {
  name = "my_tool",
  description = "Does a thing",
  input_schema = {
    type = "object",
    properties = {
      message = { type = "string", description = "Message to show" },
    },
    required = {},
  },
  run = do_thing,

  setup = {
    keymaps = {
      { "n", "<leader>mt", function() do_thing({}) end, { desc = "My Tool" } },
    },
    commands = {
      { "MyTool", function(opts) do_thing({ message = opts.args }) end, nargs = "?" },
    },
    autocmds = {
      { "BufEnter", pattern = "*.md", callback = function() print("Markdown!") end },
    },
  },
}

现在你的工具:

  • AI呼叫时通过MCP工作 my_tool
  • 作品通过 <leader>mt 键位映射
  • 作品通过 :MyTool 命令
  • 运行于 BufEnter 用于markdown文件

编辑文件时,关键帧映射和命令会自动更新。无需重新启动。

看 docs/creating-tools.md 完整的指南。


配置

require("buddy").setup({
  host = "127.0.0.1",  -- Bind address (default: "127.0.0.1" for security)
  port = 7234,         -- Server port (default: 7234)
  auto_start = false,  -- Start on VimEnter (default: false)
  auth = true,         -- Bearer token auth on HTTP endpoints (default: true)
  watch = true,        -- Hot reload file watching (default: true)
  log_level = "info",  -- Log level: "debug", "info", "warn", "error"
  tools = {
    disabled = {},     -- Disable specific tools: {"grep", "diagnostics", ...}
  },
  buffer = {
    ignored_filetypes = {},  -- Hide filetypes from buffer listings
  },
})

看 docs/configuration.md 以获取完整的配置参考。


API

local buddy = require("buddy")

-- Start the MCP server
buddy.start()

-- Stop the server
buddy.stop()

-- Restart (stop + start)
buddy.restart()

-- Check status
local status = buddy.status()
-- { running = true, port = 7234 }

-- Call a tool programmatically
local result = buddy.call("buffer", { action = "list" })

-- Register a tool programmatically
buddy.register_tool({
  name = "my_tool",
  description = "Does something",
  args = {
    param = { type = "string", description = "A parameter" },
  },
  required = { "param" },
  run = function(args) return { success = true, param = args.param } end,
})

需求

  • 新 0.10+
  • mini.nvim (依赖性)
  • 尼翁 (依赖关系--异步操作)

故障排除

端口已在使用中

Failed to bind to 127.0.0.1:7234 - address already in use

另一个实例正在运行,或者另一个应用程序正在使用端口7234。停止其他进程或更改端口:

require("buddy").setup({ port = 7235 })

工具未加载

检查 :messages 对于错误。常见问题:

  • 工具文件中存在语法错误
  • 缺失 name, description,或 run 领域
  • 无效 input_schema

SSE连接失败

确保:

  1. buddy.nvim正在运行: :lua print(require('buddy').status().running)
  2. URL与您的配置匹配(默认值: http://127.0.0.1:7234/sse)
  3. 没有防火墙阻止连接

许可证

麻省理工学院