ADR-015: 標記為「已實作」✅ (Phase 16 R1 完成) ADR-009: 標記為「已實作」✅ (Phase 9.1-9.5 全部完成) ADR-006: 新增智能路由整合章節 (Phase 13.3) 首席架構師 ADR 審計 P0/P1 完成 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.1 KiB
4.1 KiB
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 |
違反的鐵律
- Interface 先行 - 無 ABC 定義
- 禁止跨模組非法引用 - plugins → services 直接 import
- 模組間透過 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)
優點
- 符合 leWOOOgo 積木化 - Interface 先行,DI 注入
- 可測試性 - 可輕鬆 Mock Provider
- 可擴展性 - 新增 Provider 無需修改 mcp_bridge.py
- 單一職責 - 每個 Provider 只負責一個領域
缺點
- 重構工時 - 需要 2-3 天
- 檔案數增加 - 從 1 個變 6+ 個
- 學習曲線 - 新成員需了解 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 審查)