MCP Architecture
Technical documentation for the MCP (Model Context Protocol) subsystem. Covers the two-server design, gateway proxy architecture, configuration flow, and data storage.
System Overview
Claude Code connects to exactly two MCP servers. One of those servers (the gateway) acts as a proxy, aggregating tools from any number of backend servers. This keeps the Claude Code connection count fixed while allowing unlimited MCP server expansion.
Claude Code (in MultiTerminal terminal)
|
|-- --mcp-config %APPDATA%\multiterminal\.mcp.json
|
+-- mcp-gateway (McpGateway.exe) [.NET 8 console app]
| |
| +-- sqlite MCP server [backend, managed by gateway]
| +-- mssql MCP server [backend, managed by gateway]
| +-- any-other-mcp [backend, managed by gateway]
| +-- gateway__* tools [self-management tools]
|
+-- multiterminal (index.js) [Node.js MCP server]
|
+-- REST API (localhost:5050) [MultiTerminal app]
From Claude Code's perspective, it sees tools from all sources merged into two server connections. The gateway transparently proxies tool calls to the correct backend.
Configuration & Launch Flow
When MultiTerminal launches a terminal with Claude Code, the following happens:
- LaunchCommandBuilder constructs the Claude Code command line, adding
--mcp-configpointing to%APPDATA%\multiterminal\.mcp.json - McpConfigService writes an empty
.mcp.jsonto the project folder (project-level servers are managed by gateway profiles, not static config) - Claude Code starts and reads the
--mcp-configfile, connecting to both servers - The mcp-gateway starts, reads its SQLite database, and spawns all enabled backend servers for the active profile
- The multiterminal server starts and connects to the REST API at
localhost:5050
Configuration file
The MCP configuration lives at %APPDATA%\multiterminal\.mcp.json:
{
"mcpServers": {
"mcp-gateway": {
"type": "stdio",
"command": "C:\\Program Files\\MultiTerminal\\mcp-gateway\\McpGateway.exe",
"args": []
},
"multiterminal": {
"type": "stdio",
"command": "node",
"args": ["C:\\Users\\...\\AppData\\Roaming\\multiterminal\\mcp\\index.js"]
}
}
}
This file is generated by the installer's post-install.js script with correct paths for the target machine. It is not shipped as a static file.
MultiTerminal MCP Server
The multiterminal server is a Node.js application that wraps the MultiTerminal REST API (port 5050) with MCP tool interfaces. It provides ~90 tools organized into categories:
| Category | Tools | Examples |
|---|---|---|
| Task Management | 14 | list_tasks, create_task, update_checklist |
| Messaging | 7 | send_message, broadcast_message, get_inbox |
| Code Search | 2 | search_code (ripgrep), search_files |
| Browser Tabs | 7 | open_browser_tab, set_browser_content, capture_browser_screenshot |
| Projects | 6 | get_project, list_projects, update_project |
| Session & Knowledge | 8 | search_session_history, query_knowledge, save_code_digest |
| Build & Run | 5 | build_project, run_command, run_powershell_script |
Key files
| File | Location | Role |
|---|---|---|
index.js |
%APPDATA%\multiterminal\mcp\ |
Entry point, tool registration, stdio transport |
package.json |
%APPDATA%\multiterminal\mcp\ |
Dependencies (@modelcontextprotocol/sdk) |
All tool calls are translated to HTTP requests against http://localhost:5050/api/*. The REST API is hosted by the MultiTerminal WinForms application via MultiTerminalRestServer.cs.
MCP Gateway
The gateway is a .NET 8 console application that implements the MCP protocol over stdio. It serves two purposes:
- Proxy: spawns backend MCP servers as child processes and aggregates their tools into its own tool list. Tool calls are routed to the correct backend transparently.
- Manager: exposes its own
gateway__*tools for adding, removing, enabling, and disabling backend servers at runtime.
Application architecture
McpGateway.exe
|
Program.cs Entry point, DI container setup
|
Services/
| GatewayHostedService.cs MCP server host, tool routing, startup orchestration
| BackendManager.cs Spawns/stops backend MCP processes, stdio communication
| ProfileManager.cs Active profile tracking, server filtering
| ToolAggregator.cs Merges tool lists from all connected backends
|
Tools/
| ServerManagementTools.cs gateway__list/add/remove/enable/disable_server
| ProfileManagementTools.cs gateway__list/create/delete/set_profile
| ImportTools.cs gateway__import_mcp_config, gateway__import_claude_config
|
Data/
GatewayDatabase.cs SQLite persistence (servers, profiles, associations)
Communication
- Upstream (Claude Code ↔ gateway): MCP protocol over stdio (stdin/stdout)
- Downstream (gateway ↔ backends): MCP protocol over stdio (each backend is a child process)
- Logging: stderr only, disabled by default. Set
MCP_GATEWAY_DEBUG=1to enable.
Stdout is reserved for the MCP protocol. Any console output to stdout will corrupt the protocol stream. All logging must go to stderr.
Gateway Database Schema
The gateway stores all configuration in SQLite at %APPDATA%\multiterminal\gateway\gateway.db. The database is created automatically on first run.
servers
Registry of all MCP servers known to the gateway.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment ID |
name | TEXT UNIQUE | Server name (e.g., "sqlite", "my-api") |
command | TEXT | Executable to run (e.g., "npx", "node") |
args_json | TEXT | JSON array of command arguments |
env_json | TEXT | JSON object of environment variables |
is_enabled | INTEGER | 1 = enabled, 0 = disabled |
created_at | TEXT | ISO 8601 timestamp |
profiles
Named server groupings for different contexts.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment ID |
name | TEXT UNIQUE | Profile name (e.g., "default", "web-dev") |
is_active | INTEGER | 1 = currently active profile |
created_at | TEXT | ISO 8601 timestamp |
profile_servers
Many-to-many join between profiles and servers.
| Column | Type | Description |
|---|---|---|
profile_id | INTEGER FK | References profiles(id) |
server_id | INTEGER FK | References servers(id) |
Foreign keys are enforced. Deleting a profile cascades to remove its profile_servers entries.
Tool Routing & Aggregation
When Claude Code requests the tool list, the gateway:
- Collects tools from all connected backend servers via
ToolAggregator - Prefixes each tool name with the server name (e.g.,
sqlite__read_query,mssql__query) to avoid collisions - Adds its own management tools (
gateway__list_servers, etc.) - Returns the merged list to Claude Code
When Claude Code calls a tool:
GatewayHostedServicereceives the call- If the tool starts with
gateway__, it's handled internally (server/profile/import tools) - Otherwise, the prefix identifies the backend server, and the call is forwarded via
BackendManager - The backend's response is returned to Claude Code
Claude Code calls: mssql__query(sql="SELECT 1")
|
GatewayHostedService
|
prefix = "mssql"
tool = "query"
|
BackendManager.CallTool("mssql", "query", {sql: "SELECT 1"})
|
mssql child process (stdio)
|
result returned to Claude Code
Profile System
Profiles control which backend servers are active. Only one profile is active at a time.
Startup behavior
- Gateway reads
gateway.db - If no profiles exist, creates a
defaultprofile containing all servers - If
--profile <name>orMCP_GATEWAY_PROFILEis set, activates that profile - Connects all enabled servers in the active profile
Runtime switching
When gateway__set_profile is called:
- Disconnects servers not in the new profile
- Connects servers that are in the new profile but weren't connected
- Keeps servers that are in both profiles running
- Fires a
tools/list_changednotification so Claude Code refreshes its tool list
MultiTerminal's GatewayIntegrationService can sync project-specific profiles automatically. When you open a project, it activates the corresponding gateway profile, giving agents access to the right set of tools for that project.
Server Lifecycle & Recovery
Backend startup
Each backend server is spawned as a child process with a 30-second connection timeout. If a server fails to initialize within this window, it's marked as disconnected but remains registered.
Crash recovery
If a backend process crashes, the gateway detects the exit and attempts automatic restart:
- 3 retry attempts with exponential backoff (2s, 5s, 10s)
- If all retries fail, the server is marked as disconnected
- The server can be manually restarted via
gateway__enable_server
Gateway shutdown
When Claude Code closes the MCP connection (session end), the gateway:
- Sends shutdown signals to all backend child processes
- Waits briefly for graceful shutdown
- Terminates any remaining processes
- Exits cleanly
Installer Integration
The Inno Setup installer handles MCP distribution and configuration:
What gets installed
| Component | Install Location | Contents |
|---|---|---|
| MCP Gateway | {app}\mcp-gateway\ |
McpGateway.exe + .NET dependencies (framework-dependent) |
| MultiTerminal MCP | %APPDATA%\multiterminal\mcp\ |
index.js, package.json, node_modules\ |
Post-install configuration
The post-install.js script runs after file installation and:
- Sets
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1in Claude Code's globalsettings.json(required for Team Agents) - Opt-in only ("Register MCP servers globally" component, unchecked by default): registers
multiterminal+mcp-gatewayin~/.claude.jsonfor Claude Code sessions started outside MultiTerminal. MT-spawned terminals don't need this — the app regenerates%APPDATA%\multiterminal\.mcp.jsonat startup and passes it per-launch via--mcp-config - Writes
gateway-defaults.jsonfor the optional MCP servers selected in the wizard (the gateway auto-seeds on startup) - Patches
runtimeconfig.jsonfor framework-dependent mode when .NET 8 is already installed
Uninstall cleanup
The post-uninstall.js script:
- Removes the agent-teams env var from
settings.json - Removes MCP server files from AppData (including
%APPDATA%\multiterminal\.mcp.json) - Removes
multiterminal+mcp-gatewayentries from~/.claude.jsonif present (no-op when the global-registration opt-in was off) - Removes optional MCP servers from the gateway database and deletes
gateway-defaults.json - Removes the plugin marketplace directory
- Restores the
runtimeconfig.jsonbackup if one exists
Build process
Run installer\build-installer.ps1 to publish both projects and compile the installer:
# Full build: publish + installer
.\build-installer.ps1
# Installer only (reuse last publish output)
.\build-installer.ps1 -SkipPublish
The script publishes MultiTerminal (self-contained) and MCP Gateway (framework-dependent, win-x64) before invoking Inno Setup.
File Reference
Runtime files (end-user machine)
| Path | Purpose |
|---|---|
%APPDATA%\multiterminal\.mcp.json |
MCP server config (loaded via --mcp-config) |
%APPDATA%\multiterminal\mcp\index.js |
MultiTerminal MCP server entry point |
%APPDATA%\multiterminal\gateway\gateway.db |
Gateway SQLite database (servers, profiles) |
{app}\mcp-gateway\McpGateway.exe |
MCP Gateway executable |
Source files (development)
| Path | Purpose |
|---|---|
McpGateway/Program.cs |
Gateway entry point and DI setup |
McpGateway/Services/BackendManager.cs |
Backend MCP process lifecycle |
McpGateway/Services/GatewayHostedService.cs |
MCP server host and tool routing |
McpGateway/Data/GatewayDatabase.cs |
SQLite persistence layer |
MultiTerminal/Services/McpConfigService.cs |
Per-project MCP config generation |
MultiTerminal/Services/GatewayIntegrationService.cs |
Gateway profile sync for projects |
MultiTerminal/Services/LaunchCommandBuilder.cs |
Adds --mcp-config to Claude Code launch command |
MultiTerminal/installer/post-install.js |
Generates .mcp.json during installation |
MultiTerminal/installer/build-installer.ps1 |
Publish + compile installer script |