Configuration
Please read the getting started guide before reading this.
Default Configuration
All options are optional with sensible defaults. See below for each option in detail.
{
"ravitemer/mcphub.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
},
build = "npm install -g mcp-hub@latest", -- Installs `mcp-hub` node binary globally
config = function()
require("mcphub").setup({
--- `mcp-hub` binary related options-------------------
config = vim.fn.expand("~/.config/mcphub/servers.json"), -- Absolute path to MCP Servers config file (will create if not exists)
port = 37373, -- The port `mcp-hub` server listens to
shutdown_delay = 5 * 60 * 000, -- Delay in ms before shutting down the server when last instance closes (default: 5 minutes)
use_bundled_binary = false, -- Use local `mcp-hub` binary (set this to true when using build = "bundled_build.lua")
mcp_request_timeout = 60000, --Max time allowed for a MCP tool or resource to execute in milliseconds, set longer for long running tasks
global_env = {}, -- Global environment variables available to all MCP servers (can be a table or a function returning a table)
workspace = {
enabled = true, -- Enable project-local configuration files
look_for = { ".mcphub/servers.json", ".vscode/mcp.json", ".cursor/mcp.json" }, -- Files to look for when detecting project boundaries (VS Code format supported)
reload_on_dir_changed = true, -- Automatically switch hubs on DirChanged event
port_range = { min = 40000, max = 41000 }, -- Port range for generating unique workspace ports
get_port = nil, -- Optional function returning custom port number. Called when generating ports to allow custom port assignment logic
},
---Chat-plugin related options-----------------
auto_approve = false, -- Auto approve mcp tool calls
auto_toggle_mcp_servers = true, -- Let LLMs start and stop MCP servers automatically
extensions = {
avante = {
make_slash_commands = true, -- make /slash commands from MCP server prompts
}
},
--- Plugin specific options-------------------
native_servers = {}, -- add your custom lua native servers here
builtin_tools = {
edit_file = {
parser = {
track_issues = true,
extract_inline_content = true,
},
locator = {
fuzzy_threshold = 0.8,
enable_fuzzy_matching = true,
},
ui = {
go_to_origin_on_complete = true,
keybindings = {
accept = ".",
reject = ",",
next = "n",
prev = "p",
accept_all = "ga",
reject_all = "gr",
},
},
},
},
ui = {
window = {
width = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number)
height = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number)
align = "center", -- "center", "top-left", "top-right", "bottom-left", "bottom-right", "top", "bottom", "left", "right"
relative = "editor",
zindex = 50,
border = "rounded", -- "none", "single", "double", "rounded", "solid", "shadow"
},
wo = { -- window-scoped options (vim.wo)
winhl = "Normal:MCPHubNormal,FloatBorder:MCPHubBorder",
},
},
json_decode = nil, -- Custom JSON parser function (e.g., require('json5').parse for JSON5 support)
on_ready = function(hub)
-- Called when hub is ready
end,
on_error = function(err)
-- Called on errors
end,
log = {
level = vim.log.levels.WARN,
to_file = false,
file_path = nil,
prefix = "MCPHub",
},
})
end
}
Binary mcp-hub
Options
On calling require("mcphub").setup()
, MCPHub.nvim starts the mcp-hub
process with the given arguments. Internally the default command looks something like:
mcp-hub --config ~/.config/mcphub/servers.json --port 37373 --auto-shutdown --shutdown-delay 600000 --watch
We can configure how the mcp-hub
process starts and stops as follows:
config
Default: ~/.config/mcphub/servers.json
Absolute path to the MCP Servers configuration file. The plugin will create this file if it doesn't exist. See servers.json page to see how servers.json
should look like, how to safely add it to source control and more
port
Default: 37373
The port number that the mcp-hub
's express server should listen on. MCPHub.nvim sends curl requests to http://localhost:37373/
endpoint to manage MCP servers. We first check if mcp-hub
is already running before trying to start a new one.
server_url
Default: nil
By default, we send curl requests to http://localhost:37373/
to manage MCP servers. However, in cases where you want to run mcp-hub
on another machine in your local network or remotely you can override the endpoint by setting this to the server URL e.g http://mydomain.com:customport
or https://url_without_need_for_port.com
shutdown_delay
Default: 5 * 60 * 000
(5 minutes)
Time in milliseconds to wait before shutting down the mcp-hub
server when the last Neovim instance closes. The mcp-hub
server stays up for 10 minutes after exiting neovim. On entering, MCPHub.nvim checks for the running server and connects to it. This makes the MCP servers readily available. You can set it to a longer time to keep mcp-hub
running.
use_bundled_binary
Default: false
Uses local mcp-hub
binary. Enable this when using build = "bundled_build.lua"
in your plugin configuration.
mcp_request_timeout
Default: 60000
(1 minute)
Maximum time allowed for a MCP tool or resource or prompt to execute in milliseconds. If exceeded, an McpError with code RequestTimeout
will be raised. Set longer if you have longer running tools.
cmd, cmdArgs
Default: nil
Internally cmd
points to the mcp-hub
binary. e.g for global installations it is mcp-hub
. When use_bundled_binary
is true
it is ~/.local/share/nvim/lazy/mcphub.nvim/bundled/mcp-hub/node_modules/mcp-hub/dist/cli.js
. You can set this to something else so that MCPHub.nvim uses cmd
and cmdArgs
to start the mcp-hub
server. You can clone the mcp-hub
repo locally using gh clone ravitemer/mcp-hub
and provide the path to the cli.js
as shown below:
require("mcphub").setup({
cmd = "node",
cmdArgs = {"/path/to/mcp-hub/src/utils/cli.js"},
})
See Contributing guide for detailed development setup.
global_env
Default: {}
The global_env
option lets you inject environment variables into all MCP servers started by MCPHub. This is useful for secrets, tokens, or session variables (like DBUS_SESSION_BUS_ADDRESS
) that should be available to every server process.
You can use either a table or a function that returns a table. The function receives the job context (workspace info, port, config files, etc).
Table Example
require("mcphub").setup({
global_env = {
-- Array-style: uses os.getenv("VAR")
"DBUS_SESSION_BUS_ADDRESS",
-- Hash-style: explicit value
PROJECT_ROOT = vim.fn.getcwd(),
CUSTOM_VAR = "custom_value",
}
})
Function Example
require("mcphub").setup({
global_env = function(context)
local env = {
"DBUS_SESSION_BUS_ADDRESS",
}
-- Add context-aware variables
if context.is_workspace_mode then
env.WORKSPACE_ROOT = context.workspace_root
env.WORKSPACE_PORT = tostring(context.port)
end
env.CONFIG_FILES = table.concat(context.config_files, ":")
return env
end
})
Notes:
- Array-style entries (
"VAR"
) will use the value fromos.getenv("VAR")
. - Hash-style entries (
KEY = "value"
) use the explicit value. - The function receives a context table with fields like
port
,cwd
,config_files
,is_workspace_mode
, andworkspace_root
.
workspace
Default:
{
workspace = {
enabled = true,
look_for = { ".mcphub/servers.json", ".vscode/mcp.json", ".cursor/mcp.json" },
reload_on_dir_changed = true,
port_range = { min = 40000, max = 41000 },
get_port = nil,
}
}
Enables project-local configuration files. When enabled, MCP Hub automatically detects project boundaries and creates isolated hub instances with merged configurations (project overrides global).
enabled
: Master switch for workspace functionalitylook_for
: Files to search for when detecting project boundariesreload_on_dir_changed
: Auto-switch hubs on directory changeport_range
: Port range for generating unique workspace portsget_port
: Optional function returning custom port number. Called when generating ports to allow custom port assignment logic
Custom Port Example
require("mcphub").setup({
workspace = {
get_port = function()
local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":t")
if project_name == "critical-project" then
return 45000 -- Use fixed port for specific project
end
return nil -- Use default hash-based port generation
end
}
})
See Workspace Guide for detailed usage examples.
Chat-Plugin Related Options
auto_approve
Default: false
By default when the LLM calls a tool or resource on a MCP server, we show a confirmation window like below.
Boolean Auto-Approval
Set it to true
to automatically approve all MCP tool calls without user confirmation:
require("mcphub").setup({
auto_approve = true, -- Auto approve all MCP tool calls
})
This also sets vim.g.mcphub_auto_approve
variable to true
. You can toggle this option in the MCP Hub UI with ga
keymap. You can see the current auto approval status in the Hub UI.
Function-Based Auto-Approval
For maximum control, provide a function that decides approval based on the specific tool call:
require("mcphub").setup({
auto_approve = function(params)
-- Auto-approve GitHub issue reading
if params.server_name == "github" and params.tool_name == "get_issue" then
return true -- Auto approve
end
-- Block access to private repos
if params.arguments.repo == "private" then
return "You can't access my private repo" -- Error message
end
-- Auto-approve safe file operations in current project
if params.tool_name == "read_file" then
local path = params.arguments.path or ""
if path:match("^" .. vim.fn.getcwd()) then
return true -- Auto approve
end
end
-- Check if tool is configured for auto-approval in servers.json
if params.is_auto_approved_in_server then
return true -- Respect servers.json configuration
end
return false -- Show confirmation prompt
end,
})
Parameters available in the function:
params.server_name
- Name of the MCP serverparams.tool_name
- Name of the tool being called (nil for resources)params.arguments
- Table of arguments passed to the toolparams.action
- Either "use_mcp_tool" or "access_mcp_resource"params.uri
- Resource URI (for resource access)params.is_auto_approved_in_server
- Boolean indicating if tool is configured for auto-approval in servers.json Return values:true
- Auto-approve the callfalse
- Show confirmation promptstring
- Deny with error messagenil
- Show confirmation prompt (same as false)
Events: When the confirmation window is shown, MCPHub fires MCPHubApprovalWindowOpened
and MCPHubApprovalWindowClosed
events that can be used for sound notifications or other integrations.
Server-Level Auto-Approval
For fine-grained control per server or tool, configure auto-approval using the autoApprove
field in your servers.json
. You can also toggle auto-approval from the Hub UI using the a
keymap on individual servers or tools. See servers.json configuration for detailed examples and configuration options.
Auto-Approval Priority
The system checks auto-approval in this order:
- Function: Custom
auto_approve
function (if provided) - Server-specific:
autoApprove
field in server config - Default: Show confirmation dialog
auto_toggle_mcp_servers
Default: true
Allow LLMs to automatically start and stop MCP servers as needed. Disable to require manual server management. The following demo shows avante auto starting a disabled MCP server to acheive it's objective. See discussion for details.
extensions
Default:
{
extensions = {
avante = {
enabled = true,
make_slash_commands = true
}
}
}
Avante integration options:
make_slash_commands
: Convert MCP server prompts to slash commands in Avante chat- Please visit Avante for full integration documentation
Also see CodeCompanion, CopilotChat pages for detailed setup guides.
Plugin Options
native_servers
Default: {}
Define custom Lua native MCP servers that run directly in Neovim without external processes. Each server can provide tools, resources, and prompts. Please see native servers guide to create MCP Servers in lua.
builtin_tools
Default:
{
builtin_tools = {
edit_file = {
},
},
}
Configuration options for MCPHub's builtin tools like edit_file
tool. View complete Builtin Tools Documentation for all available tools and their configuration options.
ui
Default:
{
ui = {
window = {
width = 0.85, -- 0-1 (ratio); "50%" (percentage); 50 (raw number)
height = 0.85, -- 0-1 (ratio); "50%" (percentage); 50 (raw number)
align = "center", -- "center", "top-left", "top-right", "bottom-left", "bottom-right", "top", "bottom", "left", "right"
border = nil, -- When nil, uses vim.o.winborder. Can be set to "none", "single", "double", "rounded", "solid", "shadow" to override
relative = "editor",
zindex = 50,
},
wo = { -- window-scoped options (vim.wo)
winhl = "Normal:MCPHubNormal,FloatBorder:MCPHubBorder",
},
},
}
Controls the appearance and behavior of the MCPHub UI window:
width
: Window width (0-1 for ratio, "50%" for percentage, or raw number)height
: Window height (same format as width)align
: Window alignment position. Options:"center"
: Center the window (default)"top-left"
,"top-right"
,"bottom-left"
,"bottom-right"
: Corner positions"top"
,"bottom"
: Top/bottom edge, centered horizontally"left"
,"right"
: Left/right edge, centered vertically
relative
: Window placement relative to ("editor", "win", or "cursor")zindex
: Window stacking orderborder
: Border style (defaults tovim.o.winborder
). Can be set to "none", "single", "double", "rounded", "solid", "shadow" to override the global setting
on_ready
Default: function(hub) end
Callback function executed when the MCP Hub server is ready and connected. Receives the hub instance as an argument.
on_error
Default: function(err) end
Callback function executed when an error occurs in the MCP Hub server. Receives the error message as an argument.
json_decode
Default: nil
Custom JSON parser function for configuration files. This is particularly useful for supporting JSON5 syntax (comments and trailing commas) in VS Code config files.
JSON5 Support Example
To enable JSON5 support for .vscode/mcp.json
files with comments and trailing commas:
Install the lua-json5 parser:
bash# Using your package manager, e.g., lazy.nvim { "Joakker/lua-json5" }
Configure MCPHub to use it:
luarequire("mcphub").setup({ json_decode = require('json5').parse, -- other config... })
With this setup, your config files can include:
{
// This is a comment
"servers": {
"github": {
"url": "https://api.githubcopilot.com/mcp/",
}, // Trailing comma is fine
},
}
log
Default:
{
level = vim.log.levels.WARN,
to_file = false,
file_path = nil,
prefix = "MCPHub"
}
Logging configuration options:
level
: Log level (vim.log.levels.ERROR, WARN, INFO, DEBUG, TRACE)to_file
: Whether to write logs to filefile_path
: Custom log file pathprefix
: Prefix for log messages