Skip to content

MCP Layer Refactoring Summary

Problem Statement

When running in Docker mode with memory tools, the bot was creating MCP configurations (Qwen CLI and universal configs) even though it shouldn't. This violated the architectural principle that the MCP Hub service should own ALL MCP-related logic.

Original Logs (Issue)

2025-10-15 10:05:57.110 | INFO | src.mcp.server_manager:_create_qwen_config:422 | [MCPServerManager] Creating MCP configurations for various clients...
2025-10-15 10:05:57.110 | INFO | src.mcp.server_manager:_create_qwen_config:430 | [MCPServerManager] Creating Qwen CLI config (HTTP/SSE mode)
2025-10-15 10:05:57.112 | INFO | src.mcp.server_manager:_create_qwen_config:458 | [MCPServerManager] Docker mode detected; skipping universal config generation

Problem: Bot was creating configs in Docker mode when it should be a pure client.

Architecture Goals

  1. MCP Hub Service owns ALL MCP logic:
  2. Built-in MCP tools (memory, etc.)
  3. MCP server registry
  4. Configuration file generation
  5. HTTP/SSE API

  6. Bot is a pure client:

  7. Docker mode: Connects to external MCP Hub service
  8. Standalone mode: Launches MCP Hub subprocess
  9. Never creates configuration files

Changes Made

1. Removed Config Generation from Bot (src/mcp/server_manager.py)

Removed Methods: - _create_qwen_config() - Deleted entirely - _setup_mcp_hub_connection() - Deleted entirely - Config file creation from _setup_memory_subprocess() - Removed

Updated Methods: - setup_default_servers() - Now only manages subprocess lifecycle - _setup_memory_subprocess() - Only registers subprocess, no config creation

Updated Class Docstring:

class MCPServerManager:
    """
    MCP Server Manager - Subprocess Lifecycle Manager

    IMPORTANT: This manager is ONLY responsible for managing MCP Hub subprocess
    lifecycle in standalone mode. It does NOT create any configurations.
    """

2. Added Config Generation to MCP Hub (src/mcp/mcp_hub_server.py)

New Function:

def _generate_client_configs(host: str, port: int) -> None:
    """
    Generate MCP client configurations for various clients

    This is the MCP Hub's responsibility - it knows its URL and should
    generate configs for clients to connect to it.
    """

What It Does: - Generates Qwen CLI config (~/.qwen/settings.json) - Generates universal config (data/mcp_servers/mcp-hub.json) in standalone mode - Skips universal config in Docker mode (as intended)

Startup Flow: 1. Initialize registry 2. Generate client configs (unless --skip-config-gen) 3. Start HTTP/SSE server

3. Added Config API Endpoint (src/mcp/mcp_hub_server.py)

New Endpoint:

@mcp.custom_route("/config/client/{client_type}", methods=["GET"])
async def http_get_client_config(request: Request):
    """
    HTTP: Get client configuration for a specific client type

    Supported client types:
    - standard: Standard MCP format (Cursor, Claude Desktop, Qwen CLI)
    - lmstudio: LM Studio specific format
    - openai: OpenAI-compatible format
    """

Usage:

# Get standard config
curl http://localhost:8765/config/client/standard

# Download as file
curl http://localhost:8765/config/client/standard?format=raw -o mcp-hub.json

4. Updated Documentation

Created: - docs_site/architecture/mcp-architecture.md - Comprehensive architecture guide

Updated: - src/mcp/README.md - Reflects new architecture

Behavior Changes

Before Refactoring

Docker Mode:

Bot starts
MCPServerManager.setup_default_servers()
_create_qwen_config() runs  ← WRONG!
Creates ~/.qwen/settings.json  ← WRONG!
Bot connects to MCP Hub

Standalone Mode:

Bot starts
MCPServerManager.setup_default_servers()
_setup_memory_subprocess() creates config file  ← WRONG!
_create_qwen_config() runs  ← WRONG!
Starts MCP Hub subprocess
Bot connects to MCP Hub

After Refactoring

Docker Mode:

MCP Hub container starts
MCP Hub generates configs on startup ✓
Bot container starts
MCPServerManager.setup_default_servers() does nothing ✓
Bot connects to MCP Hub via MCP_HUB_URL ✓

Standalone Mode:

Bot starts
MCPServerManager.setup_default_servers()
_setup_memory_subprocess() registers subprocess only ✓
Starts MCP Hub subprocess ✓
MCP Hub generates configs on startup ✓
Bot connects to MCP Hub ✓

Files Changed

  1. src/mcp/server_manager.py
  2. Removed: _create_qwen_config(), _setup_mcp_hub_connection()
  3. Updated: setup_default_servers(), _setup_memory_subprocess()
  4. Updated: Class docstring

  5. src/mcp/mcp_hub_server.py

  6. Added: _generate_client_configs() function
  7. Added: --skip-config-gen CLI argument
  8. Added: /config/client/{client_type} API endpoint
  9. Updated: main() to call config generation on startup

  10. docs_site/architecture/mcp-architecture.md

  11. Created: Comprehensive architecture documentation

  12. src/mcp/README.md

  13. Updated: Architecture section to reflect new design

Testing

Syntax Check

python3 -m py_compile src/mcp/server_manager.py
python3 -m py_compile src/mcp/mcp_hub_server.py
# ✓ Both pass

Docker Mode Test

# Start services
docker-compose up

# Expected logs from MCP Hub:
# "📝 Generating client configurations..."
# "✓ Qwen CLI config: ..."
# "Docker mode: Skipping universal config generation"

# Expected logs from Bot:
# "[MCPServerManager] Docker mode: Bot will connect to external MCP Hub at ..."
# NO config generation logs from bot ✓

# Verify health
curl http://localhost:8765/health

# Verify config API
curl http://localhost:8765/config/client/standard

Standalone Mode Test

# Start bot
python -m main

# Expected logs:
# Bot: "[MCPServerManager] Standalone mode: Will launch MCP Hub as subprocess"
# MCP Hub subprocess: "📝 Generating client configurations..."
# MCP Hub subprocess: "✓ Qwen CLI config: ..."
# MCP Hub subprocess: "✓ Universal config: ..."

# Verify configs created by MCP Hub
ls -la ~/.qwen/settings.json
ls -la data/mcp_servers/mcp-hub.json

Migration Guide

For Existing Deployments

  1. Pull latest code with refactored MCP layer

  2. Docker deployments:

  3. Rebuild images: docker-compose build
  4. Restart services: docker-compose up -d
  5. Verify no config logs from bot container
  6. Verify config logs from mcp-hub container

  7. Standalone deployments:

  8. Update code
  9. Restart bot: python -m main
  10. Verify MCP Hub subprocess creates configs

  11. Verify configs:

    # Check Qwen CLI config
    cat ~/.qwen/settings.json | jq '.mcpServers["mcp-hub"]'
    
    # Check universal config (standalone only)
    cat data/mcp_servers/mcp-hub.json | jq
    

Rollback (if needed)

If issues occur: 1. Revert to previous commit before refactoring 2. Rebuild/restart services 3. Report issue with logs

Benefits

  1. Clear Separation of Concerns
  2. MCP Hub: owns all MCP logic
  3. Bot: pure client

  4. No Config Duplication

  5. Single source of truth (MCP Hub)
  6. Consistent configs across deployments

  7. Mode-Agnostic Bot

  8. Same bot code for Docker and standalone
  9. Mode detected via MCP_HUB_URL env var

  10. Dynamic Config API

  11. Clients can fetch configs programmatically
  12. Useful for automation and tooling

  13. Better Testability

  14. Clear interface boundaries
  15. Easier to mock and test

Known Issues / Future Work

  1. Config API Authentication
  2. Currently no auth on /config/client/* endpoints
  3. Consider adding in production environments

  4. Config Caching

  5. Configs generated on every startup
  6. Could cache and only regenerate on change

  7. Multi-Hub Support

  8. Currently assumes single MCP Hub
  9. Could extend to support multiple hubs

  10. Config Validation

  11. No validation of generated configs
  12. Could add schema validation

References

Author

  • Refactored by: AI Agent
  • Date: 2025-10-15
  • Issue: Config generation in Docker mode when it shouldn't