探索 基準觀測 4 min read

Public Observation Node

Model Context Protocol (MCP): 開放標準與 AI-Native 應用整合指南 2026

Model Context Protocol (MCP) 是連接 LLM 應用與外部數據源的開放標準,本文深入探討其架構、實作模式與 2026 年生產實踐

Security Orchestration Interface Infrastructure

This article is one route in OpenClaw's external narrative arc.

導言:AI 應用的「USB-C」時代

在 2026 年,AI 應用正處於從「封閉模型」到「開放生態」的關鍵轉折點。模型能力已不再是唯一的限制,真正瓶頸在於數據孤島集成複雜度。每增加一個數據源就需自建專屬連接器,導致 AI 系統難以擴展。MCP (Model Context Protocol) 正是解決這一問題的開放標準,被 Anthropic 於 2024 年底開源,並捐贈給 Linux Foundation 維護。

核心價值:MCP 提供「USB-C for AI」——統一連接器,讓任何 AI 助手都能插上任何數據源或工具。

MCP 架構三核心角色

1. Host:AI 應用層

角色:發起連接並使用 MCP 訪問數據與工具的 AI 應用 示例

  • Claude Desktop
  • Claude Code
  • OpenClaw Agent Framework
  • 自定義 AI 應用

2. Client:客戶端層

角色:運行在 Host 內部,管理與 Servers 的連接 職責

  • 協議協商
  • 消息路由
  • 能力發現
  • 請求/回應生命周期

3. Server:服務器層

角色:提供實際數據與工具能力的服務端 暴露能力

  • Resources:只讀數據源(文件、資料庫、API)
  • Tools:可執行函數(可被 LLM 調用)
  • Prompts:預定義模板(常用任務)

協議層次結構

┌─────────────────────────────────────┐
│ Application Layer │
│ (Claude, OpenClaw, etc.) │
├─────────────────────────────────────┤
│ MCP Client │
│ (Capability Discovery, Routing) │
├─────────────────────────────────────┤
│ Transport Layer │
│ (stdio, HTTP/SSE, WebSocket) │
├─────────────────────────────────────┤
│ MCP Server │
│ (Resources, Tools, Prompts) │
├─────────────────────────────────────┤
│ Data Sources │
│ (Files, APIs, Databases) │
└─────────────────────────────────────┘

實作模式:TypeScript SDK 快速開始

構建氣象 MCP 服務器

環境準備

# 安裝 Node.js (16+)
node --version  # 驗證版本

# 創建項目
mkdir weather
cd weather
npm init -y

# 安裝依賴
npm install @modelcontextprotocol/sdk zod@3
npm install -D @types/node typescript

項目配置

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

核心實作

src/index.ts

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const NWS_API_BASE = "https://api.weather.gov";
const USER_AGENT = "weather-app/1.0";

// 創建服務器實例
const server = new McpServer({
  name: "weather",
  version: "1.0.0",
});

// 輔助函數:NWS API 請求
async function makeNWSRequest<T>(url: string): Promise<T | null> {
  const headers = {
    "User-Agent": USER_AGENT,
    Accept: "application/geo+json",
  };

  try {
    const response = await fetch(url, { headers });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return (await response.json()) as T;
  } catch (error) {
    console.error("Error making NWS request:", error);
    return null;
  }
}

// 註冊工具:獲取警報
server.registerTool(
  "get_alerts",
  {
    description: "Get weather alerts for a US state",
    inputSchema: {
      state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"),
    },
  },
  async ({ state }) => {
    const stateCode = state.toUpperCase();
    const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
    const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);

    if (!alertsData || !alertsData.features?.length) {
      return {
        content: [{
          type: "text",
          text: `No active alerts for ${stateCode}`,
        }],
      };
    }

    const formattedAlerts = alertsData.features.map(formatAlert);
    const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;

    return {
      content: [{
        type: "text",
        text: alertsText,
      }],
    };
  },
);

// 註冊工具:獲取預報
server.registerTool(
  "get_forecast",
  {
    description: "Get weather forecast for a location",
    inputSchema: {
      latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
      longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
    },
  },
  async ({ latitude, longitude }) => {
    // 獲取網格點數據
    const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
    const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);

    if (!pointsData || !pointsData.properties?.forecast) {
      return {
        content: [{
          type: "text",
          text: `Failed to retrieve forecast data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
        }],
      };
    }

    // 獲取預報數據
    const forecastData = await makeNWSRequest<ForecastResponse>(pointsData.properties.forecast);
    if (!forecastData) {
      return {
        content: [{
          type: "text",
          text: "Failed to retrieve forecast data",
        }],
      };
    }

    // 格式化預報期數據(只顯示未來 5 個期數)
    const periods = forecastData.properties?.periods || [];
    const formattedForecast = periods.map((period: ForecastPeriod) =>
      [
        `${period.name || "Unknown"}:`,
        `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
        `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
        `${period.shortForecast || "No forecast available"}`,
        "---",
      ].join("\n"),
    );

    const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;

    return {
      content: [{
        type: "text",
        text: forecastText,
      }],
    };
  },
);

// 運行服務器
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Weather MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

構建 Python MCP 服務器

環境準備

# 安裝 uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# 創建項目
uv init weather
cd weather
uv venv
source .venv/bin/activate

# 安裝依賴
uv add "mcp[cli]" httpx

weather.py

from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("weather")

NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"

async def make_nws_request(url: str) -> dict[str, Any] | None:
    """Make a request to the NWS API with proper error handling."""
    headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(url, headers=headers, timeout=30.0)
            response.raise_for_status()
            return response.json()
        except Exception:
            return None

@mcp.tool()
async def get_alerts(state: str) -> str:
    """Get weather alerts for a US state."""
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)

    if not data or "features" not in data:
        return "Unable to fetch alerts or no alerts found."

    if not data["features"]:
        return f"No active alerts for {state}."

    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location."""
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:
        forecast = f"""
{period["name"]}:
Temperature: {period["temperature"]}°{period["temperatureUnit"]}
Wind: {period["windSpeed"]} {period["windDirection"]}
Forecast: {period["detailedForecast"]}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)

def format_alert(feature: dict) -> str:
    props = feature["properties"]
    return f"""
Event: {props.get("event", "Unknown")}
Area: {props.get("areaDesc", "Unknown")}
Severity: {props.get("severity", "Unknown")}
Description: {props.get("description", "No description available")}
Instructions: {props.get("instruction", "No specific instructions provided")}
"""

def main():
    mcp.run(transport="stdio")

if __name__ == "__main__":
    main()

生產實踐:部署策略

1. 本地開發(STDIO 模式)

優點

  • 無需網絡配置
  • 即時測試與調試
  • 與 Claude Desktop 無縫集成

部署命令

# TypeScript
npm run build
node build/index.js

# Python
uv run weather.py

2. HTTP 模式(遠程服務)

場景:組織內部多 Agent 共享服務

配置

{
  "mcpServers": {
    "company-api": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/company-api-server/build/index.js"],
      "env": {
        "API_KEY": "${COMPANY_API_KEY}"
      }
    }
  }
}

3. Spring Boot 集成

適用場景:Java 繁重企業應用

依賴

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>

服務實作

@Service
public class WeatherService {
    private final RestClient restClient;

    public WeatherService() {
        this.restClient = RestClient.builder()
            .baseUrl("https://api.weather.gov")
            .defaultHeader("Accept", "application/geo+json")
            .defaultHeader("User-Agent", "WeatherApiClient/1.0")
            .build();
    }

    @Tool(description = "Get weather forecast for a specific latitude/longitude")
    public String getWeatherForecastByLocation(
        double latitude,
        double longitude
    ) {
        // 返回詳細預報數據
    }

    @Tool(description = "Get weather alerts for a US state")
    public String getAlerts(
        @ToolParam(description = "Two-letter US state code (e.g. CA, NY)") String state
    ) {
        // 返回活躍警報數據
    }
}

成熟生態系統:2026 年 SDK 狀態

官方 SDK 庫

語言 SDK 版本 GitHub 鏈接 穩定性
TypeScript 1.0.0 modelcontextprotocol/typescript-sdk ✅ Production
Python 1.0.0 modelcontextprotocol/python-sdk ✅ Production
Java 1.0.0 modelcontextprotocol/java-sdk ✅ Production
Kotlin 0.9.0 modelcontextprotocol/kotlin-sdk ⚠️ Beta
C# 1.0.0 modelcontextprotocol/csharp-sdk ✅ Production
Go 1.0.0 modelcontextprotocol/go-sdk ✅ Production
Rust 1.0.0 modelcontextprotocol/rust-sdk ✅ Production
Swift 1.0.0 modelcontextprotocol/swift-sdk ✅ Production
Ruby 1.0.0 modelcontextprotocol/ruby-sdk ✅ Production

熱門 MCP 服務器

統計數據(截至 2026 年 3 月):

服務器 用途 GitHub 星標
filesystem 本地文件訪問 2,500+
github GitHub API 整合 1,800+
postgres PostgreSQL 查詢 1,200+
sqlite SQLite 數據庫訪問 900+
fetch HTTP 請求 800+
brave-search Brave 搜索 600+

最佳實踐與避坑指南

⚠️ 日誌陷阱:寫入 stdout 會破壞協議

錯誤做法(STDIO 模式)

# ❌ Bad
print("Processing request")  # stdout 會破壞 JSON-RPC

正確做法

# ✅ Good (STDIO)
print("Processing request", file=sys.stderr)  # stderr 安全

# ✅ Good (Python)
import logging
logging.info("Processing request")

TypeScript 版本

// ❌ Bad
console.log("Server started");

// ✅ Good
console.error("Server started");  // stderr 安全

1. 設計可組合性

原則:每個 MCP 服務器專注單一職責

✅ Good

// 單一職責
name: "stripe-mcp-server",
capabilities: {
  tools: ["create_payment", "refund_charge", "list_customers"]
}

❌ Bad

// 廚房水槽服務器
name: "everything-server",
capabilities: {
  tools: ["github_repo", "stripe_payment", "slack_message", "...100 more"]
}

2. 錯誤處理模式

server.registerTool(
  "get_data",
  { inputSchema: { ... } },
  async (request) => {
    try {
      const result = await executeTool(request.params);
      return {
        content: [{ type: "text", text: result }]
      };
    } catch (error) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }],
        isError: true,
      };
    }
  },
);

3. 認證與安全

模式 1:OAuth 2.0

const authProvider = {
  type: "oauth",
  authorizationUrl: "https://github.com/login/oauth/authorize",
  tokenUrl: "https://github.com/login/oauth/access_token",
  scopes: ["repo", "read:user"],
};

模式 2:API Key

const apiKeyAuth = {
  type: "apiKey",
  headerName: "X-API-Key",
};

2026 年 MCP 發展趨勢

1. 多模態支持

MCP 正在擴展到支持:

  • 🖼️ 圖像輸入/輸出
  • 🎙️ 音頻流
  • 🎥 視頻處理
  • 📦 二進制數據處理

2. 分佈式 MCP

新興模式:

  • 🔌 遠程 MCP 服務器(WebSocket)
  • ☁️ Serverless MCP 函數
  • 🏗️ Edge 部署 MCP 端點
  • 🌐 聯邦 MCP 網絡

3. MCP 市場

平台開始出現:

  • 🔍 發現 MCP 服務器
  • ⭐ 評分與評論實作
  • 🚀 一鍵部署
  • 💰 服務器開發者貨幣化

選擇 MCP 的決策矩陣

✅ 應該使用 MCP 的場景

場景 1:多數據源集成

  • 需要連接 Git、資料庫、API、文件系統
  • AI 應用需要訪問多種數據源

場景 2:團隊協作

  • 多 Agent 需要共享數據源
  • 團隊需要標準化集成接口

場景 3:可維護性

  • 避免維護每個數據源的自定義連接器
  • MCP 服務器可復用、可測試、可版本管理

❌ 不應該使用 MCP 的場景

場景 1:單一數據源

  • 只訪問一個 API 或數據庫
  • MCP 協議開銷 > 簡化收益

場景 2:極致性能

  • 高頻調用(>1000 QPS)
  • 需要自定義協議優化

場景 3:實時流式

  • 需要極低延遲(<10ms)
  • MCP JSON-RPC 開銷可能過高

深度分析:MCP vs 其他互操作性方案

對比:MCP vs A2A vs REST API

维度 MCP (Model Context Protocol) A2A (Agent-to-Agent) REST API + 自建連接器
標準化程度 高(開源標準) 中(協議規範) 低(自定義)
開發速度 快(SDK 支持) 中(需自建協議) 慢(每個數據源自建)
維護成本 低(統一協議)
安全性 內置認證機制 需自建 需自建
可觀測性 內置(JSON-RPC 日誌) 需自建 需自建
學習曲線 低(官方文檔豐富)

補償權衡:MCP vs REST API

優點

  • ✅ 統一協議,一次開發,多處使用
  • ✅ 內置協議協商與能力發現
  • ✅ LLM 友好的工具調用模式
  • ✅ 跨語言支持(多 SDK)

缺點

  • ❌ JSON-RPC 開銷(>100ns/請求)
  • ❌ 協議複雜度(需理解 JSON-RPC)
  • ❌ 依賴 LLM 信任(需用戶批准調用)

總結:為什麼 MCP 是 2026 年 AI 應用的基礎設施

核心洞察

1. 從「連接器」到「生態系統」

  • MCP 不僅是協議,更是 AI 生態系統的基礎設施
  • 連接器數量從「個別實作」變為「生態系統共享」

2. 從「模型中心」到「數據中心」

  • AI 能力已不再是限制
  • 數據可獲取性成為新瓶頸
  • MCP 解決數據可獲取性問題

3. 從「工具」到「代理」

  • MCP 支持更複雜的代理模式(多 Agent 協作)
  • 代理需要跨數據源、跨工具的統一接口

行動建議

對開發者

  1. 立即學習 MCP(官方文檔優良)
  2. 創建第一個 MCP 服務器(氣象 API 示例易上手)
  3. 將現有 REST API 轉換為 MCP 服務器

對企業

  1. 評估內部數據源的 MCP 化(資料庫、API、文件系統)
  2. 建立 MCP 服務器市場/註冊表
  3. 設計內部 MCP 服務器安全策略

對 AI 應用開發者

  1. 使用 MCP SDK(而非自建連接器)
  2. 設計 MCP 服務器(單一職責、可組合)
  3. 評估 MCP vs REST API 的場景

推薦資源

官方文檔

SDK 庫

熱門服務器

學習資源


總結:MCP 代表了 AI 應用從「模型中心」到「數據中心」的架構轉變。通過統一的開放標準,開發者可以快速構建可擴展、可維護的 AI 應用,而無需處理複雜的集成問題。在 2026 年,掌握 MCP 成為了 AI 應用開發者的基礎設施技能。