A powerful Neovim plugin that integrates MCP (Model Context Protocol) servers into your workflow. Configure and manage MCP servers through a centralized config file while providing an intuitive UI for browsing, installing and testing tools and resources. Perfect for LLM integration, offering both programmatic API access and interactive testing capabilities through the :MCPHub
command.
Discord: Join our Discord server for discussions, help, and updates
graph TD
subgraph "MCP Servers"
subgraph "Native MCP Servers"
N1["Buffer (Tools)"]
N2["LSP (Resources)"]
end
subgraph "Community"
C1["GitHub (Tools )"]
C2["Figma (Tools)"]
end
end
H[MCPHub]
M["@mcp tool + MCP Servers in text representation"]
subgraph "Chat Plugins"
A["Avante + @mcp tool"]
CC["CodeCompanion + @mcp tool"]
O[Others + @mcp tool]
end
subgraph "LLM Providers"
OAI[OpenAI]
AC[Claude]
M1[Mistral]
G[Grok]
D[DeepSeek]
end
%% MCP Servers provide capabilities
N1 & N2 --> H
C1 & C2 --> H
%% MCPHub transforms capabilities into system prompt
H --> M
%% Tools to plugins
M --> A
M --> CC
M --> O
%% Plugin to LLM connections
A --> OAI & AC
CC --> M1 & G
O --> D
For detailed documentation, visit our Wiki:
MCPHub is an open source project that relies on your support. If you like this project, please consider supporting to help maintain and improve the project by Sponsoring or :coffee: Buying A Coffee
Thank you to the following amazing people:
:MCPHub
to access all functionalityUsing lazy.nvim:
{
"ravitemer/mcphub.nvim",
dependencies = {
"nvim-lua/plenary.nvim", -- Required for Job and HTTP requests
},
-- comment the following line to ensure hub will be ready at the earliest
cmd = "MCPHub", -- lazy load by default
build = "npm install -g mcp-hub@latest", -- Installs required mcp-hub npm module
-- uncomment this if you don't want mcp-hub to be available globally or can't use -g
-- build = "bundled_build.lua", -- Use this and set use_bundled_binary = true in opts (see Advanced configuration)
config = function()
require("mcphub").setup()
end,
}
All options are optional with sensible defaults. Here's a complete example with all available options:
require("mcphub").setup({
port = 37373, -- Default port for MCP Hub
config = vim.fn.expand("~/.config/mcphub/servers.json"), -- Absolute path to config file location (will create if not exists)
native_servers = {}, -- add your native servers here
auto_approve = false, -- Auto approve mcp tool calls
auto_toggle_mcp_servers = true, -- Let LLMs start and stop MCP servers automatically
-- Extensions configuration
extensions = {
avante = {
make_slash_commands = true, -- make /slash commands from MCP server prompts
},
codecompanion = {
-- Show the mcp tool result in the chat buffer
-- NOTE:if the result is markdown with headers, content after the headers wont be sent by codecompanion
show_result_in_chat = false,
make_vars = true, -- make chat #variables from MCP server resources
make_slash_commands = true, -- make /slash commands from MCP server prompts
},
},
-- Default window settings
ui = {
window = {
width = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number)
height = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number)
relative = "editor",
zindex = 50,
border = "rounded", -- "none", "single", "double", "rounded", "solid", "shadow"
},
wo = { -- window-scoped options (vim.wo)
},
},
-- Event callbacks
on_ready = function(hub)
-- Called when hub is ready
end,
on_error = function(err)
-- Called on errors
end,
--set this to true when using build = "bundled_build.lua"
use_bundled_binary = false, -- Uses bundled mcp-hub script instead of global installation
--WARN: Use the custom setup if you can't use `npm install -g mcp-hub` or cant have `build = "bundled_build.lua"`
-- Custom Server command configuration
--cmd = "node", -- The command to invoke the MCP Hub Server
--cmdArgs = {"/path/to/node_modules/mcp-hub/dist/cli.js"}, -- Additional arguments for the command
-- In cases where mcp-hub server is hosted somewhere, set this to the server URL e.g `http://mydomain.com:customport` or `https://url_without_need_for_port.com`
-- server_url = nil, -- defaults to `http://localhost:port`
-- Multi-instance Support
shutdown_delay = 600000, -- Delay in ms before shutting down the server when last instance closes (default: 10 minutes)
-- Logging configuration
log = {
level = vim.log.levels.WARN,
to_file = false,
file_path = nil,
prefix = "MCPHub",
},
})
~/.config/mcphub/servers.json
MCPHub uses a JSON configuration file to define MCP servers. The default location is ~/.config/mcphub/servers.json
.
{
"mcpServers": {
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"],
"env": {
"API_KEY": "", // Falls back to process.env.API_KEY
"SERVER_URL": null, // Falls back to process.env.SERVER_URL
"DEBUG": "true" // Direct value, no fallback
}
},
"remote-server": {
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer your-token"
}
}
}
}
Configuration file (~/.config/mcphub/servers.json
) is watched for changes and updates are applied automatically in real-time across all Neovim instances.
mcphub.nvim
supports both stdio
(local) MCP Servers as well as sse
(remote) MCP Servers. The configuration for each type is as follows:
Local Stdio Servers:
command
: The command to start the MCP server (required)args
: Command arguments as arrayenv
: Optional environment variables. Special values:
""
(empty string): Falls back to process.env.[VAR_NAME]null
: Falls back to process.env.[VAR_NAME]Remote SSE Servers:
url
: url for remote MCP Server (required)headers
: Optional headers for the serverThere are other plugin specific options for each server like disabled
, disabled_tools
, custom_instructions
etc which can be easily updated from the UI.
Open the MCPHub UI to manage servers, test tools and monitor status:
:MCPHub
local hub = mcphub.get_hub_instance()
-- Call a tool (sync)
local response, err = hub:call_tool("server-name", "tool-name", {
param1 = "value1"
}, {
return_text = true -- Parse response to LLM-suitable text
})
-- Call a tool (async)
hub:call_tool("server-name", "tool-name", {
param1 = "value1"
}, {
return_text = true,
callback = function(response, err)
-- Use response
end
})
-- Access resource (sync)
local response, err = hub:access_resource("server-name", "resource://uri", {
return_text = true
})
-- Get prompt helpers for system prompts
local prompts = hub:generate_prompts()
-- prompts.active_servers: Lists currently active servers
-- prompts.use_mcp_tool: Instructions for tool usage with example
-- prompts.access_mcp_resource: Instructions for resource access with example
MCPHub.nvim provides extensions that integrate with popular Neovim chat plugins. These extensions allow you to use MCP tools and resources directly within your chat interfaces.
Add MCP capabilities to Avante by including the MCP tools in your setup:
Set
config.auto_approve = true
orvim.g.mcphub_auto_approve = true
to automatically approve mcp tool requests.
Set
config.extensions.avante.make_slash_commands = true
to enable prompts as slash commands (enabled by default). Server prompts will be available as/mcp:server_name:prompt_name
in chat.
The mcp_tool()
function now returns two separate tools (use_mcp_tool
and access_mcp_resource
) for better schema generation:
require("mcphub").setup({
extensions = {
avante = {
make_slash_commands = true, -- make /slash commands from MCP server prompts
}
}
})
require("avante").setup({
-- other config
-- The system_prompt type supports both a string and a function that returns a string. Using a function here allows dynamically updating the prompt with mcphub
system_prompt = function()
local hub = require("mcphub").get_hub_instance()
return hub:get_active_servers_prompt()
end,
-- The custom_tools type supports both a list and a function that returns a list. Using a function here prevents requiring mcphub before it's loaded
custom_tools = function()
return {
require("mcphub.extensions.avante").mcp_tool(),
}
end,
})
⚠️ Tool Conflicts: Disable any built-in Avante tools that might conflict with enabled MCP servers to prevent duplicate functionality or unexpected behavior.
If you are using the builtin Neovim server, you might have to disable the following tools in your avante config to avoid any conflicts.
disabled_tools = {
"list_files",
"search_files",
"read_file",
"create_file",
"rename_file",
"delete_file",
"create_dir",
"rename_dir",
"delete_dir",
"bash",
},
Add MCP capabilities to CodeCompanion.
Set
config.auto_approve = true
orvim.g.mcphub_auto_approve = true
to automatically approve tool requests.
Set
make_vars = true
to show resources as #variables in the chat buffer
Set
make_slash_commands = true
to show prompts as /slash_commands in the chat buffer
/mcp:prompt_name
slash commands in chat (Currently very few servers provide prompts, but you can add your own using mcphub.add_prompt
)/mcp:prompt_name
message is of user
role, it will be added to the chat buffer.Whenever the servers are updated, the variables and slash_commands will also be updated in realtime
E.g LSP current file diagnostics
Set
show_result_in_chat = true
to view the mcp tool call result in the chat buffer.
require("mcphub").setup({
extensions = {
codecompanion = {
-- Show the mcp tool result in the chat buffer
show_result_in_chat = true,
make_vars = true, -- make chat #variables from MCP server resources
make_slash_commands = true, -- make /slash_commands from MCP server prompts
},
}
})
require("codecompanion").setup({
strategies = {
chat = {
tools = {
["mcp"] = {
-- calling it in a function would prevent mcphub from being loaded before it's needed
callback = function() return require("mcphub.extensions.codecompanion") end,
description = "Call tools and resources from the MCP Servers",
}
}
}
}
})
require('lualine').setup {
sections = {
lualine_x = {
{require('mcphub.extensions.lualine')},
},
},
}
When connecting show warning state.
When idle shows total number of connected servers.
When a tool or resources is being called, shows spinner.
Many Neovim chat plugins like Avante and CodeCompanion already provide ways to add custom tools:
-- Avante's custom tools
require("avante").setup({
custom_tools = {
get_weather = {
name,
description,
param,
returns,
func
}
}
})
-- CodeCompanion's tools
require("codecompanion").setup({
chat = {
tools = {
get_weather = {
name,
description,
cmds,
schema,
output,
}
}
}
})
This leads to several limitations:
Feature | Regular tools | MCPHub Native Servers |
---|---|---|
Implementation | Needs reimplementing for each plugin | Write once, works everywhere |
Api | Needs plugin specific docs | Intuitive chained api res:text():image():send() |
Instructions | Can't have long schema.description | Tools,Resources converted to system prompt, instructions in one place |
Resources Support | No built-in resource handling | Full URI-based resource system |
Response Types | No standard types | MCP standard types (text, images, blobs) |
State Management | Per-plugin implementation | Centralized lifecycle management |
Plugin Updates | May break tool implementations | Tools isolated from plugin changes |
MCPHub solves these problems by providing a standardized protocol (MCP) and a central hub for tools and resources:
MCPHub Native MCP Server
config.native_servers
-- Complete server definition with tool, resource, and template
native_servers = {
weather = {
name = "weather",
capabilities = {
tools = {
{
name = "get_weather",
description = "Get current weather information for a city",
inputSchema = {
type = "object",
properties = {
city = {
type = "string",
description = "City name to get weather for",
}
},
},
handler = function(req, res)
res:text("Weather in " .. req.params.city .. ": ☀️ Sunny, 22°C"):send()
end
}
},
resources = {
{
name = "current",
uri = "weather://current/london",
description = "Get current weather data for London",
handler = function(req, res)
res:text("London: ☀️ Sunny, 22°C, Humidity: 65%"):send()
end
}
},
resourceTemplates = {
{
name = "city_weather",
uriTemplate = "weather://forecast/{city}",
description = "Get weather forecast for any city",
handler = function(req, res)
res:text(req.params.city .. " 5-day forecast:\n" ..
"Mon: ☀️ 22°C\n" ..
"Tue: ⛅ 20°C\n" ..
"Wed: 🌧️ 18°C"):send()
end
}
},
prompts = {
name = "weather_chat",
description = "Chat about weather in any city",
arguments = {
{
name = "city",
description = "City to check weather for"
}
},
handler = function(req, res)
return res
:user()
:text(string.format("What's the weather like in %s?", req.params.city))
:llm()
:text(string.format("Let me check the weather in %s for you...", req.params.city)):text(string.format("The weather in %s is ☀️ 22°C. Perfect day for outdoor activities!", req.params.city))
res:send()
end
}
}
}
}
mcphub.add_*
api to build incrementallylocal mcphub = require("mcphub")
-- Start by adding a tool. It iwll create the server if it is not already present.
mcphub.add_tool("weather", {
--tool def
})
-- Add a static resource for London weather
mcphub.add_resource("weather", {
--resource def
})
-- Add a template for any city
mcphub.add_resource_template("weather", {
--resource template def
})
-- Add a prompt
mcphub.add_prompt({
--prompt def
})
Preview:
Please read Native README.md (beta) for more information.
MCPHub acts as a central hub that:
@mcp
toolWrite Once, Use Everywhere
No Limitations
All tools, resources, and templates from the server above are converted into a clean, LLM-friendly system prompt:
## weather
### Available Tools
- get_weather: Get current weather information for a city
Input Schema:
{
type: "object",
properties: {
city: {
type: "string",
description: "City name to get weather for",
examples: ["London", "Tokyo"]
}
}
}
### Available Resources
- weather://current/london: Get current weather data for London
### Resource Templates
- weather://forecast/{city}: Get weather forecast for any city
Rich Resource Capabilities
Separation of Concerns
Easy Integration
Community Ecosystem
Environment Requirements
node --version # Should be >= 18.0.0
python --version # Should be installed
uvx --version # Should be installed
npx
or uvx
- verify these work in your terminalLLM Model Issues
If the LLM isn't making correct tool calls:
action
fieldserver_name
tool_name
or uri
Port Issues
EADDRINUSE
error, kill the existing process:
lsof -i :[port] # Find process ID
kill [pid] # Kill the process
Configuration File
mcpServers
keyMCP Server Issues
Need Help?
MCPHub.nvim uses an Express server to manage MCP servers and handle client requests:
When setup()
is called:
http://localhost:[config.port]
or at config.server_url
After successful setup:
:MCPHub
commandExpress Server Features:
When Neovim instances close:
This architecture ensures:
sequenceDiagram
participant N1 as First Neovim
participant N2 as Other Neovims
participant S as MCP Hub Server
Note over N1,S: First Client Connection
N1->>S: Check if Running
activate S
S-->>N1: Not Running
N1->>S: start_hub()
Note over S: Server Start
S-->>N1: Ready Signal
N1->>S: Register Client
S-->>N1: Registration OK
Note over N2,S: Other Clients
N2->>S: Check if Running
S-->>N2: Running
N2->>S: Register Client
S-->>N2: Registration OK
Note over N1,S: Server stays active
Note over N2,S: Client Disconnection
N2->>S: Unregister Client
S-->>N2: OK
Note over S: Keep Running
Note over N1,S: Last Client Exit
N1->>S: Unregister Client
S-->>N1: OK
Note over S: Grace Period
Note over S: Auto Shutdown
deactivate S
sequenceDiagram
participant N as Neovim
participant P as Plugin
participant S as MCP Hub Server
N->>P: start_hub()
P->>S: Health Check
alt Server Not Running
P->>S: Start Server
S-->>P: Ready Signal
end
P->>S: Register Client
S-->>P: Registration OK
N->>P: :MCPHub
P->>S: Get Status
S-->>P: Server Status
P->>N: Display UI
flowchart LR
A[VimLeavePre] -->|Trigger| B[Stop Hub]
B -->|If Ready| C[Unregister Client]
C -->|Last Client| D[Server Auto-shutdown]
C -->|Other Clients| E[Server Continues]
B --> F[Clear State]
F --> G[Ready = false]
F --> H[Owner = false]
sequenceDiagram
participant C as Chat Plugin
participant H as Hub Instance
participant S as MCP Server
C->>H: call_tool()
H->>H: Check Ready
alt Not Ready
H-->>C: Error: Not Ready
end
H->>S: POST /tools
S-->>H: Tool Result
H-->>C: Return Result
Note over C,S: Similar flow for resources
C->>H: access_resource()
H->>H: Check Ready
H->>S: POST /resources
S-->>H: Resource Data
H-->>C: Return Data
Thanks to:
For detailed documentation, visit our Wiki:
Seamless access to top MCP servers powering the future of AI integration.