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:

  1. LaunchCommandBuilder constructs the Claude Code command line, adding --mcp-config pointing to %APPDATA%\multiterminal\.mcp.json
  2. McpConfigService writes an empty .mcp.json to the project folder (project-level servers are managed by gateway profiles, not static config)
  3. Claude Code starts and reads the --mcp-config file, connecting to both servers
  4. The mcp-gateway starts, reads its SQLite database, and spawns all enabled backend servers for the active profile
  5. 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:

  1. 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.
  2. 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=1 to 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
idINTEGER PKAuto-increment ID
nameTEXT UNIQUEServer name (e.g., "sqlite", "my-api")
commandTEXTExecutable to run (e.g., "npx", "node")
args_jsonTEXTJSON array of command arguments
env_jsonTEXTJSON object of environment variables
is_enabledINTEGER1 = enabled, 0 = disabled
created_atTEXTISO 8601 timestamp

profiles

Named server groupings for different contexts.

Column Type Description
idINTEGER PKAuto-increment ID
nameTEXT UNIQUEProfile name (e.g., "default", "web-dev")
is_activeINTEGER1 = currently active profile
created_atTEXTISO 8601 timestamp

profile_servers

Many-to-many join between profiles and servers.

Column Type Description
profile_idINTEGER FKReferences profiles(id)
server_idINTEGER FKReferences 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:

  1. Collects tools from all connected backend servers via ToolAggregator
  2. Prefixes each tool name with the server name (e.g., sqlite__read_query, mssql__query) to avoid collisions
  3. Adds its own management tools (gateway__list_servers, etc.)
  4. Returns the merged list to Claude Code

When Claude Code calls a tool:

  1. GatewayHostedService receives the call
  2. If the tool starts with gateway__, it's handled internally (server/profile/import tools)
  3. Otherwise, the prefix identifies the backend server, and the call is forwarded via BackendManager
  4. 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

  1. Gateway reads gateway.db
  2. If no profiles exist, creates a default profile containing all servers
  3. If --profile <name> or MCP_GATEWAY_PROFILE is set, activates that profile
  4. Connects all enabled servers in the active profile

Runtime switching

When gateway__set_profile is called:

  1. Disconnects servers not in the new profile
  2. Connects servers that are in the new profile but weren't connected
  3. Keeps servers that are in both profiles running
  4. Fires a tools/list_changed notification 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:

  1. Sends shutdown signals to all backend child processes
  2. Waits briefly for graceful shutdown
  3. Terminates any remaining processes
  4. 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:

  1. Sets CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in Claude Code's global settings.json (required for Team Agents)
  2. Opt-in only ("Register MCP servers globally" component, unchecked by default): registers multiterminal + mcp-gateway in ~/.claude.json for Claude Code sessions started outside MultiTerminal. MT-spawned terminals don't need this — the app regenerates %APPDATA%\multiterminal\.mcp.json at startup and passes it per-launch via --mcp-config
  3. Writes gateway-defaults.json for the optional MCP servers selected in the wizard (the gateway auto-seeds on startup)
  4. Patches runtimeconfig.json for framework-dependent mode when .NET 8 is already installed

Uninstall cleanup

The post-uninstall.js script:

  1. Removes the agent-teams env var from settings.json
  2. Removes MCP server files from AppData (including %APPDATA%\multiterminal\.mcp.json)
  3. Removes multiterminal + mcp-gateway entries from ~/.claude.json if present (no-op when the global-registration opt-in was off)
  4. Removes optional MCP servers from the gateway database and deletes gateway-defaults.json
  5. Removes the plugin marketplace directory
  6. Restores the runtimeconfig.json backup 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

Related Documentation