Skip to content

Workspaces ​

MCP Hub supports project-local configuration files that enable isolated MCP server setups per project. This solves the key problem of needing different server configurations for different projects.

Why Workspaces? ​

Consider these common scenarios:

Filesystem Access: mcp-server-filesystem needs access to specific project directories:

json
{
  "mcpServers": {
    "filesystem": {
      "command": "uvx",
      "args": ["mcp-server-filesystem", "${CWD}"]
    }
  }
}

Language Server Integration: mcp-language-server requires project-specific workspace and LSP configurations:

json
{
  "mcpServers": {
    "lsp": {
      "command": "mcp-language-server", 
      "args": [
        "--workspace", "${CWD}",
        "--lsp", "typescript-language-server",
        "--", "--stdio"
      ]
    }
  }
}

Without workspaces, you'd need to manually edit the global config for every project. With workspaces, each project gets its own configuration automatically.

How It Works ​

1. Project Detection ​

When you open Neovim in a directory, MCP Hub searches upward from the current directory for:

  • .mcphub/servers.json (MCP Hub specific)
  • .vscode/mcp.json (VS Code compatibility)
  • .cursor/mcp.json (Cursor compatibility)

The first file found defines the project boundary.

2. Hub Instance Creation ​

Each detected workspace gets:

  • Unique port: Generated from project path hash (e.g., 40380)
  • Isolated processes: Separate mcp-hub instance with its own servers
  • Merged configuration: Project config overrides global config
  • Project context: Hub starts with cwd set to project directory

3. Automatic Switching ​

When you change directories (cd), MCP Hub automatically:

  • Detects the new workspace
  • Connects to the appropriate hub instance
  • Switches to the correct server configuration

Configuration ​

Enable workspaces in your MCP Hub setup:

lua
require("mcphub").setup({
  workspace = {
    enabled = true, -- Default: true
    look_for = { ".mcphub/servers.json", ".vscode/mcp.json", ".cursor/mcp.json" },
    reload_on_dir_changed = true, -- Auto-switch on directory change
    port_range = { min = 40000, max = 41000 }, -- Port range for workspace hubs
    get_port = nil, -- Optional function for custom port assignment
  }
})

Example Setup ​

Global Config (~/.config/mcphub/servers.json) ​

json
{
  "mcpServers": {
    "memory": {
      "command": "uvx",
      "args": ["@modelcontextprotocol/server-memory"]
    }
  }
}

Project Config (.mcphub/servers.json) ​

json
{
  "mcpServers": {
    "filesystem": {
      "command": "uvx", 
      "args": ["mcp-server-filesystem", "${CWD}"]
    },
    "lsp": {
      "command": "mcp-language-server",
      "args": [
        "--workspace", "${CWD}",
        "--lsp", "lua-language-server", 
        "--", "--stdio"
      ]
    }
  }
}

Environment Variables ​

CWD will be set to the working directory of the current running mcp-hub. Basic environment variables (HOME, USER, TERM, SHELL, etc.) are always available.

Additional variables can be set via:

  1. global_env configuration in MCP Hub setup
  2. Process environment when the hub starts
lua
require("mcphub").setup({
    global_env = function(context)
        return {
            DBUS_SESSION_BUS_ADDRESS = os.getenv("DBUS_SESSION_BUS_ADDRESS") or "",
        }
    end
})

⚠️ Note: Environment variables are captured when the hub starts. To refresh environment, restart the hub with R in the MCP Hub UI.

Custom Port Assignment ​

By default, MCP Hub generates ports by hashing the project path. You can override this with a custom function:

lua
require("mcphub").setup({
  workspace = {
    get_port = function()
      local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":t")
      
      -- Use fixed ports for specific projects
      if project_name == "critical-project" then
        return 45000
      elseif project_name == "test-project" then  
        return 46000
      end
      
      -- Return nil to use default hash-based port generation
      return nil
    end
  }
})

This is useful when you need consistent, predictable port numbers for specific projects.

UI Overview ​

The MCP Hub interface shows clear workspace organization:

Image

Active Hubs ​

Image

Config View ​

The Config view (C) shows all configuration files with tabs for easy switching between global and project configs.

Image

Workspace Actions ​

  • <l>: Expand/collapse workspace details
  • <d>: Kill workspace process (with confirmation)
  • <gc>: Change directory to workspace
  • <h>: Collapse expanded workspace

Troubleshooting ​

Hub Not Switching ​

  • Ensure reload_on_dir_changed = true
  • Check that config file exists in project root
  • Use :cd instead of shell directory changes

Port Conflicts ​

  • Check "Active Hubs" section for conflicts
  • Kill stale processes with <d>
  • Restart with R

Environment Variables Not Updated ​

  • Environment is captured when hub starts
  • Restart hub with R to get latest environment
  • Use global_env for dynamic values

Released under the MIT License.