Documents
Home>Documents>AI>Agent>Geny

Building an Auto-Loading System for MCP Servers

7 min readFeb 6, 2026Feb 22, 2026

Implementing an MCP (Model Context Protocol) Auto-Loading System

One of the core features of Claude Control is automatic MCP server loading. Drop MCP server code into the project's mcp/ folder, and Claude Control automatically detects and connects to it at session startup. This post documents the design and implementation of that system.

What is MCP?

MCP (Model Context Protocol) is a protocol proposed by Anthropic that provides a standard for AI models to access external tools and data sources. It communicates over JSON-RPC and exposes tools, resources, and prompts.

Auto-Discovery System

The system scans the mcp/ folder to automatically detect MCP server configurations.

import os
import json
import glob
from pathlib import Path
from typing import List

@dataclass
class MCPServerConfig:
    name: str
    command: str
    args: List[str]
    env: dict = field(default_factory=dict)

class MCPAutoLoader:
    def __init__(self, base_dir: str):
        self.base_dir = Path(base_dir)
        self.mcp_dir = self.base_dir / "mcp"
        self.servers: Dict[str, MCPServerConfig] = {}

    def discover_servers(self) -> List[MCPServerConfig]:
        configs = []
        if not self.mcp_dir.exists():
            return configs

        # mcp_config.json 파일 탐색
        for config_file in self.mcp_dir.glob("**/mcp_config.json"):
            with open(config_file) as f:
                config_data = json.load(f)
            server = MCPServerConfig(
                name=config_data["name"],
                command=config_data.get("command", "python"),
                args=config_data.get("args", [str(config_file.parent / "server.py")]),
                env=config_data.get("env", {}),
            )
            configs.append(server)

        # 단독 Python MCP 서버 탐색
        for py_file in self.mcp_dir.glob("*/server.py"):
            name = py_file.parent.name
            if name not in [c.name for c in configs]:
                configs.append(MCPServerConfig(
                    name=name,
                    command="python",
                    args=[str(py_file)],
                ))
        return configs

MCP Server Process Management

Discovered MCP servers are launched as subprocesses, and a JSON-RPC communication channel is established with each one.

import subprocess
import asyncio

class MCPProcessManager:
    def __init__(self):
        self.processes: Dict[str, subprocess.Popen] = {}

    async def start_server(self, config: MCPServerConfig) -> bool:
        try:
            env = os.environ.copy()
            env.update(config.env)
            process = subprocess.Popen(
                [config.command] + config.args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                env=env,
            )
            self.processes[config.name] = process
            # 초기화 핸드셰이크
            init_msg = {"jsonrpc": "2.0", "method": "initialize", "id": 1}
            process.stdin.write(json.dumps(init_msg).encode() + b"\n")
            process.stdin.flush()
            response = process.stdout.readline().decode()
            result = json.loads(response)
            return "result" in result
        except Exception as e:
            print(f"Failed to start MCP server {config.name}: {e}")
            return False

    async def auto_load_all(self, loader: MCPAutoLoader):
        configs = loader.discover_servers()
        for config in configs:
            success = await self.start_server(config)
            status = "✅" if success else "❌"
            print(f"  {status} MCP Server: {config.name}")

Loading Custom Tools from the tools/ Folder

In addition to MCP servers, Claude Control also loads custom tools from the tools/ folder. It automatically detects any function decorated with @tool in Python files there and registers them with Claude.

import importlib.util

def load_custom_tools(tools_dir: str) -> List[dict]:
    tools = []
    for py_file in Path(tools_dir).glob("*.py"):
        spec = importlib.util.spec_from_file_location(py_file.stem, py_file)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        for attr_name in dir(module):
            attr = getattr(module, attr_name)
            if hasattr(attr, "_is_tool"):
                tools.append(attr._tool_schema)
    return tools

Retrospective

MCP auto-loading has significantly improved the extensibility of Claude Control. Adding a new MCP server now only requires dropping in a config file — the connection is handled automatically, which has sped up development considerably. It also makes it much easier to share MCP servers across the team.

Tags
MCPModel Context Protocolauto-loadingPluginAgent