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

| 欄位 | 值 |
|------|-----|
| **狀態** | **已實作** ✅ |
| **決策日期** | 2026-03-26 |
| **實作完成** | 2026-03-26 (Phase 16 R1) |
| **決策者** | 統帥 + 首席架構師 |
| **觸發原因** | 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 定義

```python
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 注入模式

```python
# 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** |

---

## 實作驗收 (2026-03-26)

| 項目 | 狀態 |
|------|------|
| interfaces.py | ✅ 已建立 MCPToolProvider ABC |
| registry.py | ✅ 已建立 ProviderRegistry |
| k8s_provider.py | ✅ 已實作 |
| signoz_provider.py | ✅ 已實作 |
| database_provider.py | ✅ 已實作 |
| mcp_bridge.py 重構 | ✅ 透過 DI 注入 |
| 測試驗證 | ✅ 28/28 通過 |

**驗收人**: 首席架構師 (Phase 16 R1.3 審查)

---

## 相關文件

- [feedback_modular_architecture.md](../../memory/feedback_modular_architecture.md)
- [feedback_modular_core_spirit.md](../../memory/feedback_modular_core_spirit.md)
- [ADR-003: leWOOOgo 模組化架構](ADR-003-lewooogo-module-architecture.md)
