實施級 PRD · v1.0

ai-mcp-server:多 API Key 多模型能力的本地 MCP 橋樑

把分散在多個 (api_key, base_url) 中的模型能力(chat / vision / reasoning / embedding / image_gen / tts / stt / rerank)收編成單一本地 MCP 橋樑,讓只能配一個模型的 Agent 也能按需路由到任意能力的模型。三進程拓撲:MCP server (stdio) + CLI + Web UI,透過 in-process 共享 application/* 與 WAL 模式 SQLite 構成單一邏輯後端;探活異步化、樂觀鎖避雙跑。

術語解釋

術語解釋
MCPModel Context Protocol,Anthropic 主導的客戶端與工具服務的協議;本項目以 stdio 模式對接 MCP client(如 Claude Desktop、Cursor、Cline)。
MCP server本倉庫主交付物,以 stdio 啟動,被 Agent 客戶端按需拉起。
MCP toolMCP server 暴露給 Agent 的可調用功能,本期共 6 個:usage_guide / list_models / invoke_model / model_performance / refresh_endpoint / add_models
endpoint用戶登記的一組 (name, base_url, api_key, provider_type),代表一個上游 API 提供商。
modelendpoint 下發現的單一模型 id,附帶 capabilities 標籤集。
capability模型能力標籤:text_chatvisiontool_callreasoningjson_modeembeddingimage_genaudio_ttsaudio_sttrerank
probe能力探活,發最小 payload(內容統一為「1」)驗證模型在某能力上是否真實可用。
resolver能力來源融合器,按「用戶覆寫 > 探活 > LiteLLM metadata > 內建靜態表」優先級合併。
provider adapter協議防腐層;本期只實作 OpenAICompatAdapter,Anthropic 預留接口。
LiteLLM第三方項目,維護一份 model_prices_and_context_window.json,包含主流模型的 context_length、modality、定價等 metadata。
Fernetcryptography 庫提供的對稱加密方案,用於加密儲存 api_key。
keyring系統級密鑰儲存(macOS Keychain / Windows Credential Vault),用於儲存 master key。
透傳對上游 API 的請求與響應原樣轉發,不做業務語義改寫(除協議格式轉換外)。
stdio標準輸入輸出流;MCP server 透過 stdio 與 client 進程通信,無網路埠。
DAOData Access Object,封裝對 SQLite 表的讀寫的薄函數層。
ER實體關係圖,展示資料表及其關係。
ABCPython abc.ABC 抽象基類,定義 Provider Adapter 接口契約。
解讀 X「邏輯單一後端」架構:UI / CLI / MCP server 三個進程各自 import ai_mcp_server.application.* 共享同一份業務邏輯與同一個 SQLite,但不共享進程。
WALSQLite Write-Ahead Logging journal mode;支援多進程並發讀寫,本期所有進程啟動時設定 PRAGMA journal_mode=WAL
Worker探活背景執行單元;可由 MCP server 進程內背景任務承擔,也可由 CLI endpoint probe 同步消化。
probe_jobs探活任務佇列表;UI / CLI / MCP 任一入口都可入隊;任務狀態 pending / claiming / running / done / failed
instance_id每個 worker 實例啟動時生成的 UUID,寫入 probe_jobs.claimed_by 作為樂觀鎖標記。
樂觀鎖並發控制策略:先寫 claimed_by → 等 0.5 秒 → 二次讀;若仍是自己才執行,否則放棄。
leaseworker 認領任務後的時效租約;超時未完成則被視為孤兒任務,被定期掃描回退為 pending
Jinja2Python 後端模板引擎,本期 Web UI 使用其純後端渲染,不引入 SPA。
FastAPIPython 異步 Web 框架;本期 ai-mcp ui 子命令以 uvicorn 託管 FastAPI 應用。
SSEServer-Sent Events;本期 UI 監聽 probe_jobs 狀態變化用 SSE 推送進度。

0. 審查結論與交付門禁

結論可進入實施。需求、技術棧、6 個 MCP tool 形態、能力來源優先級均已與用戶確認。
硬門禁真實 MCP client(如 Claude Desktop)拉起 stdio server 後,6 個 tool 的 schema、響應結構、透傳行為必須可見、可診斷。CLI 單元測試不可替代此驗收。
MVP 不變量橋樑不攔截、靜態優先探活兜底、四來源優先級不動、stdio 部署不引入帳號層。

本輪契約變更:MCP tool 從 4 個升級為 6 個

2026-06-28 決策:將現有實作中的 model_performanceadd_models 正式納入 v1 MCP 公共契約,避免設計文檔、協作指引、README、驗收腳本與 server.py 分離。6 個 tool 是本期刻意上限;後續新增 tool 必須先回到本 PRD 更新設計與驗收。

Tool契約定位邊界
usage_guide連線後第一步,返回動態 inventory、能力分佈與推薦路由模式。只提供說明與統計,不調上游 API。
list_models按 capability、context length、endpoint、probe 狀態篩選可用模型。只查本地 SQLite 與 resolver,不做自動 fallback。
invoke_model對選定 endpoint/model 透傳上游調用。只做協議格式轉換與 model 注入,不改寫 messages 或業務語義。
model_performance查詢近 3 天每模型調用次數、成功率、首字延遲與 token 均值,輔助 Agent 在同能力模型間做選擇。讀本地聚合指標,不做計費、不做成本估算、不影響路由決策。
refresh_endpoint刷新 model list 並入隊 capability probes,由 worker 異步消化。不同步阻塞等待所有 probe 完成;不做重試或自動 fallback。
add_models為不暴露 /v1/models 的 endpoint 手動登記 model_id、context length 與能力覆寫。只寫本地模型/覆寫資料;應由 Agent 先向用戶確認 model_id 與能力來源。

本輪發布阻斷修復

2026-06-28 發布審查後修復以下阻斷項;本表是設計與實施同步的發布準入記錄。

問題修復策略驗收
sdist 夾帶 .keys.trae/ 等本地敏感或工具文件。.gitignore 改為忽略 .keys 並保留 .keys.examplepyproject.toml 使用 sdist 白名單 include 與 build exclude。uv build 後檢查 tarball / wheel,不得包含 .keys.trae/
wheel 中 probe assets 被重複打包。移除 wheel shared-data 規則,只保留 force-include assets/probe → ai_mcp_server/_assets/probewheel 中每個 probe asset 只出現一次,且可被 probe_assets_dir() 找到。
默認 DB 寫入源碼/安裝目錄附近的 .data默認改為 ~/.ai-mcp-server;相對 AI_MCP_CONFIG_DIR/AI_MCP_DB_PATH 按當前工作目錄解析。tests/unit/test_path_util.py 覆蓋 home-relative default 與 cwd-relative env。
timeout / rate limit / skipped probe 會把已知 capability 覆蓋為 false。worker 僅在 ok 或明確 not_supported 時寫回 capability;其他狀態只記 probe_runs 與 job error。timeout 測試保持 gpt-4o 的 static vision=true,不被 probe false 污染。
assets/probe/digit_1.wav 缺失,STT probe 永遠 skipped。新增 digit_1.wav,並擴展 scripts/generate_probe_assets.py 同時生成 PNG/WAV。file assets/probe/digit_1.wav 顯示 16kHz mono PCM WAV;wheel/sdist 均包含該資產。
TTS 透傳成功時只返回音訊長度,沒有返回可用音訊內容。OpenAICompatAdapter.tts() 將二進位音訊以 audio_base64 放入 JSON body,同時保留 byte length 與 content-type。Agent 可從 invoke_model(operation="tts")body.audio_base64 取得音訊產物。
AI_MCP_UI_TOKEN 開啟時 /jobs/stream 被放行。token middleware 僅放行 static assets;SSE job stream 必須帶 token。tests/unit/test_web_security.py 覆蓋無 token 訪問 /jobs/stream 返回 401。
MCP stdio smoke 未納入 CI,且舊腳本仍驗 4 tools。smoke 腳本改驗 6 tools;CI 新增 uv run python scripts/verify_mcp_server.pyCI 與本地 smoke 都必須看到 6 個 MCP tool 並能調用 usage_guide

已確認決策

決策項選擇備註
部署形態本地單用戶 stdio MCP不做多用戶 SaaS、不做 HTTP 服務
協議支援OpenAI 兼容(首期),Anthropic 預留Provider ABC 留接口,不寫 Anthropic 殼
MCP tool 形態方案 C 擴展:guide + list + invoke + performance + refresh + manual add正式契約共 6 個 tool;model_performanceadd_models 納入 v1
使用說明承載MCP instructions + usage_guide tool 雙保險instructions 強提示、tool 動態組裝
能力來源四來源融合:用戶覆寫 > 探活 > LiteLLM > 靜態表resolver 統一收口
探活覆蓋10 種能力全做內容統一「1」,vision/stt 用內建資產
探活觸發UI / CLI / MCP 任一入隊;worker 異步消化狀態綁定 DB,非進程記憶體
Worker 模型(δ) MCP server 內背景任務 + (γ) CLI endpoint probe 同步消化雙來源驅動,UI 不開也能跑
並發控制樂觀鎖:寫 claimed_by=instance_id → 等 0.5s → 二次讀 → 仍是自己才執行含 lease 超時回退機制
Web UI納入 MVP:ai-mcp ui 子命令、FastAPI + Jinja2、127.0.0.1 本機無認證;設置 AI_MCP_UI_TOKEN 時非 static route 均需 token9 個頁面,純後端渲染 + SSE 進度
後端架構解讀 X:UI / CLI / MCP 三進程共享 application/*,各自 in-process 調用,共享 WAL 模式 SQLite不引入 subprocess 反代
透傳邊界強制非流式、支援多輪 tool_calls、不做重試/容錯錯誤原樣冒泡
儲存SQLite (WAL) + Fernet 加密 api_key路徑 ~/.ai-mcp-server/db.sqlite3
技術棧Python 3.11+ / mcp SDK / httpx / typer / sqlite3 / cryptography / keyring / FastAPI / Jinja2 / uvicorn不上 ORM

會構成驗收假通過的情況

  • 只跑 pytest 通過但 MCP client 拉不起來 server,或拉起來後 tool list 為空。
  • 探活返回「全部 true」但其實 vision / tool_call 走的是 fallback(如 4xx 被當成 ok)。
  • capability resolver 返回的能力與實際 invoke 結果不一致。
  • api_key 在 SQLite 中以明文落盤、或在日誌 / 錯誤訊息中出現。
  • 「不做」清單(streaming、自動重試、自動 fallback)被悄悄做了。

1. 產品價值

目標用戶與場景

  • 目標用戶:手上同時持有多個 LLM API key(OpenAI、DeepSeek、Moonshot、SiliconFlow、OpenRouter、Together、vLLM、Ollama…)的開發者,並使用至少一個 MCP client(Claude Desktop / Cursor / Cline)。
  • 核心 Job:在不切換 Agent 配置的前提下,按任務性質讓 Agent 自動挑選最合適的模型(長上下文走 Gemini、視覺走 GPT-4o、推理走 DeepSeek-R1、便宜對話走國產、Embedding 走 BGE 等)。

當前痛點

痛點當前做法代價
Agent 只配一個模型大多數 MCP client 的 model 設定是全域單選其他 API key 與能力閒置
模型 metadata 散落每家 /v1/models 只返回 id,能力靠用戶記憶無法按能力路由
key 管理混亂vendor 多了之後 .env 變成一張表容易誤用、容易洩漏
能力驗證靠玄學不知道某 endpoint 上某 model 真的支援 vision / tool_call 嗎到 Agent 對話中才報錯

產品價值(用戶可見)

  • 登記一次,所有 key 與模型即可被 Agent 統一發現與調用。
  • Agent 透過 list_models 按能力篩選,透過 invoke_model 透傳調用,不被服務語義污染
  • 能力標籤可被「探活」驗證,避免「以為能用」。
  • 所有 key 本地加密儲存,無雲端、無遙測。

成功信號

  • 同一個 Claude Desktop 會話中,Agent 能在 vision 問題上自動選 GPT-4o、在長文檔問題上自動選 Gemini,不需要用戶手動切換 client model 設定。
  • endpoint probe --all 跑完後,至少 90% 的模型能拿到 ≥1 個探活確認的 capability。
  • 本地 SQLite 中 api_key 欄位無明文,strings db.sqlite3 | grep sk- 無命中。

2. 範圍

本期範圍 (MVP)非目標後續階段
  • CLI 登記 / 查詢 / 刪除 endpoint
  • OpenAI 兼容協議 list_models / chat / embedding / image_gen / tts / stt / rerank 透傳
  • 10 種能力探活
  • 四來源能力 resolver
  • 6 個 MCP tool + stdio 啟動
  • SQLite (WAL) + Fernet 加密儲存
  • LiteLLM metadata 本地快取
  • 探活異步化:probe_jobs 佇列 + 樂觀鎖 + lease 超時回退
  • Worker:MCP server 進程內背景任務 + CLI 同步消化
  • Web UIai-mcp ui + FastAPI + Jinja2,9 個管理頁面
  • streaming 響應
  • 自動重試、自動 fallback、rate limit
  • token 計費與用量統計
  • 多用戶、帳號、權限、Web 認證
  • Anthropic / Gemini 原生協議實作
  • 定時探活、跨機同步、雲端備份
  • SPA / 前端構建工具鏈(UI 純後端模板)
  • Anthropic / Gemini adapter
  • 定時探活與健康監控
  • cost-aware 路由建議
  • HTTP 模式(給遠端 MCP client)
  • 多用戶分租
  • Web 管理 UI

假設與待用戶確認項

  • 假設:用戶能接受首次啟動時自動建立 ~/.ai-mcp-server/ 目錄並向系統 keyring 寫入 master key。
  • 已落地assets/probe/digit_1.wav 已納入倉庫,並可由 scripts/generate_probe_assets.py 重建;stt 探活不再依賴用戶手工補檔。
  • 待確認:LiteLLM metadata 是內建一份 snapshot 進 wheel,還是首次運行時從 GitHub 拉取?默認傾向「內建 snapshot + 可選 ai-mcp meta refresh 拉取最新版」。

3. 現況與差距

當前倉庫狀態

  • 已具備 pyproject.tomlsrc/ai_mcp_server/tests/assets/probe/docs/、CI 與發布 workflow。
  • 三入口已落地:ai-mcp CLI、ai-mcp-server stdio MCP server、ai-mcp ui Web UI。
  • 本 PRD 是設計與實施同步的源頭文件;發布審查發現的阻斷項需先回寫本文件,再落到 source/test。

外部生態現況

項目觀察對本期的影響
MCP Python SDK官方 mcp 包穩定,支援 stdio + sse + streamable_http;提供 Server / FastMCP 兩種寫法FastMCP,schema 與 docstring 自動推導
OpenAI /v1/models只返回 idowned_by,無能力欄位必須四來源融合
OpenRouter /api/v1/models返回完整 metadata(context_length、modality、定價、tool_call 支援)對於配置為 OpenRouter 的 endpoint,可優先採用其原生 metadata
LiteLLM model_prices_and_context_window.json覆蓋 200+ 主流模型;定期更新作為靜態 metadata 主要來源
MCP client streamingtool response 為一次性 JSON;progress notification 可選但實作彆扭本期強制非流式

差距

  • 無任何代碼基線,從零開始。
  • assets/probe/digit_1.wav 已提供;若安裝包或本地資產缺失,stt 探活仍需自動降級為 skip,不影響其他能力探活。

4. 目標旅程

4.1 首次安裝與登記

  1. 用戶 uv tool install ai-mcp-server 安裝。
  2. 首次運行任意 ai-mcp 命令時自動建立 ~/.ai-mcp-server/ 與 SQLite。
  3. 首次需要加密時自動生成 master key 並寫入系統 keyring。
  4. 用戶執行 ai-mcp endpoint add 完成登記,緊接著 ai-mcp endpoint probe 探活。

4.2 Agent 透過 MCP 調用

  1. MCP client 啟動時拉起 ai-mcp-server 進程(stdio)。
  2. client 收到 instructions:「請先調用 usage_guide 取得能力說明」。
  3. Agent 視任務需要調用 list_models 篩選能力。
  4. 如 endpoint 不提供 /v1/models,Agent 先向用戶確認後可調用 add_models 手動登記。
  5. 如多個模型能力相近,Agent 可調用 model_performance 查看近期成功率與延遲作為選擇依據。
  6. Agent 帶上選定的 endpoint + model 調用 invoke_model
  7. MCP server 找對應 adapter,透傳請求;響應原樣返回。

4.3 異常與兜底

場景系統行為Agent 可見
上游 4xx(如 key 失效)原樣冒泡 status + body完整錯誤 JSON,Agent 可決策換 endpoint
上游 5xx / 超時原樣冒泡,不重試完整錯誤,Agent 自行決定是否重試
用戶指定 capability 但無模型匹配list_models 返回空陣列 + hintAgent 知道要放寬條件
endpoint 從未探活list_models 標註 probe_status: neverAgent 可建議用戶先 refresh
探活時上游限流該 capability 標記 probe_status: rate_limited,不污染既有 truerefresh tool 響應中報告
vision 探活素材缺失啟動時警告 + 探活時 skip不影響其他 capability 探測

5. 產品方案

5.1 CLI 命令

# endpoint 管理
ai-mcp endpoint add --name <n> --base-url <url> --key <k> [--provider openai-compat]
ai-mcp endpoint list [--json]
ai-mcp endpoint show <name>
ai-mcp endpoint remove <name>

# 模型與能力
ai-mcp endpoint probe <name> [--capability text_chat,vision,...]
ai-mcp endpoint probe --all
ai-mcp model list [--endpoint <name>] [--capability vision] [--min-context 128000]
ai-mcp model show <endpoint> <model_id>
ai-mcp model override <endpoint> <model_id> --capability vision=true
ai-mcp model override <endpoint> <model_id> --context-length 200000

# metadata
ai-mcp meta refresh        # 拉取最新 LiteLLM metadata

# MCP server
ai-mcp-server              # stdio 啟動(給 MCP client 用)

5.2 MCP Tool 規格

usage_guide

內容
入參
出參結構化 Markdown 文本 + JSON 統計
動態內容當前已登記 endpoint 數、模型總數、按 capability 的模型分佈、最近探活時間、推薦使用順序
靜態 hintMCP server instructions 中強制提示:「You MUST call usage_guide first before using any other tool.」

list_models

入參類型說明
capabilitystring[] (可選)過濾必須具備的能力標籤
min_context_lengthint (可選)過濾最小上下文長度
endpointstring (可選)限定 endpoint name
include_unprobedbool, 默認 true是否包含未探活的模型

出參:模型陣列,每個元素含 endpoint, model_id, capabilities, context_length, probe_status, capability_source(標明每個 capability 來自哪一來源)。

invoke_model

入參類型說明
endpointstringendpoint name
modelstringmodel_id
operationenumchat / embedding / image_gen / tts / stt / rerank
payloadobject原樣透傳給上游 API 的 body(OpenAI 兼容格式)

出參:透傳上游響應 + 附加 _meta: {endpoint, model, latency_ms, upstream_status}。錯誤時返回 {error: {status, body}},不拋出。TTS 成功時二進位音訊以 body.audio_base64 返回,並附 audio_bytes_lencontent_type

model_performance

入參類型說明
endpointstring (可選)限定 endpoint name;留空則查全部。
sort_byenum, 默認 call_countcall_count / success_count / avg_first_byte_ms / avg_prompt_tokens / avg_output_tokens
limitint, 默認 50最多返回行數。

出參:模型陣列,每個元素含 endpoint, model_id, full_id, call_count, success_count, success_rate, avg_first_byte_ms, avg_prompt_tokens, avg_output_tokens, window_days。此 tool 只讀本地聚合性能資料,不做成本估算、不替 Agent 自動路由。

refresh_endpoint

入參類型說明
endpointstring (可選)留空則全部
capabilitiesstring[] (可選)留空則按 model metadata 與名稱 hint 生成智能 probe plan;顯式傳入時按指定能力入隊。
refresh_model_listbool, 默認 true是否先重新拉 /v1/models

出參:{enqueued, plan, note}。此 tool 只入隊,不等待所有 probe 同步完成;MCP server 進程內 worker 或 CLI worker 會異步消化。

add_models

入參類型說明
endpointstringendpoint name。
model_idsstring[]一個或多個待手動登記的 model_id。
context_lengthint (可選)可選上下文窗口。
capabilitiesstring[] (可選)可選能力標籤;寫入 override source,視為用戶確認的能力覆寫。

出參:{endpoint, added, count}{error}。Agent 使用此 tool 前應先向用戶確認模型 id、context length 與能力來源,避免憑空登記不存在模型。

5.3 能力路由建議(給 Agent 的引導)

不在服務側做路由;服務只提供能力標籤與篩選 API。usage_guide 中向 Agent 提示常見的選擇模式,例如「長文檔 → 按 context_length 排序」「視覺問題 → 篩 capability=vision」。

5.4 Web 管理 UI(ai-mcp ui

本地單用戶管理頁面,純後端 Jinja2 模板渲染;預設綁定 127.0.0.1、本機無認證;設置 AI_MCP_UI_TOKEN 後,除 static assets 外所有 route(含 /jobs/stream SSE)均需 ?token=...。UI 進程 in-process 調用 application/*,與 CLI / MCP 共享同一份業務邏輯。

# 啟動
ai-mcp ui [--host 127.0.0.1] [--port 8765]
# 控制台輸出:
#   ai-mcp ui ready at http://127.0.0.1:8765/
#   按 Ctrl+C 退出

5.5 UI 頁面清單(9 個,全為 MVP)

路由頁面功能
GET /Dashboardendpoint 總數、模型總數、按 capability 分佈直方圖、最近探活時間、MCP server 狀態提示
GET /endpointsEndpoints 列表表格顯示所有 endpoint;操作:新增、編輯、刪除
GET /endpoints/<name>Endpoint 詳情該 endpoint 下所有 model、探活狀態、按鈕「探活此 endpoint」
GET /modelsModels 全表跨 endpoint 模型表;可按 capability / min_context / endpoint 篩選
GET /models/<endpoint>/<model_id>Model 詳情顯示四來源每個 capability 判定值與 source;連結到能力覆寫
GET /overrides能力覆寫列出所有 override;新增 / 編輯 / 刪除
GET /probes探活歷史probe_runs;可按 endpoint / model / capability / 時間範圍篩選
GET /jobs探活佇列顯示 probe_jobs 當前狀態;SSE 推送進度
GET /metaMetadata 管理顯示 LiteLLM metadata 版本;按鈕「拉取最新」

寫操作以 form POST 提交,UI route 直接 in-process 調 application/*;不走 subprocess、不走 HTTP 反代到 MCP server。SSE 用於 /jobs/endpoints/<name> 中的探活進度刷新。

5.6 探活異步化流程

探活不再阻塞觸發者;改為「入隊 → worker 認領 → 寫回結果」三段式。

  1. 入隊:UI / CLI / MCP 任一入口都可 INSERT INTO probe_jobs,狀態 pending,無 claimed_by
  2. 認領(樂觀鎖)
    • worker 啟動時生成 instance_id = uuid4()
    • UPDATE probe_jobs SET claimed_by=instance_id, claimed_at=now, status='claiming' WHERE id=? AND claimed_by IS NULL
    • 等 0.5 秒;SELECT claimed_by FROM probe_jobs WHERE id=?;如仍是自己 → status='running' 進入執行,否則 noop。
  3. 執行:跑 provider 探活 → 寫 probe_runs raw 響應 → 更新 models.capabilities_json(透過 resolver)→ UPDATE probe_jobs SET status='done', finished_at=now
  4. lease 超時回退:背景定期掃描 status IN ('claiming','running') AND lease_until < now,重置為 pending, claimed_by=NULL(孤兒任務恢復)。
  5. 失敗:探活內部錯誤 → status='failed'error 欄位記原因;不重試(用戶自行重新入隊)。

Worker 承擔:(δ) ai-mcp-server MCP 進程內以 asyncio task 常駐輪詢 + (γ) ai-mcp endpoint probe CLI 也跑 worker loop 直到佇列清空。兩者用同一份 worker 代碼,靠樂觀鎖避免並發雙跑。

6. 架構擴展

6.1 整體架構

  1. 入口層:三個獨立進程入口共享 application/*server.py(stdio MCP);cli.py(typer CLI);web/app.py(FastAPI + Jinja2,由 ai-mcp ui 子命令拉起 uvicorn)。
  2. 編排層 application/:endpoint 管理、模型發現、capability 解析、probe_jobs 入隊與消化;無 IO 細節。CLI / UI / MCP route 都直接 import。
  3. Worker 層application/worker.py 提供 claim_one() / run_loop();MCP server 進程啟動時 asyncio task 常駐輪詢,CLI endpoint probe 也跑直到 queue 清空。
  4. Provider 層 providers/:ABC + OpenAICompat 實作;負責協議格式、HTTP 細節、錯誤碼透傳。
  5. Capability 層:static_map(內建表)、litellm_meta(拉取/快取)、resolver(四來源融合)。
  6. Probe 層:每能力一個模組,輸入 (adapter, model_id) → ProbeResult。
  7. Storage 層sqlite3(連線時設 PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000)+ Fernet + keyring;DAO 函數薄。
  8. 架構原則「解讀 X」:三進程不共享記憶體、各自 in-process 調 application;共享真相在 SQLite(WAL 多進程併發安全)。

6.2 倉庫結構

ai-mcp-server/
├── pyproject.toml
├── AGENTS.md
├── docs/prd/ai-mcp-server-v1/index.html
├── assets/probe/
│   ├── digit_1.png         # vision 探活素材
│   └── digit_1.wav         # stt 探活素材
├── src/ai_mcp_server/
│   ├── __init__.py
│   ├── server.py           # MCP server 入口 (ai-mcp-server)
│   ├── cli.py              # CLI 入口 (ai-mcp; 含 ui / endpoint / model / meta / worker 子命令)
│   ├── application/
│   │   ├── endpoint_service.py
│   │   ├── model_discovery.py
│   │   ├── probe_jobs.py        # enqueue / claim / lease / list
│   │   ├── worker.py            # claim_one / run_loop / lease_sweeper
│   │   ├── capability_query.py
│   │   └── meta_service.py
│   ├── providers/
│   ├── capability/
│   ├── probes/
│   ├── storage/
│   │   ├── db.py                # WAL + busy_timeout + migration
│   │   ├── crypto.py
│   │   └── dao.py
│   ├── web/
│   │   ├── app.py               # FastAPI app factory
│   │   ├── routes/
│   │   │   ├── dashboard.py
│   │   │   ├── endpoints.py
│   │   │   ├── models.py
│   │   │   ├── overrides.py
│   │   │   ├── probes.py
│   │   │   ├── jobs.py          # 含 SSE endpoint
│   │   │   └── meta.py
│   │   ├── templates/           # Jinja2
│   │   │   ├── base.html
│   │   │   ├── dashboard.html
│   │   │   └── ...
│   │   └── static/              # 樸素 CSS,不引入前端構建
│   ├── models/
│   └── utils/
└── tests/{unit,integration,conftest.py}

6.3 代碼變更影響矩陣

層級文件或模組當前職責計劃修改影響驗證
toolingpyproject.toml不存在新建:依賴(mcp / httpx / typer / cryptography / keyring / pydantic)、entry points(ai-mcp / ai-mcp-server)、ruff / mypy 配置uv sync 可解依賴,CLI 與 server 可被 uv run 拉起uv run ai-mcp --help
storagestorage/db.py不存在新建:SQLite 連線、初始化三張表、migration 編號首次運行自動建表pytest 覆蓋連線、建表、二次運行不重建
storagestorage/crypto.py不存在新建:Fernet 包裝、master key 取得(env > keyring > 生成)api_key 加密寫入pytest + strings db.sqlite3 無命中
storagestorage/dao.py不存在新建:endpoints / models / overrides 三套 CRUD編排層僅依賴 DAOpytest 隔離 DB 覆蓋 CRUD
providersproviders/base.py不存在新建:ProviderAdapter ABC,方法 list_models / chat / embed / image_gen / tts / stt / rerank所有 provider 必須實作;為 Anthropic 預留mypy + ABC 實例化測試
providersproviders/openai_compat.py不存在新建:用 httpx 對接 /v1/models 與 /v1/* 路徑;錯誤原樣冒泡覆蓋首期所有上游對 mock httpx 跑單測 + 真實 endpoint smoke
providersproviders/factory.py不存在新建:按 provider_type 路由到 adapter 實例編排層不知道具體 adapterpytest 覆蓋路由
capabilitycapability/static_map.py不存在新建:內建 model_id 模式 → capability set 的字典(覆蓋 OpenAI / Claude / Gemini / DeepSeek / Qwen / Moonshot 等常見前綴)resolver 第四級兜底pytest 覆蓋若干典型 model_id 命中
capabilitycapability/litellm_meta.py不存在新建:內建 snapshot + 可選遠端拉取;本地 JSON 快取resolver 第三級pytest mock 網路 + 離線降級測試
capabilitycapability/resolver.py不存在新建:合併四來源;返回時保留 capability_source 標註tool 層、CLI 層統一入口pytest 覆蓋四來源衝突案例
probesprobes/*.py不存在新建:10 個 probe 模組 + ProbeResult dataclass + 統一「1」素材探活輸出統一可被 resolver 寫回pytest mock adapter + 真實 endpoint 抽測
applicationapplication/*.py不存在新建:endpoint CRUD / model discovery / probe batch / capability queryCLI 與 MCP tool handler 共用pytest 覆蓋編排語義
clicli.py不存在新建:typer app;endpoint / model / meta 子命令用戶可登記、查詢、覆寫typer CliRunner 單測 + 真實命令 smoke
mcpserver.py不存在新建:FastMCP 註冊 6 個 tool、設定 instructionsMCP client 可拉起並調用mcp inspector + Claude Desktop 真實串通
assetsassets/probe/digit_1.png不存在新建:白底黑色「1」的 64x64 PNG(生成腳本一次性)vision 探活素材檔案存在 + 可被 PIL 讀取
assetsassets/probe/digit_1.wav已納入scripts/generate_probe_assets.py 生成;缺失時 stt 探活降級為 skipstt 探活素材可隨包發布file assets/probe/digit_1.wav 顯示 16kHz mono PCM WAV
storagestorage/db.py(補強)新建連線時設 PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000;新增 probe_jobs 表 schema 與 migration支援三進程並發讀寫pytest 多進程同時寫測試
applicationapplication/probe_jobs.py不存在新建:enqueue、list、樂觀鎖 claim、lease 回退UI / CLI / MCP 共用入隊與查詢pytest 模擬兩個 instance 搶 claim
applicationapplication/worker.py不存在新建:instance_id = uuid4()claim_one()(含 0.5s 二次確認)、run_loop()lease_sweeper()MCP server 與 CLI 共用 worker 代碼pytest + 真實 sqlite 並發測試
mcpserver.py(補強)新建啟動時 asyncio.create_task(worker.run_loop()) 常駐;shutdown 時優雅停止Claude Desktop 拉起 MCP 後自動消化探活佇列integration 啟動 server 後入隊一個 job,預期被消化
clicli.py(補強)新建新增 ai-mcp uiai-mcp workerai-mcp endpoint probe 改為入隊 + 同步跑 worker loop 直到清空CLI 也能驅動消化,無 MCP server 也能跑typer CliRunner + 真實命令 smoke
webweb/app.py不存在新建:FastAPI app factory、Jinja2 模板註冊、靜態目錄掛載、127.0.0.1 綁定預設ai-mcp ui 可拉起 uvicornhttpx async client 對 ASGI app 整合測試
webweb/routes/*.py不存在新建 9 個頁面 route(Dashboard / Endpoints / Endpoint detail / Models / Model detail / Overrides / Probes / Jobs / Meta);jobs 含 SSEUI 全部頁面就緒各 route 對 ASGI 跑 smoke + Jinja 渲染 snapshot
webweb/templates/*.html不存在新建:base.html 含側邊導航;每頁一個模板;樸素 CSS,無前端構建UI 視覺一致真實瀏覽器打開所有頁面截圖
modelsmodels/enums.py / models/schemas.py不存在新建:CapabilityProbeStatusJobStatus(pending/claiming/running/done/failed)EndpointDTOProbeJobDTO共用型別契約mypy

6.4 對外契約

  • CLI 契約:見 §5.1,命令名與參數穩定;新增子命令不破壞既有。
  • MCP tool 契約:6 個 tool 的 name、入參 schema、出參結構為穩定契約;演進時新增可選欄位、不刪除既有欄位。
  • Provider 契約:上游 API 響應原樣透傳;僅附加 _meta,不修改 body。

7. 數據與資料庫規劃

7.1 ER 視圖

  1. endpoints 是根表,主鍵 id;存 (name 唯一, base_url, api_key_enc, provider_type, created_at)。
  2. models 多對一引用 endpoints;(endpoint_id, model_id) 聯合主鍵;存 capability 探活結果與 metadata 緩存。
  3. overrides 多對一引用 models;(endpoint_id, model_id, capability_key) 聯合主鍵;存用戶手動覆寫。
  4. probe_runs 記錄歷次探活的 raw 響應,便於追溯;無 FK,按 (endpoint_id, model_id) 字串關聯。
  5. probe_jobs 探活任務佇列;含 claimed_by(worker instance_id)、claimed_atlease_untilstatus;UI / CLI / MCP 任一入隊。

7.2 Schema

-- endpoints
CREATE TABLE endpoints (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  name          TEXT NOT NULL UNIQUE,
  base_url      TEXT NOT NULL,
  api_key_enc   BLOB NOT NULL,        -- Fernet ciphertext
  provider_type TEXT NOT NULL DEFAULT 'openai-compat',
  created_at    TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at    TEXT NOT NULL DEFAULT (datetime('now'))
);

-- models
CREATE TABLE models (
  endpoint_id        INTEGER NOT NULL REFERENCES endpoints(id) ON DELETE CASCADE,
  model_id           TEXT NOT NULL,
  capabilities_json  TEXT NOT NULL DEFAULT '{}',  -- {cap: {value, source, probed_at}}
  context_length     INTEGER,
  raw_meta_json      TEXT,                         -- 上游 /v1/models 原始 item
  last_discovered_at TEXT NOT NULL DEFAULT (datetime('now')),
  PRIMARY KEY (endpoint_id, model_id)
);

-- overrides
CREATE TABLE overrides (
  endpoint_id    INTEGER NOT NULL,
  model_id       TEXT NOT NULL,
  capability_key TEXT NOT NULL,         -- e.g. 'vision', 'context_length'
  value_json     TEXT NOT NULL,
  updated_at     TEXT NOT NULL DEFAULT (datetime('now')),
  PRIMARY KEY (endpoint_id, model_id, capability_key)
);

-- probe_runs
CREATE TABLE probe_runs (
  id           INTEGER PRIMARY KEY AUTOINCREMENT,
  endpoint_id  INTEGER NOT NULL,
  model_id     TEXT NOT NULL,
  capability   TEXT NOT NULL,
  ok           INTEGER NOT NULL,
  latency_ms   INTEGER,
  raw_json     TEXT,
  error        TEXT,
  ran_at       TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_probe_runs_lookup ON probe_runs(endpoint_id, model_id, capability, ran_at);

-- probe_jobs (探活任務佇列)
CREATE TABLE probe_jobs (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  endpoint_id   INTEGER NOT NULL REFERENCES endpoints(id) ON DELETE CASCADE,
  model_id      TEXT NOT NULL,
  capability    TEXT NOT NULL,        -- 待探活的 capability key
  status        TEXT NOT NULL DEFAULT 'pending',
                  -- pending | claiming | running | done | failed
  priority      INTEGER NOT NULL DEFAULT 0,
  claimed_by    TEXT,                  -- worker instance_id (UUID)
  claimed_at    TEXT,
  lease_until   TEXT,                  -- claim 後預估完成時限,超時可被回退
  finished_at   TEXT,
  error         TEXT,
  created_at    TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_probe_jobs_pending ON probe_jobs(status, priority DESC, id ASC)
  WHERE status='pending';
CREATE INDEX idx_probe_jobs_lease ON probe_jobs(status, lease_until)
  WHERE status IN ('claiming','running');

-- 連線初始化
PRAGMA journal_mode=WAL;
PRAGMA busy_timeout=5000;

-- migrations
CREATE TABLE _schema_version (version INTEGER PRIMARY KEY);

7.3 變更與兼容性

對象變更原因兼容性測試
endpoints新建表持久化用戶登記的上游初版,無歷史建表 + CRUD + name UNIQUE 衝突測試
models新建表緩存模型發現結果與能力初版聯合主鍵 + 級聯刪除測試
overrides新建表用戶覆寫優先級最高初版resolver 衝突合併測試
probe_runs新建表探活歷史追溯初版,可選表插入 + 按時間查詢
probe_jobs新建表探活異步化的任務佇列;UI / CLI / MCP 共用初版樂觀鎖並發測試 + lease 超時回退測試
WAL journal mode所有連線開啟三進程並發讀寫共享 DB單機 SQLite 標配;多寫者透過 busy_timeout 排隊多進程同時寫測試
_schema_version新建表後續 migration 編號初版設為 1migration 函數冪等測試

7.4 加密、回滾、隱私

  • 加密api_key_enc 使用 Fernet(AES-128-CBC + HMAC);master key 來自 env AI_MCP_MASTER_KEY > 系統 keyring > 首次運行自動生成並寫入 keyring。
  • 回滾:MVP schema 不需 down migration;直接刪除 ~/.ai-mcp-server/db.sqlite3 重建即可(用戶會被警示)。
  • 遺留可讀性:master key 一旦遺失,所有 api_key_enc 不可解密 → CLI 在加密失敗時提示用戶 re-add endpoint。
  • 隱私:無遙測;所有 IO 限於本機 SQLite、本機 keyring、向用戶登記的 base_url 發 HTTPS。
  • 日誌:所有日誌路徑禁止輸出 api_key 明文與 Authorization header;錯誤響應原樣冒泡時需 mask 上游 echo back 的 key(如有)。

8. 實施計劃

分 9 個里程碑,每個獨立可測。

#里程碑交付物主要文件驗證
M1腳手架pyproject.toml + 目錄骨架 + typer CLI 入口pyproject.toml, src/ai_mcp_server/{cli,__init__}.pyuv sync, uv run ai-mcp --help
M2儲存層SQLite schema (含 WAL + busy_timeout)、Fernet 加密、DAOstorage/*.pypytest 隔離 DB + strings 驗證無明文 + 多進程同時寫
M3Provider ABC + OpenAI 兼容ProviderAdapter + OpenAICompatAdapter + factoryproviders/*.pypytest mock httpx + 對真實 endpoint smoke
M4CLI endpoint 子命令add / list / show / removecli.py, application/endpoint_service.pytyper CliRunner + 真實命令跑通
M5Capability 來源層static_map + litellm_meta + resolver(四來源融合)capability/*.pypytest 覆蓋四來源衝突
M6探活 + probe_jobs 入隊10 個 probe + probe_jobs 表 + enqueue API + 探活素材probes/*.py, application/probe_jobs.pypytest 覆蓋 enqueue + 真實 endpoint 探活
M7Worker(樂觀鎖)worker.py 含 instance_id、claim_one 含 0.5s 二次確認、run_loop、lease_sweeper;CLI ai-mcp endpoint probe 改為入隊 + 同步消化application/worker.py並發測試:兩 instance 同時搶 100 個 job,無雙跑、無遺漏
M8MCP Server + 背景 workerFastMCP 註冊 6 個 tool + instructions + stdio 入口 + 啟動時 spawn worker taskserver.pymcp inspector + Claude Desktop 真實串通 + 入隊一個 job 預期被消化
M9Web UIai-mcp ui 子命令 + FastAPI app + 9 個頁面 + Jinja2 模板 + SSE 進度web/**瀏覽器跑通 9 個頁面截圖 + SSE 進度刷新

8.1 依賴與順序

  • M1 → M2 → M3 / M5(可並行)→ M4 → M6 → M7 → M8 / M9(可並行)。
  • M7 依賴 M6 的 probe_jobs 表與 enqueue API。
  • M8 / M9 都依賴 M7 的 worker;M8 用內建 task,M9 不啟動 worker(只入隊)。

8.2 回滾

  • 任何里程碑失敗,回退至上一里程碑 tag;MVP 階段 SQLite 直接刪庫重建。

9. 開發風險(Developer Reality)

風險觸發場景緩解
探活 false negative上游 429 / 排隊 / 暫時超時被當成「不支援」區分 ok / not_supported / rate_limited / timeout / error 五態;rate_limited / timeout 不污染既有 true
探活 false positive上游對未知 tool_call schema 返回空字串而非報錯探活時校驗響應結構(tool_call 必須有 tool_calls 欄位、vision 必須命中「1」)
不同 endpoint 的 model_id 撞名OpenAI 和 OpenRouter 都有 gpt-4o所有對外 ID 統一為 {endpoint_name}/{model_id};list_models / invoke_model 均接受此複合 id
OpenAI 兼容協議方言差異Anthropic-via-OpenAI、Gemini-via-OpenAI、本地 vLLM 在 tool_calls / finish_reason 欄位上略有不同透傳不改寫;在 README 標明已知差異;後續按需在 adapter 內加 quirk 開關
master key 遺失用戶清空 keychain 或換機CLI 解密失敗時清晰報錯:「請設置 AI_MCP_MASTER_KEY 或重新登記 endpoint」
MCP stdio 啟動失敗難診斷用戶在 Claude Desktop 配置後黑屏提供 ai-mcp-server --debug,輸出到 stderr;README 給 Claude Desktop config 範例
LiteLLM metadata 結構演進上游欄位更名internal mapping 函數隔離;解析失敗降級為「無 metadata」,不影響其他來源
image_gen / tts 探活費用批量探活時可能花幾分錢~幾毛錢CLI endpoint probe 顯示「以下能力探活會產生上游費用 (image_gen, tts),是否繼續? [y/N]」
非流式對長響應的影響長文生成可能讓 MCP tool call 看起來「卡住」記錄到 README;後續用 MCP progress notification 緩解
Anthropic 預留接口走樣未來實作時發現 ABC 不夠用ABC 方法簽名按「OpenAI 兼容超集」設計;message 結構用 list[dict],不過度封裝
樂觀鎖未生效導致雙跑兩個 worker 同時跑 UPDATE ... WHERE claimed_by IS NULL條件 UPDATE 在 SQLite 是原子的;再加 0.5s 二次讀;最終 status 流轉只允許 pending → claiming → running → done/failed 一向單調
Worker 孤兒任務worker 崩潰時 status='running' 永不結束lease_sweeper 定期掃描 lease_until < now 的 claiming/running 重置為 pending;探活開始時設 lease_until = now + 5min,過程中可續租
三進程共寫 SQLiteUI / CLI / MCP server 同時寫WAL 模式 + busy_timeout=5000;長交易禁用;寫操作短小
SSE 連線斷開後 UI 看不到進度瀏覽器或網路抖動SSE 帶 Last-Event-Id;前端重連時用最後一個 job id 補拉
UI 進程意外被外網訪問用戶誤改 --host 0.0.0.0預設 127.0.0.1;改為非 loopback 時 CLI 加大紅警告
UI 與 MCP server 共寫 capabilities探活 worker 與用戶 override 同時寫 capabilities_json所有寫入 capabilities 都走 resolver;override 是覆蓋層不寫主表的同一欄位

10. 測試與驗收

10.1 測試矩陣

層級類型內容命令
儲存unitschema 建表冪等、Fernet 加密解密、DAO CRUDuv run pytest tests/unit/storage
providerunitOpenAI 兼容 list_models / chat / embed 各端點請求拼裝與錯誤透傳uv run pytest tests/unit/providers
capabilityunitresolver 四來源衝突優先級、static_map 命中、litellm 解析、離線降級uv run pytest tests/unit/capability
probeunit每個 probe 對 mock adapter 的 ok / not_supported / rate_limited 路徑uv run pytest tests/unit/probes
cliintegrationtyper CliRunner 跑 endpoint add / list / probe / model overrideuv run pytest tests/integration/cli
MCP serverintegrationmcp SDK in-memory transport 跑 6 個 tool 的 schema 與響應;server 啟動時 worker task 消化已入隊 jobuv run pytest tests/integration/mcp
workerintegration兩個 worker 實例同時啟動,搶 100 個 pending job:無雙跑、無遺漏;lease_sweeper 能把孤兒任務回退uv run pytest tests/integration/worker
webintegrationhttpx 對 ASGI app 跑 9 個頁面 200 OK;form POST 寫操作落 DB;SSE 接收一個 job 完成事件uv run pytest tests/integration/web
lint / typestaticruff / mypyuv run ruff check src tests && uv run mypy src

10.2 真實串通驗收(硬門禁)

  1. 登記至少 2 個真實 endpoint(如 OpenRouter + 本地 Ollama):
    uv run ai-mcp endpoint add --name openrouter --base-url https://openrouter.ai/api/v1 --key sk-...
  2. 跑探活:uv run ai-mcp endpoint probe --all(CLI 模式:入隊 + 同步消化 worker loop),預期 ≥90% model 拿到至少 1 個 ok 的 capability。
  3. 用 mcp inspector 拉起:npx @modelcontextprotocol/inspector uv run ai-mcp-server,校驗 6 個 tool 出現、schema 正確。
  4. 啟動 web UI:uv run ai-mcp ui,瀏覽器打開 http://127.0.0.1:8765/,依序驗證 9 個頁面渲染正常。
  5. 在 UI 的「Endpoint 詳情」點「探活」→ /jobs 頁面看 SSE 進度條推進 → 跑完後 Models 表 capability 標籤更新。
  6. 並發驗證:UI 點探活的同時,CLI 也跑 ai-mcp endpoint probe --all,預期無雙跑(樂觀鎖生效),所有 job 最終都 done 或 failed。
  7. 在 Claude Desktop 配置:
    {
      "mcpServers": {
        "ai-mcp": {
          "command": "uv",
          "args": ["run", "--directory", "/path/to/ai-mcp-server", "ai-mcp-server"]
        }
      }
    }
  8. 在 Claude Desktop 對話中依次驗證:
    • chat 透傳:要求 Claude 透過 invoke_model 走 OpenRouter 上某 chat model,得到回答。
    • vision 透傳:傳一張圖,要求 Claude 路由到具備 vision 能力的 model 進行識別。
    • embedding 透傳:要求 Claude 透過 invoke_model 取一段文字的 embedding,返回向量長度正確。
    • model_performance:要求 Claude 查詢近期模型成功率與首字延遲,確認返回本地聚合指標。
    • refresh_endpoint:透過 MCP 調用此 tool 入隊;確認 MCP server 進程內的背景 worker 自動消化並寫回。
    • add_models:對不暴露 /v1/models 的測試 endpoint 手動登記一個模型,確認 list_models 可見。
  9. 驗證 ~/.ai-mcp-server/db.sqlite3api_key_enc 為二進位密文:strings db.sqlite3 | grep -E '^sk-' 無命中。

10.3 不能宣告完成的情況

  • 10.2 任一步驟未跑通,僅靠 pytest 通過不算完成。
  • 探活對至少一個真實 endpoint 全部失敗。
  • api_key 在任何路徑(DB / 日誌 / stderr / MCP 響應)以明文出現。

11. 安全、隱私與權限

  • 敏感資料:api_key 加密儲存;master key 在 system keyring 或 env;任何路徑禁止明文輸出。
  • 留存:所有資料只在本機;無雲端、無遙測。
  • 日誌脫敏:日誌中 Authorization header 與 api_key 字段強制 mask;錯誤透傳前掃描上游 echo 並 mask。
  • 權限:MCP server 本身為當前用戶進程;無多用戶 / 無權限分層。
  • 濫用風險:用戶可能用 invoke_model 跑昂貴模型(如 image_gen)→ usage_guide 中明示「該操作可能產生上游費用」,但服務側不做攔截。
  • 探活費用透明:CLI endpoint probe 在執行涉及付費能力(image_gen / tts)前提示用戶確認。

12. 風險、開放問題與決策

12.1 主要風險與緩解

風險嚴重度緩解
能力探活的 false positive / false negative五態 ProbeStatus + 結構校驗 + 不污染既有 true
master key 遺失導致 api_key 不可解密清晰報錯 + re-add 流程
OpenAI 兼容方言差異造成 invoke 失敗透傳不改寫 + adapter 內 quirk 開關空間
image_gen / tts 探活造成意外費用CLI 二次確認 + usage_guide 明示
MCP stdio 配置失敗無法診斷--debug stderr 輸出 + 文檔 config 範例
LiteLLM metadata 結構演進解析失敗降級,不影響其他來源
樂觀鎖實際失效並發 pytest 覆蓋;status 流轉單調保證最差只是少跑、不會雙跑
UI 進程被外網訪問預設 127.0.0.1;改 host 時 CLI 警告
SQLite 寫衝突WAL + busy_timeout,已驗證在 macOS 本地用戶下穩定

12.2 開放問題

  • LiteLLM metadata 是內建 snapshot 還是首次遠端拉取?(默認 snapshot + 可選 refresh)
  • 是否在 list_models 出參中暴露上游 raw_meta_json?(默認否,按需展開)
  • 是否提供 ai-mcp-server --http 模式給遠端 MCP client?(默認 P2+ 階段)

12.3 已確認決策

見 §0「已確認決策」表格。

13. 完成定義(Definition of Done)

產品級
  • 用戶可登記 ≥2 endpoint 並完成 10 種能力探活。
  • Claude Desktop 中可看到 6 個 tool,並能透過 invoke_model 完成 chat / vision / embedding 三條路徑。
  • usage_guide 動態反映當前能力分佈。
  • Web UI 9 個頁面可用,SSE 進度條能反映探活進展。
  • UI / CLI / MCP 三入口同時操作不衝突(樂觀鎖生效)。
架構級
  • 四層分明:MCP / CLI / Web 入口 → application → providers / capability / probes → storage。
  • 「解讀 X」原則:三進程不共享記憶體、共享 SQLite (WAL)。
  • ProviderAdapter ABC 可塞入 Anthropic 實作而不改上層。
  • resolver 四來源優先級可診斷(每個 capability 帶 source 標籤)。
  • Worker 樂觀鎖 + lease 回退驗證通過。
測試級
  • unit + integration pytest 全綠;ruff / mypy 無 error。
  • 10.2 真實串通驗收全部走通並留下截圖或 transcript。
  • strings db.sqlite3 | grep -E '^sk-' 無命中。

文檔與發布

  • README 含安裝、CLI 範例、Claude Desktop 配置範例、故障排查。
  • 本 PRD 與 AGENTS.md 隨倉庫一起發布。
  • CHANGELOG 由 update-changelog skill 自動維護。

回滾開關

  • 用戶可隨時刪除 ~/.ai-mcp-server/ 與 system keyring 中的 ai-mcp-server 條目,徹底重置。
  • MCP client 端只需從配置中移除 ai-mcp 條目即可解除接入。