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.