# ECS MCP Server 開發心得報告

> 一份關於 AI 協作開發 MCP Server 的完整紀錄
>
> 撰寫日期：2026-01-22

---

## 前言

本報告記錄了 ECS 合約管理系統 MCP Server 的完整開發過程。從最初的資料庫連線測試，到分析兩套既有系統的程式碼，再到 MCP Server 架構設計的多次迭代，最終完成一個可運作的 MCP Server。

這不僅是一份技術文件，更是一份「與 AI 協作開發」的實戰紀錄。希望能幫助不熟悉 Vibe Coding 的開發者，了解如何透過 AI 工具有效地完成複雜的系統開發任務。

### 專案目標

為 ECS 合約管理系統開發 MCP (Model Context Protocol) Server，讓 AI 助理（如 Claude Desktop）能夠：

1. 理解系統的資料結構與業務邏輯
2. 安全地查詢合約資料庫
3. 回答各部門的決策支援問題

### 專案規模

| 項目 | 數量 |
|------|------|
| 資料庫表 | 187 張 |
| 資料庫 View | 70 個 |
| 資料庫 SP | 504 個 |
| 既有後台系統 Entity | 104 個 |
| 既有前台系統 Model | 158 個 |
| MCP Server 程式碼 | 21 個 Python 檔案 |
| 測試案例 | 98 個 |

---

## Phase 1：資料庫連線測通

### 目標

確認能夠連線到 SQL Server 資料庫，為後續開發建立基礎。

### 過程

**第一步：安裝驅動程式**

```bash
# macOS 上安裝 Microsoft ODBC Driver
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
brew install msodbcsql18 mssql-tools18
```

**第二步：測試連線 - 遇到問題**

最初的連線資訊文件（`MSSQL Connection Infomation.md`）中的帳號密碼無法連線。

**第三步：從原始碼找答案**

這是第一次體會到「程式碼是真相來源」的重要性。透過 AI 協作，我們在既有系統的設定檔中找到了正確的連線資訊：

```
# 在 ecscore-master 的 appsettings 中找到正確連線字串
reference/ecscore-master/WebApp.ECS2009/Customization/ltc/configs/appsettings.lt.json
```

**第四步：成功連線**

```bash
sqlcmd -S ecs2022.ltc -U ECSRoot -P "****" -d LT_ECS_LTCCore -C -Q "SELECT @@VERSION"
# SQL Server 2019 Enterprise Edition - 15.0.4415.2 (X64)
```

### 教訓

> **程式碼是資料結構的定義來源，文件可能過時**
>
> 當遇到連線問題時，不要只看文件，要去看正在運行的系統使用什麼設定。

---

## Phase 2：原始碼分析 - 理解雙系統架構

### 目標

理解資料庫的 Schema 架構與業務邏輯，為 MCP Server 設計提供依據。

### 關鍵發現：雙系統架構

分析過程中發現，ECS 系統實際上由兩套獨立的應用程式組成：

```
┌─────────────────────────────────────────────────────────┐
│                    SQL Server 資料庫                     │
│          （187 張表 / 70 Views / 504 SPs）               │
└─────────────────────────────────────────────────────────┘
          ▲                              ▲
          │                              │
┌─────────┴─────────┐      ┌─────────────┴─────────────┐
│  ecscore-master   │      │      ecs-ten-main         │
│  ─────────────    │      │    ─────────────────      │
│  後台管理系統      │      │    前台使用者系統          │
│  管理者權限        │      │    一般使用者權限          │
│  ─────────────    │      │    ─────────────────      │
│  ASP.NET Core 8   │      │    Express + Bun          │
│  EF Core 8        │      │    Prisma ORM             │
└───────────────────┘      └───────────────────────────┘
```

這個發現改變了整個分析策略：
- 我們需要分別分析兩套系統
- 理解它們如何共用同一個資料庫
- 找出它們存取資料的差異

### 分析策略：程式碼優先

採用「程式碼優先」的分析策略，原因是：

1. **ORM 是資料結構的定義來源**
   - EF Core Entity → 定義了哪些欄位被使用
   - Prisma Schema → 定義了資料關聯

2. **資料庫是結果，不是起點**
   - 直接看資料庫只能看到表結構
   - 看程式碼才能理解業務邏輯

3. **CLAUDE.md 是金礦**
   - 兩套系統都有完善的 CLAUDE.md 文件
   - 這些文件是前人與 AI 協作時留下的知識

### 與 AI 協作分析程式碼

**對話範例 1：探索 Entity 模型**

```
我：分析 ecscore-master 的 Entity 模型結構

AI：我來分析 lib/Ltc.EcsDB/Models/ 目錄下的 Entity...
   找到 104 個 Entity 類別，主要分為以下幾類：
   - 合約主體：Contract, ContractType, MainContractType
   - 審查流程：ExamStage, ExamStatus, ContractExaminer
   - 使用者權限：User, Department, Role, Authority
   ...
```

**對話範例 2：確認前後端分工**

```
我：ecs-ten-main 和 ecscore-master 存取資料庫有什麼差異？

AI：經過分析，主要差異在於：
   1. 後台系統（ecscore）：
      - 管理者權限，可存取所有資料
      - 透過 EF Core 直接操作表

   2. 前台系統（ecs-ten）：
      - 一般使用者權限，需要過濾
      - 透過 Prisma 查詢，有 Repository 層
      - 實作了權限過濾邏輯

   建議 MCP Server 參考前台系統的安全模式...
```

### 分析成果

完成 9 份技術文件：

| 文件 | 內容 | 分析方式 |
|------|------|---------|
| ecscore-analysis.md | 後台系統架構 | 從 CLAUDE.md 取得概覽，深入分析關鍵模組 |
| ecscore-entities.md | 104 個 Entity 清單 | glob + grep 搜尋所有 .cs 檔案 |
| ecs-ten-analysis.md | 前台系統架構 | 從 CLAUDE.md 取得概覽 |
| ecs-ten-models.md | 158 個 Model 清單 | 解析 schema.prisma |
| db-schema.md | 資料庫結構 | 實際查詢資料庫 |
| business-logic-contract.md | 合約生命週期 | 分析 Service 層程式碼 |
| business-logic-approval.md | 審核流程 | 分析 ExamStage 相關程式碼 |
| permission-control.md | 權限控制 | 分析 Authority 相關程式碼 |
| system-access-diff.md | 兩套系統差異 | 比較分析 |

### 教訓

> **善用既有的 CLAUDE.md 文件**
>
> 如果專案已經有 CLAUDE.md，這是前人與 AI 協作留下的寶貴知識。
> 不要重新分析，而是以此為起點深入探索。

> **分析順序很重要**
>
> 程式碼 → ORM 模型 → 資料庫
> 這個順序讓你能理解「為什麼」資料庫長這樣，而不只是「是什麼」。

---

## Phase 3：MCP Server 設計演進

這是整個專案最具教育意義的部分。MCP Server 的設計經歷了一次重大的架構轉變。

### 最初的想法：情境驅動設計

一開始，我們分析了各部門的使用情境（DSS 決策支援分析），整理出約 70 個具體情境：

| 部門 | 情境範例 |
|------|---------|
| ESG | ESG 條款覆蓋率、供應商盡職調查 |
| 採購 | 供應商合約到期預警、單一供應商依賴度 |
| 銷售 | 客戶合約續約率、價格折扣分布 |
| 財務 | 收付款預測、匯率曝險統計 |
| 法務 | 審核效率、非標準條款追蹤 |
| 稽核 | 權限盤點、流程遵循檢查 |

基於這些情境，最初設計了 14 個固定的 MCP Tools：

```python
# 最初的設計（後來被放棄）
@mcp.tool()
def get_expiring_contracts(days: int) -> list:
    """查詢即將到期的合約"""
    ...

@mcp.tool()
def get_department_stats(department_id: int) -> dict:
    """查詢部門統計"""
    ...

@mcp.tool()
def get_approval_efficiency() -> dict:
    """查詢審核效率"""
    ...

# ... 還有 11 個 Tools
```

### 發現問題：情境驅動的局限

在設計過程中，我們發現了嚴重的問題：

**問題 1：無法回答第 N+1 個問題**

如果使用者問：「採購部門在 Q3 簽了多少美元合約，其中有多少是與前五大供應商？」

這個問題結合了：
- 部門篩選
- 時間範圍
- 幣別篩選
- 相對人排名
- 多層聚合

沒有任何一個預定義的 Tool 能回答這個問題。

**問題 2：Tools 越加越多**

每次發現新情境就要加新 Tool，最終會變成：
- 難以維護
- 功能重疊
- AI 難以選擇正確的 Tool

**問題 3：違背 AI 的優勢**

AI 的強項是「理解問題並組合答案」，而不是「選擇正確的按鈕」。

### 架構轉變：能力驅動設計

經過深思，我們決定重新設計架構：

```
┌────────────────────────────────────────────────────────────┐
│                     設計哲學對比                             │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  ❌ 情境驅動：設計 N 個 Tools 回答 N 個固定問題              │
│     → 第 N+1 個問題就無法回答                               │
│                                                            │
│  ✅ 能力驅動：給 AI 足夠的知識 + 通用查詢能力                │
│     → AI 自己組合出任意問題的答案                           │
│                                                            │
└────────────────────────────────────────────────────────────┘
```

**核心思想：讓 AI 成為「資料分析師」，而非「報表產生器」**

### 最終架構

```
┌─────────────────────────────────────────────────────────────────┐
│                         用戶提問                                 │
└─────────────────────────────────────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│  AI 讀取 Resources（背景知識）                                   │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐               │
│  │   Schema    │ │   Context   │ │  Reference  │               │
│  │ (資料結構)  │ │ (業務邏輯)  │ │  (對照表)   │               │
│  └─────────────┘ └─────────────┘ └─────────────┘               │
└─────────────────────────────────────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│  AI 規劃查詢步驟（可能需要多個 SQL）                              │
└─────────────────────────────────────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│  AI 呼叫 Tool: query_database                                    │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  安全查詢執行器                                          │   │
│  │  - 只允許 SELECT                                         │   │
│  │  - 只允許查詢白名單 View（37 個）                         │   │
│  │  - 限制回傳 1000 筆                                       │   │
│  │  - 記錄稽核日誌                                          │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│  AI 分析結果、匯總回答                                           │
└─────────────────────────────────────────────────────────────────┘
```

### MCP 三大功能的分工

| 功能 | 職責 | 數量 | 設計原則 |
|------|------|------|---------|
| **Resource** | 提供背景知識 | 12 個 | 豐富、完整、結構化 |
| **Tool** | 提供查詢能力 | 1 個 | 精簡、安全、通用 |
| **Prompt** | 提供分析指引 | 2 個 | 框架化、可擴展 |

### Resources 設計

```
ecs://
├── schema/                 # 資料結構知識
│   ├── overview           # 資料庫概覽
│   ├── views              # View 清單與欄位（37 個 View 的完整說明）
│   └── relationships      # 資料表關聯
│
├── context/               # 業務脈絡知識
│   ├── business-terms     # 業務術語（什麼是「進行中合約」？）
│   ├── contract-lifecycle # 合約生命週期
│   ├── approval-flow      # 審核流程（14 個關卡的意義）
│   └── sla-definitions    # SLA 定義（各關卡標準處理天數）
│
├── reference/             # 對照表（動態，從資料庫取得）
│   ├── contract-types     # 合約類型清單
│   ├── departments        # 部門清單
│   ├── exam-stages        # 審核階段清單
│   └── currencies         # 幣別清單
│
└── stats/                 # 即時統計（動態）
    └── dashboard          # 系統儀表板
```

### Tool 設計：唯一的 `query_database`

```python
@mcp.tool()
async def query_database(sql: str, purpose: str) -> dict:
    """
    執行唯讀 SQL 查詢

    安全限制：
    - 只允許 SELECT 語句
    - 只能查詢 view.* 開頭的 View（共 37 個）
    - 回傳最多 1000 筆
    - 查詢 timeout 30 秒
    - 所有查詢記錄稽核日誌
    """
```

**為什麼只有一個 Tool？**

1. **安全性**：所有查詢都經過同一個安全檢查點
2. **彈性**：AI 可以寫任意合法的 SQL 來回答問題
3. **可稽核**：所有查詢都有記錄

### 安全機制

**View 白名單**：只允許查詢 37 個預先審核過的 View

```python
ALLOWED_VIEWS = [
    "view.Contract",
    "view.ContractHistory",
    "view.ContractExaminer",
    "view.Partner",
    "view.Department",
    "view.User",
    # ... 共 37 個
]
```

**SQL 驗證**：多層防護

```python
# 1. 只允許 SELECT
if not sql_upper.startswith("SELECT"):
    raise SecurityError("只允許 SELECT 語句")

# 2. 禁止危險關鍵字
DANGEROUS_KEYWORDS = [
    "INSERT", "UPDATE", "DELETE", "DROP", "CREATE",
    "ALTER", "TRUNCATE", "EXEC", "EXECUTE", "sp_", "xp_",
    "GRANT", "REVOKE", "DENY", "BACKUP", "RESTORE",
    "SHUTDOWN", "DBCC", "BULK", "OPENROWSET", "OPENDATASOURCE"
]

# 3. 禁止 SQL 註解（防繞過）
if "--" in sql or "/*" in sql:
    raise SecurityError("不允許使用 SQL 註解")

# 4. 強制 TOP 限制
sql = f"SELECT TOP {MAX_ROWS} ..."
```

### 教訓

> **設計 AI 工具時，給能力而非給答案**
>
> AI 的強項是推理和組合，不是選擇預設選項。
> 提供足夠的背景知識（Resources）+ 通用能力（Tool），
> 讓 AI 自己想出如何解決問題。

> **安全性要在能力提供點集中處理**
>
> 只有一個 Tool 意味著只有一個需要嚴格把關的地方。
> 比起分散在 14 個 Tools 中各自處理，更容易確保安全。

---

## 實作過程

### 專案結構

```
mcp_server/
├── __init__.py
├── __main__.py                # 模組入口
├── server.py                  # MCP Server 入口
├── config.py                  # 環境變數配置
│
├── database/                  # 資料庫層
│   ├── connection.py          # 連線池管理
│   ├── allowed_views.py       # View 白名單（單一資訊來源）
│   └── query_executor.py      # 安全查詢執行器
│
├── resources/                 # MCP Resources
│   ├── schema.py              # Schema 相關（靜態）
│   ├── context.py             # 業務脈絡（靜態）
│   ├── reference.py           # 對照表（動態）
│   └── stats.py               # 統計（動態）
│
├── tools/                     # MCP Tools
│   └── query.py               # 核心查詢 Tool
│
├── prompts/                   # MCP Prompts
│   └── analysis_guide.py      # 分析框架指引
│
└── utils/                     # 工具函數
    ├── logging.py             # 日誌配置
    ├── errors.py              # 錯誤處理
    └── audit.py               # 稽核記錄
```

### 技術選型

| 項目 | 選擇 | 原因 |
|------|------|------|
| 語言 | Python 3.11+ | MCP SDK 生態系最成熟 |
| MCP SDK | `mcp>=1.0.0` | Anthropic 官方維護 |
| 資料庫驅動 | `pyodbc` | 最穩定的 MSSQL 驅動 |
| 日誌 | `structlog` | 結構化日誌，方便分析 |
| 配置 | `pydantic-settings` | 類型安全的環境變數管理 |

### 測試策略

| 類型 | 測試數量 | 涵蓋範圍 |
|------|----------|---------|
| View 白名單 | 26 個 | 名稱正規化、白名單檢查、SQL 解析 |
| SQL Injection | 42 個 | SELECT 限制、危險關鍵字、註解阻擋、編碼繞過 |
| 稽核日誌 | 15 個 | 記錄完整性、欄位驗證、層級正確性 |
| 錯誤處理 | 15 個 | 錯誤類型、恢復機制、優雅降級 |
| **總計** | **98 個** | **100% 通過率** |

---

## 與 AI 協作的心得

### 有效的協作模式

**1. 先探索，再設計**

不要一開始就讓 AI 寫程式碼。先用 AI 幫助你理解問題：

```
❌ 錯誤：「幫我寫一個 MCP Server」
✅ 正確：「分析 ecscore 的 Entity 模型，整理出核心的資料結構」
```

**2. 分階段驗證**

每完成一個階段就驗證，不要等到最後：

```
Phase 1: 資料庫連線 → 驗證連線成功
Phase 2: 程式碼分析 → 驗證理解正確（與既有系統對照）
Phase 3.1: 基礎建設 → 驗證 Server 可啟動
Phase 3.2: Resources → 驗證內容正確
Phase 3.3: Tool → 驗證查詢可執行
Phase 3.4: 安全測試 → 驗證防護有效
```

**3. 善用 CLAUDE.md**

既有專案的 CLAUDE.md 是金礦，新專案也應該維護 CLAUDE.md：

```markdown
# CLAUDE.md 應該包含：
- 專案結構
- 技術棧
- 關鍵設計決策
- 開發日誌
- 快速參考連結
```

**4. 讓 AI 看程式碼，而非描述程式碼**

```
❌ 錯誤：「我們的系統有 Entity Framework，用了 Code First 模式...」
✅ 正確：「讀取 lib/Ltc.EcsDB/Models/ 目錄下的所有 .cs 檔案」
```

### 常見陷阱

**陷阱 1：過早寫程式碼**

沒有充分理解問題就開始實作，會導致頻繁重構。

**解決**：Phase 2 花了大量時間分析既有系統，這些投資在 Phase 3 得到了回報。

**陷阱 2：設計過度複雜**

最初的 14 個 Tools 設計就是過度複雜的例子。

**解決**：問自己「這個設計能不能更簡單？」

**陷阱 3：忽略安全性**

開發時容易只關注功能，忘記安全。

**解決**：安全機制應該在架構層面考慮，而非事後補丁。

---

## 專案成果

### 完成的功能

**MCP Server 核心**：
- 1 個安全的查詢 Tool（`query_database`）
- 12 個豐富的 Resources（背景知識）
- 2 個分析指引 Prompts

**安全機制**：
- View 白名單（37 個授權 View）
- SQL Injection 防護（多層驗證）
- 稽核日誌（所有查詢都有記錄）
- 結果限制（最多 1000 筆）

**技術文件**：
- Phase 2 分析文件（9 份）
- Phase 3 設計文件（5 份）
- 完整的 CLAUDE.md 維護

### 可以回答的問題類型

因為採用了能力驅動設計，MCP Server 可以回答任意組合的問題：

```
「採購部門在 Q3 簽了多少美元合約？」
「哪些合約在法務審核階段停留超過 5 天？」
「前 20 大供應商的合約到期分布如何？」
「ESG 條款覆蓋率在各部門的差異？」
「本月會辦阻塞最嚴重的案件是哪些？」
```

---

## 給初學者的建議

### 如果你想用 AI 開發 MCP Server

**1. 先理解 MCP 的三個概念**

```
Resource = 提供知識（AI 讀取來理解背景）
Tool = 提供能力（AI 呼叫來執行動作）
Prompt = 提供指引（AI 參考來組織回答）
```

**2. 設計時問自己這些問題**

```
- AI 需要知道什麼才能回答使用者的問題？ → Resource
- AI 需要什麼能力才能取得資料？ → Tool
- AI 應該用什麼框架來組織答案？ → Prompt
```

**3. 從簡單開始**

不要一開始就設計完整系統。先做一個最小可行版本：

```
第一版：1 個 Resource + 1 個 Tool
第二版：加入更多 Resources
第三版：加入安全機制
第四版：加入稽核日誌
```

### 如果你想用 AI 分析既有系統

**1. 找到 ORM 層**

ORM 模型是理解資料結構的最佳入口：
- C# → EF Core Entity
- Node.js → Prisma Schema
- Python → SQLAlchemy Model

**2. 讓 AI 幫你整理清單**

```
「列出所有 Entity/Model 的名稱和用途」
「整理出核心的資料表關聯」
「找出與 XXX 相關的所有程式碼」
```

**3. 產出文件，而非只是對話**

讓 AI 把分析結果整理成 Markdown 文件，方便日後參考。

---

## 總結

這個專案的成功要素：

1. **程式碼優先的分析策略** - 從 ORM 層開始理解系統
2. **善用既有的 CLAUDE.md** - 站在前人的肩膀上
3. **從情境驅動到能力驅動的架構轉變** - 讓 AI 發揮推理能力
4. **分階段驗證** - 確保每一步都正確
5. **安全性內建於架構** - 不是事後補丁

希望這份報告能幫助你理解如何與 AI 協作開發 MCP Server，以及更廣泛地，如何用 AI 工具來完成複雜的軟體工程任務。

---

## 附錄：關鍵設計決策紀錄

| 決策點 | 選項 | 最終選擇 | 原因 |
|--------|------|---------|------|
| MCP Tools 設計 | 多個固定情境 vs 單一通用 | 單一通用 | 彈性更高，AI 能組合任意查詢 |
| 資料存取 | 直接查表 vs 查 View | 查 View | 安全性更高，欄位可控 |
| 認證模式 | 多用戶 RLS vs 單一帳號 | 單一帳號 | 簡化實作，符合使用場景 |
| 稽核方式 | 資料庫表 vs 日誌檔案 | 日誌檔案 | 不侵入既有系統 |
| Resources 內容 | 精簡 vs 豐富 | 豐富 | AI 需要足夠的背景知識 |

---

*本報告由人類與 Claude Opus 4.5 協作完成*
