Files
awoooi/docs/adr/ADR-015-mcp-modular-architecture.md
OG T 643946e60c refactor(api): ADR-015 MCP 模組化架構重構
## 重構內容

符合 leWOOOgo 積木化原則:
- 新增 interfaces.py: MCPToolProvider ABC 定義
- 新增 registry.py: Provider 註冊中心 (DI 模式)
- 新增 providers/: K8s, SignOz, Database 具體實作
- 重構 mcp_bridge.py: 透過 ProviderRegistry 委派執行

## 修復 Code Review 問題

- 🔴 移除 _execute_stdio logging 敏感 parameters
- 🔴 修復 conversational-view.tsx i18n 硬編碼

## 新增檔案

- apps/api/src/plugins/mcp/interfaces.py
- apps/api/src/plugins/mcp/registry.py
- apps/api/src/plugins/mcp/providers/__init__.py
- apps/api/src/plugins/mcp/providers/k8s_provider.py
- apps/api/src/plugins/mcp/providers/signoz_provider.py
- apps/api/src/plugins/mcp/providers/database_provider.py
- docs/adr/ADR-015-mcp-modular-architecture.md
- .dependency-cruiser.cjs (Phase 14.2 準備)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-25 14:31:32 +08:00

3.6 KiB
Raw Blame History

ADR-015: MCP 模組化架構重構

欄位
狀態 已批准
決策日期 2026-03-26
決策者 統帥 + 首席架構師
觸發原因 Code Review 發現嚴重模組化違規

背景

Phase 13.2 實作 MCP Tool 整合時,為了快速交付,在 mcp_bridge.py 直接 import services 層,違反了 leWOOOgo 積木化原則。

違規清單

位置 違規
mcp_bridge.py:570 from src.services.executor import get_executor
mcp_bridge.py:655 from src.services.signoz_client import get_signoz_client
mcp_bridge.py:734 from src.services.approval_db import ...
mcp_bridge.py:738 from src.services.incident_service import get_incident_service

違反的鐵律

  1. Interface 先行 - 無 ABC 定義
  2. 禁止跨模組非法引用 - plugins → services 直接 import
  3. 模組間透過 Public API 溝通 - 直接呼叫具體實作

決策

架構重構

apps/api/src/plugins/mcp/
├── __init__.py
├── interfaces.py          # MCPToolProvider ABC (新增)
├── mcp_bridge.py          # 透過 DI 注入 providers (重構)
├── registry.py            # Provider 註冊中心 (新增)
└── providers/             # 具體實作 (新增)
    ├── __init__.py
    ├── k8s_provider.py
    ├── signoz_provider.py
    └── database_provider.py

Interface 定義

from abc import ABC, abstractmethod
from typing import Any

class MCPToolProvider(ABC):
    """MCP Tool Provider 抽象介面"""

    @property
    @abstractmethod
    def name(self) -> str:
        """Provider 名稱 (如 'kubernetes', 'signoz')"""
        pass

    @abstractmethod
    async def list_tools(self) -> list[dict]:
        """列出可用工具"""
        pass

    @abstractmethod
    async def execute(self, tool_name: str, parameters: dict) -> Any:
        """執行工具"""
        pass

DI 注入模式

# registry.py
class ProviderRegistry:
    _providers: dict[str, MCPToolProvider] = {}

    @classmethod
    def register(cls, provider: MCPToolProvider) -> None:
        cls._providers[provider.name] = provider

    @classmethod
    def get(cls, name: str) -> MCPToolProvider | None:
        return cls._providers.get(name)

# mcp_bridge.py (重構後)
async def call_tool(self, server_name: str, tool_name: str, parameters: dict):
    provider = ProviderRegistry.get(server_name)
    if not provider:
        raise ValueError(f"Unknown provider: {server_name}")
    return await provider.execute(tool_name, parameters)

優點

  1. 符合 leWOOOgo 積木化 - Interface 先行DI 注入
  2. 可測試性 - 可輕鬆 Mock Provider
  3. 可擴展性 - 新增 Provider 無需修改 mcp_bridge.py
  4. 單一職責 - 每個 Provider 只負責一個領域

缺點

  1. 重構工時 - 需要 2-3 天
  2. 檔案數增加 - 從 1 個變 6+ 個
  3. 學習曲線 - 新成員需了解 DI 模式

實作計畫

步驟 內容 工時
1 建立 interfaces.py 30min
2 建立 registry.py 30min
3 建立 providers/ 目錄 15min
4 實作 k8s_provider.py 1h
5 實作 signoz_provider.py 1h
6 實作 database_provider.py 1h
7 重構 mcp_bridge.py 2h
8 更新測試 1h
9 Code Review 1h
總計 8-9h

相關文件