MCP 實戰:讓 AI 像 USB-C 一樣接工具

MCP 實戰:讓 AI 像 USB-C 一樣接工具

📌 本文重點

  • MCP 讓工具接入一次即可多客戶端共用
  • 安全與權限集中在 MCP 層,比直接給 API 安全
  • 多代理、多工具、多客戶端場景特別適合用 MCP
  • MCP server 要當成長期基礎設施來管理

MCP 解決的核心痛點很直接:你不需要再為每個系統寫一套專屬「AI 版 API」。不管是日曆、TradingView、內部 CRM 或 CI/CD,大多數情況下只要掛一個 MCP server,所有支援 MCP 的客戶端(Claude Desktop、Cursor、VS Code 等)就能共用這個入口。對有多代理、多產品線的團隊來說,這代表 一次接好、到處用,權限與治理集中在 MCP 層,減少「每個 Agent 一套整合程式」的維護地獄。

💡 關鍵: MCP 讓一個工具整合點可被多個客戶端共用,顯著降低整合與維護成本。


重點說明:為什麼需要「AI 的 USB-C」

1. 協議 vs. API:少寫一層 Glue Code

傳統作法:

  • 為 LLM/Agent 寫一個 HTTP API 或 SDK
  • 再在每個客戶端(聊天機器人、VS Code 擴充、內部 Agent 平台)各自寫一份整合

MCP 的做法:

  • 定義標準能力:tools、resources、prompts、采樣事件(sampling)
  • 你只要寫一個 MCP server,宣告有哪些可呼叫的工具、如何讀資料
  • 任意 MCP client 都知道怎麼:列出工具、呼叫工具、抓資料、處理錯誤

好處:

  • 工程師不再為每個模型/產品寫客製 API;改成「一次 MCP server,多客戶端共用」
  • 權限管控、審計 log、錯誤格式集中在 MCP,企業合規更好做

💡 關鍵: 把「API 風格」升級成「協議層」,能在團隊內統一權限與錯誤處理,減少重複整合工作。

2. 安全模型:把「能用什麼工具」變成顯式設定

MCP 把工具能力變成顯式宣告:

  • tools:可呼叫的動作(例如 create_eventrun_queryplace_order
  • resources:只讀或有限寫入的資料源(例如日曆列表、DB 查詢結果)

在 Claude Desktop / Remote OpenClaw 類的平台中,你可以:

  • 用設定檔限制哪些 MCP server 可用
  • 在 server 端做 API key、角色權限 判斷

這比「直接把 DB URL 給 Agent」安全許多:

  • Agent 只能透過 明確定義的 tool 操作,不能隨意執行 SQL
  • 所有操作都有 統一的 request/response schema,便於審計與監控

💡 關鍵: 把安全規則寫進 MCP server 的權限與 schema,比依賴提示詞更可控又可審計。

3. 適用情境:什麼時候選 MCP,什麼時候維持 CLI / HTTP

結合 Towards AI 的觀點(#33#113):

適合 MCP 的情境:

  • 你有 多種客戶端(不同 IDE、Chat UI、多代理平台)要共用同一組工具
  • 工具操作需要 細緻權限控管與觀測性(企業環境、金融交易、內網系統)
  • 希望未來可以接其他 MCP 生態(像 Remote OpenClaw 的 13,000+ server)

不適合 MCP(先用 CLI/HTTP)的情境:

  • 單一腳本或單一產品內部,沒有要對外共享工具
  • 工具邏輯已經是穩定 CLI / REST API,Agent 只是偶爾呼叫
  • 團隊還沒能力維護一層協議 server,多一層只會變技術債

一句話總結:MCP 是面向「多代理、多工具、多客戶端」的協議層;單工具小專案,CLI/HTTP 通常更便宜。


實作範例:寫一個最小可用 MCP server

以下用 Node.js 示意一個最小的 MCP server,暴露「日曆建立事件」與「查資料庫」兩個能力,讓 LLM/Agent 可以透過 MCP 呼叫。

注意:為了篇幅,用近似概念的虛擬碼,重點在 MCP 結構與安全邏輯,而不是完整實作細節。

1. Server 結構:宣告 tools 與基本 metadata

// mcp-server.ts
import {
  createMcpServer,
  ToolDefinition,
  McpRequest,
  McpResponse,
} from 'mcp-core'; // 假想 MCP 基礎庫

const tools: ToolDefinition[] = [
  {
    name: 'create_calendar_event',
    description: '在使用者的日曆中建立事件',
    inputSchema: {
      type: 'object',
      required: ['title', 'start', 'end'],
      properties: {
        title: { type: 'string' },
        start: { type: 'string', format: 'date-time' },
        end: { type: 'string', format: 'date-time' },
        attendees: { type: 'array', items: { type: 'string', format: 'email' } },
      },
    },
  },
  {
    name: 'run_report_query',
    description: '在報表資料庫上執行安全查詢',
    inputSchema: {
      type: 'object',
      required: ['report_name'],
      properties: {
        report_name: { type: 'string' },
        from: { type: 'string', format: 'date' },
        to: { type: 'string', format: 'date' },
      },
    },
  },
];

const server = createMcpServer({
  name: 'internal-tools-server',
  version: '1.0.0',
  tools,
});

server.onToolCall('create_calendar_event', async (req: McpRequest) => {
  const user = await authenticate(req); // ✅ 先做身份確認
  authorize(user, 'calendar:write');    // ✅ 再做權限確認

  const { title, start, end, attendees } = req.input;
  const eventId = await calendarApi.createEvent({
    ownerId: user.id,
    title,
    start,
    end,
    attendees,
  });

  const res: McpResponse = {
    status: 'ok',
    data: { eventId },
  };
  return res;
});

server.onToolCall('run_report_query', async (req: McpRequest) => {
  const user = await authenticate(req);
  authorize(user, `report:${req.input.report_name}:read`);

  try {
    const rows = await db.safeReportQuery({
      reportName: req.input.report_name,
      from: req.input.from,
      to: req.input.to,
    });

    return { status: 'ok', data: rows };
  } catch (err) {
    // ✅ 統一錯誤格式,讓 client/Agent 好處理
    return {
      status: 'error',
      errorType: 'DB_ERROR',
      message: 'Report query failed',
      detail: process.env.NODE_ENV === 'production' ? undefined : String(err),
    };
  }
});

server.listen();

關鍵點:

  • MCP 層不做太多業務邏輯,只做 工具宣告、調度、權限與錯誤格式統一
  • 上游客戶端(Claude Desktop 等)能列出 tools,並請 LLM 自行決定何時呼叫

2. 客戶端配置片段:讓 Claude / Agent 知道有這個 server

以 Claude Desktop 設定檔為例(非官方格式,示意):

// claude-desktop-mcp.json
{
  "servers": [
    {
      "id": "internal-tools",
      "name": "Internal Tools Server",
      "endpoint": "https://mcp.example.com",
      "auth": {
        "type": "token",
        "env": "MCP_INTERNAL_TOKEN" // ✅ 用環境變數注入
      },
      "tools": [
        "create_calendar_event",
        "run_report_query"
      ],
      "permissions": {
        "create_calendar_event": {
          "allowed_users": ["alice", "bob"],
          "max_calls_per_session": 5
        },
        "run_report_query": {
          "allowed_roles": ["manager", "analyst"]
        }
      }
    }
  ]
}

對開發者的實際好處:

  • 新增一個工具(例如 cancel_event)只改 MCP server;所有支援 MCP 的客戶端自動能用
  • 權限策略集中在一份設定檔和 server 邏輯;不需要在每個 Agent 都重複實作

3. TradingView / Remote OpenClaw 類場景的延伸

tradingview-mcp 為例,核心想法類似:

  • MCP server 包一層 TradingView Desktop 的操作能力(讀圖表資料、下單、拉指標)
  • Claude/Agent 在對話中決定何時呼叫 get_chart_statesuggest_trades 等 tool

對 FinTech 專案的實際好處:

  • 新增一個策略或指標,只要在 MCP server 定義新的 tool,不必改聊天 UI 或 IDE 擴充
  • 可以在 MCP 層做 風控(最大下單金額、白名單市場),避免 Agent 直接碰交易 API

Remote OpenClaw 類平台則把這件事做成 工具市場

  • 13,000+ MCP server / skills,以統一協議掛進多代理系統
  • 你可以只寫「自己內部系統的 MCP server」,然後利用平台既有的工具擴展能力

建議與注意事項:避免 MCP 變成新技術債

1. 權限控制:把風險鎖在 MCP 層,而不是 Agent Prompt

常見錯誤:

  • 把風控寫在「系統提示詞」裡:「請不要刪除任何資料」

這樣很脆弱。正確作法:

  • 在 MCP server 的 authorize() 裡明確限制可做的事:
  • 讀操作 vs 寫操作分開 tool
  • 依使用者/角色限制可呼叫的 tool
  • 設定 rate limit、最大影響範圍(例如最多只查 30 天內的資料)

核心結論:安全規則必須寫在可驗證的程式碼與設定,而不是交給 LLM 理解。

2. 錯誤處理:統一格式,讓 Agent 能有策略反應

讓所有工具的錯誤返回遵守一個 schema,例如:

{
  "status": "error",
  "errorType": "UNAUTHORIZED", // or DB_ERROR, VALIDATION_ERROR
  "message": "User not allowed to run this report",
  "hint": "請聯絡管理員開啟 report:weekly-sales 權限"
}

實務好處:

  • Agent 能學會針對不同 errorType 有不同回應策略(重試、改參數、詢問人類)
  • 觀測系統可以直接按 errorType 做統計與警報,而不是解析雜亂文字訊息

3. 版本管理:把 MCP server 當成一個獨立產品

常見坑:

  • 在 MCP server 隨意改 tool schema,結果所有 Agent prompt 壞掉

最佳實踐:

  • 給 MCP server 明確版本,例如 internal-tools-server@1.2.0
  • 改動 inputSchema / outputSchema 時,使用 新 tool 名稱或新 version tag
  • 為重要工具保留 向下相容行為,或至少加上清楚的 deprecation 訊息

4. 觀測性:沒有監控的 MCP = 黑箱

避免 MCP 變成黑箱需要:

  • 為每次 tool call 記錄:使用者、tool 名稱、參數摘要、執行時間、結果/錯誤
  • 對關鍵工具(交易、刪除、批量更新)增加 審計 log 與告警
  • 在多代理環境(像 Remote OpenClaw)記錄 哪個 Agent 發起了呼叫,方便追責

這些 log 最好整合到既有 APM/Logging 系統,而不是 MCP server 自己寫一套。

5. MCP vs. CLI / HTTP 的取捨準則

綜合以上經驗,可用以下簡化決策:

  • 如果你的工具:
  • 僅在單一服務/專案內使用
  • 沒有複雜權限 / 審計要求
  • 已有穩定 CLI 或 REST API

結論:先保持 CLI / HTTP,透過簡單 wrapper 給 Agent 用就好。

  • 如果你的工具:
  • 要被 多種 Agent / IDE / Chat UI 共用
  • 涉及敏感資料或關鍵操作,需要集中治理
  • 希望未來快速接入 MCP 生態(Remote OpenClaw、第三方工具市場)

結論:投資 MCP server 是值得的,並把它當成長期基礎設施管理。


收斂:對你的專案的實際好處

如果你正在建多代理平台、內部 AI 協作工具或金融交易輔助系統:

  • MCP 幫你把「如何連接工具」抽象成標準協議,減少重複 Glue Code
  • 專案可以快速掛載像 tradingview-mcp 或 Remote OpenClaw 上的現成技能
  • 權限、安全與觀測性集中在 MCP 層,讓你可以放心讓更多 Agent 自動操作

前提是:你願意認真設計 MCP server 的權限、錯誤與版本管理,而不是把它當「再多一個 API」。這樣 MCP 才會變成你 AI 架構的 USB-C,而不是新的技術債。

🚀 你現在可以做的事

  • 審視現有內部 CLI / HTTP 工具,挑選一個多客戶端共用場景嘗試寫第一個 MCP server
  • 為預計要 MCP 化的工具先設計 toolinputSchema / outputSchema 與權限策略
  • 到 Remote OpenClaw 或類似平台搜尋現成 MCP server,評估哪些可直接掛入你的多代理系統

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *