Architecture
This guide explains the architecture of MCP Server Manager and how the gateway pattern works.
System Overview
MCP Server Manager uses a gateway pattern to manage multiple MCP servers across different AI clients:
┌─────────────────────────────────────────────────────────┐
│ Your Servers │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Filesystem │ │ Database │ │ APIs │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
▲
│ TCP/stdio
│
┌───────────────────┐
│ mcpsm Daemon │
│ (Gateway Server) │
└───────────────────┘
▲
┌───────────────────┼───────────────────┐
│ │ │
┌────────────┐ ┌──────────────┐ ┌─────────────┐
│ Claude │ │ Cursor │ │ Windsurf │
│ Desktop │ │ │ │ │
└────────────┘ └──────────────┘ └─────────────┘Core Concepts
Gateway Pattern
Instead of syncing individual servers to each client, mcpsm operates as a gateway server:
- Daemon: Runs a central
mcpsmserver that listens onlocalhost:{port}/mcp - Client Connection: Each client connects to the daemon through a single
mcpsmserver entry - Gateway: The
mcpsmserver points to the daemon (viasupergatewayor a direct URL, depending on the client) - All Servers Accessible: All configured servers are accessible through this single gateway
Benefits
- Single Point of Configuration: Add a server once, it's available in all connected clients
- No Individual Sync: Clients don't need individual server copies
- Easy Port Changes: Changing the port automatically updates all connected clients
- Real-time Loading: Supported clients see changes without restart
- Scalability: Adding new clients is as simple as running a connect command
3-State Connection Model
Each MCP client has three possible states:
| State | Meaning | How to Reach It |
|---|---|---|
| Connected | Client has mcpsm gateway; can access servers | mcpsm clients connect <client> |
| Disconnected | Client installed but not connected to mcpsm | mcpsm clients disconnect <client> |
| Not Installed | Client application not found on system | Install the client |
State Transitions
┌───────────────┐
│ Not Installed │
└───────────────┘
│
│ (user installs client)
▼
┌───────────────┐ mcpsm clients ┌───────────────┐
│ Disconnected │ ────────────────────→ │ Connected │
│ │ ←──────────────────────│ │
│ │ mcpsm clients disconnect │
└───────────────┘ └───────────────┘Client Service
The ClientService (src/services/client.service.ts) manages client detection and connections.
Client Detection
When you run mcpsm clients, the service:
- Checks for each supported client application
- Detects the config file location (OS-specific paths)
- Reads the config to check if mcpsm gateway is already connected
- Returns the status for each client
Client Paths
Config files are stored in platform-specific locations:
macOS
Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
Cursor: ~/Library/Application Support/Cursor/User/globalStorage/cursor.mcp/config.json
Windsurf: ~/Library/Application Support/Windsurf/User/globalStorage/windsurf.mcp/config.json
VS Code: ~/Library/Application Support/Code/User/mcp.json
Zed: ~/.config/zed/settings.json
Claude Code: ~/.claude/claude_code_config.json
Codex CLI: ~/.codex/config.toml
Gemini CLI: ~/.gemini/settings.jsonWindows
Claude Desktop: %APPDATA%/Claude/claude_desktop_config.json
Cursor: %APPDATA%/Cursor/User/globalStorage/cursor.mcp/config.json
Windsurf: %APPDATA%/Windsurf/User/globalStorage/windsurf.mcp/config.json
VS Code: %APPDATA%/Code/User/mcp.json
Zed: %APPDATA%/Zed/settings.json
Claude Code: %USERPROFILE%/.claude/claude_code_config.json
Codex CLI: %USERPROFILE%/.codex/config.toml
Gemini CLI: %USERPROFILE%/.gemini/settings.jsonLinux
Claude Desktop: ~/.config/Claude/claude_desktop_config.json
Cursor: ~/.config/Cursor/User/globalStorage/cursor.mcp/config.json
Windsurf: ~/.config/Windsurf/User/globalStorage/windsurf.mcp/config.json
VS Code: ~/.config/Code/User/mcp.json
Zed: ~/.config/zed/settings.json
Claude Code: ~/.claude/claude_code_config.json
Codex CLI: ~/.codex/config.toml
Gemini CLI: ~/.gemini/settings.jsonReal-time Config Paths
Some clients support real-time config loading (no restart required). These use additional config paths:
| Client | Real-time Path |
|---|---|
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code | ~/Library/Application Support/Code/User/mcp.json |
| Zed | Uses its primary settings.json path |
When connecting a client, mcpsm writes to both the primary config path and the real-time path (if supported).
Connection Process
When you run mcpsm clients connect <client>:
- Check Installation: Verify the client application exists
- Read Current Config: Load the client's current MCP configuration
- Preserve Existing Servers: Keep all existing servers in the config
- Add Gateway Server: Add the
mcpsmgateway server entry:json{ "mcpsm": { "command": "npx", "args": ["-y", "supergateway", "--streamableHttp", "http://localhost:PORT/mcp"] } } - Write Configs: Write to both primary and real-time paths
- Update Status: Client moves to "Connected" state
Disconnection Process
When you run mcpsm clients disconnect <client>:
- Read Current Config: Load the client's MCP configuration
- Remove Only mcpsm: Delete only the
mcpsmgateway server entry - Preserve Existing Servers: Keep all other servers intact
- Write Configs: Write updated config to both paths
- Update Status: Client moves to "Disconnected" state
Port Auto-Update
When you change the gateway port in Settings:
- Detect Connected Clients: Find all clients that have the mcpsm gateway
- Disconnect All: Remove the mcpsm gateway from all connected clients
- Update Port: Change the port in settings
- Reconnect All: Add the mcpsm gateway back with the new port
- Update All Configs: Write changes to both primary and real-time paths
This ensures all connected clients automatically update to use the new port without manual intervention.
Port Change Flow
User changes port in Settings
↓
Detect all connected clients
↓
Disconnect all clients (remove mcpsm gateway)
↓
Update port setting
↓
Reconnect all clients (add mcpsm gateway with new port)
↓
Write to both primary + real-time config paths
↓
Show success message with count of updated clientsDaemon and Gateway
The daemon is the background process running mcpsm:
- Gateway Server: The daemon hosts a gateway server on
localhost:{port}/mcp - All Servers: The daemon manages and proxies all configured MCP servers
- Client Proxy: When a client connects through mcpsm, requests are proxied to the daemon
The gateway server in each client configuration is what connects them:
{
"mcpsm": {
"command": "npx",
"args": ["-y", "supergateway", "--streamableHttp", "http://localhost:PORT/mcp"]
}
}This uses supergateway to forward all MCP protocol messages to the daemon's gateway endpoint.
Configuration Files
Main Configuration
The system stores configuration in ~/.mcp-manager/:
| File | Purpose |
|---|---|
config.json | Server definitions (local STDIO and remote HTTP/SSE) |
settings.json | Application settings (port, default editor, etc.) |
profiles.json | Server profiles (groupings by project/context) |
tool-filters.json | Per-server tool enable/disable settings |
clients.json | Client connection state cache (informational only) |
Client Configurations
Each client maintains its own config file (see Client Paths above). mcpsm reads and writes to these files to manage the gateway server entry.
Real-Time vs Primary Config
Primary Config
- The main config file for each client (as listed in Client Paths)
- Always written to when connecting/disconnecting
- Required for all clients
Real-time Config
- Additional paths for clients that support live config reloading
- Automatically written to when connected
- Allows changes to take effect without restart
- Cursor, Windsurf, VS Code, and Zed support real-time loading
When mcpsm connects a client, it writes the gateway server to both locations. This ensures:
- The primary config is always up-to-date
- Clients that support real-time loading see changes immediately
- Clients without real-time support still work (they'll pick up changes on restart)
Supported Clients
| Client | ID | Platforms | Real-time | Primary Config Path |
|---|---|---|---|---|
| Claude Desktop | claude | macOS, Windows | No | claude_desktop_config.json |
| Cursor | cursor | macOS, Windows, Linux | Yes | cursor.mcp/config.json |
| Windsurf | windsurf | macOS, Windows, Linux | Yes | windsurf.mcp/config.json |
| VS Code | vscode | macOS, Windows, Linux | Yes | Code/User/mcp.json |
| Zed | zed | macOS, Windows, Linux | Yes | Zed/settings.json |
| Claude Code | claude-code | CLI | No | claude_code_config.json |
| Codex | codex | macOS, Windows, Linux | No | .codex/config.toml (TOML) |
| Gemini | gemini | macOS, Windows, Linux | No | .gemini/settings.json |
Data Flow
Connecting a Client
mcpsm clients connect cursor
↓
ClientService.connectClient('cursor')
↓
1. Check if Cursor is installed
2. Read ~/.config/Cursor/User/globalStorage/cursor.mcp/config.json
3. Preserve all existing servers
4. Add mcpsm gateway server with current port
5. Write to primary config
6. Write to ~/.cursor/mcp.json (real-time)
↓
✓ ConnectedChanging Port
User: mcpsm port 9000
↓
SettingsScreen detects port change
↓
1. Find all connected clients (cursor, claude, windsurf, etc.)
2. For each connected client:
a. disconnectClient(id) - remove mcpsm entry
b. Disconnect done, port updated
c. connectClient(id) - add mcpsm entry with new port
d. Write to both primary + real-time paths
3. Show: "Updated port for 3 clients"
↓
All clients now use new portClient Using Servers
User opens Claude Desktop / Cursor / etc.
↓
Client loads mcpsm gateway server config
↓
supergateway connects to http://localhost:PORT/mcp
↓
User selects a tool from any server
↓
Tool request flows: Client → supergateway → mcpsm daemon → actual server
↓
Response flows back through the same pathImplementation Details
Key Services
ClientService (src/services/client.service.ts)
- Detects installed MCP clients
- Manages connections (connect/disconnect)
- Handles config file reading/writing
- Manages both primary and real-time config paths
ConfigService (src/services/config.service.ts)
- Manages server definitions
- Stores configuration in
~/.mcp-manager/
SettingsService (src/services/settings.service.ts)
- Manages application settings
- Triggers client reconnection on port changes
ProfileService (src/services/profile.service.ts)
- Manages server profiles
- Groups servers by context
Type Safety
All services are implemented in TypeScript with strict mode enabled. Key types:
ClientId- Union type of supported client IDsClientStatus- Union type: 'connected' | 'disconnected' | 'not-installed'DetectedClient- Client with name, status, and pathsClientMcpConfig- MCP server configuration structureServerDefinition- Local or remote server configuration
Error Handling
The system handles several error scenarios:
- Client not installed: Returns 'not-installed' status
- Config file missing: Creates new config with mcpsm gateway
- File write errors: Reports error to user, doesn't partially update
- Port in use: Caught by daemon, reported to user
- Invalid config format: Detects and preserves valid portions
Threading and Concurrency
- Client operations are synchronous (using
fsandspawnSync) - Port updates reconnect clients in sequence to ensure consistency
- Settings changes are atomic per client
For more information:
- Getting Started - Quick overview
- Client Connections - Detailed connection guide
- Configuration - Config file details
- Troubleshooting - Common issues