<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>小人物看世界</title>
	<atom:link href="https://blog.che-ya.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.che-ya.com</link>
	<description>軟體工程師的技術筆記</description>
	<lastBuildDate>Wed, 08 Apr 2026 08:07:42 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.che-ya.com/wp-content/uploads/2021/08/cropped-APP_icon-32x32.png</url>
	<title>小人物看世界</title>
	<link>https://blog.che-ya.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>實戰專案：用 Agent SDK 打造自動化工具</title>
		<link>https://blog.che-ya.com/agent-sdk-automation-tools/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Tue, 05 May 2026 02:47:00 +0000</pubDate>
				<category><![CDATA[Claude Agent SDK]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[Agent SDK]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[實戰專案]]></category>
		<category><![CDATA[自動化工具]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=878</guid>

					<description><![CDATA[前兩篇文章中，我們分別學習了 Claude Agent SDK 的基礎建構方式，以及 Guardrails 與 ... <a title="實戰專案：用 Agent SDK 打造自動化工具" class="read-more" href="https://blog.che-ya.com/agent-sdk-automation-tools/" aria-label="Read more about 實戰專案：用 Agent SDK 打造自動化工具">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>前兩篇文章中，我們分別學習了 <a href="https://blog.che-ya.com/claude-agent-sdk-getting-started/">Claude Agent SDK 的基礎建構方式</a>，以及 <a href="https://blog.che-ya.com/claude-agent-sdk-guardrails-handoffs/">Guardrails 與 Handoffs 的進階機制</a>。理論學完了，現在是時候動手實作了。本篇將帶你完成四個真實可執行的自動化工具專案，從程式碼品質檢查、研究報告產生，到批次檔案處理，讓你的 Agent SDK 技能真正派上用場。</p>



<h2 class="wp-block-heading">為什麼用 Agent SDK 打造自動化工具？</h2>



<p>傳統的自動化腳本需要你預先定義每一個步驟，遇到例外狀況就會卡住。用 Agent SDK 建構的自動化工具則不同：你只需要描述「要做什麼」，Claude 會自行判斷「要怎麼做」，並在過程中隨機應變。這讓 Agent 特別適合處理那些「邏輯複雜但可描述」的任務。</p>



<figure class="wp-block-table"><table><thead><tr><th>面向</th><th>傳統腳本</th><th>Agent SDK</th></tr></thead><tbody><tr><td>開發方式</td><td>逐步定義每個操作</td><td>用自然語言描述目標</td></tr><tr><td>例外處理</td><td>需手動撰寫所有分支</td><td>Claude 自動應對</td></tr><tr><td>維護成本</td><td>需求改變時大幅重寫</td><td>調整 Prompt 即可</td></tr><tr><td>工具整合</td><td>手動接 API 和 SDK</td><td>MCP Server 即插即用</td></tr><tr><td>適用場景</td><td>固定流程的重複任務</td><td>需要判斷力的複雜任務</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">專案一：程式碼品質自動檢查 Agent</h2>



<p>這是最實用的入門專案：讓 Claude 自動讀取指定目錄的程式碼，找出潛在問題並產生報告。這類任務傳統做法需要整合多個 linting 工具，但 Agent SDK 讓你用幾十行程式碼就能完成。</p>



<h3 class="wp-block-heading">Python 版本</h3>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
from pathlib import Path
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def code_review_agent(target_dir: str = ".") -&gt; str:
    """程式碼品質檢查 Agent：掃描目錄並產生品質報告"""
    
    report_lines = []
    
    async for message in query(
        prompt=f"""請對 {target_dir} 目錄中的 Python 程式碼進行全面品質檢查。

        **檢查項目：**
        1. 找出所有可能導致 crash 的 bug（除以零、None 存取、索引越界等）
        2. 找出未使用的匯入和變數
        3. 找出缺少錯誤處理的危險操作（檔案 I/O、網路請求等）
        4. 找出命名不規範或難以理解的程式碼
        5. 找出重複程式碼（DRY 原則違反）

        **輸出格式：**
        - 以 Markdown 格式輸出報告
        - 每個問題列出：檔案路徑、行號、問題描述、建議修正方式
        - 最後給出整體評分（1-10 分）和優先修正建議
        """,
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Glob", "Grep", "Bash"],
            system_prompt="你是資深 Python 工程師，專注於程式碼品質與安全性。請用繁體中文輸出報告。",
        ),
    ):
        if isinstance(message, ResultMessage):
            report_lines.append(message.result or "")
    
    return "
".join(report_lines)


async def main():
    import sys
    target = sys.argv[1] if len(sys.argv) &gt; 1 else "."
    
    print(f"🔍 開始分析 {target} 目錄的程式碼品質...")
    report = await code_review_agent(target)
    
    # 儲存報告
    report_path = Path("code_review_report.md")
    report_path.write_text(report, encoding="utf-8")
    print(f"✅ 報告已儲存到 {report_path}")
    print(report)


asyncio.run(main())
</code></pre>



<h3 class="wp-block-heading">TypeScript 版本</h3>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { query } from "@anthropic-ai/claude-agent-sdk";
import { writeFile } from "fs/promises";

async function codeReviewAgent(targetDir: string = "."): Promise&lt;string&gt; {
  const reportLines: string[] = [];

  for await (const message of query({
    prompt: `請對 ${targetDir} 目錄中的 TypeScript/JavaScript 程式碼進行全面品質檢查。

    **檢查項目：**
    1. 找出型別安全問題（any 濫用、未處理的 null/undefined）
    2. 找出非同步處理問題（未 await 的 Promise、競態條件）
    3. 找出效能問題（不必要的重新渲染、記憶體洩漏風險）
    4. 找出安全性問題（XSS 風險、敏感資料外洩）
    5. 找出過時 API 使用和相依套件問題

    **輸出格式：**
    以 Markdown 格式輸出，包含每個問題的檔案路徑、行號與修正建議。`,
    options: {
      allowedTools: ["Read", "Glob", "Grep", "Bash"],
      systemPrompt: "你是資深 TypeScript 工程師，專注於程式碼品質與安全性。請用繁體中文輸出報告。"
    }
  })) {
    if ("result" in message &amp;&amp; message.result) {
      reportLines.push(message.result);
    }
  }

  return reportLines.join("\n");
}

async function main() {
  const target = process.argv[2] || ".";
  
  console.log(`🔍 開始分析 ${target} 目錄的程式碼品質...`);
  const report = await codeReviewAgent(target);
  
  await writeFile("code_review_report.md", report, "utf-8");
  console.log("✅ 報告已儲存到 code_review_report.md");
  console.log(report);
}

main().catch(console.error);
</code></pre>



<p>執行方式很簡單，在專案根目錄執行 <code>python agent.py ./src</code> 或 <code>npx tsx agent.ts ./src</code>，Claude 就會自動讀取所有 Python/TypeScript 檔案、分析問題，並輸出結構化的 Markdown 報告。</p>



<h2 class="wp-block-heading">專案二：自動化研究報告 Agent</h2>



<p>這個專案展示 Agent SDK 最強大的能力之一：Multi-agent 架構。主 Agent 負責規劃研究策略，並派遣多個子 Agent 並行搜尋不同面向的資訊，最後匯整成完整報告。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ResultMessage


async def research_agent(topic: str, output_file: str = "research_report.md") -&gt; str:
    """多 Agent 研究報告產生器"""
    
    # 定義專門的研究子 Agent
    trend_researcher = AgentDefinition(
        description="搜尋最新趨勢與新聞。用於了解近期發展、市場動態和業界現況。",
        prompt="""你是趨勢分析師，專注於搜尋最新資訊。
        使用 WebSearch 搜尋過去 6 個月的最新動態、市場趨勢和重要新聞。
        整理成有條理的摘要，標注資訊來源和日期。""",
        tools=["WebSearch", "WebFetch"],
    )
    
    technical_researcher = AgentDefinition(
        description="搜尋技術細節與深度分析。用於了解技術原理、架構設計和實作方式。",
        prompt="""你是技術分析師，專注於搜尋深度技術資料。
        使用 WebSearch 和 WebFetch 搜尋官方文件、技術部落格和學術資料。
        整理核心概念、技術優缺點和使用場景。""",
        tools=["WebSearch", "WebFetch"],
    )
    
    comparison_researcher = AgentDefinition(
        description="搜尋競品比較與替代方案。用於比較不同工具、框架或方法的差異。",
        prompt="""你是競品分析師，專注於比較分析。
        使用 WebSearch 搜尋同類產品或方法的比較資料、使用者評價和選型建議。
        整理成清晰的比較表格和選型指南。""",
        tools=["WebSearch", "WebFetch"],
    )
    
    result_lines = []
    
    async for message in query(
        prompt=f"""請針對「{topic}」這個主題產生一份完整的研究報告。

        **研究策略：**
        1. 先用 trend_researcher 子 Agent 搜尋最新趨勢與發展
        2. 再用 technical_researcher 子 Agent 深入了解技術細節
        3. 最後用 comparison_researcher 子 Agent 分析競品和替代方案
        4. 匯整三個子 Agent 的研究成果，寫成完整的研究報告

        **報告格式（Markdown）：**
        - 執行摘要（300字以內）
        - 最新趨勢與市場動態
        - 技術深度分析
        - 競品比較與選型建議
        - 結論與行動建議
        
        請確保報告內容具體、有數據支撐，並附上參考來源。
        """,
        options=ClaudeAgentOptions(
            allowed_tools=["Agent", "Write"],
            agents={
                "trend_researcher": trend_researcher,
                "technical_researcher": technical_researcher,
                "comparison_researcher": comparison_researcher,
            },
            system_prompt="你是研究協調員，負責規劃研究策略並整合各子 Agent 的研究成果。請用繁體中文輸出。",
        ),
    ):
        if isinstance(message, ResultMessage):
            result_lines.append(message.result or "")
    
    report = "
".join(result_lines)
    
    # 儲存報告
    with open(output_file, "w", encoding="utf-8") as f:
        f.write(report)
    
    return report


async def main():
    import sys
    topic = sys.argv[1] if len(sys.argv) &gt; 1 else "Claude Agent SDK"
    
    print(f"🔬 開始研究：{topic}")
    report = await research_agent(topic)
    print("✅ 研究報告已產生！")
    print(report[:500] + "..." if len(report) &gt; 500 else report)


asyncio.run(main())
</code></pre>



<p>這個架構的優雅之處在於：主 Agent 像是研究主管，負責分派工作；三個子 Agent 像是各有專長的研究員，並行蒐集不同面向的資料。這種 Delegation 模式讓研究效率大幅提升。</p>



<h2 class="wp-block-heading">專案三：智慧檔案整理 Agent</h2>



<p>這個專案展示如何讓 Agent 處理日常的檔案管理任務。Agent 會分析指定目錄的檔案，根據內容和類型自動分類整理，並生成整理報告。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def file_organizer_agent(source_dir: str, dry_run: bool = True) -&gt; str:
    """智慧檔案整理 Agent
    
    Args:
        source_dir: 要整理的目錄路徑
        dry_run: True 時只顯示計畫不執行，False 時實際移動檔案
    """
    
    mode_desc = "（模擬模式：只顯示計畫，不實際移動檔案）" if dry_run else "（執行模式：將實際移動檔案）"
    
    result_lines = []
    
    async for message in query(
        prompt=f"""請整理 {source_dir} 目錄中的檔案 {mode_desc}。

        **整理策略：**
        1. 先用 Glob 和 Bash 列出所有檔案，了解目錄結構
        2. 根據以下規則分類：
           - 圖片（jpg/png/gif/webp）→ images/ 子目錄
           - 文件（pdf/doc/docx/txt/md）→ documents/ 子目錄
           - 程式碼（py/js/ts/go/rs）→ code/ 子目錄
           - 影片（mp4/mov/avi）→ videos/ 子目錄
           - 壓縮檔（zip/tar/gz）→ archives/ 子目錄
           - 其他 → others/ 子目錄
        3. 若為模擬模式，輸出完整的整理計畫清單
        4. 若為執行模式，使用 Bash 執行 mkdir 和 mv 指令實際整理
        
        **輸出格式：**
        - 統計各類別檔案數量
        - 列出每個檔案的原始位置和目標位置
        - 標注任何需要人工確認的情況（如重複檔名）
        """,
        options=ClaudeAgentOptions(
            # dry_run 時只允許讀取工具，不允許寫入
            allowed_tools=["Glob", "Bash", "Read"] if dry_run else ["Glob", "Bash", "Read", "Write"],
            permission_mode="acceptEdits" if not dry_run else "default",
            system_prompt="你是專業的檔案管理助手。整理時務必謹慎，遇到不確定的情況要說明。",
        ),
    ):
        if isinstance(message, ResultMessage):
            result_lines.append(message.result or "")
    
    return "
".join(result_lines)


async def main():
    import sys
    
    source = sys.argv[1] if len(sys.argv) &gt; 1 else "./downloads"
    execute = "--execute" in sys.argv
    
    if execute:
        print("⚠️  執行模式：將實際移動檔案，請確認後繼續")
        confirm = input("確定要繼續嗎？(y/N) ")
        if confirm.lower() != "y":
            print("已取消")
            return
    else:
        print("📋 模擬模式：只顯示整理計畫")
    
    result = await file_organizer_agent(source, dry_run=not execute)
    print(result)


asyncio.run(main())
</code></pre>



<p>注意這個設計中的安全機制：預設使用 <code>dry_run=True</code> 模擬模式，只有在使用者明確傳入 <code>--execute</code> 參數且輸入確認後，才會實際移動檔案。這種「先預覽，後執行」的模式能有效防止意外操作。</p>



<h2 class="wp-block-heading">專案四：Git 提交訊息自動產生器</h2>



<p>這個小而實用的工具展示如何在開發工作流程中嵌入 Agent。每次準備 commit 時，Agent 自動分析 <code>git diff</code>，產生符合 Conventional Commits 規範的提交訊息。</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { query } from "@anthropic-ai/claude-agent-sdk";

interface CommitMessage {
  type: string;
  scope?: string;
  subject: string;
  body?: string;
  breaking?: boolean;
}

async function generateCommitMessage(): Promise&lt;CommitMessage&gt; {
  let result: CommitMessage | null = null;

  for await (const message of query({
    prompt: `請分析目前的 Git 變更並產生一個符合 Conventional Commits 規範的提交訊息。

    步驟：
    1. 執行 git diff --staged 查看暫存的變更
    2. 如果沒有暫存變更，執行 git diff 查看未暫存的變更
    3. 分析變更的性質（新功能、修復、重構等）
    4. 產生提交訊息

    Conventional Commits 格式：
    - feat: 新功能
    - fix: 錯誤修復
    - docs: 文件更新
    - style: 格式調整（不影響邏輯）
    - refactor: 重構
    - test: 測試相關
    - chore: 建構或輔助工具變更

    請以 JSON 格式輸出：
    {
      "type": "feat|fix|docs|style|refactor|test|chore",
      "scope": "選填，影響的模組",
      "subject": "簡短描述（英文，祈使語氣，不超過 50 字）",
      "body": "選填，詳細說明（中文或英文皆可）",
      "breaking": false
    }`,
    options: {
      allowedTools: ["Bash"],
      systemPrompt: "你是 Git 提交訊息專家，熟悉 Conventional Commits 規範。只輸出 JSON，不要其他文字。"
    }
  })) {
    if ("result" in message &amp;&amp; message.result) {
      try {
        // 嘗試解析 JSON 結果
        const jsonMatch = message.result.match(/{[sS]*}/);
        if (jsonMatch) {
          result = JSON.parse(jsonMatch[0]);
        }
      } catch (e) {
        console.error("解析 JSON 失敗:", e);
      }
    }
  }

  if (!result) {
    throw new Error("無法產生提交訊息");
  }

  return result;
}

async function main() {
  console.log("🔍 分析 Git 變更中...");
  
  const commit = await generateCommitMessage();
  
  // 組合提交訊息
  let fullMessage = `${commit.type}${commit.scope ? `(${commit.scope})` : ""}: ${commit.subject}`;
  
  if (commit.breaking) {
    fullMessage += "\n\nBREAKING CHANGE: 此版本包含不相容的變更";
  }
  
  if (commit.body) {
    fullMessage += `\n\n${commit.body}`;
  }
  
  console.log("\n📝 建議的提交訊息：");
  console.log("---");
  console.log(fullMessage);
  console.log("---");
  
  // 詢問是否直接使用
  const readline = await import("readline");
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  
  rl.question("\n使用此訊息提交？(y/N) ", async (answer) =&gt; {
    if (answer.toLowerCase() === "y") {
      const { exec } = await import("child_process");
      const { promisify } = await import("util");
      const execAsync = promisify(exec);
      
      await execAsync(`git commit -m "${fullMessage.replace(/"/g, '\\"')}"`);
      console.log("✅ 提交成功！");
    } else {
      console.log("已取消，你可以手動使用上面的訊息。");
    }
    rl.close();
  });
}

main().catch(console.error);
</code></pre>



<p>這個工具可以整合進你的 Git hooks 中。在 <code>.git/hooks/prepare-commit-msg</code> 中呼叫這個腳本，每次 <code>git commit</code> 時就會自動分析變更並建議訊息，大幅降低撰寫提交訊息的心智負擔。</p>



<h2 class="wp-block-heading">Agent 設計模式：讓工具更可靠</h2>



<p>在開發以上四個專案的過程中，我們可以歸納出幾個讓 Agent 自動化工具更可靠的設計模式。</p>



<h3 class="wp-block-heading">模式一：漸進式授權（Progressive Permissions）</h3>



<p>先用唯讀工具分析，確認後再授予寫入權限。這是最重要的安全設計原則。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def safe_refactor(file_path: str):
    """安全重構：先分析，後修改"""
    
    # 第一階段：唯讀分析
    print("📋 第一階段：分析程式碼...")
    analysis = []
    async for msg in query(
        prompt=f"分析 {file_path} 中需要重構的地方，列出具體的修改建議",
        options=ClaudeAgentOptions(allowed_tools=["Read", "Grep"]),
    ):
        if hasattr(msg, "result") and msg.result:
            analysis.append(msg.result)
    
    plan = "
".join(analysis)
    print(f"
修改計畫：
{plan}
")
    
    # 確認後才進入修改階段
    confirm = input("確定要執行以上修改嗎？(y/N) ")
    if confirm.lower() != "y":
        print("已取消")
        return
    
    # 第二階段：執行修改
    print("
✏️  第二階段：執行修改...")
    async for msg in query(
        prompt=f"根據以下計畫修改 {file_path}：
{plan}",
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Edit"],
            permission_mode="acceptEdits",
        ),
    ):
        if hasattr(msg, "result"):
            print("✅ 重構完成！")
</code></pre>



<h3 class="wp-block-heading">模式二：結果驗證（Output Validation）</h3>



<p>不要盲目信任 Agent 的輸出，加入驗證步驟確保結果符合預期。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


def validate_report(report: str) -&gt; tuple[bool, str]:
    """驗證報告是否包含必要章節"""
    required_sections = ["## 摘要", "## 分析", "## 建議"]
    missing = [s for s in required_sections if s not in report]
    
    if missing:
        return False, f"報告缺少以下章節：{', '.join(missing)}"
    
    if len(report) &lt; 500:
        return False, "報告內容太短，可能不完整"
    
    return True, "驗證通過"


async def generate_validated_report(topic: str, max_retries: int = 3) -&gt; str:
    """帶驗證和重試機制的報告產生器"""
    
    for attempt in range(1, max_retries + 1):
        print(f"🔄 嘗試第 {attempt} 次...")
        
        result_lines = []
        async for message in query(
            prompt=f"請針對「{topic}」產生一份包含摘要、分析和建議三個章節的報告",
            options=ClaudeAgentOptions(allowed_tools=["WebSearch", "WebFetch"]),
        ):
            if isinstance(message, ResultMessage) and message.result:
                result_lines.append(message.result)
        
        report = "
".join(result_lines)
        
        # 驗證輸出
        is_valid, reason = validate_report(report)
        if is_valid:
            print(f"✅ 第 {attempt} 次成功")
            return report
        else:
            print(f"⚠️  第 {attempt} 次失敗：{reason}")
    
    raise ValueError(f"經過 {max_retries} 次嘗試後仍無法產生有效報告")
</code></pre>



<h3 class="wp-block-heading">模式三：進度追蹤（Progress Tracking）</h3>



<p>對於耗時較長的 Agent 任務，即時顯示進度讓使用者知道 Agent 正在做什麼。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
import time
from claude_agent_sdk import query, ClaudeAgentOptions
from claude_agent_sdk import AssistantMessage, ToolUseBlock, ResultMessage


async def track_progress_agent(prompt: str):
    """帶進度追蹤的 Agent 執行器"""
    
    start_time = time.time()
    tool_call_count = 0
    
    async for message in query(
        prompt=prompt,
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Glob", "Grep", "Bash", "WebSearch"],
        ),
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, ToolUseBlock):
                    tool_call_count += 1
                    elapsed = time.time() - start_time
                    print(f"⚙️  [{elapsed:.1f}s] 工具呼叫 #{tool_call_count}: {block.name}")
                    
                    # 顯示工具參數摘要
                    if block.name in ["Read", "Write", "Edit"] and "file_path" in block.input:
                        print(f"   📄 {block.input['file_path']}")
                    elif block.name == "Bash" and "command" in block.input:
                        cmd = block.input["command"][:60]
                        print(f"   💻 {cmd}...")
                    elif block.name == "WebSearch" and "query" in block.input:
                        print(f"   🔍 {block.input['query']}")
        
        elif isinstance(message, ResultMessage):
            elapsed = time.time() - start_time
            print(f"
✅ 完成！耗時 {elapsed:.1f}s，共執行 {tool_call_count} 次工具呼叫")
            if message.result:
                print("
📋 結果：")
                print(message.result)
</code></pre>



<h2 class="wp-block-heading">效能優化：讓 Agent 更快更省錢</h2>



<p>Agent SDK 的計費基於 token 用量。以下幾個技巧可以在不犧牲品質的前提下降低成本。</p>



<figure class="wp-block-table"><table><thead><tr><th>優化技巧</th><th>說明</th><th>預估節省</th></tr></thead><tbody><tr><td>精確的 allowed_tools</td><td>只授予任務所需工具，避免 Claude 嘗試不相關工具</td><td>10-20%</td></tr><tr><td>清晰的 system_prompt</td><td>明確定義角色和輸出格式，減少反覆修正</td><td>15-30%</td></tr><tr><td>分段執行</td><td>複雜任務拆分成多個小 Agent，每段 context 更乾淨</td><td>20-40%</td></tr><tr><td>Session 復用</td><td>多輪對話使用 resume session，避免重複讀取相同檔案</td><td>30-50%</td></tr><tr><td>結果快取</td><td>對相同輸入的 Agent 結果進行快取，避免重複執行</td><td>依情況</td></tr></tbody></table></figure>



<p>其中 Session 復用是最容易被忽略但效果最顯著的優化。當你需要對同一份程式碼做多次分析時，第一次讀取後可以保留 session_id，後續的 query 直接 resume，Claude 不需要重新讀取所有檔案。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage, ResultMessage


async def multi_pass_analysis(file_path: str):
    """多次分析同一檔案：使用 Session 復用節省 Token"""
    
    session_id = None
    
    # 第一輪：讀取並理解程式碼
    print("第一輪：讀取程式碼...")
    async for message in query(
        prompt=f"請讀取並理解 {file_path} 的結構和功能",
        options=ClaudeAgentOptions(allowed_tools=["Read"]),
    ):
        if isinstance(message, SystemMessage) and message.subtype == "init":
            session_id = message.data.get("session_id")
    
    print(f"Session ID: {session_id}")
    
    # 第二輪：在已有 context 的基礎上分析 bug（不需重讀檔案）
    print("
第二輪：分析潛在 Bug...")
    bugs = []
    async for message in query(
        prompt="根據你剛讀取的程式碼，找出所有可能的 Bug",
        options=ClaudeAgentOptions(
            resume=session_id,  # 復用 session，不需重讀檔案
        ),
    ):
        if isinstance(message, ResultMessage) and message.result:
            bugs.append(message.result)
    
    # 第三輪：繼續在相同 context 中找效能問題
    print("
第三輪：分析效能問題...")
    perf_issues = []
    async for message in query(
        prompt="根據你剛讀取的程式碼，找出效能瓶頸和優化機會",
        options=ClaudeAgentOptions(
            resume=session_id,  # 繼續復用同一個 session
        ),
    ):
        if isinstance(message, ResultMessage) and message.result:
            perf_issues.append(message.result)
    
    print("
=== 分析完成 ===")
    print("Bug 報告：", "
".join(bugs))
    print("
效能分析：", "
".join(perf_issues))


asyncio.run(multi_pass_analysis("./src/main.py"))
</code></pre>



<h2 class="wp-block-heading">錯誤處理與生產環境準備</h2>



<p>把 Agent 部署到生產環境前，需要加入完善的錯誤處理機制。以下是一個封裝好的 Agent 執行器，包含超時控制、重試邏輯和錯誤記錄。</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import asyncio
import logging
from typing import AsyncIterator, TypeVar
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


# 設定日誌
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class AgentTimeoutError(Exception):
    pass


class AgentRunner:
    """生產環境用的 Agent 執行器"""
    
    def __init__(
        self,
        max_retries: int = 3,
        timeout_seconds: int = 300,
        retry_delay: float = 5.0,
    ):
        self.max_retries = max_retries
        self.timeout_seconds = timeout_seconds
        self.retry_delay = retry_delay
    
    async def run(
        self,
        prompt: str,
        options: ClaudeAgentOptions,
    ) -&gt; str:
        """執行 Agent，帶重試和超時機制"""
        
        last_error = None
        
        for attempt in range(1, self.max_retries + 1):
            try:
                logger.info(f"Agent 執行中（第 {attempt}/{self.max_retries} 次）")
                
                result = await asyncio.wait_for(
                    self._run_single(prompt, options),
                    timeout=self.timeout_seconds,
                )
                
                logger.info("Agent 執行成功")
                return result
                
            except asyncio.TimeoutError:
                last_error = AgentTimeoutError(
                    f"Agent 執行超時（{self.timeout_seconds}s）"
                )
                logger.warning(f"第 {attempt} 次超時，{self.retry_delay}s 後重試...")
                
            except Exception as e:
                last_error = e
                logger.error(f"第 {attempt} 次失敗：{e}")
                
                # 部分錯誤不值得重試
                if "API key" in str(e) or "authentication" in str(e).lower():
                    raise
            
            if attempt &lt; self.max_retries:
                await asyncio.sleep(self.retry_delay)
        
        raise last_error or RuntimeError("Agent 執行失敗")
    
    async def _run_single(self, prompt: str, options: ClaudeAgentOptions) -&gt; str:
        """單次執行 Agent"""
        result_parts = []
        async for message in query(prompt=prompt, options=options):
            if isinstance(message, ResultMessage) and message.result:
                result_parts.append(message.result)
        return "
".join(result_parts)


# 使用範例
async def main():
    runner = AgentRunner(
        max_retries=3,
        timeout_seconds=120,
        retry_delay=3.0,
    )
    
    try:
        result = await runner.run(
            prompt="分析目前目錄的 Python 檔案並找出所有 TODO 註解",
            options=ClaudeAgentOptions(
                allowed_tools=["Read", "Glob", "Grep"],
            ),
        )
        print(result)
    except AgentTimeoutError:
        print("❌ 任務超時，請縮小任務範圍後重試")
    except Exception as e:
        print(f"❌ 執行失敗：{e}")


asyncio.run(main())
</code></pre>



<h2 class="wp-block-heading">總結</h2>



<p>透過本篇的四個實戰專案，你已經掌握了用 Claude Agent SDK 打造自動化工具的核心技能。回顧一下我們學到的重點：</p>



<ul class="wp-block-list">
<li><strong>程式碼品質 Agent</strong>：展示如何用 Read、Glob、Grep 工具做唯讀分析，適合整合進 CI/CD 流程</li>



<li><strong>研究報告 Agent</strong>：展示 Multi-agent 架構如何讓複雜研究任務並行化，大幅提升效率</li>



<li><strong>檔案整理 Agent</strong>：展示漸進式授權模式，先模擬預覽後執行，保護資料安全</li>



<li><strong>Git 提交訊息產生器</strong>：展示如何把 Agent 嵌入日常開發工作流</li>
</ul>



<p>更重要的是幾個跨專案通用的設計原則：<strong>漸進式授權</strong>保護安全、<strong>結果驗證</strong>確保品質、<strong>進度追蹤</strong>提升體驗、<strong>Session 復用</strong>節省成本。這些原則在任何 Agent 自動化工具的開發中都同樣適用。</p>



<p>Agent SDK 最強大的地方在於：它讓你把「做什麼」和「怎麼做」解耦。你負責定義目標和規則，Claude 負責執行決策。這種分工讓你能快速建構出傳統自動化腳本需要數倍時間才能完成的工具。</p>



<p>在系列文章的下一篇，我們將進一步探討如何將這些 Agent 工具整合進企業級的工具鏈，包括 CI/CD 整合、權限管理和大規模部署策略。</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fagent-sdk-automation-tools%2F&amp;linkname=%E5%AF%A6%E6%88%B0%E5%B0%88%E6%A1%88%EF%BC%9A%E7%94%A8%20Agent%20SDK%20%E6%89%93%E9%80%A0%E8%87%AA%E5%8B%95%E5%8C%96%E5%B7%A5%E5%85%B7" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fagent-sdk-automation-tools%2F&amp;linkname=%E5%AF%A6%E6%88%B0%E5%B0%88%E6%A1%88%EF%BC%9A%E7%94%A8%20Agent%20SDK%20%E6%89%93%E9%80%A0%E8%87%AA%E5%8B%95%E5%8C%96%E5%B7%A5%E5%85%B7" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fagent-sdk-automation-tools%2F&amp;linkname=%E5%AF%A6%E6%88%B0%E5%B0%88%E6%A1%88%EF%BC%9A%E7%94%A8%20Agent%20SDK%20%E6%89%93%E9%80%A0%E8%87%AA%E5%8B%95%E5%8C%96%E5%B7%A5%E5%85%B7" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fagent-sdk-automation-tools%2F&#038;title=%E5%AF%A6%E6%88%B0%E5%B0%88%E6%A1%88%EF%BC%9A%E7%94%A8%20Agent%20SDK%20%E6%89%93%E9%80%A0%E8%87%AA%E5%8B%95%E5%8C%96%E5%B7%A5%E5%85%B7" data-a2a-url="https://blog.che-ya.com/agent-sdk-automation-tools/" data-a2a-title="實戰專案：用 Agent SDK 打造自動化工具"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Agent SDK 進階：Guardrails 與 Handoffs</title>
		<link>https://blog.che-ya.com/claude-agent-sdk-guardrails-handoffs/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Mon, 04 May 2026 02:17:00 +0000</pubDate>
				<category><![CDATA[Claude Agent SDK]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[Agent SDK]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[Guardrails]]></category>
		<category><![CDATA[Handoffs]]></category>
		<category><![CDATA[Multi-agent]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=873</guid>

					<description><![CDATA[在上一篇 Claude Agent SDK 入門教學中，我們學會了如何建構基本的 AI Agent。本篇將深入 ... <a title="Agent SDK 進階：Guardrails 與 Handoffs" class="read-more" href="https://blog.che-ya.com/claude-agent-sdk-guardrails-handoffs/" aria-label="Read more about Agent SDK 進階：Guardrails 與 Handoffs">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>在<a href="https://blog.che-ya.com/claude-agent-sdk-getting-started/">上一篇 Claude Agent SDK 入門教學</a>中，我們學會了如何建構基本的 AI Agent。本篇將深入探討兩個進階主題：<strong>Guardrails（護欄）</strong>與 <strong>Handoffs（任務移交）</strong>。這兩者是打造生產級 Agent 應用的關鍵機制，讓你的 Agent 既安全可靠，又能有效處理複雜任務。</p>



<h2 class="wp-block-heading">什麼是 Guardrails？</h2>



<p>Guardrails（護欄）是在 Agent 執行前後加入的驗證機制，用來確保輸入合法、輸出符合預期。簡單來說，就是在 Agent 的「進出口」設立檢查站。</p>



<p>與 OpenAI Agents SDK 使用裝飾器（<code>@input_guardrail</code>、<code>@output_guardrail</code>）的方式不同，Claude Agent SDK 採用更靈活的設計：<strong>Guardrails 就是你自己撰寫的普通函式</strong>，在程式碼中直接呼叫，搭配 Hooks 機制實現攔截與驗證。</p>



<h3 class="wp-block-heading">Guardrails 的兩種類型</h3>



<figure class="wp-block-table"><table><thead><tr><th>類型</th><th>時機</th><th>用途</th><th>實作方式</th></tr></thead><tbody><tr><td>Input Guardrail</td><td>Agent 執行前</td><td>驗證使用者輸入是否合法</td><td>普通函式 + 提前返回，或 UserPromptSubmit Hook</td></tr><tr><td>Output Guardrail</td><td>Agent 執行後</td><td>驗證輸出結果是否符合規範</td><td>對 result.result 執行驗證函式</td></tr><tr><td>Tool-level Guardrail</td><td>工具呼叫前後</td><td>控制特定工具的存取與行為</td><td>PreToolUse / PostToolUse Hook</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">Input Guardrail：過濾不合法輸入</h3>



<p>最簡單的輸入護欄是在呼叫 Agent 前用普通函式驗證輸入。以費用申報 Agent 為例，我們要求使用者必須提供金額：</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import re
from claude_agent_sdk import query, ClaudeAgentOptions

def check_has_dollar_amount(user_input: str) -> tuple[bool, str | None]:
    """Input Guardrail：檢查是否包含金額"""
    if re.search(r"$d+", user_input):
        return True, None
    return False, "請提供金額（例如：$100）才能處理這個請求。"

async def run_expense_agent(msg: str) -> None:
    # Input Guardrail：在 Agent 執行前驗證
    allowed, rejection = check_has_dollar_amount(msg)
    if not allowed:
        print(rejection)  # 直接返回，不執行 Agent
        return

    async for message in query(
        prompt=msg,
        options=ClaudeAgentOptions(allowed_tools=["Read", "Bash"]),
    ):
        if hasattr(message, "result"):
            print(message.result)</code></pre>



<h3 class="wp-block-heading">使用 UserPromptSubmit Hook 實作 Input Guardrail</h3>



<p>若想讓 Guardrail 與 Agent 框架深度整合，可以使用 <code>UserPromptSubmit</code> Hook，這是最接近 OpenAI <code>@input_guardrail</code> 裝飾器的做法：</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import re
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher

async def has_dollar_amount_hook(input_data, tool_use_id, context):
    """透過 Hook 實作 Input Guardrail"""
    if re.search(r"$d+", input_data["prompt"]):
        return {}  # 允許繼續執行
    # 返回 block 決策，Agent 不會執行
    return {
        "decision": "block",
        "reason": "請提供金額（例如：$100）才能處理這個請求。"
    }

async for message in query(
    prompt="幫我申報這個費用",  # 沒有金額，會被攔截
    options=ClaudeAgentOptions(
        allowed_tools=["Read", "Bash"],
        hooks={
            "UserPromptSubmit": [
                HookMatcher(hooks=[has_dollar_amount_hook])
            ]
        },
    ),
):
    print(message)</code></pre>



<h3 class="wp-block-heading">Output Guardrail：驗證輸出結果</h3>



<p>Output Guardrail 在 Agent 完成後對輸出進行檢查。以費用申報為例，我們要確認輸出包含明確的核准或拒絕決策：</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import re
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

def check_has_decision(result: str) -> tuple[bool, str | None]:
    """Output Guardrail：檢查是否包含明確決策"""
    if re.search(r"(核准|拒絕|需要審查|approv|reject|review)", result, re.IGNORECASE):
        return True, None
    return False, "無法得出明確決策，請重新提交。"

async def run_with_output_guardrail(msg: str) -> None:
    messages = []

    async for message in query(
        prompt=msg,
        options=ClaudeAgentOptions(allowed_tools=["Read", "Bash"]),
    ):
        if isinstance(message, ResultMessage):
            messages.append(message)

    # Output Guardrail：驗證最終輸出
    if messages:
        final_result = messages[-1].result or ""
        ok, override = check_has_decision(final_result)
        if not ok:
            print(override)  # 輸出不符合要求
        else:
            print(final_result)  # 正常輸出</code></pre>



<h3 class="wp-block-heading">Tool-level Guardrail：保護敏感操作</h3>



<p>透過 <code>PreToolUse</code> Hook，你可以在工具執行前攔截危險操作。例如禁止修改 <code>.env</code> 檔案：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { query, HookCallback, PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";

const protectEnvFiles: HookCallback = async (input, toolUseID, { signal }) => {
  const preInput = input as PreToolUseHookInput;
  const toolInput = preInput.tool_input as Record&lt;string, unknown&gt;;
  const filePath = toolInput?.file_path as string;
  const fileName = filePath?.split("/").pop();

  if (fileName === ".env") {
    return {
      hookSpecificOutput: {
        hookEventName: preInput.hook_event_name,
        permissionDecision: "deny",
        permissionDecisionReason: "禁止修改 .env 檔案以保護安全性"
      }
    };
  }
  return {};  // 允許其他檔案操作
};

for await (const message of query({
  prompt: "更新資料庫設定",
  options: {
    hooks: {
      PreToolUse: [{ matcher: "Write|Edit", hooks: [protectEnvFiles] }]
    }
  }
})) {
  console.log(message);
}</code></pre>



<h2 class="wp-block-heading">什麼是 Handoffs？</h2>



<p>Handoffs（任務移交）是 Multi-agent 架構中的核心概念：主 Agent 將特定任務委派給專門的子 Agent 處理。在 OpenAI Agents SDK 中，Handoffs 會讓第一個 Agent「完全退場」，由第二個 Agent 接手對話；而在 Claude Agent SDK 中，設計哲學略有不同。</p>



<h3 class="wp-block-heading">OpenAI vs Claude 的 Handoffs 差異</h3>



<figure class="wp-block-table"><table><thead><tr><th>面向</th><th>OpenAI Agents SDK</th><th>Claude Agent SDK</th></tr></thead><tbody><tr><td>機制</td><td>Handoff 轉移控制權</td><td>Delegation（委派），主 Agent 保持控制</td></tr><tr><td>主 Agent 狀態</td><td>Handoff 後停止運行</td><td>持續活躍，接收子 Agent 結果</td></tr><tr><td>定義方式</td><td><code>handoffs=[specialist]</code></td><td><code>AgentDefinition</code> + <code>agents={}</code> 參數</td></tr><tr><td>結果回傳</td><td>第二個 Agent 直接輸出</td><td>子 Agent 結果回傳給主 Agent</td></tr><tr><td>適用場景</td><td>純路由（分診後交棒）</td><td>需要主 Agent 綜合子結果的複雜任務</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">用 AgentDefinition 實作 Handoffs</h3>



<p>Claude Agent SDK 透過 <code>AgentDefinition</code> 定義子 Agent，再由主 Agent 透過 Agent 工具進行委派。以費用申報為例：</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition

# 定義核准子 Agent：處理符合規定的費用
approver = AgentDefinition(
    description="核准符合政策的費用申請。當金額在政策限額內時使用。",
    prompt="你是費用核准專員。確認金額與類別，若符合規定即核准，並提醒是否需要收據。",
    tools=["mcp__expense__check_policy"],
)

# 定義升級子 Agent：處理超出限額的費用
escalator = AgentDefinition(
    description="將超出限額的費用升級給主管。當金額超出政策限額時使用。",
    prompt="你是費用升級專員。草擬一行通知給主管，包含金額、類別及超出限額的幅度。",
    tools=["mcp__expense__check_policy"],
)

# 主 Agent：根據政策決定路由方向
async for message in query(
    prompt="申請出差費用 $350，類別：交通",
    options=ClaudeAgentOptions(
        system_prompt="根據費用政策，將每筆申請路由到適當的子 Agent 處理。金額在限額內交給 approver，超出則交給 escalator。",
        mcp_servers={"expense": {"command": "npx", "args": ["@company/expense-mcp"]}},
        allowed_tools=["Agent", "mcp__expense__check_policy"],
        agents={"approver": approver, "escalator": escalator},
    ),
):
    if hasattr(message, "result"):
        print(message.result)</code></pre>



<h3 class="wp-block-heading">TypeScript 版本的 Handoffs 實作</h3>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { query } from "@anthropic-ai/claude-agent-sdk";

const approver = {
  description: "核准符合政策的費用申請。當金額在政策限額內時使用。",
  prompt: "你是費用核准專員。確認金額與類別，若符合規定即核准，並提醒是否需要收據。",
  tools: ["mcp__expense__check_policy"] as string[]
};

const escalator = {
  description: "將超出限額的費用升級給主管。當金額超出政策限額時使用。",
  prompt: "你是費用升級專員。草擬一行通知給主管，包含金額、類別及超出限額的幅度。",
  tools: ["mcp__expense__check_policy"] as string[]
};

for await (const message of query({
  prompt: "申請出差費用 $350，類別：交通",
  options: {
    systemPrompt: "根據費用政策，將每筆申請路由到適當的子 Agent 處理。",
    mcpServers: {
      expense: { command: "npx", args: ["@company/expense-mcp"] }
    },
    allowedTools: ["Agent", "mcp__expense__check_policy"],
    agents: { approver, escalator }
  }
})) {
  if ("result" in message) console.log(message.result);
}</code></pre>



<h3 class="wp-block-heading">用 SubagentStart / SubagentStop Hook 監控委派</h3>



<p>你可以使用 SubagentStart 和 SubagentStop Hook 追蹤子 Agent 的執行狀況，這對於除錯與效能分析非常有用：</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher
import time

start_times = {}

async def track_subagent_start(input_data, tool_use_id, context):
    """記錄子 Agent 啟動時間"""
    agent_id = input_data.get("agent_id", "unknown")
    start_times[agent_id] = time.time()
    print(f"[子 Agent 啟動] ID: {agent_id}")
    return {}

async def track_subagent_stop(input_data, tool_use_id, context):
    """計算子 Agent 執行時間"""
    agent_id = input_data.get("agent_id", "unknown")
    if agent_id in start_times:
        duration = time.time() - start_times[agent_id]
        print(f"[子 Agent 完成] ID: {agent_id}，耗時: {duration:.2f}秒")
    return {}

async for message in query(
    prompt="分析這份程式碼並找出所有安全漏洞",
    options=ClaudeAgentOptions(
        allowed_tools=["Read", "Glob", "Grep", "Agent"],
        hooks={
            "SubagentStart": [HookMatcher(hooks=[track_subagent_start])],
            "SubagentStop": [HookMatcher(hooks=[track_subagent_stop])],
        },
        agents={
            "security-scanner": {
                "description": "專門掃描安全漏洞的子 Agent",
                "prompt": "你是資安專家，專注於找出 SQL Injection、XSS、CSRF 等常見漏洞。",
                "tools": ["Read", "Glob", "Grep"]
            }
        }
    ),
):
    if hasattr(message, "result"):
        print(message.result)</code></pre>



<h2 class="wp-block-heading">Guardrails 與 Handoffs 的組合應用</h2>



<p>在實際的生產環境中，Guardrails 與 Handoffs 通常會搭配使用。以下是一個完整的費用申報系統範例，結合了輸入驗證、多 Agent 路由與輸出檢查：</p>



<pre class="wp-block-code"><code lang="python" class="language-python">import re
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, HookMatcher, ResultMessage

# ---- Guardrails ----
async def input_guardrail_hook(input_data, tool_use_id, context):
    """Input Guardrail：要求必須包含金額"""
    if not re.search(r"$d+", input_data["prompt"]):
        return {
            "decision": "block",
            "reason": "請提供金額（例如：$100）才能處理費用申請。"
        }
    return {}

# ---- Sub-agents（Handoffs 的目標）----
approver = AgentDefinition(
    description="核准符合政策限額的費用申請",
    prompt="你是費用核准專員。確認金額符合政策，給出核准通知。",
    tools=["mcp__expense__check_policy"],
)

escalator = AgentDefinition(
    description="升級超出政策限額的費用申請給主管",
    prompt="你是費用升級專員。說明超出限額的情況，草擬主管通知。",
    tools=["mcp__expense__check_policy"],
)

# ---- 主 Agent：結合 Guardrails + Handoffs ----
async def process_expense(expense_request: str):
    messages = []

    async for message in query(
        prompt=expense_request,
        options=ClaudeAgentOptions(
            system_prompt="你是費用申報路由系統。先用 check_policy 確認限額，再根據結果委派給 approver 或 escalator。",
            mcp_servers={"expense": {"command": "npx", "args": ["@company/expense-mcp"]}},
            allowed_tools=["Agent", "mcp__expense__check_policy"],
            agents={"approver": approver, "escalator": escalator},
            hooks={
                "UserPromptSubmit": [HookMatcher(hooks=[input_guardrail_hook])]
            },
        ),
    ):
        if isinstance(message, ResultMessage):
            messages.append(message)

    # Output Guardrail：確認輸出包含明確決策
    if messages:
        result = messages[-1].result or ""
        if not re.search(r"(核准|升級|拒絕)", result):
            print("⚠️ 無法得出明確決策，請重新提交")
        else:
            print(result)

# 執行
import asyncio
asyncio.run(process_expense("申請出差費用 $350，類別：交通"))</code></pre>



<h2 class="wp-block-heading">Hook 的執行優先順序</h2>



<p>當多個 Hooks 同時存在時，了解執行順序非常重要：</p>



<figure class="wp-block-table"><table><thead><tr><th>優先順序</th><th>步驟</th><th>說明</th></tr></thead><tbody><tr><td>1</td><td>Hooks 執行</td><td>PreToolUse 等 Hook 先行判斷，可允許、拒絕或繼續</td></tr><tr><td>2</td><td>Deny 規則</td><td>disallowed_tools 設定，即使 bypassPermissions 也有效</td></tr><tr><td>3</td><td>Permission Mode</td><td>bypassPermissions / acceptEdits / dontAsk / default</td></tr><tr><td>4</td><td>Allow 規則</td><td>allowed_tools 設定的白名單</td></tr><tr><td>5</td><td>canUseTool Callback</td><td>最後的互動確認（dontAsk 模式跳過此步）</td></tr></tbody></table></figure>



<p>重要原則：當多個 Hook 對同一操作返回不同決策時，<strong>deny 優先於 ask，ask 優先於 allow</strong>。只要有一個 Hook 返回 deny，操作就會被阻止。</p>



<h2 class="wp-block-heading">Guardrails 最佳實踐</h2>



<ul class="wp-block-list">
<li><strong>職責單一</strong>：每個 Guardrail 只做一件事，透過 Hook 鏈組合多個驗證邏輯，保持程式碼清晰</li>



<li><strong>錯誤訊息清楚</strong>：拒絕請求時，提供具體的拒絕原因，讓使用者知道該如何修正</li>



<li><strong>避免無限迴圈</strong>：<code>UserPromptSubmit</code> Hook 若觸發子 Agent，需防止遞迴呼叫；在 Hook 內部加入子 Agent 標記來避免</li>



<li><strong>非同步 Hook 用於記錄</strong>：純記錄用途的 Hook 使用非同步模式（<code>async: true</code>），避免阻塞 Agent 執行</li>
</ul>



<h2 class="wp-block-heading">Handoffs 最佳實踐</h2>



<ul class="wp-block-list">
<li><strong>AgentDefinition 描述要精確</strong>：子 Agent 的 <code>description</code> 欄位是主 Agent 決定路由的依據，描述要清楚說明「何時」應該使用這個子 Agent</li>



<li><strong>子 Agent 工具最小化</strong>：每個子 Agent 只授予完成任務所需的工具，避免過度授權</li>



<li><strong>若需要「真正交棒」</strong>：如果你的場景需要子 Agent 完全接管（不回傳給主 Agent），考慮用 Python 薄層 Dispatcher 直接呼叫不同的 Agent，而非依賴 LLM 決策路由</li>



<li><strong>監控子 Agent 執行</strong>：使用 SubagentStart / SubagentStop Hook 記錄每個子 Agent 的執行時間與結果，便於效能分析與除錯</li>
</ul>



<h2 class="wp-block-heading">總結</h2>



<p>Guardrails 與 Handoffs 是 Claude Agent SDK 中讓 Agent 達到生產級可靠性的兩大支柱。Guardrails 透過 Hook 機制在 Agent 的「進出口」設立檢查站，確保輸入合法、輸出符合預期、工具使用安全；Handoffs 透過 AgentDefinition 實現多 Agent 協作，讓複雜任務被分解到專門的子 Agent 處理，主 Agent 保持對全局的控制。</p>



<p>掌握這兩個機制後，你就具備了打造複雜 Agent 應用的核心能力。在接下來的系列文章中，我們將進一步探討如何將這些技術應用在實戰專案中，打造真正解決問題的自動化工具。</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-guardrails-handoffs%2F&amp;linkname=Agent%20SDK%20%E9%80%B2%E9%9A%8E%EF%BC%9AGuardrails%20%E8%88%87%20Handoffs" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-guardrails-handoffs%2F&amp;linkname=Agent%20SDK%20%E9%80%B2%E9%9A%8E%EF%BC%9AGuardrails%20%E8%88%87%20Handoffs" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-guardrails-handoffs%2F&amp;linkname=Agent%20SDK%20%E9%80%B2%E9%9A%8E%EF%BC%9AGuardrails%20%E8%88%87%20Handoffs" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-guardrails-handoffs%2F&#038;title=Agent%20SDK%20%E9%80%B2%E9%9A%8E%EF%BC%9AGuardrails%20%E8%88%87%20Handoffs" data-a2a-url="https://blog.che-ya.com/claude-agent-sdk-guardrails-handoffs/" data-a2a-title="Agent SDK 進階：Guardrails 與 Handoffs"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Claude Agent SDK 入門：建構你的 AI Agent</title>
		<link>https://blog.che-ya.com/claude-agent-sdk-getting-started/</link>
					<comments>https://blog.che-ya.com/claude-agent-sdk-getting-started/#comments</comments>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Sun, 03 May 2026 01:07:00 +0000</pubDate>
				<category><![CDATA[Claude Agent SDK]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[Agent SDK]]></category>
		<category><![CDATA[AI Agent]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=863</guid>

					<description><![CDATA[Claude Agent SDK 是 Anthropic 推出的開發套件，讓你能以程式化方式建構 AI Age ... <a title="Claude Agent SDK 入門：建構你的 AI Agent" class="read-more" href="https://blog.che-ya.com/claude-agent-sdk-getting-started/" aria-label="Read more about Claude Agent SDK 入門：建構你的 AI Agent">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>Claude Agent SDK 是 Anthropic 推出的開發套件，讓你能以程式化方式建構 AI Agent。它將驅動 Claude Code 的核心引擎——包括 Agent 迴圈、內建工具、Context 管理——全部封裝成可程式化的 Library，支援 TypeScript 與 Python 兩種語言。本篇將帶你從零開始，了解 Agent SDK 的核心概念、安裝方式、Tool 定義、Agent 生命週期，並透過完整範例實際建構一個 AI Agent。</p>



<h2 class="wp-block-heading">什麼是 Claude Agent SDK？</h2>



<p>Claude Agent SDK（前身為 Claude Code SDK）是 Anthropic 官方提供的開發套件，讓開發者能建構具有自主能力的 AI Agent。這些 Agent 可以自動讀取檔案、執行終端指令、搜尋網頁、編輯程式碼等，無需你手動實作工具執行邏輯。簡單來說，Agent SDK 就是把 Claude Code 的能力開放給你，讓你能在自己的應用程式中嵌入同等級的 AI 自動化能力。</p>



<h3 class="wp-block-heading">Agent SDK vs Client SDK vs Claude Code CLI</h3>



<p>Anthropic 提供了多種方式與 Claude 互動，它們之間的定位各不相同。以下整理三者的差異，幫助你選擇適合的工具：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>比較項目</th><th>Client SDK</th><th>Agent SDK</th><th>Claude Code CLI</th></tr></thead><tbody><tr><td>定位</td><td>API 直接存取</td><td>內建工具的 Agent 框架</td><td>互動式開發工具</td></tr><tr><td>工具執行</td><td>需自行實作 Tool Loop</td><td>Claude 自主處理</td><td>Claude 自主處理</td></tr><tr><td>適用場景</td><td>自訂 API 整合</td><td>CI/CD、自動化、產品嵌入</td><td>日常開發、一次性任務</td></tr><tr><td>程式語言</td><td>Python / TypeScript</td><td>Python / TypeScript</td><td>終端指令</td></tr></tbody></table></figure>



<p>用一段程式碼來說明 Client SDK 與 Agent SDK 的差異：</p>



<pre class="wp-block-code"><code class="">// Client SDK：你需要自己實作 Tool Loop
let response = await client.messages.create({ ...params });
while (response.stop_reason === "tool_use") {
  const result = yourToolExecutor(response.tool_use);
  response = await client.messages.create({ tool_result: result, ...params });
}

// Agent SDK：Claude 自主處理工具呼叫
for await (const message of query({
  prompt: "Fix the bug in auth.py"
})) {
  console.log(message);
}</code></pre>



<h2 class="wp-block-heading">安裝與環境設定</h2>



<h3 class="wp-block-heading">前置需求</h3>



<ul class="wp-block-list">
<li><strong>Node.js 18+</strong>（TypeScript 版本）</li>



<li><strong>Python 3.10+</strong>（Python 版本）</li>



<li><strong>Anthropic API Key</strong>：從 <a href="https://platform.claude.com/" rel="nofollow noopener" target="_blank">Claude Console</a> 取得</li>
</ul>



<h3 class="wp-block-heading">安裝套件</h3>



<p>根據你使用的程式語言，選擇對應的安裝方式：</p>



<pre class="wp-block-code"><code class=""># TypeScript
npm install @anthropic-ai/claude-agent-sdk

# Python（使用 pip）
pip install claude-agent-sdk

# Python（使用 uv，推薦）
uv init &amp;&amp; uv add claude-agent-sdk</code></pre>



<h3 class="wp-block-heading">設定 API Key</h3>



<p>安裝完成後，你需要設定 Anthropic API Key 作為環境變數。Agent SDK 也支援透過第三方雲端服務進行驗證，包括 Amazon Bedrock、Google Vertex AI 與 Microsoft Azure：</p>



<pre class="wp-block-code"><code class=""># 設定 API Key 環境變數
export ANTHROPIC_API_KEY=your-api-key

# 或建立 .env 檔案
echo "ANTHROPIC_API_KEY=your-api-key" > .env

# 若使用 Amazon Bedrock
export CLAUDE_CODE_USE_BEDROCK=1

# 若使用 Google Vertex AI
export CLAUDE_CODE_USE_VERTEX=1</code></pre>



<h2 class="wp-block-heading">建構你的第一個 Agent</h2>



<p>Agent SDK 的核心進入點是 <code>query</code> 函式。它建立一個 Agentic Loop（代理迴圈），以串流方式回傳 Claude 工作過程中的每一個訊息，包括推理過程、工具呼叫、工具結果與最終輸出。</p>



<h3 class="wp-block-heading">基本 Agent 範例（TypeScript）</h3>



<p>以下範例建立一個能讀取並修復程式碼 Bug 的 Agent：</p>



<pre class="wp-block-code"><code class="">import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Review utils.py for bugs that would cause crashes. Fix any issues you find.",
  options: {
    allowedTools: ["Read", "Edit", "Glob"],
    permissionMode: "acceptEdits"
  }
})) {
  if (message.type === "assistant" &amp;&amp; message.message?.content) {
    for (const block of message.message.content) {
      if ("text" in block) {
        console.log(block.text);     // Claude 的推理過程
      } else if ("name" in block) {
        console.log(`Tool: ${block.name}`); // 工具呼叫
      }
    }
  } else if (message.type === "result") {
    console.log(`Done: ${message.subtype}`);
  }
}</code></pre>



<h3 class="wp-block-heading">基本 Agent 範例（Python）</h3>



<pre class="wp-block-code"><code class="">import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage

async def main():
    async for message in query(
        prompt="Review utils.py for bugs that would cause crashes. Fix any issues you find.",
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Edit", "Glob"],
            permission_mode="acceptEdits",
        ),
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if hasattr(block, "text"):
                    print(block.text)
                elif hasattr(block, "name"):
                    print(f"Tool: {block.name}")
        elif isinstance(message, ResultMessage):
            print(f"Done: {message.subtype}")

asyncio.run(main())</code></pre>



<p>這段程式碼有三個關鍵部分：<code>query</code> 是建立 Agentic Loop 的主要進入點；<code>prompt</code> 告訴 Claude 要做什麼；<code>options</code> 設定 Agent 可以使用的工具與權限模式。Claude 會根據任務自動判斷該使用哪些工具。</p>



<h2 class="wp-block-heading">Tool 定義與使用</h2>



<p>Agent SDK 提供了豐富的內建工具，讓 Agent 可以直接與檔案系統、終端和網路互動。你只需在 <code>allowedTools</code> 中指定要啟用的工具，Claude 就會自動判斷何時使用它們。</p>



<h3 class="wp-block-heading">內建工具一覽</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>工具名稱</th><th>功能說明</th><th>典型用途</th></tr></thead><tbody><tr><td><code>Read</code></td><td>讀取工作目錄中的任何檔案</td><td>閱讀程式碼、設定檔</td></tr><tr><td><code>Write</code></td><td>建立新檔案</td><td>產生報告、建立設定</td></tr><tr><td><code>Edit</code></td><td>精確編輯現有檔案</td><td>修復 Bug、重構程式碼</td></tr><tr><td><code>Bash</code></td><td>執行終端指令、腳本、Git 操作</td><td>執行測試、安裝套件</td></tr><tr><td><code>Glob</code></td><td>以 Pattern 搜尋檔案</td><td>尋找特定類型的檔案</td></tr><tr><td><code>Grep</code></td><td>以正則表達式搜尋檔案內容</td><td>搜尋函式定義、錯誤訊息</td></tr><tr><td><code>WebSearch</code></td><td>搜尋網路上的最新資訊</td><td>查詢文件、API 規格</td></tr><tr><td><code>WebFetch</code></td><td>擷取並解析網頁內容</td><td>讀取線上文件</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">工具組合策略</h3>



<p>根據 Agent 的用途，可以組合不同的工具來達成目標。以下是常見的工具組合建議：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>工具組合</th><th>Agent 能力</th><th>適用場景</th></tr></thead><tbody><tr><td><code>Read</code>, <code>Glob</code>, <code>Grep</code></td><td>唯讀分析</td><td>Code Review、程式碼搜尋</td></tr><tr><td><code>Read</code>, <code>Edit</code>, <code>Glob</code></td><td>分析與修改程式碼</td><td>Bug 修復、重構</td></tr><tr><td><code>Read</code>, <code>Edit</code>, <code>Bash</code>, <code>Glob</code>, <code>Grep</code></td><td>完整自動化</td><td>CI/CD Pipeline、全面測試</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Agent 生命週期與 Hooks</h2>



<p>Agent SDK 提供了 Hooks 機制，讓你在 Agent 生命週期的關鍵節點執行自訂邏輯。你可以用 Hooks 來驗證、記錄、阻擋或轉換 Agent 的行為。</p>



<h3 class="wp-block-heading">可用的 Hook 類型</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Hook 名稱</th><th>觸發時機</th><th>常見用途</th></tr></thead><tbody><tr><td><code>PreToolUse</code></td><td>工具呼叫前</td><td>參數驗證、存取控制</td></tr><tr><td><code>PostToolUse</code></td><td>工具呼叫後</td><td>結果記錄、稽核日誌</td></tr><tr><td><code>Stop</code></td><td>Agent 完成任務時</td><td>結果驗證、清理作業</td></tr><tr><td><code>SessionStart</code></td><td>Session 開始時</td><td>初始化設定、載入環境</td></tr><tr><td><code>SessionEnd</code></td><td>Session 結束時</td><td>資源釋放、產出報告</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">Hook 實作範例：稽核日誌</h3>



<p>以下範例展示如何使用 <code>PostToolUse</code> Hook 將所有檔案變更記錄到稽核日誌中：</p>



<pre class="wp-block-code"><code class="">import { query, HookCallback } from "@anthropic-ai/claude-agent-sdk";
import { appendFile } from "fs/promises";

const logFileChange: HookCallback = async (input) => {
  const filePath = (input as any).tool_input?.file_path ?? "unknown";
  await appendFile(
    "./audit.log",
    `${new Date().toISOString()}: modified ${filePath}\n`
  );
  return {};
};

for await (const message of query({
  prompt: "Refactor utils.py to improve readability",
  options: {
    permissionMode: "acceptEdits",
    hooks: {
      PostToolUse: [
        { matcher: "Edit|Write", hooks: [logFileChange] }
      ]
    }
  }
})) {
  if ("result" in message) console.log(message.result);
}</code></pre>



<h2 class="wp-block-heading">權限控制模式</h2>



<p>Agent SDK 提供多種權限模式，讓你精確控制 Agent 的行為。選擇適合的模式，可以在自動化效率與安全性之間取得平衡：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>模式</th><th>行為</th><th>適用場景</th></tr></thead><tbody><tr><td><code>acceptEdits</code></td><td>自動核准檔案編輯，其他操作需確認</td><td>信任的開發環境</td></tr><tr><td><code>dontAsk</code></td><td>拒絕不在 allowedTools 中的操作</td><td>鎖定的 Headless Agent</td></tr><tr><td><code>auto</code>（僅 TypeScript）</td><td>模型分類器自動核准或拒絕</td><td>自主 Agent + 安全護欄</td></tr><tr><td><code>bypassPermissions</code></td><td>所有工具無需提示直接執行</td><td>沙箱化的 CI 環境</td></tr><tr><td><code>default</code></td><td>需提供 canUseTool callback 處理</td><td>自訂審核流程</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Subagents：多 Agent 協作</h2>



<p>Agent SDK 支援 Subagent（子代理）機制，讓主 Agent 可以將特定任務委派給專門的子 Agent 處理。你可以為每個 Subagent 定義專屬的指令與工具集，實現分工合作。</p>



<pre class="wp-block-code"><code class="">import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Use the code-reviewer agent to review this codebase",
  options: {
    allowedTools: ["Read", "Glob", "Grep", "Agent"],
    agents: {
      "code-reviewer": {
        description: "Expert code reviewer for quality and security.",
        prompt: "Analyze code quality and suggest improvements.",
        tools: ["Read", "Glob", "Grep"]
      }
    }
  }
})) {
  if ("result" in message) console.log(message.result);
}</code></pre>



<p>使用 Subagent 時，需要在 <code>allowedTools</code> 中加入 <code>Agent</code> 工具。每個 Subagent 執行時產生的訊息會帶有 <code>parent_tool_use_id</code> 欄位，方便你追蹤哪些訊息屬於哪個 Subagent。</p>



<h2 class="wp-block-heading">MCP 整合：連接外部系統</h2>



<p>Agent SDK 透過 Model Context Protocol（MCP）支援連接外部系統，包括資料庫、瀏覽器、API 等。你可以透過 <code>mcpServers</code> 選項配置 MCP Server，讓 Agent 獲得額外的能力。</p>



<pre class="wp-block-code"><code class="">import { query } from "@anthropic-ai/claude-agent-sdk";

// 連接 Playwright MCP Server 賦予瀏覽器自動化能力
for await (const message of query({
  prompt: "Open example.com and describe what you see",
  options: {
    mcpServers: {
      playwright: {
        command: "npx",
        args: ["@playwright/mcp@latest"]
      }
    }
  }
})) {
  if ("result" in message) console.log(message.result);
}</code></pre>



<p>MCP 生態系中有數百個現成的 Server 可供使用，包括 Slack、GitHub、Google Drive、Asana 等，無需自行撰寫整合程式碼即可讓你的 Agent 連接各種外部服務。</p>



<h2 class="wp-block-heading">Session 管理：維持對話脈絡</h2>



<p>Agent SDK 支援 Session（會話）機制，讓 Agent 能在多次交互中保持上下文。Claude 會記住已讀取的檔案、分析結果與對話歷史。你可以恢復先前的 Session，或分叉 Session 來探索不同的方案。</p>



<pre class="wp-block-code"><code class="">import { query } from "@anthropic-ai/claude-agent-sdk";

let sessionId: string | undefined;

// 第一次查詢：取得 Session ID
for await (const message of query({
  prompt: "Read the authentication module",
  options: { allowedTools: ["Read", "Glob"] }
})) {
  if (message.type === "system" &amp;&amp; message.subtype === "init") {
    sessionId = message.session_id;
  }
}

// 恢復 Session，延續先前的上下文
for await (const message of query({
  prompt: "Now find all places that call it",
  options: { resume: sessionId }
})) {
  if ("result" in message) console.log(message.result);
}</code></pre>



<h2 class="wp-block-heading">完整範例：自動化 Bug 修復 Agent</h2>



<p>以下是一個完整的 Agent 範例，結合了前面介紹的各項功能。這個 Agent 能自動掃描程式碼、找出潛在的 Bug、修復問題，並產出修復報告：</p>



<pre class="wp-block-code"><code class="">import { query, HookCallback } from "@anthropic-ai/claude-agent-sdk";
import { appendFile, writeFile } from "fs/promises";

// Hook：記錄所有檔案變更
const auditLog: HookCallback = async (input) => {
  const filePath = (input as any).tool_input?.file_path ?? "unknown";
  await appendFile(
    "./bug-fix-audit.log",
    `${new Date().toISOString()}: modified ${filePath}\n`
  );
  return {};
};

// 執行 Bug 修復 Agent
async function runBugFixer() {
  const results: string[] = [];

  for await (const message of query({
    prompt: `Scan all Python files for common bugs:
      1. Division by zero risks
      2. Null/None reference errors
      3. Unhandled exceptions
      Fix each issue and add defensive coding.`,
    options: {
      allowedTools: ["Read", "Edit", "Glob", "Grep", "Bash"],
      permissionMode: "acceptEdits",
      systemPrompt: "You are a senior Python developer. Follow PEP 8.",
      hooks: {
        PostToolUse: [
          { matcher: "Edit|Write", hooks: [auditLog] }
        ]
      }
    }
  })) {
    if (message.type === "assistant") {
      for (const block of message.message?.content ?? []) {
        if ("text" in block) results.push(block.text);
      }
    }
  }

  // 產出修復報告
  await writeFile("./fix-report.md", results.join("\n"));
  console.log("Bug fix complete! See fix-report.md");
}

runBugFixer();</code></pre>



<p>這個範例展示了 Agent SDK 的幾個核心特性：透過 <code>systemPrompt</code> 設定 Agent 角色、使用 <code>hooks</code> 記錄稽核日誌、結合多種工具實現完整的自動化流程，以及將結果輸出到檔案中。</p>



<h2 class="wp-block-heading">Agent SDK 與 Claude Code 的關係</h2>



<p>Agent SDK 與 Claude Code 共享相同的底層引擎。你在 Claude Code CLI 中能做到的事，透過 Agent SDK 都能以程式化方式實現。許多團隊會同時使用兩者：在日常開發中使用 CLI 進行互動式操作，在 CI/CD Pipeline 和自動化流程中使用 SDK。</p>



<p>Agent SDK 也支援 Claude Code 基於檔案系統的設定機制。只需在選項中設定 <code>settingSources: ['project']</code>，就能啟用以下功能：</p>



<ul class="wp-block-list">
<li><strong>Skills</strong>：在 <code>.claude/skills/*/SKILL.md</code> 定義專門能力</li>



<li><strong>Slash Commands</strong>：在 <code>.claude/commands/*.md</code> 建立自訂指令</li>



<li><strong>Memory</strong>：透過 <code>CLAUDE.md</code> 設定專案上下文與指令</li>



<li><strong>Plugins</strong>：以程式化方式透過 <code>plugins</code> 選項擴展功能</li>
</ul>



<h2 class="wp-block-heading">部署與最佳實踐</h2>



<p>在將 Agent 部署到正式環境前，以下幾點建議能幫助你建構更穩定、更安全的 Agent：</p>



<ul class="wp-block-list">
<li><strong>最小權限原則</strong>：只授權 Agent 真正需要的工具，避免使用 <code>bypassPermissions</code>（除非在完全隔離的沙箱環境中）</li>



<li><strong>使用 Hooks 記錄操作</strong>：透過 <code>PostToolUse</code> Hook 建立完整的稽核軌跡，方便追蹤問題</li>



<li><strong>設定 System Prompt</strong>：為 Agent 提供明確的角色定義與行為準則，提升輸出品質的一致性</li>



<li><strong>善用 Session 管理</strong>：在需要多步驟的任務中使用 Session 保持上下文，避免重複讀取相同的檔案</li>



<li><strong>錯誤處理</strong>：Agent 可能會遇到工具執行失敗的情況，確保你的程式碼能妥善處理這些情境</li>



<li><strong>容器化部署</strong>：Agent SDK 支援 Docker 部署，建議在容器中執行以獲得更好的隔離性</li>
</ul>



<h2 class="wp-block-heading">延伸閱讀</h2>



<p>想要深入了解 Claude Agent SDK 的更多功能，可以參考以下官方資源：</p>



<ul class="wp-block-list">
<li><a href="https://platform.claude.com/docs/en/agent-sdk/overview" rel="nofollow noopener" target="_blank">Agent SDK 官方文件</a>：完整的 API 參考與概念說明</li>



<li><a href="https://platform.claude.com/docs/en/agent-sdk/quickstart" rel="nofollow noopener" target="_blank">Quickstart 快速入門</a>：在幾分鐘內建立你的第一個 Agent</li>



<li><a href="https://github.com/anthropics/claude-agent-sdk-typescript" rel="nofollow noopener" target="_blank">TypeScript SDK GitHub</a>：原始碼、Issue 追蹤與更新日誌</li>



<li><a href="https://github.com/anthropics/claude-agent-sdk-python" rel="nofollow noopener" target="_blank">Python SDK GitHub</a>：原始碼與社群貢獻</li>



<li><a href="https://github.com/anthropics/claude-agent-sdk-demos" rel="nofollow noopener" target="_blank">範例 Agent 專案</a>：Email 助理、研究代理等實用範例</li>



<li><a href="https://platform.claude.com/docs/en/agent-sdk/hooks" rel="nofollow noopener" target="_blank">Hooks 進階教學</a>：深入了解 Hook 機制與進階用法</li>



<li><a href="https://platform.claude.com/docs/en/agent-sdk/mcp" rel="nofollow noopener" target="_blank">MCP 整合指南</a>：連接外部系統的完整說明</li>
</ul>



<h2 class="wp-block-heading">總結</h2>



<p>Claude Agent SDK 為開發者提供了一個強大的框架，讓你能以程式化方式建構具有自主能力的 AI Agent。無論是自動化程式碼審查、Bug 修復、測試執行，還是與外部系統整合，Agent SDK 都能勝任。它的設計哲學是「讓 Claude 自主處理工具呼叫」，你只需定義目標與限制，Claude 會自動規劃與執行所需的步驟。</p>



<p>從本系列的第一篇到現在的第二十篇，我們已經走過了 Claude Code 的完整旅程——從基礎安裝、CLI 指令、Context 管理到 Hooks、Plugins，一直到今天的 Agent SDK。掌握了這些知識，你已經具備了在開發流程中充分運用 AI 能力的基礎。接下來，就是動手實踐的時候了！</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-getting-started%2F&amp;linkname=Claude%20Agent%20SDK%20%E5%85%A5%E9%96%80%EF%BC%9A%E5%BB%BA%E6%A7%8B%E4%BD%A0%E7%9A%84%20AI%20Agent" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-getting-started%2F&amp;linkname=Claude%20Agent%20SDK%20%E5%85%A5%E9%96%80%EF%BC%9A%E5%BB%BA%E6%A7%8B%E4%BD%A0%E7%9A%84%20AI%20Agent" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-getting-started%2F&amp;linkname=Claude%20Agent%20SDK%20%E5%85%A5%E9%96%80%EF%BC%9A%E5%BB%BA%E6%A7%8B%E4%BD%A0%E7%9A%84%20AI%20Agent" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fclaude-agent-sdk-getting-started%2F&#038;title=Claude%20Agent%20SDK%20%E5%85%A5%E9%96%80%EF%BC%9A%E5%BB%BA%E6%A7%8B%E4%BD%A0%E7%9A%84%20AI%20Agent" data-a2a-url="https://blog.che-ya.com/claude-agent-sdk-getting-started/" data-a2a-title="Claude Agent SDK 入門：建構你的 AI Agent"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.che-ya.com/claude-agent-sdk-getting-started/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Injection（SQL 注入防範）</title>
		<link>https://blog.che-ya.com/sql-injection/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Sat, 02 May 2026 01:27:00 +0000</pubDate>
				<category><![CDATA[SQL 基礎]]></category>
		<category><![CDATA[SQL 教學]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=605</guid>

					<description><![CDATA[什麼是 SQL Injection（What is SQL Injection） 這篇 SQL Injecti ... <a title="SQL Injection（SQL 注入防範）" class="read-more" href="https://blog.che-ya.com/sql-injection/" aria-label="Read more about SQL Injection（SQL 注入防範）">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">什麼是 SQL Injection（What is SQL Injection）</h2>



<p>這篇 SQL Injection 教學將帶你認識 SQL 注入攻擊的原理與防範方式。SQL Injection（SQL 注入）是一種常見且危險的網路攻擊手法，攻擊者透過在使用者輸入欄位中插入惡意的 SQL 程式碼，使資料庫執行非預期的操作。</p>



<p>透過 SQL Injection，攻擊者可以繞過登入驗證、竃取或篤改資料庫中的機密資料、刪除整個資料表，甚至控制整台伺服器。由於許多網站和應用程式都依賴 SQL 資料庫，因此理解並防範 SQL Injection 是每位開發者必備的資安知識。</p>



<h2 class="wp-block-heading">SQL Injection 攻擊原理（How SQL Injection Works）</h2>



<p>SQL Injection 的核心原理是：當應用程式將使用者輸入的內容直接拼接到 SQL 查詢字串中，而沒有進行驗證或處理時，攻擊者就可以透過特殊字元來改變 SQL 語句的邏輯。</p>



<p>假設有一個登入表單，後端程式使用以下方式驗證使用者身份：</p>



<pre class="wp-block-code"><code class="">-- 後端程式直接拼接使用者輸入
SELECT * FROM users
WHERE username = '' + input_username + ''
AND password = '' + input_password + '';</code></pre>



<p>當使用者正常輸入帳號 admin 和密碼 1234 時，SQL 查詢如下：</p>



<pre class="wp-block-code"><code class="">SELECT * FROM users
WHERE username = 'admin'
AND password = '1234';</code></pre>



<p>這是正常的查詢，沒有任何問題。但如果攻擊者在帳號欄位輸入以下內容：</p>



<pre class="wp-block-code"><code class="">-- 攻擊者在帳號欄位輸入：
' OR '1'='1' --</code></pre>



<p>那麼拼接後的 SQL 語句就會變成：</p>



<pre class="wp-block-code"><code class="">SELECT * FROM users
WHERE username = '' OR '1'='1' --'
AND password = '';</code></pre>



<p>由於 <code>'1'='1'</code> 永遠為 TRUE，而 <code>--</code> 是 SQL 的註解符號會忽略後面的密碼驗證，因此這個查詢會回傳所有使用者資料，攻擊者就能不需要密碼就成功登入。</p>



<h2 class="wp-block-heading">常見 SQL Injection 攻擊類型（Common SQL Injection Types）</h2>



<figure class="wp-block-table"><table><thead><tr><th>攻擊類型</th><th>說明</th></tr></thead><tbody><tr><td>Classic SQL Injection</td><td>直接在輸入欄位插入惡意 SQL，立即看到攻擊結果</td></tr><tr><td>Blind SQL Injection</td><td>應用程式不會顯示錯誤訊息，攻擊者透過 TRUE/FALSE 回應推測資料</td></tr><tr><td>Union-based Injection</td><td>利用 UNION 合併額外的 SELECT 查詢來竃取資料</td></tr><tr><td>Time-based Injection</td><td>透過 SQL 延遲函數（如 SLEEP）判斷條件是否成立</td></tr><tr><td>Error-based Injection</td><td>利用資料庫的錯誤訊息來獲取資料庫結構資訊</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">SQL Injection 攻擊範例（SQL Injection Examples）</h2>



<h3 class="wp-block-heading">繞過登入驗證</h3>



<p>假設有一個使用者資料表 users 如下（若需了解如何建立資料表，請參考 <a href="https://blog.che-ya.com/create-table/">CREATE TABLE 教學</a>）：</p>



<figure class="wp-block-table"><table><thead><tr><th>id</th><th>username</th><th>password</th><th>role</th></tr></thead><tbody><tr><td>1</td><td>admin</td><td>a1b2c3d4</td><td>admin</td></tr><tr><td>2</td><td>john</td><td>pass123</td><td>user</td></tr><tr><td>3</td><td>mary</td><td>mary5678</td><td>user</td></tr></tbody></table></figure>



<p>攻擊者在登入表單的帳號欄位輸入以下內容，密碼欄位隨便輸入：</p>



<pre class="wp-block-code"><code class="">-- 帳號欄位輸入：
admin' --

-- 產生的 SQL：
SELECT * FROM users
WHERE username = 'admin' --'
AND password = 'anything';</code></pre>



<p><code>--</code> 後面的密碼驗證被註解掉，攻擊者直接以 admin 身份登入，不需要知道密碼。</p>



<h3 class="wp-block-heading">竃取其他資料表的資料</h3>



<p>攻擊者可以利用 UNION 合併查詢來竃取其他資料表的內容。假設網站有一個商品查詢功能：</p>



<pre class="wp-block-code"><code class="">-- 原始查詢（依照商品名稱搜尋）
SELECT name, price FROM products
WHERE name LIKE '%輸入內容%';

-- 攻擊者輸入：
' UNION SELECT username, password FROM users --

-- 產生的 SQL：
SELECT name, price FROM products
WHERE name LIKE '%' UNION SELECT username, password FROM users --%';</code></pre>



<p>這樣攻擊者就能在商品清單的頁面上看到所有使用者的帳號和密碼。這就是 UNION-based SQL Injection 的典型攻擊方式。</p>



<h3 class="wp-block-heading">刪除資料表</h3>



<p>更危險的情況是，攻擊者可以過注入破壞性的 SQL 指令：</p>



<pre class="wp-block-code"><code class="">-- 攻擊者輸入：
'; DROP TABLE users; --

-- 產生的 SQL：
SELECT * FROM users
WHERE username = ''; DROP TABLE users; --'
AND password = '';</code></pre>



<p>如果資料庫支援多行指令執行，整個 users 資料表就會被刪除，造成無法挖回的損失。</p>



<h2 class="wp-block-heading">SQL Injection 防範方法（How to Prevent SQL Injection）</h2>



<p>防範 SQL Injection 最重要的原則是：<strong>永遠不要將使用者輸入的內容直接拼接到 SQL 查詢字串中</strong>。以下是幾種主要的防範方法：</p>



<h3 class="wp-block-heading">參數化查詢（Parameterized Queries）</h3>



<p>參數化查詢（也稱為 Prepared Statements）是防範 SQL Injection 最有效且最推薦的方法。它將 SQL 查詢的結構和資料分開處理，資料庫會將參數視為純資料，而不是 SQL 指令的一部分。</p>



<p>以下是不同程式語言使用參數化查詢的範例：</p>



<pre class="wp-block-code"><code class="">-- ✘ 不安全的寫法（字串拼接）
SELECT * FROM users
WHERE username = '' + input + '';

-- ✔ 安全的寫法（參數化查詢）
SELECT * FROM users
WHERE username = ?;</code></pre>



<p>各種程式語言的實作方式：</p>



<pre class="wp-block-code"><code class=""># Python (MySQL Connector)
cursor.execute(
    "SELECT * FROM users WHERE username = %s AND password = %s",
    (input_username, input_password)
)</code></pre>



<pre class="wp-block-code"><code class="">// PHP (PDO)
$stmt = $pdo->prepare(
    "SELECT * FROM users WHERE username = :username AND password = :password"
);
$stmt->execute([
    ':username' => $input_username,
    ':password' => $input_password
]);</code></pre>



<pre class="wp-block-code"><code class="">// Java (JDBC)
PreparedStatement stmt = conn.prepareStatement(
    "SELECT * FROM users WHERE username = ? AND password = ?"
);
stmt.setString(1, inputUsername);
stmt.setString(2, inputPassword);
ResultSet rs = stmt.executeQuery();</code></pre>



<pre class="wp-block-code"><code class="">// Node.js (mysql2)
const [rows] = await connection.execute(
    'SELECT * FROM users WHERE username = ? AND password = ?',
    [inputUsername, inputPassword]
);</code></pre>



<p>當使用參數化查詢時，即使攻擊者輸入 <code>' OR '1'='1' --</code>，資料庫也只會將它當作普通的字串資料來比對，而不會執行其中的 SQL 指令。</p>



<h3 class="wp-block-heading">輸入驗證與過濾（Input Validation）</h3>



<p>除了參數化查詢之外，對使用者輸入的內容進行驗證和過濾也是重要的防範層。常見的做法包括：</p>



<figure class="wp-block-table"><table><thead><tr><th>驗證方式</th><th>說明</th><th>範例</th></tr></thead><tbody><tr><td>白名單驗證</td><td>只允許特定格式的輸入</td><td>帳號只允許英文字母和數字</td></tr><tr><td>長度限制</td><td>限制輸入字串的最大長度</td><td>帳號最多 20 個字元</td></tr><tr><td>特殊字元轉義</td><td>將单引號等特殊字元進行轉義</td><td>將 &#8216; 轉為 &#8221;</td></tr><tr><td>型別檢查</td><td>確保輸入符合預期的資料型別</td><td>ID 參數必須是整數</td></tr></tbody></table></figure>



<pre class="wp-block-code"><code class=""># Python 輸入驗證範例
import re

def validate_username(username):
    # 只允許英文字母、數字和底線，長度 3-20
    if re.match(r'^[a-zA-Z0-9_]{3,20}$', username):
        return True
    return False

def validate_id(user_id):
    # 確保是正整數
    try:
        return int(user_id) > 0
    except ValueError:
        return False</code></pre>



<p>注意：輸入驗證應該作為額外的防護層，不能取代參數化查詢。因為単純的過濾可能被繞過，而參數化查詢才是根本的解決方案。</p>



<h3 class="wp-block-heading">最小權限原則（Least Privilege）</h3>



<p>資料庫帳號應該只給予應用程式必要的權限。例如，如果應用程式只需要讀取資料，就不要給予 DELETE 或 DROP 的權限：</p>



<pre class="wp-block-code"><code class="">-- 建立只有讀取權限的資料庫帳號
CREATE USER 'app_readonly'@'localhost'
IDENTIFIED BY 'strong_password';

-- 只給予 SELECT 權限
GRANT SELECT ON mydb.* TO 'app_readonly'@'localhost';

-- 如果需要寫入，只給必要的權限
GRANT SELECT, INSERT, UPDATE ON mydb.orders
TO 'app_write'@'localhost';</code></pre>



<p>即使攻擊者成功注入 SQL，也無法執行超出權限範圍的操作，例如無法 DROP TABLE 或存取其他資料庫。</p>



<h3 class="wp-block-heading">使用 ORM（Object-Relational Mapping）</h3>



<p>現代的網頁框架通常提供 ORM 工具，它會自動使用參數化查詢來存取資料庫，大幅降低 SQL Injection 的風險：</p>



<pre class="wp-block-code"><code class=""># Python Django ORM
# ✔ 安全：ORM 自動處理參數化
user = User.objects.filter(
    username=input_username,
    password=input_password
).first()

# ✘ 不安全：直接使用 raw SQL 拼接
User.objects.raw(
    "SELECT * FROM users WHERE username = '" + input_username + "'"
)</code></pre>



<h2 class="wp-block-heading">錯誤訊息處理（Error Handling）</h2>



<p>在正式環境中，不應該將資料庫的詳細錯誤訊息顯示給使用者。因為攻擊者可以利用這些資訊來推測資料庫的結構，進而發動更精準的攻擊。</p>



<pre class="wp-block-code"><code class=""># ✘ 不安全：顯示詳細錯誤訊息
try:
    cursor.execute(query)
except Exception as e:
    return str(e)  # 暴露資料庫結構資訊

# ✔ 安全：回傳通用錯誤訊息
try:
    cursor.execute(query)
except Exception as e:
    logging.error(f"Database error: {e}")  # 記錄到日誌
    return "系統發生錯誤，請稍後再試"  # 給使用者看的</code></pre>



<h2 class="wp-block-heading">防範方法整理表（Prevention Summary）</h2>



<figure class="wp-block-table"><table><thead><tr><th>防範方法</th><th>效果</th><th>優先級</th></tr></thead><tbody><tr><td>參數化查詢</td><td>從根本上防止 SQL 注入，將資料與指令分離</td><td>★★★ 必要</td></tr><tr><td>輸入驗證</td><td>過濾不合法的輸入，提供額外保護</td><td>★★★ 必要</td></tr><tr><td>最小權限</td><td>限制攻擊成功後的危害範圍</td><td>★★ 建議</td></tr><tr><td>使用 ORM</td><td>自動處理參數化，減少人為疏失</td><td>★★ 建議</td></tr><tr><td>錯誤訊息處理</td><td>避免洩漏資料庫結構資訊</td><td>★★ 建議</td></tr><tr><td>定期更新與檢測</td><td>保持軟體更新，使用安全掃描工具</td><td>★ 加分</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">延伸閱讀</h2>



<ul class="wp-block-list">
<li><a href="https://blog.che-ya.com/sql-tutorial/">SQL 教學 — 完整 SQL 語法教學</a></li>



<li><a href="https://blog.che-ya.com/sql-select/">SQL SELECT — 資料查詢語法</a></li>



<li><a href="https://blog.che-ya.com/sql-where/">SQL WHERE — 條件查詢教學</a></li>



<li><a href="https://blog.che-ya.com/sql-subquery/">SQL Subquery — 子查詢教學</a></li>



<li><a href="https://blog.che-ya.com/sql-union/">SQL UNION — 合併查詢教學</a></li>



<li><a href="https://blog.che-ya.com/sql-view/">SQL VIEW — 檢視表教學</a></li>



<li><a href="https://blog.che-ya.com/create-table/">CREATE TABLE — 建立資料表</a></li>



<li><a href="https://blog.che-ya.com/sql-constraints/">SQL Constraints — 資料約束教學</a></li>
</ul>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fsql-injection%2F&amp;linkname=SQL%20Injection%EF%BC%88SQL%20%E6%B3%A8%E5%85%A5%E9%98%B2%E7%AF%84%EF%BC%89" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fsql-injection%2F&amp;linkname=SQL%20Injection%EF%BC%88SQL%20%E6%B3%A8%E5%85%A5%E9%98%B2%E7%AF%84%EF%BC%89" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fsql-injection%2F&amp;linkname=SQL%20Injection%EF%BC%88SQL%20%E6%B3%A8%E5%85%A5%E9%98%B2%E7%AF%84%EF%BC%89" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fsql-injection%2F&#038;title=SQL%20Injection%EF%BC%88SQL%20%E6%B3%A8%E5%85%A5%E9%98%B2%E7%AF%84%EF%BC%89" data-a2a-url="https://blog.che-ya.com/sql-injection/" data-a2a-title="SQL Injection（SQL 注入防範）"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>用 Python 開發 MCP Server</title>
		<link>https://blog.che-ya.com/python-mcp-server/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Fri, 01 May 2026 01:33:00 +0000</pubDate>
				<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=860</guid>

					<description><![CDATA[在前一篇文章中，我們學會了如何使用現有的 MCP Server 來擴展 Claude 的能力。但如果現有的 S ... <a title="用 Python 開發 MCP Server" class="read-more" href="https://blog.che-ya.com/python-mcp-server/" aria-label="Read more about 用 Python 開發 MCP Server">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>在前一篇文章中，我們學會了如何使用現有的 MCP Server 來擴展 Claude 的能力。但如果現有的 Server 無法滿足你的需求，或者你想為團隊打造專屬的工具整合，那就需要自己動手開發 MCP Server 了。本篇將帶你使用 Python 搭配官方的 MCP SDK 與 FastMCP 框架，從零開始建構一個功能完整的 MCP Server。</p>



<h2 class="wp-block-heading">為什麼選擇 Python 開發 MCP Server</h2>



<p>MCP Server 可以使用多種語言開發，官方提供了 TypeScript 和 Python 兩套 SDK。選擇 Python 有幾個明確的優勢：</p>



<ul class="wp-block-list">
<li><strong>語法簡潔直覺</strong>：Python 的 decorator 語法讓定義 Tool 和 Resource 變得非常優雅，幾行程式碼就能完成一個工具</li>



<li><strong>豐富的生態系</strong>：Python 擁有大量的資料處理、機器學習、網路爬蟲等套件，開發 MCP Server 時可以直接整合這些能力</li>



<li><strong>FastMCP 框架</strong>：官方 SDK 內建的 FastMCP 框架大幅簡化了開發流程，用類似 Flask 的寫法就能建立 Server</li>



<li><strong>廣泛的使用者基礎</strong>：Python 是全球最受歡迎的程式語言之一，團隊成員更容易上手維護</li>



<li><strong>快速原型開發</strong>：Python 的動態特性讓你能快速驗證想法，適合敏捷開發流程</li>
</ul>



<h2 class="wp-block-heading">環境準備與安裝</h2>



<p>在開始之前，請確認你的開發環境已準備就緒。MCP Python SDK 需要 Python 3.10 以上的版本，建議使用 <code>uv</code> 作為套件管理工具，因為它速度更快且是 MCP 官方推薦的方案。</p>



<h3 class="wp-block-heading">安裝 uv 套件管理工具</h3>



<pre class="wp-block-code"><code class=""># macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# 驗證安裝
uv --version</code></pre>



<h3 class="wp-block-heading">建立專案與安裝 SDK</h3>



<pre class="wp-block-code"><code class=""># 建立專案目錄
mkdir my-mcp-server
cd my-mcp-server

# 初始化 Python 專案
uv init

# 安裝 MCP Python SDK（內含 FastMCP）
uv add "mcp[cli]"

# 如需額外的 HTTP 功能
uv add httpx</code></pre>



<p>安裝完成後，你的 <code>pyproject.toml</code> 會自動加入 <code>mcp</code> 作為依賴項。MCP Python SDK 的核心模組就是 <code>FastMCP</code>，它是整個開發體驗的基礎。</p>



<h2 class="wp-block-heading">認識 FastMCP 框架</h2>



<p>FastMCP 是 MCP Python SDK 的核心框架，它的設計理念類似 Python 的 Web 框架（如 Flask、FastAPI），透過 decorator 來註冊各種功能。FastMCP 最初由社群開發，後來被納入官方 SDK，現已成為 Python 開發 MCP Server 的標準方式。</p>



<p>一個最基本的 MCP Server 只需要幾行程式碼：</p>



<pre class="wp-block-code"><code class="">from mcp.server.fastmcp import FastMCP

# 建立 MCP Server 實例
mcp = FastMCP("my-server")

# 定義一個簡單的 Tool
@mcp.tool()
def hello(name: str) -&gt; str:
    """向指定的人打招呼"""
    return f"你好，{name}！歡迎使用 MCP Server。"

# 啟動 Server
if __name__ == "__main__":
    mcp.run()</code></pre>



<p>這段程式碼展示了 FastMCP 的核心概念：建立實例、用 decorator 註冊功能、啟動伺服器。FastMCP 會自動根據函式的型別標註（type hints）和 docstring 產生 MCP 協定所需的 schema，你不需要手動撰寫 JSON Schema。</p>



<h2 class="wp-block-heading">MCP Server 的三大核心功能</h2>



<p>MCP 協定定義了三種主要的功能類型，每種都有不同的用途和使用場景：</p>



<figure class="wp-block-table"><table><thead><tr><th>功能類型</th><th>說明</th><th>類比</th><th>使用場景</th></tr></thead><tbody><tr><td>Tools</td><td>可被 AI 呼叫的函式，會產生副作用或執行運算</td><td>類似 POST API</td><td>執行查詢、發送通知、操作資料庫</td></tr><tr><td>Resources</td><td>提供資料給 AI 讀取，類似檔案或 API 端點</td><td>類似 GET API</td><td>讀取設定檔、載入資料集、取得狀態</td></tr><tr><td>Prompts</td><td>預定義的提示詞範本，引導 AI 執行特定任務</td><td>類似訊息範本</td><td>程式碼審查、報告產生、文件摘要</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">定義 Tools（工具）</h2>



<p>Tools 是 MCP Server 最常用的功能，它讓 AI 能夠呼叫你定義的函式來執行各種操作。定義 Tool 的關鍵在於提供清楚的型別標註和 docstring，因為 FastMCP 會將這些資訊轉換為 AI 可以理解的描述。</p>



<pre class="wp-block-code"><code class="">from mcp.server.fastmcp import FastMCP
import httpx
import json

mcp = FastMCP("weather-server")

@mcp.tool()
async def get_weather(city: str, unit: str = "celsius") -&gt; str:
    """查詢指定城市的天氣資訊
    
    Args:
        city: 城市名稱，例如 "Taipei" 或 "Tokyo"
        unit: 溫度單位，可選 "celsius" 或 "fahrenheit"，預設 celsius
    """
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.weatherapi.com/v1/current.json",
            params={"q": city, "key": "YOUR_API_KEY"}
        )
        data = response.json()
        temp = data["current"]["temp_c"] if unit == "celsius" else data["current"]["temp_f"]
        condition = data["current"]["condition"]["text"]
        return f"{city} 目前天氣：{condition}，溫度 {temp}°{'C' if unit == 'celsius' else 'F'}"

@mcp.tool()
def calculate_bmi(weight_kg: float, height_cm: float) -&gt; str:
    """計算身體質量指數（BMI）
    
    Args:
        weight_kg: 體重（公斤）
        height_cm: 身高（公分）
    """
    height_m = height_cm / 100
    bmi = weight_kg / (height_m ** 2)
    if bmi &lt; 18.5:
        category = "體重過輕"
    elif bmi &lt; 24:
        category = "正常範圍"
    elif bmi &lt; 27:
        category = "過重"
    else:
        category = "肥胖"
    return f"BMI: {bmi:.1f}（{category}）"</code></pre>



<p>上面的範例展示了幾個重要的 Tool 開發技巧：</p>



<ul class="wp-block-list">
<li><strong>型別標註是必要的</strong>：FastMCP 透過型別標註來產生 JSON Schema，告訴 AI 每個參數的型別</li>



<li><strong>docstring 就是描述</strong>：函式的 docstring 會成為 Tool 的說明文字，AI 會依此判斷何時該使用這個工具</li>



<li><strong>支援 async</strong>：對於需要網路請求的 Tool，建議使用 async 函式來提升效能</li>



<li><strong>預設值會變成可選參數</strong>：有預設值的參數在 Schema 中會被標記為 optional</li>
</ul>



<h2 class="wp-block-heading">定義 Resources（資源）</h2>



<p>Resources 用來向 AI 提供可讀取的資料，它的角色類似 REST API 的 GET 端點。每個 Resource 都有一個唯一的 URI，AI 可以透過這個 URI 來存取資料。</p>



<pre class="wp-block-code"><code class="">import json
from pathlib import Path
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("data-server")

# 靜態資源：固定 URI
@mcp.resource("config://app-settings")
def get_app_settings() -&gt; str:
    """取得應用程式的設定資訊"""
    settings = {
        "app_name": "MyApp",
        "version": "2.1.0",
        "environment": "production",
        "features": ["auth", "logging", "cache"]
    }
    return json.dumps(settings, indent=2, ensure_ascii=False)

# 動態資源：URI 中包含參數
@mcp.resource("file://logs/{date}")
def get_log_by_date(date: str) -&gt; str:
    """讀取指定日期的 log 檔案
    
    Args:
        date: 日期格式為 YYYY-MM-DD
    """
    log_path = Path(f"/var/log/app/{date}.log")
    if log_path.exists():
        return log_path.read_text()
    return f"找不到 {date} 的 log 檔案"

# Resource Template：動態產生資源清單
@mcp.resource("db://users/{user_id}")
def get_user(user_id: int) -&gt; str:
    """根據 ID 查詢使用者資訊"""
    # 模擬資料庫查詢
    users = {
        1: {"name": "Alice", "role": "admin"},
        2: {"name": "Bob", "role": "user"}
    }
    user = users.get(user_id)
    if user:
        return json.dumps(user, ensure_ascii=False)
    return f"找不到 ID 為 {user_id} 的使用者"</code></pre>



<h2 class="wp-block-heading">定義 Prompts（提示範本）</h2>



<p>Prompts 是預先定義好的提示詞範本，讓使用者可以快速啟動特定的 AI 工作流程。它不像 Tool 是由 AI 自動決定呼叫，而是由使用者主動選擇觸發。</p>



<pre class="wp-block-code"><code class="">from mcp.server.fastmcp import FastMCP

mcp = FastMCP("code-review-server")

@mcp.prompt()
def code_review(code: str, language: str = "python") -&gt; str:
    """產生程式碼審查的提示詞
    
    Args:
        code: 需要審查的程式碼
        language: 程式語言，預設 python
    """
    return f"""請審查以下 {language} 程式碼，並提供改善建議：

```{language}
{code}
```

請從以下面向進行審查：
1. 程式碼品質與可讀性
2. 潛在的 Bug 或安全性問題
3. 效能最佳化建議
4. 是否符合 {language} 的最佳實踐"""

@mcp.prompt()
def summarize_doc(content: str, max_words: int = 200) -&gt; str:
    """產生文件摘要的提示詞"""
    return f"請將以下內容摘要為不超過 {max_words} 字的重點整理：\n\n{content}"</code></pre>



<h2 class="wp-block-heading">完整範例：專案管理 MCP Server</h2>



<p>接下來，我們用一個實際的專案管理工具來展示如何結合 Tools、Resources 和 Prompts 開發一個功能完整的 MCP Server。這個範例模擬了一個簡單的 TODO 管理系統。</p>



<pre class="wp-block-code"><code class="">from mcp.server.fastmcp import FastMCP
from datetime import datetime
import json

# 建立 Server 並設定相依套件
mcp = FastMCP(
    "todo-manager",
    dependencies=["httpx"]
)

# 模擬的任務資料庫
tasks: dict[int, dict] = {}
next_id = 1

# ===== Tools =====

@mcp.tool()
def add_task(title: str, priority: str = "medium") -&gt; str:
    """新增一個待辦任務
    
    Args:
        title: 任務標題
        priority: 優先級，可選 high、medium、low
    """
    global next_id
    task = {
        "id": next_id,
        "title": title,
        "priority": priority,
        "status": "pending",
        "created_at": datetime.now().isoformat()
    }
    tasks[next_id] = task
    next_id += 1
    return f"已新增任務：{title}（ID: {task['id']}）"

@mcp.tool()
def complete_task(task_id: int) -&gt; str:
    """將指定任務標記為完成
    
    Args:
        task_id: 任務 ID
    """
    if task_id not in tasks:
        return f"找不到 ID 為 {task_id} 的任務"
    tasks[task_id]["status"] = "completed"
    return f"任務 {tasks[task_id]['title']} 已標記為完成"

@mcp.tool()
def delete_task(task_id: int) -&gt; str:
    """刪除指定的任務
    
    Args:
        task_id: 任務 ID
    """
    if task_id not in tasks:
        return f"找不到 ID 為 {task_id} 的任務"
    removed = tasks.pop(task_id)
    return f"已刪除任務：{removed['title']}"

# ===== Resources =====

@mcp.resource("todo://tasks")
def list_all_tasks() -&gt; str:
    """取得所有任務的清單"""
    return json.dumps(list(tasks.values()), indent=2, ensure_ascii=False)

@mcp.resource("todo://tasks/{task_id}")
def get_task_detail(task_id: int) -&gt; str:
    """取得單一任務的詳細資訊"""
    task = tasks.get(task_id)
    if task:
        return json.dumps(task, indent=2, ensure_ascii=False)
    return f"找不到 ID 為 {task_id} 的任務"

@mcp.resource("todo://stats")
def get_task_stats() -&gt; str:
    """取得任務統計資訊"""
    total = len(tasks)
    completed = sum(1 for t in tasks.values() if t["status"] == "completed")
    pending = total - completed
    return json.dumps({
        "total": total,
        "completed": completed,
        "pending": pending
    })

# ===== Prompts =====

@mcp.prompt()
def daily_summary() -&gt; str:
    """產生每日任務摘要的提示詞"""
    return "請根據目前的任務清單，產生今日的工作摘要報告，包含已完成和待處理的任務。"

if __name__ == "__main__":
    mcp.run()</code></pre>



<h2 class="wp-block-heading">在 Claude Code 中測試你的 Server</h2>



<p>開發完成後，你需要在 Claude Code 中實際測試 Server 的功能。MCP SDK 提供了多種測試方式。</p>



<h3 class="wp-block-heading">使用 MCP Inspector 測試</h3>



<p>MCP Inspector 是官方提供的視覺化測試工具，它提供了一個 Web 介面讓你可以互動式地測試每個 Tool、Resource 和 Prompt。</p>



<pre class="wp-block-code"><code class=""># 啟動 MCP Inspector
mcp dev server.py

# Inspector 預設會在 http://localhost:5173 開啟
# 你可以在介面中：
# - 查看所有已註冊的 Tools、Resources、Prompts
# - 手動輸入參數測試每個功能
# - 檢視回傳結果和錯誤訊息</code></pre>



<h3 class="wp-block-heading">直接加入 Claude Code</h3>



<p>確認功能正常後，就可以將 Server 加入 Claude Code 使用：</p>



<pre class="wp-block-code"><code class=""># 將 Server 加入 Claude Code（本地 stdio 模式）
claude mcp add todo-manager -- uv run server.py

# 如果使用 HTTP 傳輸模式
# 先啟動 Server
uv run server.py --transport http --port 8000

# 再加入 Claude Code
claude mcp add --transport http todo-manager http://localhost:8000/mcp

# 驗證 Server 已正確載入
claude mcp list</code></pre>



<p>加入成功後，你可以直接在 Claude Code 中使用自然語言與 Server 互動。例如，輸入「幫我新增一個高優先級的任務：完成 API 文件撰寫」，Claude 就會自動呼叫 <code>add_task</code> 工具來執行。</p>



<h2 class="wp-block-heading">Python vs TypeScript：該選哪個？</h2>



<p>MCP 官方同時提供了 Python 和 TypeScript 兩套 SDK，兩者都能開發功能完整的 MCP Server，但在開發體驗和適用場景上有一些差異：</p>



<figure class="wp-block-table"><table><thead><tr><th>比較項目</th><th>Python SDK</th><th>TypeScript SDK</th></tr></thead><tbody><tr><td>框架</td><td>FastMCP（decorator 風格）</td><td>McpServer（method chain 風格）</td></tr><tr><td>型別系統</td><td>動態型別 + type hints</td><td>靜態型別（Zod schema）</td></tr><tr><td>Schema 產生</td><td>自動從 type hints 和 docstring 產生</td><td>需手動定義 Zod schema</td></tr><tr><td>套件管理</td><td>uv / pip</td><td>npm / yarn</td></tr><tr><td>非同步支援</td><td>asyncio（原生支援）</td><td>Promise / async-await</td></tr><tr><td>適合場景</td><td>資料處理、ML 整合、快速原型</td><td>前端整合、Node.js 生態系</td></tr><tr><td>學習曲線</td><td>較低（Python 開發者友善）</td><td>中等（需熟悉 Zod）</td></tr><tr><td>程式碼量</td><td>較少（decorator 自動化程度高）</td><td>較多（需手動定義 schema）</td></tr></tbody></table></figure>



<p>簡單來說，如果你的團隊主要使用 Python，或者你需要整合資料處理和機器學習的功能，Python SDK 是更好的選擇。如果你的團隊以前端或 Node.js 為主，TypeScript SDK 會更自然。</p>



<h2 class="wp-block-heading">進階技巧：Context 與 Lifespan</h2>



<p>FastMCP 提供了一些進階功能，讓你能建構更複雜的 Server。</p>



<h3 class="wp-block-heading">使用 Context 存取 MCP 功能</h3>



<p>在 Tool 函式中，你可以透過 <code>Context</code> 物件來存取 MCP 的進階功能，例如回報進度、記錄日誌，或讀取其他 Resource。</p>



<pre class="wp-block-code"><code class="">from mcp.server.fastmcp import FastMCP, Context

mcp = FastMCP("advanced-server")

@mcp.tool()
async def process_data(file_path: str, ctx: Context) -&gt; str:
    """處理大量資料並回報進度
    
    Args:
        file_path: 資料檔案路徑
    """
    # 回報進度給 Client
    await ctx.report_progress(0, 100)
    
    # 記錄日誌
    await ctx.info(f"開始處理檔案：{file_path}")
    
    # 模擬處理過程
    for i in range(1, 101):
        # 處理資料...
        if i % 10 == 0:
            await ctx.report_progress(i, 100)
    
    await ctx.info("處理完成")
    return "資料處理完成，共處理 100 筆記錄"</code></pre>



<h3 class="wp-block-heading">使用 Lifespan 管理生命週期</h3>



<p>當你的 Server 需要管理外部連線（如資料庫連接池）時，可以使用 lifespan 來處理啟動和關閉時的初始化邏輯。</p>



<pre class="wp-block-code"><code class="">from contextlib import asynccontextmanager
from mcp.server.fastmcp import FastMCP

@asynccontextmanager
async def app_lifespan(server: FastMCP):
    """管理 Server 的生命週期"""
    # 啟動時執行：建立資料庫連線
    db = await create_db_connection()
    try:
        yield {"db": db}  # 將資源傳遞給 Tools
    finally:
        # 關閉時執行：釋放資源
        await db.close()

mcp = FastMCP("db-server", lifespan=app_lifespan)

@mcp.tool()
async def query_users(ctx: Context) -&gt; str:
    """查詢所有使用者"""
    db = ctx.request_context.lifespan_context["db"]
    users = await db.fetch_all("SELECT * FROM users")
    return json.dumps(users, ensure_ascii=False)</code></pre>



<h2 class="wp-block-heading">部署你的 MCP Server</h2>



<p>MCP Server 支援兩種主要的傳輸模式，各有不同的部署方式。</p>



<h3 class="wp-block-heading">stdio 模式（本地部署）</h3>



<p>stdio 是最簡單的部署方式，Server 作為本地行程執行，透過標準輸入/輸出與 Claude Code 溝通。適合個人使用或開發階段。</p>



<pre class="wp-block-code"><code class=""># server.py 的啟動方式
if __name__ == "__main__":
    mcp.run()  # 預設使用 stdio

# 加入 Claude Code
claude mcp add my-server -- uv run server.py</code></pre>



<h3 class="wp-block-heading">HTTP 模式（遠端部署）</h3>



<p>HTTP 模式（Streamable HTTP）適合部署到雲端服務器，讓多人可以共享同一個 MCP Server。這是目前官方推薦的遠端傳輸方式。</p>



<pre class="wp-block-code"><code class=""># server.py 使用 HTTP 模式啟動
if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

# 加入 Claude Code（連線到遠端 Server）
claude mcp add --transport http my-remote-server https://your-server.com/mcp</code></pre>



<h2 class="wp-block-heading">專案結構建議</h2>



<p>當你的 MCP Server 功能越來越多時，良好的專案結構能讓程式碼更容易維護。以下是建議的目錄配置：</p>



<pre class="wp-block-code"><code class="">my-mcp-server/
├── pyproject.toml                                # 專案設定與依賴管理
├── README.md                                    # 專案說明文件
├── src/
│   └── my_mcp_server/
│       ├── __init__.py
│       ├── server.py                                 # Server 主程式與 FastMCP 實例
│       ├── tools/                                       # Tools 定義
│       │   ├── __init__.py
│       │   ├── task_tools.py
│       │   └── data_tools.py
│       ├── resources/                               # Resources 定義
│       │   ├── __init__.py
│       │   └── data_resources.py
│       └── prompts/                                 # Prompts 定義
│           ├── __init__.py
│           └── review_prompts.py
└── tests/                                                  # 測試檔案
    ├── test_tools.py
    └── test_resources.py</code></pre>



<h2 class="wp-block-heading">常見問題與除錯技巧</h2>



<p>在開發 MCP Server 的過程中，你可能會遇到一些常見的問題。以下整理了幾個最常見的狀況和解決方法：</p>



<ul class="wp-block-list">
<li><strong>Tool 沒有出現在 Claude 中</strong>：確認 docstring 是否完整，FastMCP 需要 docstring 才能產生描述。同時檢查 <code>claude mcp list</code> 確認 Server 狀態為 running</li>



<li><strong>參數型別錯誤</strong>：確保所有參數都有型別標註，FastMCP 無法處理沒有標註的參數。使用 <code>int</code>、<code>str</code>、<code>float</code>、<code>bool</code> 等基本型別</li>



<li><strong>async 函式沒有正確執行</strong>：如果你的 Tool 使用了 async，確認所有呼叫鏈都是 async 的。混合使用同步和非同步可能導致執行卡住</li>



<li><strong>Server 啟動後立即退出</strong>：檢查是否有語法錯誤或 import 失敗。使用 <code>mcp dev server.py</code> 來查看詳細的錯誤訊息</li>



<li><strong>Resource URI 無法存取</strong>：確認 URI 格式正確，動態參數需要與函式參數名稱一致。例如 <code>file://logs/{date}</code> 對應函式參數 <code>date</code></li>
</ul>



<h2 class="wp-block-heading">總結</h2>



<p>使用 Python 開發 MCP Server 是擴展 Claude Code 能力最靈活的方式。透過 FastMCP 框架，你可以用簡潔的 decorator 語法快速定義 Tools、Resources 和 Prompts，不需要手動處理複雜的 MCP 協定細節。</p>



<p>本篇涵蓋了從環境建置、核心功能開發到測試部署的完整流程。你已經學會了如何建立 FastMCP 實例、定義三種核心功能類型、使用 Context 和 Lifespan 處理進階場景，以及如何在 Claude Code 中測試和部署你的 Server。</p>



<p>下一篇我們將進一步探討如何用 TypeScript 開發 MCP Server，並深入比較兩種語言在 MCP 開發上的實際體驗差異。如果你的需求偏向資料處理或 Python 生態系整合，現在就可以開始動手打造你的第一個 Python MCP Server 了。</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fpython-mcp-server%2F&amp;linkname=%E7%94%A8%20Python%20%E9%96%8B%E7%99%BC%20MCP%20Server" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fpython-mcp-server%2F&amp;linkname=%E7%94%A8%20Python%20%E9%96%8B%E7%99%BC%20MCP%20Server" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fpython-mcp-server%2F&amp;linkname=%E7%94%A8%20Python%20%E9%96%8B%E7%99%BC%20MCP%20Server" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fpython-mcp-server%2F&#038;title=%E7%94%A8%20Python%20%E9%96%8B%E7%99%BC%20MCP%20Server" data-a2a-url="https://blog.che-ya.com/python-mcp-server/" data-a2a-title="用 Python 開發 MCP Server"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>用 TypeScript 開發你的第一個 MCP Server</title>
		<link>https://blog.che-ya.com/typescript-mcp-server-development/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Thu, 30 Apr 2026 03:55:00 +0000</pubDate>
				<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[TypeScript]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=861</guid>

					<description><![CDATA[Model Context Protocol（MCP）是 Anthropic 推出的開放標準，讓 AI 模型能 ... <a title="用 TypeScript 開發你的第一個 MCP Server" class="read-more" href="https://blog.che-ya.com/typescript-mcp-server-development/" aria-label="Read more about 用 TypeScript 開發你的第一個 MCP Server">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>Model Context Protocol（MCP）是 Anthropic 推出的開放標準，讓 AI 模型能夠與外部工具和資料來源互動。透過開發自己的 MCP Server，你可以為 Claude Code 擴充無限可能：從查詢資料庫、操作 API、到整合內部系統，一切皆可實現。本篇文章將帶你從零開始，使用 TypeScript 與官方 <code>@modelcontextprotocol/sdk</code> 套件，打造你的第一個 MCP Server，並完成測試與部署。</p>



<h2 class="wp-block-heading">什麼是 MCP Server？</h2>



<p>MCP Server 是 Model Context Protocol 架構中的服務提供者角色。在 MCP 的架構中，Client（如 Claude Code）向 Server 發送請求，Server 負責提供三種核心能力：Tools（工具）、Resources（資源）和 Prompts（提示範本）。透過這個標準化的協議，AI 應用可以安全、一致地存取外部功能。</p>



<figure class="wp-block-table"><table><thead><tr><th>元件</th><th>角色</th><th>說明</th></tr></thead><tbody><tr><td>MCP Host</td><td>宿主應用</td><td>如 Claude Desktop、IDE 外掛，負責管理 Client 連線</td></tr><tr><td>MCP Client</td><td>協議客戶端</td><td>與 Server 建立一對一連線，傳遞請求與回應</td></tr><tr><td>MCP Server</td><td>服務提供者</td><td>暴露 Tools、Resources、Prompts 給 Client 使用</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">環境準備與套件安裝</h2>



<p>在開始開發之前，請確保你的開發環境已準備就緒。MCP TypeScript SDK 支援 Node.js、Bun 和 Deno 三種執行環境，本文以 Node.js 為主要範例。</p>



<h3 class="wp-block-heading">系統需求</h3>



<figure class="wp-block-table"><table><thead><tr><th>項目</th><th>最低版本</th><th>建議版本</th></tr></thead><tbody><tr><td>Node.js</td><td>18.0+</td><td>20 LTS 或 22 LTS</td></tr><tr><td>TypeScript</td><td>5.0+</td><td>5.5+</td></tr><tr><td>npm</td><td>9.0+</td><td>10+</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">建立專案與安裝套件</h3>



<p>首先建立一個新的 TypeScript 專案，並安裝 MCP SDK 與必要的開發工具：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash"># 建立專案資料夾
mkdir my-mcp-server
cd my-mcp-server

# 初始化專案
npm init -y

# 安裝 MCP SDK 與相關套件
npm install @modelcontextprotocol/sdk zod

# 安裝 TypeScript 開發工具
npm install -D typescript @types/node tsx

# 初始化 TypeScript 設定
npx tsc --init</code></pre>



<p>其中 <code>zod</code> 是用於定義工具參數驗證的 Schema 庫，MCP SDK 內建整合了 Zod，讓你可以輕鬆定義型別安全的工具輸入參數。</p>



<h3 class="wp-block-heading">TypeScript 設定檔</h3>



<p>修改 <code>tsconfig.json</code>，確保編譯設定適合 MCP Server 開發：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true
  },
  "include": ["src/**/*"]
}</code></pre>



<h3 class="wp-block-heading">package.json 設定</h3>



<p>在 <code>package.json</code> 中加入必要的設定，包括 ES Module 支援與執行腳本：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "name": "my-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "bin": {
    "my-mcp-server": "./dist/index.js"
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsx src/index.ts",
    "start": "node dist/index.js",
    "inspector": "npx @modelcontextprotocol/inspector node dist/index.js"
  }
}</code></pre>



<h2 class="wp-block-heading">建構你的第一個 MCP Server</h2>



<p>MCP SDK 提供了高階的 <code>McpServer</code> 類別，讓你可以快速建構 Server。以下我們會逐步介紹如何建立 Server 實例、註冊 Tools、Resources 和 Prompts。</p>



<h3 class="wp-block-heading">Server 基本架構</h3>



<p>建立 <code>src/index.ts</code> 檔案，撰寫 Server 的基本架構：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// 建立 MCP Server 實例
const server = new McpServer({
  name: "my-mcp-server",
  version: "1.0.0",
});

// 建立 stdio 傳輸層
const transport = new StdioServerTransport();

// 連接 Server 與 Transport
await server.connect(transport);

// 注意：使用 console.error() 輸出除錯訊息
// 絕對不要使用 console.log()，因為 stdout 是 MCP 通訊通道
console.error("MCP Server is running...");</code></pre>



<p>這裡有一個非常重要的觀念：MCP 使用 <code>stdout</code> 作為 JSON-RPC 通訊管道，因此你的 Server 中所有的除錯或日誌輸出都必須使用 <code>console.error()</code> 而非 <code>console.log()</code>，否則會破壞通訊協議。</p>



<h2 class="wp-block-heading">定義 Tools：讓 AI 執行動作</h2>



<p>Tools 是 MCP 中最常用的能力，讓 AI 模型可以呼叫你定義的函式來執行特定動作。每個 Tool 需要定義名稱、描述、輸入參數的 Schema，以及實際執行的處理函式。</p>



<h3 class="wp-block-heading">基本 Tool 定義</h3>



<p>使用 <code>server.tool()</code> 方法註冊一個工具。以下範例定義了一個簡單的加法計算工具：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { z } from "zod";

// 定義一個加法計算工具
server.tool(
  "add",
  "計算兩個數字的加總",
  {
    a: z.number().describe("第一個數字"),
    b: z.number().describe("第二個數字"),
  },
  async ({ a, b }) => {
    const result = a + b;
    return {
      content: [
        {
          type: "text",
          text: `計算結果：${a} + ${b} = ${result}`,
        },
      ],
    };
  }
);</code></pre>



<p><code>server.tool()</code> 方法接受四個參數：工具名稱、描述文字、使用 Zod 定義的輸入參數 Schema，以及非同步的處理函式。處理函式的回傳格式固定為包含 <code>content</code> 陣列的物件。</p>



<h3 class="wp-block-heading">進階 Tool：API 查詢範例</h3>



<p>以下是一個更實用的範例，透過 Tool 查詢外部 API 取得天氣資訊：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">server.tool(
  "get-weather",
  "查詢指定城市的天氣資訊",
  {
    city: z.string().describe("城市名稱，例如 Taipei"),
    unit: z.enum(["celsius", "fahrenheit"])
      .default("celsius")
      .describe("溫度單位"),
  },
  async ({ city, unit }) => {
    try {
      const response = await fetch(
        `https://api.weather.example/v1/current?city=${city}&amp;unit=${unit}`
      );
      const data = await response.json();

      return {
        content: [
          {
            type: "text",
            text: `${city} 目前天氣：${data.condition}，溫度 ${data.temperature}°${unit === "celsius" ? "C" : "F"}`,
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `查詢天氣失敗：${error.message}`,
          },
        ],
        isError: true,
      };
    }
  }
);</code></pre>



<p>注意錯誤處理的部分：當工具執行失敗時，回傳物件中加入 <code>isError: true</code> 可以讓 Client 知道這是一個錯誤回應，AI 模型會據此調整後續行為。</p>



<h3 class="wp-block-heading">Zod Schema 常用型別</h3>



<figure class="wp-block-table"><table><thead><tr><th>Zod 型別</th><th>說明</th><th>範例</th></tr></thead><tbody><tr><td><code>z.string()</code></td><td>字串型別</td><td><code>z.string().min(1).max(100)</code></td></tr><tr><td><code>z.number()</code></td><td>數字型別</td><td><code>z.number().int().positive()</code></td></tr><tr><td><code>z.boolean()</code></td><td>布林型別</td><td><code>z.boolean().default(false)</code></td></tr><tr><td><code>z.enum()</code></td><td>列舉型別</td><td><code>z.enum(["a", "b", "c"])</code></td></tr><tr><td><code>z.array()</code></td><td>陣列型別</td><td><code>z.array(z.string())</code></td></tr><tr><td><code>z.object()</code></td><td>物件型別</td><td><code>z.object({ key: z.string() })</code></td></tr><tr><td><code>z.optional()</code></td><td>可選參數</td><td><code>z.string().optional()</code></td></tr></tbody></table></figure>



<h2 class="wp-block-heading">定義 Resources：提供資料給 AI</h2>



<p>Resources 讓你的 MCP Server 可以向 AI 模型提供結構化的資料。與 Tools 不同的是，Resources 是被動讀取的資料來源，類似於 REST API 的 GET 端點。每個 Resource 透過 URI 識別，Client 可以列出並讀取可用的 Resources。</p>



<h3 class="wp-block-heading">靜態 Resource</h3>



<p>靜態 Resource 是最簡單的形式，提供固定 URI 的資料。使用 <code>server.resource()</code> 方法註冊：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">// 靜態 Resource：提供系統設定檔
server.resource(
  "config",
  "config://app/settings",
  async (uri) => {
    const config = {
      appName: "My Application",
      version: "2.0.0",
      environment: "production",
      features: ["auth", "logging", "cache"],
    };

    return {
      contents: [
        {
          uri: uri.href,
          mimeType: "application/json",
          text: JSON.stringify(config, null, 2),
        },
      ],
    };
  }
);</code></pre>



<h3 class="wp-block-heading">動態 Resource（ResourceTemplate）</h3>



<p>當你需要根據參數提供不同資料時，可以使用 <code>ResourceTemplate</code> 定義動態 Resource。URI 中的 <code>{參數名}</code> 會被自動解析：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";

// 動態 Resource：根據使用者 ID 提供使用者資料
server.resource(
  "user-profile",
  new ResourceTemplate("users://{userId}/profile", { list: undefined }),
  async (uri, { userId }) => {
    // 從資料庫或 API 查詢使用者資料
    const user = await getUserById(userId);

    return {
      contents: [
        {
          uri: uri.href,
          mimeType: "application/json",
          text: JSON.stringify({
            id: user.id,
            name: user.name,
            email: user.email,
            role: user.role,
          }, null, 2),
        },
      ],
    };
  }
);</code></pre>



<p><code>ResourceTemplate</code> 的第二個參數可以傳入 <code>{ list: undefined }</code>，表示這個動態 Resource 不支援列出所有可用的 URI。如果你想支援列出功能，可以傳入一個回傳 URI 陣列的函式。</p>



<h2 class="wp-block-heading">定義 Prompts：建立可重用的提示範本</h2>



<p>Prompts 讓你預先定義好結構化的對話範本，使用者或 Client 可以直接取用這些範本來進行特定類型的互動。這對於建立標準化的工作流程特別有用。</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">// 定義 Code Review Prompt 範本
server.prompt(
  "code-review",
  "進行程式碼審查的提示範本",
  {
    language: z.string().describe("程式語言"),
    code: z.string().describe("要審查的程式碼"),
    focus: z.enum(["security", "performance", "readability", "all"])
      .default("all")
      .describe("審查重點"),
  },
  async ({ language, code, focus }) => {
    const focusText = focus === "all"
      ? "安全性、效能與可讀性"
      : focus === "security" ? "安全性"
      : focus === "performance" ? "效能" : "可讀性";

    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `請審查以下 ${language} 程式碼，重點關注${focusText}：\n\n\`\`\`${language}\n${code}\n\`\`\`\n\n請提供具體的改善建議，包含修改後的程式碼範例。`,
          },
        },
      ],
    };
  }
);</code></pre>



<p>Prompts 的回傳格式是一個包含 <code>messages</code> 陣列的物件，每個 message 包含 <code>role</code>（user 或 assistant）和 <code>content</code>。這讓你可以建立多輪對話的範本。</p>



<h3 class="wp-block-heading">Tools、Resources、Prompts 比較</h3>



<figure class="wp-block-table"><table><thead><tr><th>特性</th><th>Tools</th><th>Resources</th><th>Prompts</th></tr></thead><tbody><tr><td>用途</td><td>執行動作、呼叫 API</td><td>提供資料給 AI 讀取</td><td>預定義對話範本</td></tr><tr><td>觸發方式</td><td>AI 模型主動呼叫</td><td>Client 讀取</td><td>使用者選取</td></tr><tr><td>類比</td><td>POST / PUT API</td><td>GET API</td><td>範本系統</td></tr><tr><td>副作用</td><td>可能有（修改資料）</td><td>無（唯讀）</td><td>無</td></tr><tr><td>參數定義</td><td>Zod Schema</td><td>URI Template</td><td>Zod Schema</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">完整範例專案：待辦事項 MCP Server</h2>



<p>以下是一個完整的待辦事項（Todo）MCP Server 範例，整合了 Tools、Resources 和 Prompts 三大功能，展示如何在實際專案中組織程式碼：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// 型別定義
interface Todo {
  id: string;
  title: string;
  completed: boolean;
  createdAt: string;
  priority: "low" | "medium" | "high";
}

// 模擬資料庫
const todos: Map<string, todo=""> = new Map();
let nextId = 1;

// 建立 Server
const server = new McpServer({
  name: "todo-mcp-server",
  version: "1.0.0",
});

// === Tools ===

// 新增待辦事項
server.tool(
  "add-todo",
  "新增一個待辦事項",
  {
    title: z.string().min(1).describe("待辦事項標題"),
    priority: z.enum(["low", "medium", "high"])
      .default("medium")
      .describe("優先順序"),
  },
  async ({ title, priority }) => {
    const id = String(nextId++);
    const todo: Todo = {
      id,
      title,
      completed: false,
      createdAt: new Date().toISOString(),
      priority,
    };
    todos.set(id, todo);

    return {
      content: [
        {
          type: "text",
          text: `已新增待辦事項 #${id}：${title}（優先度：${priority}）`,
        },
      ],
    };
  }
);

// 完成待辦事項
server.tool(
  "complete-todo",
  "將待辦事項標記為完成",
  {
    id: z.string().describe("待辦事項 ID"),
  },
  async ({ id }) => {
    const todo = todos.get(id);
    if (!todo) {
      return {
        content: [{ type: "text", text: `找不到 ID 為 ${id} 的待辦事項` }],
        isError: true,
      };
    }
    todo.completed = true;

    return {
      content: [
        {
          type: "text",
          text: `已完成待辦事項 #${id}：${todo.title}`,
        },
      ],
    };
  }
);

// === Resources ===

// 列出所有待辦事項
server.resource(
  "all-todos",
  "todo://list",
  async (uri) => ({
    contents: [
      {
        uri: uri.href,
        mimeType: "application/json",
        text: JSON.stringify([...todos.values()], null, 2),
      },
    ],
  })
);

// 查詢單一待辦事項
server.resource(
  "single-todo",
  new ResourceTemplate("todo://{id}", { list: undefined }),
  async (uri, { id }) => {
    const todo = todos.get(String(id));
    if (!todo) throw new Error(`Todo ${id} not found`);

    return {
      contents: [
        {
          uri: uri.href,
          mimeType: "application/json",
          text: JSON.stringify(todo, null, 2),
        },
      ],
    };
  }
);

// === Prompts ===

server.prompt(
  "daily-summary",
  "產生每日待辦事項摘要",
  {},
  async () => {
    const allTodos = [...todos.values()];
    const pending = allTodos.filter((t) => !t.completed);
    const completed = allTodos.filter((t) => t.completed);

    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `請根據以下待辦事項資料，產生今日工作摘要：\n\n待完成（${pending.length} 項）：\n${pending.map((t) => `- [${t.priority}] ${t.title}`).join("\n")}\n\n已完成（${completed.length} 項）：\n${completed.map((t) => `- ${t.title}`).join("\n")}\n\n請提供進度分析與建議。`,
          },
        },
      ],
    };
  }
);

// 啟動 Server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Todo MCP Server started!");</string,></code></pre>



<h2 class="wp-block-heading">測試與除錯</h2>



<p>完成 Server 開發後，測試是確保一切正常運作的關鍵步驟。MCP 生態系提供了多種測試工具，讓你可以在不同層級驗證 Server 的行為。</p>



<h3 class="wp-block-heading">使用 MCP Inspector 測試</h3>



<p>MCP Inspector 是官方提供的互動式測試工具，可以讓你在瀏覽器中直接測試 Server 的各項功能。它提供了視覺化的介面來列出和呼叫 Tools、讀取 Resources、以及測試 Prompts。</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash"># 使用 Inspector 測試你的 Server
npx @modelcontextprotocol/inspector node dist/index.js

# 如果使用 tsx 開發模式
npx @modelcontextprotocol/inspector npx tsx src/index.ts</code></pre>



<p>執行後會在瀏覽器開啟 Inspector 介面，你可以在左側看到 Server 提供的所有 Tools、Resources 和 Prompts，點選任一項目即可進行互動測試。</p>



<h3 class="wp-block-heading">撰寫單元測試</h3>



<p>對於正式專案，建議使用測試框架撰寫自動化測試。以下範例使用 Vitest 測試我們的 Todo Server：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">// tests/server.test.ts
import { describe, it, expect, beforeEach } from "vitest";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { createServer } from "../src/server.js";

describe("Todo MCP Server", () => {
  let client: Client;

  beforeEach(async () => {
    const server = createServer();
    const [clientTransport, serverTransport] =
      InMemoryTransport.createLinkedPair();

    await server.connect(serverTransport);
    client = new Client({ name: "test-client", version: "1.0.0" });
    await client.connect(clientTransport);
  });

  it("should add a todo", async () => {
    const result = await client.callTool({
      name: "add-todo",
      arguments: { title: "寫測試", priority: "high" },
    });

    expect(result.content[0].text).toContain("已新增待辦事項");
  });

  it("should list todos via resource", async () => {
    await client.callTool({
      name: "add-todo",
      arguments: { title: "測試資源", priority: "low" },
    });

    const resource = await client.readResource({
      uri: "todo://list",
    });

    const todos = JSON.parse(resource.contents[0].text);
    expect(todos).toHaveLength(1);
    expect(todos[0].title).toBe("測試資源");
  });
});</code></pre>



<p>使用 <code>InMemoryTransport</code> 可以建立記憶體內的 Client-Server 連線對，不需要真正啟動 stdio 程序，非常適合單元測試場景。</p>



<h2 class="wp-block-heading">部署你的 MCP Server</h2>



<p>MCP Server 支援兩種主要的傳輸方式：stdio（標準輸入輸出）和 Streamable HTTP。根據你的使用場景選擇適合的部署方式。</p>



<figure class="wp-block-table"><table><thead><tr><th>傳輸方式</th><th>適用場景</th><th>優點</th><th>限制</th></tr></thead><tbody><tr><td>stdio</td><td>本地工具、CLI 整合</td><td>簡單、安全、無需網路</td><td>只能本地使用</td></tr><tr><td>Streamable HTTP</td><td>遠端服務、多人共用</td><td>可遠端存取、支援多 Client</td><td>需處理認證與安全</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">stdio 部署（本地使用）</h3>



<p>stdio 是最簡單的部署方式，適合個人本地使用。只需要編譯 TypeScript 並確保執行檔可被呼叫：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash"># 編譯專案
npm run build

# 確保入口檔案有執行權限（Linux/macOS）
chmod +x dist/index.js

# 在 dist/index.js 最上方加入 shebang
# #!/usr/bin/env node</code></pre>



<h3 class="wp-block-heading">Streamable HTTP 部署（遠端服務）</h3>



<p>如果你需要將 MCP Server 部署為遠端服務，可以使用 Streamable HTTP 傳輸層搭配 Express 等 Web 框架：</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

const app = express();

app.post("/mcp", async (req, res) => {
  const server = new McpServer({
    name: "remote-mcp-server",
    version: "1.0.0",
  });

  // 註冊你的 Tools、Resources、Prompts...

  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
  });

  res.on("close", () => {
    transport.close();
    server.close();
  });

  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

app.listen(3000, () => {
  console.error("MCP HTTP Server listening on port 3000");
});</code></pre>



<h2 class="wp-block-heading">與 Claude Code 整合測試</h2>



<p>開發完成後，最重要的一步是將你的 MCP Server 與 Claude Code 整合。Claude Code 透過設定檔來管理 MCP Server 連線，你可以在專案層級或全域層級進行設定。</p>



<h3 class="wp-block-heading">設定 Claude Code 連線</h3>



<p>在你的專案根目錄建立 <code>.mcp.json</code> 設定檔，告訴 Claude Code 如何啟動你的 MCP Server：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "mcpServers": {
    "todo-server": {
      "command": "node",
      "args": ["./dist/index.js"],
      "cwd": "/path/to/my-mcp-server"
    }
  }
}</code></pre>



<p>如果你想在所有專案中都能使用這個 Server，可以將設定加到全域設定檔 <code>~/.claude/settings.json</code> 中。</p>



<h3 class="wp-block-heading">驗證 Server 連線</h3>



<p>設定完成後，在 Claude Code 中使用以下指令確認 Server 已正確連線：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash"># 查看已連線的 MCP Server 列表
/mcp

# 確認你的 Server 狀態為 "connected"
# 如果顯示 "failed"，檢查 Server 的 stderr 輸出找出錯誤原因</code></pre>



<p>連線成功後，你就可以在 Claude Code 對話中直接使用你定義的 Tools 了。例如輸入「幫我新增一個高優先度的待辦事項：完成 MCP Server 文件」，Claude 會自動呼叫你的 <code>add-todo</code> Tool。</p>



<h2 class="wp-block-heading">專案結構建議</h2>



<p>隨著 MCP Server 功能的增長，良好的專案結構可以幫助你維護和擴展程式碼。以下是建議的目錄結構：</p>



<pre class="wp-block-code"><code lang="text" class="language-text">my-mcp-server/
├── src/
│   ├── index.ts                               # 入口檔案，啟動 Server
│   ├── server.ts                              # Server 建構與設定
│   ├── tools/
│   │   ├── index.ts                         # 匯出所有 Tools
│   │   ├── add-todo.ts                 # 個別 Tool 定義
│   │   └── complete-todo.ts
│   ├── resources/
│   │   ├── index.ts                         # 匯出所有 Resources
│   │   └── todos.ts
│   └── prompts/
│       ├── index.ts                          # 匯出所有 Prompts
│       └── daily-summary.ts
├── tests/
│   └── server.test.ts
├── package.json
├── tsconfig.json
└── README.md</code></pre>



<h2 class="wp-block-heading">常見問題與最佳實踐</h2>



<figure class="wp-block-table"><table><thead><tr><th>問題</th><th>原因</th><th>解決方案</th></tr></thead><tbody><tr><td>Server 無法連線</td><td>使用了 console.log() 輸出訊息</td><td>改用 console.error()，保持 stdout 乾淨</td></tr><tr><td>Tool 參數驗證失敗</td><td>Zod Schema 不符合傳入資料</td><td>使用 .describe() 提供清楚的參數說明</td></tr><tr><td>Inspector 無法啟動</td><td>編譯錯誤或路徑不正確</td><td>先執行 npm run build 確認編譯成功</td></tr><tr><td>Resource 回傳空資料</td><td>URI 格式不匹配</td><td>確認 ResourceTemplate URI 的參數名稱一致</td></tr><tr><td>TypeScript 型別錯誤</td><td>SDK 版本不相容</td><td>確認安裝最新版 SDK 並更新 tsconfig 設定</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">總結</h2>



<p>透過本篇教學，你已經學會了如何使用 TypeScript 與 <code>@modelcontextprotocol/sdk</code> 開發一個完整的 MCP Server。從環境建置、定義 Tools、Resources 和 Prompts、撰寫測試、到部署與 Claude Code 整合，你已經掌握了 MCP Server 開發的完整流程。</p>



<p>MCP 的生態系正在快速發展，越來越多的工具和服務都開始支援 MCP 協議。建議你持續關注官方 TypeScript SDK 的更新，並嘗試開發更多實用的 MCP Server 來擴充 Claude Code 的能力。在下一篇文章中，我們將探討更進階的 MCP 開發技巧，包括認證機制、錯誤處理策略、以及效能最佳化。</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Ftypescript-mcp-server-development%2F&amp;linkname=%E7%94%A8%20TypeScript%20%E9%96%8B%E7%99%BC%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E5%80%8B%20MCP%20Server" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Ftypescript-mcp-server-development%2F&amp;linkname=%E7%94%A8%20TypeScript%20%E9%96%8B%E7%99%BC%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E5%80%8B%20MCP%20Server" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Ftypescript-mcp-server-development%2F&amp;linkname=%E7%94%A8%20TypeScript%20%E9%96%8B%E7%99%BC%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E5%80%8B%20MCP%20Server" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Ftypescript-mcp-server-development%2F&#038;title=%E7%94%A8%20TypeScript%20%E9%96%8B%E7%99%BC%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E5%80%8B%20MCP%20Server" data-a2a-url="https://blog.che-ya.com/typescript-mcp-server-development/" data-a2a-title="用 TypeScript 開發你的第一個 MCP Server"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>使用現有 MCP Server 擴展 Claude 功能</title>
		<link>https://blog.che-ya.com/claude-code-mcp-server/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Wed, 29 Apr 2026 02:32:00 +0000</pubDate>
				<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[MCP]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=856</guid>

					<description><![CDATA[Claude Code 最強大的特色之一，就是透過 MCP（Model Context Protocol）連接 ... <a title="使用現有 MCP Server 擴展 Claude 功能" class="read-more" href="https://blog.che-ya.com/claude-code-mcp-server/" aria-label="Read more about 使用現有 MCP Server 擴展 Claude 功能">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>Claude Code 最強大的特色之一，就是透過 MCP（Model Context Protocol）連接外部工具與服務。MCP 是 Anthropic 推出的開放標準協定，讓 Claude Code 能夠存取你的資料庫、版本控制系統、瀏覽器、搜尋引擎等各種外部資源。你不需要自己從頭開發這些整合，社群和官方已經提供了大量現成的 MCP Server，只要一行指令就能完成設定，立即擴展 Claude 的能力範圍。</p>



<h2 class="wp-block-heading">什麼是 MCP Server</h2>



<p>MCP（Model Context Protocol）是一個開放原始碼的標準協定，定義了 AI 工具與外部服務之間的溝通方式。在這個架構中，Claude Code 扮演的是 MCP Client 的角色，而各種外部工具（如 GitHub、PostgreSQL、檔案系統等）則透過 MCP Server 來提供服務。</p>



<p>你可以把 MCP 想像成 AI 世界的 USB 介面——只要符合這個標準，任何工具都能「插上」Claude Code 使用。這代表你不再需要為每個工具寫獨立的整合程式，MCP 提供了統一的溝通規範。</p>



<h3 class="wp-block-heading">為什麼要用現有的 MCP Server</h3>



<ul class="wp-block-list">
<li><strong>節省開發時間</strong>：社群已經開發了數百個 MCP Server，涵蓋主流工具與服務</li>



<li><strong>品質有保障</strong>：許多 MCP Server 由官方維護或經過社群大量測試</li>



<li><strong>一行指令安裝</strong>：透過 <code>claude mcp add</code> 指令，幾秒鐘就能完成設定</li>



<li><strong>標準化協定</strong>：所有 MCP Server 遵循相同的通訊規範，行為一致且可預測</li>



<li><strong>安全性</strong>：MCP Server 在本地執行或透過認證連線，你可以完全掌控資料流向</li>
</ul>



<h2 class="wp-block-heading">MCP Server 的傳輸方式</h2>



<p>在安裝 MCP Server 之前，你需要了解三種不同的傳輸方式（Transport），它們決定了 Claude Code 如何與 MCP Server 溝通：</p>



<figure class="wp-block-table"><table><thead><tr><th>傳輸方式</th><th>說明</th><th>適用場景</th></tr></thead><tbody><tr><td>stdio</td><td>在本機執行程序，透過標準輸入/輸出溝通</td><td>需要直接存取系統資源的工具</td></tr><tr><td>http</td><td>連接遠端伺服器（推薦的遠端傳輸方式）</td><td>雲端服務、SaaS 工具</td></tr><tr><td>sse</td><td>Server-Sent Events（已棄用）</td><td>舊版遠端服務，建議改用 http</td></tr></tbody></table></figure>



<p>對於大多數本地工具（如 filesystem、sqlite），你會使用 <code>stdio</code> 傳輸方式；對於雲端服務（如 GitHub、Sentry），則使用 <code>http</code> 傳輸方式。</p>



<h2 class="wp-block-heading">claude mcp add 指令完整用法</h2>



<p><code>claude mcp add</code> 是新增 MCP Server 的核心指令。它的基本語法如下：</p>



<pre class="wp-block-code"><code class=""># 基本語法
claude mcp add [選項] &lt;名稱> -- &lt;指令> [參數...]

# 遠端 HTTP 伺服器
claude mcp add --transport http &lt;名稱> <url>

# 本地 stdio 伺服器
claude mcp add --transport stdio &lt;名稱> -- &lt;執行指令> [參數...]</url></code></pre>



<p>重要的語法規則：所有選項（<code>--transport</code>、<code>--env</code>、<code>--scope</code>、<code>--header</code>）必須放在伺服器名稱<strong>之前</strong>。雙破折號 <code>--</code> 用來分隔伺服器名稱與要執行的指令及參數。</p>



<h3 class="wp-block-heading">常用選項說明</h3>



<figure class="wp-block-table"><table><thead><tr><th>選項</th><th>說明</th><th>範例</th></tr></thead><tbody><tr><td><code>--transport</code></td><td>指定傳輸方式：stdio、http、sse</td><td><code>--transport stdio</code></td></tr><tr><td><code>--scope</code></td><td>設定作用範圍：local、project、user</td><td><code>--scope user</code></td></tr><tr><td><code>--env</code></td><td>設定環境變數</td><td><code>--env API_KEY=xxx</code></td></tr><tr><td><code>--header</code></td><td>設定 HTTP 標頭（用於認證）</td><td><code>--header "Authorization: Bearer token"</code></td></tr><tr><td><code>--client-id</code></td><td>OAuth 用戶端 ID</td><td><code>--client-id your-id</code></td></tr><tr><td><code>--client-secret</code></td><td>OAuth 用戶端密鑰（互動式輸入）</td><td><code>--client-secret</code></td></tr></tbody></table></figure>



<h3 class="wp-block-heading">作用範圍（Scope）詳解</h3>



<p>MCP Server 的設定可以儲存在三個不同的範圍，每個範圍適合不同的使用情境：</p>



<figure class="wp-block-table"><table><thead><tr><th>Scope</th><th>儲存位置</th><th>可見範圍</th><th>適用情境</th></tr></thead><tbody><tr><td><code>local</code>（預設）</td><td><code>~/.claude.json</code></td><td>僅限你自己在目前專案</td><td>個人開發、含敏感憑證的設定</td></tr><tr><td><code>project</code></td><td><code>.mcp.json</code>（專案根目錄）</td><td>所有團隊成員</td><td>團隊共用的工具設定</td></tr><tr><td><code>user</code></td><td><code>~/.claude.json</code></td><td>你所有的專案</td><td>個人常用工具（跨專案）</td></tr></tbody></table></figure>



<pre class="wp-block-code"><code class=""># 預設為 local scope
claude mcp add --transport http stripe https://mcp.stripe.com

# 明確指定 local scope
claude mcp add --transport http stripe --scope local https://mcp.stripe.com

# 設定為團隊共用（會建立 .mcp.json）
claude mcp add --transport http paypal --scope project https://mcp.paypal.com/mcp

# 設定為跨專案個人使用
claude mcp add --transport http hubspot --scope user https://mcp.hubspot.com/anthropic</code></pre>



<p>當同名的 MCP Server 存在於多個範圍時，優先順序為：<code>local</code> > <code>project</code> > <code>user</code>。這代表本地設定會覆蓋團隊共用設定，讓你可以在不影響團隊的情況下使用自己的憑證。</p>



<h2 class="wp-block-heading">常用 MCP Server 介紹與設定</h2>



<p>以下介紹幾個最實用的 MCP Server，從檔案系統操作到資料庫查詢，再到網頁搜尋與瀏覽器自動化，這些都能大幅提升你的開發效率。</p>



<h3 class="wp-block-heading">Filesystem（檔案系統）</h3>



<p>Filesystem MCP Server 讓 Claude 可以讀取、寫入和管理你指定目錄中的檔案。這是最基礎也最常用的 MCP Server 之一，適合需要讓 Claude 操作專案以外目錄的場景。</p>



<pre class="wp-block-code"><code class=""># 安裝 Filesystem MCP Server
claude mcp add --transport stdio --scope user filesystem \
  -- npx -y @modelcontextprotocol/server-filesystem /path/to/allowed/directory

# 範例：允許存取 ~/Documents 目錄
claude mcp add --transport stdio --scope user filesystem \
  -- npx -y @modelcontextprotocol/server-filesystem ~/Documents</code></pre>



<p>安裝後你可以請 Claude 讀取或修改指定目錄中的檔案，例如「幫我整理 ~/Documents 裡的 CSV 檔案」。</p>



<h3 class="wp-block-heading">GitHub（版本控制與協作）</h3>



<p>GitHub MCP Server 讓 Claude 可以直接操作 GitHub 的 Issue、Pull Request、Repository 等功能。官方推薦使用 HTTP 傳輸方式並透過 OAuth 認證：</p>



<pre class="wp-block-code"><code class=""># 使用官方 HTTP 端點（推薦）
claude mcp add --transport http github https://api.githubcopilot.com/mcp/

# 在 Claude Code 中進行 OAuth 認證
/mcp</code></pre>



<p>認證完成後，你可以請 Claude 執行各種 GitHub 操作，例如「幫我檢視 PR #456 並提出改善建議」或「建立一個新 Issue 描述這個 Bug」。</p>



<h3 class="wp-block-heading">PostgreSQL / SQLite（資料庫）</h3>



<p>資料庫相關的 MCP Server 讓 Claude 可以直接查詢你的資料庫，非常適合資料分析和除錯：</p>



<pre class="wp-block-code"><code class=""># PostgreSQL - 使用 dbhub
claude mcp add --transport stdio db \
  -- npx -y @bytebase/dbhub \
  --dsn "postgresql://user:pass@localhost:5432/mydb"

# SQLite
claude mcp add --transport stdio sqlite \
  -- npx -y @modelcontextprotocol/server-sqlite /path/to/database.db</code></pre>



<p>安裝後你可以用自然語言查詢資料庫，例如「這個月的營收總額是多少？」或「找出 90 天內沒有消費的客戶」。</p>



<h3 class="wp-block-heading">Brave Search（網頁搜尋）</h3>



<p>Brave Search MCP Server 讓 Claude 可以搜尋網路上的即時資訊，突破訓練資料的時間限制：</p>



<pre class="wp-block-code"><code class=""># 安裝 Brave Search（需要 API Key）
claude mcp add --transport stdio --env BRAVE_API_KEY=your-api-key \
  brave-search -- npx -y @anthropic/mcp-server-brave-search</code></pre>



<p>你可以在 <a href="https://brave.com/search/api/" rel="nofollow noopener" target="_blank">Brave Search API</a> 網站申請免費的 API Key。安裝後就能請 Claude 搜尋最新資訊，例如「搜尋 React 19 的最新功能」。</p>



<h3 class="wp-block-heading">Puppeteer / Playwright（瀏覽器自動化）</h3>



<p>瀏覽器自動化的 MCP Server 讓 Claude 可以操控瀏覽器，進行網頁測試、截圖和資料擷取：</p>



<pre class="wp-block-code"><code class=""># Puppeteer
claude mcp add --transport stdio puppeteer \
  -- npx -y @anthropic/mcp-server-puppeteer

# Playwright（推薦）
claude mcp add --transport stdio playwright \
  -- npx -y @playwright/mcp@latest</code></pre>



<h3 class="wp-block-heading">Sentry（錯誤監控）</h3>



<p>Sentry MCP Server 讓 Claude 可以直接查詢生產環境的錯誤記錄，快速定位問題：</p>



<pre class="wp-block-code"><code class=""># 安裝 Sentry MCP Server
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

# 進行 OAuth 認證
/mcp</code></pre>



<p>認證後你可以請 Claude 分析生產環境的錯誤，例如「過去 24 小時最常見的錯誤有哪些？」或「這個錯誤是哪次部署引入的？」。</p>



<h3 class="wp-block-heading">更多推薦的 MCP Server</h3>



<figure class="wp-block-table"><table><thead><tr><th>MCP Server</th><th>功能</th><th>安裝方式</th></tr></thead><tbody><tr><td>Notion</td><td>筆記與知識庫管理</td><td><code>claude mcp add --transport http notion https://mcp.notion.com/mcp</code></td></tr><tr><td>Slack</td><td>團隊溝通與訊息管理</td><td><code>claude mcp add --transport http slack https://slack.com/api/mcp</code></td></tr><tr><td>Linear</td><td>專案管理與 Issue 追蹤</td><td><code>claude mcp add --transport http linear https://mcp.linear.app/sse</code></td></tr><tr><td>Memory</td><td>持久化記憶與知識圖譜</td><td><code>claude mcp add --transport stdio memory -- npx -y @modelcontextprotocol/server-memory</code></td></tr></tbody></table></figure>



<p>你可以在 <a href="https://github.com/modelcontextprotocol/servers" rel="nofollow noopener" target="_blank">MCP Servers GitHub 儲存庫</a> 找到更多社群開發的 MCP Server，或者使用 <a href="https://modelcontextprotocol.io/quickstart/server" rel="nofollow noopener" target="_blank">MCP SDK</a> 自己開發。</p>



<h2 class="wp-block-heading">MCP Server 的管理</h2>



<p>安裝完 MCP Server 後，你可以使用以下指令來管理它們：</p>



<pre class="wp-block-code"><code class=""># 列出所有已設定的 MCP Server
claude mcp list

# 查看特定 MCP Server 的詳細資訊
claude mcp get github

# 移除 MCP Server
claude mcp remove github

# 在 Claude Code 互動模式中檢查伺服器狀態
/mcp

# 重置專案範圍的 MCP Server 核准選擇
claude mcp reset-project-choices</code></pre>



<p>在 Claude Code 的互動模式中，<code>/mcp</code> 指令特別有用。它不僅可以顯示所有 MCP Server 的連線狀態，還能用來進行 OAuth 認證——選擇需要認證的伺服器後，Claude Code 會自動開啟瀏覽器完成認證流程。</p>



<h3 class="wp-block-heading">從 Claude Desktop 匯入設定</h3>



<p>如果你已經在 Claude Desktop 中設定過 MCP Server，可以直接匯入到 Claude Code：</p>



<pre class="wp-block-code"><code class=""># 從 Claude Desktop 匯入 MCP Server 設定
claude mcp add-from-claude-desktop

# 匯入後確認
claude mcp list</code></pre>



<p>這個功能支援 macOS 和 WSL（Windows Subsystem for Linux），匯入後的伺服器會保留原有名稱。如果名稱衝突，會自動加上數字後綴（例如 <code>server_1</code>）。</p>



<h2 class="wp-block-heading">設定檔的位置與格式</h2>



<p>MCP Server 的設定會根據不同的 scope 儲存在不同位置。了解設定檔的結構有助於手動修改或除錯。</p>



<figure class="wp-block-table"><table><thead><tr><th>範圍</th><th>設定檔位置</th><th>用途</th></tr></thead><tbody><tr><td>user / local</td><td><code>~/.claude.json</code></td><td>個人的 MCP Server 設定</td></tr><tr><td>project</td><td><code>.mcp.json</code>（專案根目錄）</td><td>團隊共用設定（可提交版本控制）</td></tr><tr><td>企業管理</td><td><code>managed-mcp.json</code>（系統目錄）</td><td>組織層級的統一管理</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">.mcp.json 檔案格式</h3>



<p>團隊共用的 <code>.mcp.json</code> 檔案格式如下：</p>



<pre class="wp-block-code"><code class="">{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/"
    },
    "database": {
      "command": "npx",
      "args": ["-y", "@bytebase/dbhub", "--dsn", "${DB_CONNECTION_STRING}"],
      "env": {
        "DB_CONNECTION_STRING": "${DB_CONNECTION_STRING:-postgresql://localhost:5432/dev}"
      }
    }
  }
}</code></pre>



<p>注意 <code>.mcp.json</code> 支援環境變數展開語法：<code>${VAR}</code> 會展開為環境變數的值，<code>${VAR:-default}</code> 則在變數未設定時使用預設值。這讓團隊可以共享設定結構，同時讓每個開發者使用自己的憑證。</p>



<h2 class="wp-block-heading">環境變數與 API Key 設定</h2>



<p>許多 MCP Server 需要 API Key 或其他憑證才能運作。Claude Code 提供了多種方式來安全地管理這些敏感資訊。</p>



<h3 class="wp-block-heading">使用 &#8211;env 旗標</h3>



<p>最直接的方式是在 <code>claude mcp add</code> 指令中使用 <code>--env</code> 旗標：</p>



<pre class="wp-block-code"><code class=""># 設定單一環境變數
claude mcp add --transport stdio --env BRAVE_API_KEY=your-key \
  brave-search -- npx -y @anthropic/mcp-server-brave-search

# 設定多個環境變數
claude mcp add --transport stdio \
  --env API_KEY=your-key \
  --env API_SECRET=your-secret \
  my-server -- npx -y my-mcp-server</code></pre>



<h3 class="wp-block-heading">在 .mcp.json 中使用環境變數展開</h3>



<p>對於團隊共用的設定，建議在 <code>.mcp.json</code> 中使用環境變數參照，讓每個開發者在自己的環境中設定實際的值：</p>



<pre class="wp-block-code"><code class="">// .mcp.json（提交到版本控制）
{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_KEY}"
      }
    }
  }
}</code></pre>



<p>團隊成員只需要在自己的 shell 設定檔（如 <code>.bashrc</code> 或 <code>.zshrc</code>）中設定對應的環境變數即可。如果必要的環境變數未設定且沒有預設值，Claude Code 會在啟動時報錯。</p>



<h3 class="wp-block-heading">OAuth 認證流程</h3>



<p>許多雲端服務的 MCP Server 支援 OAuth 2.0 認證。設定流程非常簡單：</p>



<pre class="wp-block-code"><code class=""># 步驟 1：新增需要認證的 MCP Server
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

# 步驟 2：在 Claude Code 中執行認證
/mcp
# 選擇需要認證的伺服器，Claude Code 會自動開啟瀏覽器完成登入</code></pre>



<p>認證 Token 會安全地儲存在系統鑰匙圈（macOS）或憑證檔案中，並且會自動刷新。如果需要撤銷存取權限，可以在 <code>/mcp</code> 選單中選擇「Clear authentication」。</p>



<h2 class="wp-block-heading">MCP Server 的除錯與疑難排解</h2>



<p>在使用 MCP Server 時可能會遇到各種問題，以下是常見的疑難排解方法。</p>



<h3 class="wp-block-heading">常見問題與解決方案</h3>



<figure class="wp-block-table"><table><thead><tr><th>問題</th><th>可能原因</th><th>解決方案</th></tr></thead><tbody><tr><td>Connection closed</td><td>Windows 未使用 cmd /c 包裝</td><td>使用 <code>cmd /c npx -y @some/package</code></td></tr><tr><td>Server 啟動逾時</td><td>預設逾時時間太短</td><td>設定 <code>MCP_TIMEOUT=10000 claude</code></td></tr><tr><td>輸出超過限制警告</td><td>MCP 工具回傳資料過大</td><td>設定 <code>MAX_MCP_OUTPUT_TOKENS=50000</code></td></tr><tr><td>OAuth 認證失敗</td><td>不支援動態用戶端註冊</td><td>使用 <code>--client-id</code> 和 <code>--client-secret</code></td></tr><tr><td>環境變數未展開</td><td>變數未設定且無預設值</td><td>確認環境變數已設定或加上預設值語法</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">除錯技巧</h3>



<pre class="wp-block-code"><code class=""># 1. 檢查 MCP Server 的連線狀態
/mcp

# 2. 查看特定伺服器的完整設定
claude mcp get <server-name>

# 3. 列出所有設定的伺服器
claude mcp list

# 4. 調整啟動逾時時間（毫秒）
MCP_TIMEOUT=10000 claude

# 5. 增加輸出 Token 限制
MAX_MCP_OUTPUT_TOKENS=50000 claude</server-name></code></pre>



<p>如果瀏覽器在 OAuth 認證後重新導向失敗，可以手動複製瀏覽器網址列中的完整回調 URL，貼到 Claude Code 中顯示的 URL 提示中。</p>



<h2 class="wp-block-heading">安全性注意事項</h2>



<p>使用 MCP Server 時務必注意安全性。雖然 MCP 協定本身設計了安全機制，但你仍需要遵循最佳實踐來保護你的系統和資料。</p>



<ul class="wp-block-list">
<li><strong>只安裝信任的 MCP Server</strong>：優先選擇官方維護或知名社群開發者的 Server。Anthropic 並未驗證所有第三方 MCP Server 的正確性和安全性</li>



<li><strong>注意 Prompt Injection 風險</strong>：會擷取外部內容的 MCP Server（如網頁瀏覽器、搜尋引擎）可能暴露於 Prompt Injection 攻擊，使用時要格外小心</li>



<li><strong>最小權限原則</strong>：只授予 MCP Server 必要的權限。例如資料庫連線建議使用唯讀帳號，檔案系統只開放需要的目錄</li>



<li><strong>妥善管理 API Key</strong>：不要將 API Key 直接寫在 <code>.mcp.json</code> 中並提交到版本控制。使用環境變數參照語法 <code>${VAR}</code> 來引用</li>



<li><strong>審查 project scope 的 MCP Server</strong>：Claude Code 在使用 <code>.mcp.json</code> 中的伺服器前會要求你核准。如需重置核准選擇，使用 <code>claude mcp reset-project-choices</code></li>



<li><strong>定期檢查已安裝的 Server</strong>：使用 <code>claude mcp list</code> 定期檢視已安裝的 MCP Server，移除不再需要的服務</li>
</ul>



<h2 class="wp-block-heading">進階用法</h2>



<h3 class="wp-block-heading">使用 JSON 直接新增設定</h3>



<p>如果你已經有完整的 JSON 設定，可以使用 <code>claude mcp add-json</code> 指令直接新增：</p>



<pre class="wp-block-code"><code class=""># 新增 HTTP 伺服器（含認證標頭）
claude mcp add-json weather-api '{"type":"http","url":"https://api.weather.com/mcp","headers":{"Authorization":"Bearer token"}}'

# 新增 stdio 伺服器（含完整設定）
claude mcp add-json local-tool '{"type":"stdio","command":"/path/to/tool","args":["--config","config.json"],"env":{"CACHE_DIR":"/tmp"}}'</code></pre>



<h3 class="wp-block-heading">將 Claude Code 作為 MCP Server</h3>



<p>Claude Code 本身也可以作為 MCP Server 供其他應用程式連接。這讓你可以在 Claude Desktop 等其他 MCP Client 中使用 Claude Code 的強大工具：</p>



<pre class="wp-block-code"><code class=""># 啟動 Claude Code 作為 MCP Server
claude mcp serve

# 在 Claude Desktop 的設定檔中新增：
{
  "mcpServers": {
    "claude-code": {
      "type": "stdio",
      "command": "claude",
      "args": ["mcp", "serve"],
      "env": {}
    }
  }
}</code></pre>



<h3 class="wp-block-heading">Tool Search 智慧工具搜尋</h3>



<p>Claude Code 預設啟用 Tool Search 機制。當你安裝了大量 MCP Server 時，Claude 不會在啟動時載入所有工具定義，而是只載入工具名稱，需要時才動態搜尋相關工具。這大幅降低了 Context Window 的佔用，讓你可以安裝更多 MCP Server 而不影響效能。</p>



<h2 class="wp-block-heading">實戰範例：完整的開發工作流程</h2>



<p>讓我們用一個完整的範例來展示 MCP Server 如何提升開發效率。假設你是一個全端開發者，需要處理一個 Bug 修復任務：</p>



<pre class="wp-block-code"><code class=""># 步驟 1：設定必要的 MCP Server
claude mcp add --transport http github https://api.githubcopilot.com/mcp/
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
claude mcp add --transport stdio db \
  -- npx -y @bytebase/dbhub --dsn "postgresql://dev:pass@localhost:5432/app"

# 步驟 2：進行 OAuth 認證
/mcp

# 步驟 3：確認所有 Server 已連線
claude mcp list</code></pre>



<p>設定完成後，你可以在 Claude Code 中用自然語言進行完整的除錯工作流程——從查詢 Sentry 錯誤記錄，到檢視相關的 GitHub Issue，再到查詢資料庫驗證資料狀態，最後建立 PR 提交修復。所有這些操作都在同一個 Claude Code Session 中完成，不需要在多個工具之間切換。</p>



<h2 class="wp-block-heading">延伸閱讀</h2>



<ul class="wp-block-list">
<li><a href="https://code.claude.com/docs/en/mcp" rel="nofollow noopener" target="_blank">Claude Code MCP 官方文件</a>：完整的 MCP Server 設定與管理指南</li>



<li><a href="https://modelcontextprotocol.io/introduction" rel="nofollow noopener" target="_blank">Model Context Protocol 官方網站</a>：MCP 協定的技術規格與設計理念</li>



<li><a href="https://github.com/modelcontextprotocol/servers" rel="nofollow noopener" target="_blank">MCP Servers GitHub 儲存庫</a>：社群維護的 MCP Server 清單</li>



<li><a href="https://modelcontextprotocol.io/quickstart/server" rel="nofollow noopener" target="_blank">MCP SDK 快速入門</a>：學習如何開發自己的 MCP Server</li>
</ul>



<h2 class="wp-block-heading">總結</h2>



<p>MCP Server 是 Claude Code 生態系中不可或缺的一環。透過現有的 MCP Server，你可以在幾分鐘內將 Claude 連接到各種外部工具和服務，大幅提升開發效率。無論是版本控制、資料庫查詢、錯誤監控還是網頁搜尋，都有現成的解決方案可以直接使用。</p>



<p>記住幾個關鍵要點：選擇適合的傳輸方式（本地工具用 stdio、雲端服務用 http）、根據使用場景設定正確的 scope、妥善管理 API Key 和憑證，以及定期檢視已安裝的 MCP Server。掌握這些基礎後，你就能充分發揮 Claude Code 與外部工具整合的強大能力。</p>



<p>在下一篇文章中，我們將深入探討如何從零開始開發自己的 MCP Server，讓 Claude 連接到你的自訂工具和內部系統。敬請期待！</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-mcp-server%2F&amp;linkname=%E4%BD%BF%E7%94%A8%E7%8F%BE%E6%9C%89%20MCP%20Server%20%E6%93%B4%E5%B1%95%20Claude%20%E5%8A%9F%E8%83%BD" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-mcp-server%2F&amp;linkname=%E4%BD%BF%E7%94%A8%E7%8F%BE%E6%9C%89%20MCP%20Server%20%E6%93%B4%E5%B1%95%20Claude%20%E5%8A%9F%E8%83%BD" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-mcp-server%2F&amp;linkname=%E4%BD%BF%E7%94%A8%E7%8F%BE%E6%9C%89%20MCP%20Server%20%E6%93%B4%E5%B1%95%20Claude%20%E5%8A%9F%E8%83%BD" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-mcp-server%2F&#038;title=%E4%BD%BF%E7%94%A8%E7%8F%BE%E6%9C%89%20MCP%20Server%20%E6%93%B4%E5%B1%95%20Claude%20%E5%8A%9F%E8%83%BD" data-a2a-url="https://blog.che-ya.com/claude-code-mcp-server/" data-a2a-title="使用現有 MCP Server 擴展 Claude 功能"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SQL NULL 值處理</title>
		<link>https://blog.che-ya.com/sql-null/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Tue, 28 Apr 2026 02:46:00 +0000</pubDate>
				<category><![CDATA[資料查詢 DQL]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=602</guid>

					<description><![CDATA[NULL 值介紹 (SQL NULL Value) 這篇 SQL NULL 值處理教學將帶你認識 NULL 的 ... <a title="SQL NULL 值處理" class="read-more" href="https://blog.che-ya.com/sql-null/" aria-label="Read more about SQL NULL 值處理">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">NULL 值介紹 (SQL NULL Value)</h2>



<p>這篇 SQL NULL 值處理教學將帶你認識 NULL 的基本概念與常見處理方式。在 SQL 中，NULL 代表「無值」或「未知值」，它既不是 0、也不是空字串，而是一個特殊的標記，表示該欄位沒有資料。</p>



<p>當資料表中的某個欄位沒有被賦予值時，該欄位就會自動存入 NULL。由於 NULL 不等於任何值（甚至不等於另一個 NULL），因此在查詢或運算時需要特別注意處理方式，否則可能會得到意想不到的結果。</p>



<h2 class="wp-block-heading">IS NULL 與 IS NOT NULL 語法 (Syntax)</h2>



<pre class="wp-block-code"><code class="">SELECT column_name
FROM table_name
WHERE column_name IS NULL;

SELECT column_name
FROM table_name
WHERE column_name IS NOT NULL;</code></pre>



<p>說明：</p>



<figure class="wp-block-table"><table><thead><tr>語法說明</tr></thead><tbody><tr>IS NULL判斷欄位值是否為 NULL</tr><tr>IS NOT NULL判斷欄位值是否不為 NULL</tr></tbody></table></figure>



<p>注意：不能使用 <code>= NULL</code> 或 <code>&lt;> NULL</code> 來判斷 NULL 值，因為 NULL 與任何值的比較結果都是 UNKNOWN，而非 TRUE 或 FALSE。必須使用 <code>IS NULL</code> 或 <code>IS NOT NULL</code> 來判斷。</p>



<h2 class="wp-block-heading">IS NULL 與 IS NOT NULL 用法 (Example)</h2>



<p>假設我們有一個員工資料表 employees 如下（若需了解如何建立資料表，請參考 <a href="https://blog.che-ya.com/create-table/">CREATE TABLE</a> 教學）：</p>



<figure class="wp-block-table"><table><thead><tr>NameDepartmentPhoneSalary</tr></thead><tbody><tr>張一業務部02-1234567835000</tr><tr>王二資訊部NULL42000</tr><tr>李三NULL07-1234567838000</tr><tr>趙四資訊部03-12345678NULL</tr><tr>陳五人資部NULL40000</tr></tbody></table></figure>



<h3 class="wp-block-heading">查詢欄位為 NULL 的資料</h3>



<p>使用 IS NULL 可以查詢某個欄位值為 NULL 的資料列。例如，查詢沒有填寫電話的員工：</p>



<pre class="wp-block-code"><code class="">SELECT Name, Phone
FROM employees
WHERE Phone IS NULL;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>NamePhone</tr></thead><tbody><tr>王二NULL</tr><tr>陳五NULL</tr></tbody></table></figure>



<h3 class="wp-block-heading">查詢欄位不為 NULL 的資料</h3>



<p>使用 IS NOT NULL 可以查詢某個欄位值不為 NULL 的資料列。例如，查詢有填寫部門的員工：</p>



<pre class="wp-block-code"><code class="">SELECT Name, Department
FROM employees
WHERE Department IS NOT NULL;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>NameDepartment</tr></thead><tbody><tr>張一業務部</tr><tr>王二資訊部</tr><tr>趙四資訊部</tr><tr>陳五人資部</tr></tbody></table></figure>



<h2 class="wp-block-heading">COALESCE 函數 (SQL COALESCE Function)</h2>



<p>COALESCE 是 SQL 標準函數，用來從一組參數中回傳第一個非 NULL 的值。如果所有參數都是 NULL，則回傳 NULL。COALESCE 是處理 NULL 值最常用也最通用的函數，幾乎所有主流資料庫都支援。</p>



<h3 class="wp-block-heading">COALESCE 語法</h3>



<pre class="wp-block-code"><code class="">COALESCE(value1, value2, ..., valueN)</code></pre>



<p>COALESCE 會依序檢查每個參數，回傳第一個不是 NULL 的值。常見用法是將可能為 NULL 的欄位替換成預設值。</p>



<h3 class="wp-block-heading">COALESCE 用法範例</h3>



<p>使用前面的 employees 資料表，將 NULL 的電話欄位顯示為「未提供」：</p>



<pre class="wp-block-code"><code class="">SELECT Name, COALESCE(Phone, '未提供') AS Phone
FROM employees;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>NamePhone</tr></thead><tbody><tr>張一02-12345678</tr><tr>王二未提供</tr><tr>李三07-12345678</tr><tr>趙四03-12345678</tr><tr>陳五未提供</tr></tbody></table></figure>



<p>也可以提供多個替代值，COALESCE 會依序檢查，回傳第一個非 NULL 的值：</p>



<pre class="wp-block-code"><code class="">SELECT Name, COALESCE(Phone, Department, '無資料') AS contact_info
FROM employees;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>Namecontact_info</tr></thead><tbody><tr>張一02-12345678</tr><tr>王二資訊部</tr><tr>李三07-12345678</tr><tr>趙四03-12345678</tr><tr>陳五人資部</tr></tbody></table></figure>



<h2 class="wp-block-heading">各資料庫的 NULL 處理函數</h2>



<p>除了通用的 COALESCE 之外，不同的資料庫系統也提供了各自專屬的 NULL 處理函數。這些函數的功能類似，都是在欄位值為 NULL 時回傳替代值，但語法和名稱有所不同。</p>



<figure class="wp-block-table"><table><thead><tr>資料庫函數說明</tr></thead><tbody><tr>MySQLIFNULL(expr, alt)若 expr 為 NULL 則回傳 alt</tr><tr>OracleNVL(expr, alt)若 expr 為 NULL 則回傳 alt</tr><tr>SQL ServerISNULL(expr, alt)若 expr 為 NULL 則回傳 alt</tr><tr>所有資料庫COALESCE(v1, v2, &#8230;)回傳第一個非 NULL 的值（SQL 標準）</tr></tbody></table></figure>



<h3 class="wp-block-heading">MySQL IFNULL 用法</h3>



<p>MySQL 的 IFNULL 函數接受兩個參數，若第一個參數為 NULL，則回傳第二個參數的值：</p>



<pre class="wp-block-code"><code class="">-- MySQL
SELECT Name, IFNULL(Salary, 0) AS Salary
FROM employees;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>NameSalary</tr></thead><tbody><tr>張一35000</tr><tr>王二42000</tr><tr>李三38000</tr><tr>趙四0</tr><tr>陳五40000</tr></tbody></table></figure>



<h3 class="wp-block-heading">Oracle NVL 用法</h3>



<p>Oracle 的 NVL 函數功能與 IFNULL 相同，語法也類似：</p>



<pre class="wp-block-code"><code class="">-- Oracle
SELECT Name, NVL(Salary, 0) AS Salary
FROM employees;</code></pre>



<p>查詢結果與上方 IFNULL 範例相同。Oracle 還提供了 NVL2 函數，可以針對 NULL 和非 NULL 分別指定不同的回傳值：</p>



<pre class="wp-block-code"><code class="">-- Oracle NVL2(expr, not_null_value, null_value)
SELECT Name, NVL2(Phone, '已填寫', '未填寫') AS phone_status
FROM employees;</code></pre>



<h3 class="wp-block-heading">SQL Server ISNULL 用法</h3>



<p>SQL Server 的 ISNULL 函數功能同樣類似：</p>



<pre class="wp-block-code"><code class="">-- SQL Server
SELECT Name, ISNULL(Salary, 0) AS Salary
FROM employees;</code></pre>



<p>建議：如果需要跨資料庫相容，優先使用 COALESCE，因為它是 SQL 標準語法，所有主流資料庫都支援。</p>



<h2 class="wp-block-heading">NULL 與聚合函數</h2>



<p>在使用<a href="https://blog.che-ya.com/sql-aggregate-functions/">聚合函數</a>時，NULL 值的處理方式是一個重要的觀念。大多數聚合函數（如 SUM、AVG、MIN、MAX）會自動忽略 NULL 值，而 COUNT 的行為則取決於參數。</p>



<pre class="wp-block-code"><code class="">-- COUNT(*) 計算所有資料列（包含 NULL）
SELECT COUNT(*) AS total_rows
FROM employees;

-- COUNT(column) 只計算該欄位非 NULL 的資料列
SELECT COUNT(Salary) AS has_salary
FROM employees;

-- AVG 會忽略 NULL 值
SELECT AVG(Salary) AS avg_salary
FROM employees;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>查詢結果說明</tr></thead><tbody><tr>COUNT(*)5計算所有資料列，包含有 NULL 的列</tr><tr>COUNT(Salary)4只計算 Salary 不為 NULL 的列（趙四被排除）</tr><tr>AVG(Salary)38750(35000+42000+38000+40000)/4，忽略 NULL</tr></tbody></table></figure>



<p>特別注意 AVG 的計算：因為趙四的 Salary 為 NULL 被忽略，所以平均值是四筆資料的平均 (35000+42000+38000+40000)/4 = 38750，而不是除以 5。如果你希望將 NULL 視為 0 來計算，可以搭配 COALESCE 使用：</p>



<pre class="wp-block-code"><code class="">SELECT AVG(COALESCE(Salary, 0)) AS avg_salary
FROM employees;
-- 結果：(35000+42000+38000+0+40000)/5 = 31000</code></pre>



<h2 class="wp-block-heading">NULL 與排序 (ORDER BY)</h2>



<p>使用 <a href="https://blog.che-ya.com/sql-order-by/">ORDER BY</a> 排序時，NULL 值的排列位置因資料庫而異。在 MySQL 和 SQL Server 中，NULL 被視為最小值，升序排序時會出現在最前面；在 Oracle 和 PostgreSQL 中，NULL 被視為最大值，升序排序時會出現在最後面。</p>



<pre class="wp-block-code"><code class="">SELECT Name, Salary
FROM employees
ORDER BY Salary ASC;</code></pre>



<p>PostgreSQL 和 Oracle 支援 NULLS FIRST 和 NULLS LAST 語法，可以明確指定 NULL 的排列位置：</p>



<pre class="wp-block-code"><code class="">-- PostgreSQL / Oracle
SELECT Name, Salary
FROM employees
ORDER BY Salary ASC NULLS LAST;</code></pre>



<h2 class="wp-block-heading">NULL 運算注意事項</h2>



<p>NULL 在運算中有一些特殊的行為，這些是使用 SQL 時必須注意的重點：</p>



<figure class="wp-block-table"><table><thead><tr>運算結果說明</tr></thead><tbody><tr>NULL = NULLUNKNOWNNULL 不等於 NULL</tr><tr>NULL &lt;&gt; NULLUNKNOWNNULL 也不「不等於」NULL</tr><tr>NULL + 10NULL任何值與 NULL 做算術運算結果都是 NULL</tr><tr>NULL = &#8221;UNKNOWNNULL 不等於空字串</tr><tr>NULL AND TRUEUNKNOWNNULL 參與邏輯運算結果可能是 UNKNOWN</tr><tr>NULL OR TRUETRUEOR 運算中只要一方為 TRUE 結果就是 TRUE</tr></tbody></table></figure>



<p>由於 NULL 與任何值的算術運算結果都是 NULL，在計算欄位時要特別注意。例如：</p>



<pre class="wp-block-code"><code class="">SELECT Name, Salary, Salary * 12 AS annual_salary
FROM employees;</code></pre>



<p>查詢結果如下：</p>



<figure class="wp-block-table"><table><thead><tr>NameSalaryannual_salary</tr></thead><tbody><tr>張一35000420000</tr><tr>王二42000504000</tr><tr>李三38000456000</tr><tr>趙四NULLNULL</tr><tr>陳五40000480000</tr></tbody></table></figure>



<p>趙四的 Salary 為 NULL，所以 NULL * 12 的結果仍然是 NULL。若要避免這種情況，可以搭配 COALESCE 將 NULL 替換為 0：</p>



<pre class="wp-block-code"><code class="">SELECT Name, COALESCE(Salary, 0) * 12 AS annual_salary
FROM employees;</code></pre>



<h2 class="wp-block-heading">延伸閱讀</h2>



<ul class="wp-block-list">
<li><a href="https://blog.che-ya.com/sql-select/">SQL SELECT — 資料查詢語法</a></li>



<li><a href="https://blog.che-ya.com/sql-where/">SQL WHERE — 條件查詢教學</a></li>



<li><a href="https://blog.che-ya.com/sql-aggregate-functions/">SQL 聚合函數 — COUNT、SUM、AVG、MIN、MAX</a></li>



<li><a href="https://blog.che-ya.com/sql-case/">SQL CASE — 條件判斷教學</a></li>



<li><a href="https://blog.che-ya.com/sql-order-by/">SQL ORDER BY — 排序教學</a></li>



<li><a href="https://blog.che-ya.com/sql-group-by/">SQL GROUP BY — 分組統計教學</a></li>



<li><a href="https://blog.che-ya.com/sql-join/">SQL JOIN — 多表連接查詢</a></li>



<li><a href="https://blog.che-ya.com/create-table/">CREATE TABLE — 建立資料表</a></li>
</ul>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fsql-null%2F&amp;linkname=SQL%20NULL%20%E5%80%BC%E8%99%95%E7%90%86" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fsql-null%2F&amp;linkname=SQL%20NULL%20%E5%80%BC%E8%99%95%E7%90%86" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fsql-null%2F&amp;linkname=SQL%20NULL%20%E5%80%BC%E8%99%95%E7%90%86" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fsql-null%2F&#038;title=SQL%20NULL%20%E5%80%BC%E8%99%95%E7%90%86" data-a2a-url="https://blog.che-ya.com/sql-null/" data-a2a-title="SQL NULL 值處理"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>MCP 協議：連接 AI 與外部世界的橋樑</title>
		<link>https://blog.che-ya.com/mcp-protocol-introduction/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Mon, 27 Apr 2026 03:57:00 +0000</pubDate>
				<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[JSON-RPC]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[Model Context Protocol]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=845</guid>

					<description><![CDATA[當你在 Claude Code 中輸入一句話，Claude 能夠讀取檔案、執行指令、查詢資料庫、甚至操作 Gi ... <a title="MCP 協議：連接 AI 與外部世界的橋樑" class="read-more" href="https://blog.che-ya.com/mcp-protocol-introduction/" aria-label="Read more about MCP 協議：連接 AI 與外部世界的橋樑">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>當你在 Claude Code 中輸入一句話，Claude 能夠讀取檔案、執行指令、查詢資料庫、甚至操作 GitHub——這一切的背後，都依賴一個關鍵的開放標準：Model Context Protocol（MCP）。MCP 是 Anthropic 於 2024 年 11 月發布的開源協議，定義了 AI 模型與外部工具之間的標準化通訊方式。如果說 USB 統一了硬體介面，HTTP 統一了網頁通訊，那麼 MCP 就是要統一 AI 與工具之間的溝通方式。本文將帶你從零開始理解 MCP 的核心概念、架構設計與運作原理，為後續的實戰應用打下基礎。</p>



<h2 class="wp-block-heading">為什麼需要 MCP？</h2>



<p>在 MCP 出現之前，每個 AI 應用要連接外部工具，都需要自行實作整合邏輯。想讓 AI 讀取 GitHub Issues？你要寫一套 GitHub API 的封裝。想查詢資料庫？你要寫另一套資料庫連線邏輯。這就造成了所謂的「M×N 問題」——如果有 M 個 AI 應用和 N 個工具，就需要 M×N 個客製化整合。</p>



<p>MCP 透過標準化的協議層，將這個 M×N 問題簡化為 M+N。每個 AI 應用只需要實作一次 MCP Client，每個工具只需要包裝成一次 MCP Server，就能互相連接。這就像 USB 的概念——不管是鍵盤、滑鼠還是硬碟，只要支援 USB 介面，就能接上任何電腦。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>比較項目</th><th>傳統整合方式</th><th>MCP 標準化方式</th></tr></thead><tbody><tr><td>整合數量</td><td>M × N 個客製化實作</td><td>M + N 個標準化實作</td></tr><tr><td>維護成本</td><td>每個整合獨立維護</td><td>統一協議，分別維護</td></tr><tr><td>新增工具</td><td>每個 AI 應用都要更新</td><td>只需新增一個 MCP Server</td></tr><tr><td>新增 AI 應用</td><td>要重寫所有工具整合</td><td>只需實作一個 MCP Client</td></tr><tr><td>安全性</td><td>各自實作，標準不一</td><td>協議層統一處理權限控制</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">MCP 的核心架構</h2>



<p>MCP 採用經典的 Client-Server 架構，但加入了 Host 的概念來管理整個生態系。理解這三個角色的關係，是掌握 MCP 的第一步。</p>



<h3 class="wp-block-heading">三大角色：Host、Client、Server</h3>



<p><strong>Host（宿主）</strong>是使用者直接互動的 AI 應用程式，例如 Claude Code、Claude Desktop App 或任何整合了 LLM 的 IDE。Host 負責管理 LLM 實例、建立 MCP Client、控制安全與權限，並協調多個 MCP 連線。</p>



<p><strong>Client（客戶端）</strong>是由 Host 建立的協議端點，每個 Client 與一個 Server 維持一對一的連線。Client 負責處理訊息的路由、能力的協商，以及訂閱管理。在 Claude Code 中，每當你新增一個 MCP Server，系統就會自動建立一個對應的 Client。</p>



<p><strong>Server（伺服器）</strong>是實際提供工具與資料的程式。Server 可以是一個 Node.js 腳本、Python 程式、或遠端 HTTP 服務。每個 Server 透過 MCP 協議暴露自己的能力（tools、resources、prompts），讓 AI 模型可以呼叫使用。</p>



<h3 class="wp-block-heading">協議層架構</h3>



<figure class="wp-block-image size-large"><img decoding="async" src="https://blog.che-ya.com/wp-content/uploads/2026/04/mcp-protocol-architecture.png" alt="MCP 協議層架構圖：Application Layer、Protocol Layer、Transport Layer" class="wp-image-853"/><figcaption class="wp-element-caption">MCP 協議層架構：應用層、協議層、傳輸層三層架構</figcaption></figure>



<h2 class="wp-block-heading">三大核心原語：Tools、Resources、Prompts</h2>



<p>MCP Server 透過三種核心原語向 AI 暴露自己的能力。理解它們的差異，有助於你判斷什麼時候該用哪一種，以及如何設計自己的 MCP Server。</p>



<h3 class="wp-block-heading">Tools（工具）：讓 AI 執行動作</h3>



<p>Tools 是 MCP 中最常用的原語，代表 AI 可以呼叫的可執行函式。每個 Tool 都有名稱、描述和輸入參數的 JSON Schema 定義。當 AI 判斷需要使用某個 Tool 時，會自動傳入適當的參數並等待結果。</p>



<p>舉例來說，一個 GitHub MCP Server 可能暴露這些 Tools：</p>



<pre class="wp-block-code"><code class="">// Tool 定義範例
{
  "name": "create_issue",
  "description": "在 GitHub 儲存庫中建立一個新的 Issue",
  "inputSchema": {
    "type": "object",
    "properties": {
      "repo": {
        "type": "string",
        "description": "儲存庫名稱，格式為 owner/repo"
      },
      "title": {
        "type": "string",
        "description": "Issue 標題"
      },
      "body": {
        "type": "string",
        "description": "Issue 內容（支援 Markdown）"
      }
    },
    "required": ["repo", "title"]
  }
}</code></pre>



<p>如果把 MCP 想像成一家餐廳，Tools 就是菜單上的菜——你可以點什麼、需要提供什麼資訊（幾分熟、要不要辣），都清楚定義好了。</p>



<h3 class="wp-block-heading">Resources（資源）：讓 AI 讀取資料</h3>



<p>Resources 代表 MCP Server 可以提供的資料來源。與 Tools 不同，Resources 是唯讀的——AI 可以讀取資料，但不會觸發任何副作用。每個 Resource 都有一個 URI 來識別，內容可以是文字或二進位資料。</p>



<pre class="wp-block-code"><code class="">// Resource 範例
{
  "uri": "file:///project/src/config.json",
  "name": "專案設定檔",
  "description": "目前專案的 JSON 設定內容",
  "mimeType": "application/json"
}</code></pre>



<p>繼續用餐廳的比喻，Resources 就是餐廳提供的菜單、酒單、今日特餐公告板——你可以看、可以參考，但不會改變任何東西。</p>



<h3 class="wp-block-heading">Prompts（提示模板）：預設的互動模式</h3>



<p>Prompts 是預先定義好的互動模板，讓使用者可以快速啟動常見的工作流程。Prompts 可以包含固定的指令文字和動態的參數，由使用者觸發（而非 AI 自動決定）。</p>



<pre class="wp-block-code"><code class="">// Prompt 範例
{
  "name": "code_review",
  "description": "對指定的 Pull Request 進行程式碼審查",
  "arguments": [
    {
      "name": "pr_number",
      "description": "Pull Request 編號",
      "required": true
    },
    {
      "name": "focus_area",
      "description": "審查重點（如安全性、效能、可讀性）",
      "required": false
    }
  ]
}</code></pre>



<p>Prompts 就像餐廳的套餐——廚師已經幫你搭配好了主餐、配菜和甜點，你只需要選擇要幾人份就好。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>特性</th><th>Tools</th><th>Resources</th><th>Prompts</th></tr></thead><tbody><tr><td>觸發方式</td><td>AI 模型自動決定</td><td>應用程式或 AI 請求</td><td>使用者手動觸發</td></tr><tr><td>副作用</td><td>有（可執行操作）</td><td>無（唯讀）</td><td>無（模板而已）</td></tr><tr><td>類比</td><td>餐廳的菜</td><td>菜單和公告板</td><td>套餐組合</td></tr><tr><td>常見用途</td><td>API 呼叫、檔案操作</td><td>讀取檔案、查詢資料</td><td>Code Review、摘要</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">傳輸機制：stdio 與 Streamable HTTP</h2>



<p>MCP 定義了兩種主要的傳輸機制，分別適用於不同的使用場景。選擇正確的傳輸方式，直接影響 MCP Server 的部署方式和效能特性。</p>



<h3 class="wp-block-heading">stdio：本地執行的首選</h3>



<p>stdio（Standard Input/Output）傳輸是最簡單的方式。Client 啟動 Server 作為子程序，透過標準輸入（stdin）和標準輸出（stdout）交換 JSON-RPC 訊息。每條訊息以換行符號分隔。</p>



<pre class="wp-block-code"><code class=""># 在 Claude Code 中新增一個 stdio 類型的 MCP Server
claude mcp add --transport stdio my-db-server -- npx -y @example/db-server

# 帶環境變數的版本
claude mcp add --transport stdio --env DB_URL=postgresql://localhost/mydb \
  my-db-server -- npx -y @example/db-server</code></pre>



<p>stdio 的優點是延遲極低（不需要網路傳輸）、設定簡單，且天然支援安全隔離（因為只在本機執行）。缺點是無法跨機器使用，Server 的生命週期綁定在 Host 程式上。</p>



<h3 class="wp-block-heading">Streamable HTTP：遠端服務的標準</h3>



<p>Streamable HTTP 是 MCP 規格在 2025 年 3 月更新後推薦的遠端傳輸方式，取代了先前的 SSE（Server-Sent Events）傳輸。它透過標準的 HTTP 請求進行通訊，並可選擇性地使用 SSE 來串流回應。</p>



<pre class="wp-block-code"><code class=""># 在 Claude Code 中新增一個 HTTP 類型的 MCP Server
claude mcp add --transport http notion https://mcp.notion.com/mcp

# 帶認證的版本
claude mcp add --transport http secure-api https://api.example.com/mcp \
  --header "Authorization: Bearer your-token"</code></pre>



<p>Streamable HTTP 的優點是可以跨網路使用、支援多用戶共享同一個 Server、容易部署在雲端環境。缺點是需要處理網路延遲和認證機制。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>比較項目</th><th>stdio</th><th>Streamable HTTP</th></tr></thead><tbody><tr><td>執行環境</td><td>本地子程序</td><td>遠端 HTTP 服務</td></tr><tr><td>延遲</td><td>極低</td><td>取決於網路</td></tr><tr><td>跨機器存取</td><td>不支援</td><td>支援</td></tr><tr><td>多用戶共享</td><td>不支援</td><td>支援</td></tr><tr><td>適用場景</td><td>本地工具、腳本</td><td>雲端 API、SaaS 服務</td></tr><tr><td>安全性</td><td>本機隔離</td><td>需處理認證與 TLS</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">連線生命週期</h2>



<p>MCP 的連線建立遵循嚴格的初始化流程，確保 Client 和 Server 在開始通訊之前就協商好彼此的能力。</p>



<h3 class="wp-block-heading">初始化流程</h3>



<p>當 Claude Code 啟動或你新增一個 MCP Server 時，會經歷以下步驟：</p>



<figure class="wp-block-table"><table><thead><tr><th>步驟</th><th>動作</th><th>說明</th></tr></thead><tbody><tr><td>1</td><td>Client 發送 <code>initialize</code> 請求</td><td>Client 向 Server 發送初始化請求，包含支援的協議版本與能力（Capabilities）宣告</td></tr><tr><td>2</td><td>Server 回應 <code>initialize</code></td><td>Server 回傳自己支援的協議版本、能力宣告與伺服器資訊</td></tr><tr><td>3</td><td>Client 發送 <code>initialized</code> 通知</td><td>Client 確認初始化完成，通知 Server 已準備就緒</td></tr><tr><td>4</td><td>開始正常通訊</td><td>雙方完成握手，可開始進行 Tool 呼叫、Resource 讀取等正常操作</td></tr></tbody></table></figure>



<p>在初始化階段，Client 和 Server 會交換各自支援的協議版本和能力（Capabilities）。例如，Server 可能宣告它支援 tools 和 resources，但不支援 prompts。Client 則可能宣告它支援 sampling（讓 Server 請求 AI 模型進行推理）和 roots（提供檔案系統存取點）。</p>



<h3 class="wp-block-heading">訊息交換模式</h3>



<p>初始化完成後，MCP 支援三種訊息交換模式：</p>



<p><strong>Request-Response（請求-回應）</strong>：Client 發送請求，Server 回傳結果。例如呼叫一個 Tool 或讀取一個 Resource。每個 Request 都帶有唯一的 ID，用來配對對應的 Response。</p>



<p><strong>Notification（通知）</strong>：單向訊息，不需要回應。例如 Server 通知 Client 它的 Tool 列表已更新（list_changed），或 Client 通知 Server 某個 Root 已變更。</p>



<p><strong>Progress（進度）</strong>：長時間執行的操作可以回報進度，讓使用者知道目前的處理狀態。這對需要幾秒鐘以上才能完成的 Tool 來說特別實用。</p>



<h2 class="wp-block-heading">在 Claude Code 中設定 MCP Server</h2>



<p>理解了 MCP 的架構概念後，讓我們來看看如何在 Claude Code 中實際設定和使用 MCP Server。Claude Code 提供了簡潔的 CLI 指令來管理 MCP 連線。</p>



<h3 class="wp-block-heading">新增 MCP Server</h3>



<p>Claude Code 支援三種方式新增 MCP Server：</p>



<pre class="wp-block-code"><code class=""># 方式一：新增遠端 HTTP Server（推薦用於雲端服務）
claude mcp add --transport http notion https://mcp.notion.com/mcp

# 方式二：新增本地 stdio Server
claude mcp add --transport stdio my-server -- npx -y @example/mcp-server

# 方式三：新增 SSE Server（已棄用，建議改用 HTTP）
claude mcp add --transport sse legacy-api https://api.example.com/sse</code></pre>



<p>注意指令的語法規則：所有選項（<code>--transport</code>、<code>--env</code>、<code>--scope</code>、<code>--header</code>）必須放在 Server 名稱<strong>之前</strong>，<code>--</code>（雙破折號）用來分隔 Server 名稱和要傳給 Server 的命令及參數。</p>



<h3 class="wp-block-heading">三種設定範圍（Scope）</h3>



<p>MCP Server 的設定可以儲存在不同的範圍，決定了它的可見性和共享方式：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>範圍</th><th>儲存位置</th><th>適用場景</th><th>指令範例</th></tr></thead><tbody><tr><td>local（預設）</td><td><code>~/.claude.json</code></td><td>個人在特定專案使用的 Server</td><td><code>claude mcp add --scope local ...</code></td></tr><tr><td>project</td><td>專案根目錄的 <code>.mcp.json</code></td><td>團隊共享，可加入版本控制</td><td><code>claude mcp add --scope project ...</code></td></tr><tr><td>user</td><td><code>~/.claude.json</code></td><td>個人跨專案使用的 Server</td><td><code>claude mcp add --scope user ...</code></td></tr></tbody></table></figure>



<p>如果你的團隊需要共用相同的 MCP Server，使用 <code>project</code> scope 是最佳選擇。設定會儲存在 <code>.mcp.json</code> 檔案中，團隊成員只要 pull 最新的程式碼就能自動取得 MCP 設定。</p>



<h3 class="wp-block-heading">管理與除錯</h3>



<pre class="wp-block-code"><code class=""># 列出所有已設定的 MCP Server
claude mcp list

# 查看特定 Server 的設定細節
claude mcp get github

# 移除一個 MCP Server
claude mcp remove github

# 在 Claude Code 互動模式中檢查 Server 狀態
/mcp</code></pre>



<p>在 Claude Code 的互動模式中輸入 <code>/mcp</code>，可以看到所有 MCP Server 的連線狀態、可用的 Tools 數量，以及是否有錯誤發生。如果某個 Server 顯示為斷線狀態，可以嘗試重新啟動 Claude Code 或檢查 Server 的執行環境。</p>



<h2 class="wp-block-heading">Tool Search：智慧型工具載入</h2>



<p>當你連接了大量 MCP Server 後，所有 Tool 的定義加起來可能佔用數萬個 Token 的 Context。Claude Code 內建的 Tool Search 功能透過智慧索引和動態載入，只在需要時才載入相關的 Tool 定義，將 Context 消耗從約 72,000 Token 降低到約 8,700 Token——減少了約 85%。</p>



<p>Tool Search 是自動運作的，你不需要做任何設定。當你向 Claude 提出請求時，它會根據語意搜尋最相關的 Tools 來使用，就像搜尋引擎一樣。這意味著即使你連接了幾十個 MCP Server、數百個 Tools，Claude 的效能和成本也不會受到顯著影響。</p>



<h2 class="wp-block-heading">MCP 的安全性考量</h2>



<p>使用 MCP Server 時，安全性是必須重視的議題。以下是幾個關鍵的安全原則：</p>



<p><strong>審慎選擇 Server 來源</strong>：只安裝你信任的 MCP Server。第三方 Server 可能含有未經驗證的程式碼，尤其是那些需要存取敏感資料的 Server。官方推薦的 Server 列表是最安全的起點。</p>



<p><strong>注意 Prompt Injection 風險</strong>：如果 MCP Server 會抓取不受信任的外部內容（例如網頁、電子郵件），這些內容可能包含惡意的指令注入。Claude Code 有內建的安全機制來防範，但你仍應該對 Server 回傳的內容保持警覺。</p>



<p><strong>妥善管理認證資訊</strong>：使用 <code>--env</code> 參數傳遞 API Key 和認證 Token，避免將敏感資訊直接寫在 <code>.mcp.json</code> 中（因為這個檔案可能會被加入版本控制）。對於需要 OAuth 2.0 認證的遠端 Server，可以在 Claude Code 中使用 <code>/mcp</code> 指令來完成認證流程。</p>



<p><strong>善用 Project Scope 的安全機制</strong>：當 Claude Code 偵測到 <code>.mcp.json</code> 中的 Project Scope Server 時，會提示你確認是否信任這些 Server，這是一道額外的安全防線。如果需要重設這些選擇，可以使用 <code>claude mcp reset-project-choices</code> 指令。</p>



<h2 class="wp-block-heading">MCP 生態系的現況與發展</h2>



<p>MCP 自 2024 年 11 月發布以來，已經從 Anthropic 的內部實驗快速發展成為業界標準。2025 年 3 月，OpenAI 正式採用 MCP，將其整合到 ChatGPT Desktop App 中。同年 12 月，Anthropic 將 MCP 捐贈給 Linux Foundation 旗下的 Agentic AI Foundation（AAIF），由 Anthropic、Block 和 OpenAI 共同主導，Google 和 Microsoft 也加入支持。</p>



<p>目前，MCP 生態系中已有數百個開源 Server，涵蓋資料庫（PostgreSQL、MySQL）、專案管理（Jira、Asana、Linear）、溝通工具（Slack、Discord）、開發工具（GitHub、GitLab）、設計工具（Figma）等各類服務。Anthropic 也維護了一個<a href="https://github.com/modelcontextprotocol/servers" target="_blank" rel="noopener nofollow">官方 MCP Server 清單</a>，方便開發者查詢和使用。</p>



<p>2025 年 11 月的規格更新帶來了幾個重要的新功能：非同步操作支援、無狀態設計、Server 身分識別機制，以及官方的 MCP Server Registry。這些更新讓 MCP 更適合在生產環境中使用，也為未來的擴展奠定了基礎。</p>



<h2 class="wp-block-heading">實際應用場景</h2>



<p>理解了 MCP 的概念，讓我們看幾個具體的應用場景，感受 MCP 如何改變日常開發流程：</p>



<p><strong>場景一：從 Issue 到 PR 的完整工作流</strong>——連接 Jira MCP Server 和 GitHub MCP Server 後，你可以告訴 Claude：「讀取 JIRA-1234 的需求，在 main 分支上實作，完成後建立 PR 並 tag reviewer。」Claude 會自動讀取 Issue 內容、分析需求、撰寫程式碼、建立 Pull Request，一氣呵成。</p>



<p><strong>場景二：資料庫查詢與分析</strong>——連接 PostgreSQL MCP Server 後，你可以用自然語言查詢資料：「找出上個月註冊但從未登入的使用者，匯出他們的 email 清單。」Claude 會自動撰寫 SQL、執行查詢、整理結果。</p>



<p><strong>場景三：跨工具協作</strong>——同時連接 Slack、Figma 和 GitHub 後，你可以說：「根據 Figma 中最新的設計稿，更新首頁元件，完成後在 Slack 的 #frontend 頻道通知團隊。」Claude 會讀取設計稿、修改程式碼、發送通知，串連多個工具完成複雜的跨平台工作流。</p>



<h2 class="wp-block-heading">下一步：動手連接你的第一個 MCP Server</h2>



<p>本文介紹了 MCP 的核心概念、架構設計、三大原語、傳輸機制和安全考量。MCP 的出現，讓 AI 工具從「聰明的聊天機器人」進化為「能夠操作真實世界的數位助手」。</p>



<p>在下一篇文章中，我們將進入實戰環節——帶你一步步連接常見的 MCP Server，包括 GitHub、Slack、資料庫等，讓 Claude Code 真正成為你的全方位開發夥伴。如果你已經等不及了，可以先試試在 Claude Code 中執行以下指令：</p>



<pre class="wp-block-code"><code class=""># 連接 GitHub MCP Server（需要 GitHub 帳號）
claude mcp add --transport http github https://api.githubcopilot.com/mcp/

# 檢查連線狀態
/mcp</code></pre>



<p>連上之後，試著問 Claude：「列出我最近的 GitHub 通知」——你會發現，AI 與工具之間的溝通，從此變得如此自然。</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fmcp-protocol-introduction%2F&amp;linkname=MCP%20%E5%8D%94%E8%AD%B0%EF%BC%9A%E9%80%A3%E6%8E%A5%20AI%20%E8%88%87%E5%A4%96%E9%83%A8%E4%B8%96%E7%95%8C%E7%9A%84%E6%A9%8B%E6%A8%91" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fmcp-protocol-introduction%2F&amp;linkname=MCP%20%E5%8D%94%E8%AD%B0%EF%BC%9A%E9%80%A3%E6%8E%A5%20AI%20%E8%88%87%E5%A4%96%E9%83%A8%E4%B8%96%E7%95%8C%E7%9A%84%E6%A9%8B%E6%A8%91" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fmcp-protocol-introduction%2F&amp;linkname=MCP%20%E5%8D%94%E8%AD%B0%EF%BC%9A%E9%80%A3%E6%8E%A5%20AI%20%E8%88%87%E5%A4%96%E9%83%A8%E4%B8%96%E7%95%8C%E7%9A%84%E6%A9%8B%E6%A8%91" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fmcp-protocol-introduction%2F&#038;title=MCP%20%E5%8D%94%E8%AD%B0%EF%BC%9A%E9%80%A3%E6%8E%A5%20AI%20%E8%88%87%E5%A4%96%E9%83%A8%E4%B8%96%E7%95%8C%E7%9A%84%E6%A9%8B%E6%A8%91" data-a2a-url="https://blog.che-ya.com/mcp-protocol-introduction/" data-a2a-title="MCP 協議：連接 AI 與外部世界的橋樑"></a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Claude Desktop App 與 Web 版完整指南：從安裝到進階功能全攻略</title>
		<link>https://blog.che-ya.com/claude-desktop-app-web-guide/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Sun, 26 Apr 2026 01:03:00 +0000</pubDate>
				<category><![CDATA[IDE 整合]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[Cowork]]></category>
		<category><![CDATA[Desktop App]]></category>
		<category><![CDATA[MCP]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=841</guid>

					<description><![CDATA[Claude 不只是一個聊天機器人，它更是一個跨平台的 AI 工作夥伴。Anthropic 提供了 Deskt ... <a title="Claude Desktop App 與 Web 版完整指南：從安裝到進階功能全攻略" class="read-more" href="https://blog.che-ya.com/claude-desktop-app-web-guide/" aria-label="Read more about Claude Desktop App 與 Web 版完整指南：從安裝到進階功能全攻略">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>Claude 不只是一個聊天機器人，它更是一個跨平台的 AI 工作夥伴。Anthropic 提供了 Desktop App（桌面應用程式）和 Web 版（claude.ai）兩種使用方式，各有不同的功能定位和適用場景。如果你是開發者或知識工作者，搞清楚兩者的差異，選擇最適合自己的工具，將能大幅提升你的工作效率。本篇文章將完整介紹 Claude Desktop App 的安裝方式、核心功能，並和 Web 版進行詳細比較，幫助你做出最佳選擇。</p>



<h2 class="wp-block-heading">Claude Desktop App 與 Web 版的差異概觀</h2>



<p>在開始深入各項功能之前，先來看看兩者在功能面上的整體比較。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>比較項目</th><th>Desktop App</th><th>Web 版（claude.ai）</th></tr></thead><tbody><tr><td>平台支援</td><td>macOS、Windows</td><td>任何現代瀏覽器</td></tr><tr><td>Cowork 模式</td><td>完整支援</td><td>不支援</td></tr><tr><td>本地檔案存取</td><td>直接讀寫</td><td>需手動上傳</td></tr><tr><td>MCP Server 連接</td><td>支援（Desktop Extensions）</td><td>不支援</td></tr><tr><td>全域快捷鍵</td><td>支援（可自訂）</td><td>不支援</td></tr><tr><td>跨裝置同步</td><td>與行動版同步</td><td>瀏覽器登入即可</td></tr><tr><td>離線使用</td><td>不支援（需網路）</td><td>不支援（需網路）</td></tr><tr><td>Claude Code 整合</td><td>內建整合</td><td>不支援</td></tr><tr><td>排程任務</td><td>支援</td><td>不支援</td></tr><tr><td>Projects 專案管理</td><td>Cowork Projects</td><td>Web Projects</td></tr><tr><td>費用</td><td>免費下載，依訂閱方案</td><td>免費使用，依訂閱方案</td></tr></tbody></table></figure>



<p>簡單來說，Web 版適合快速對話和基本任務，而 Desktop App 則是為了深度整合本地工作流程而生的完整解決方案。</p>



<h2 class="wp-block-heading">Claude Desktop App 安裝與設定</h2>



<h3 class="wp-block-heading">系統需求與下載</h3>



<p>Claude Desktop App 目前支援 macOS 和 Windows 兩個平台，Linux 目前尚未支援。你可以直接到 <a href="https://claude.com/download" rel="nofollow noopener" target="_blank">claude.com/download</a> 下載安裝檔。macOS 版本為 Universal 架構，同時支援 Intel 和 Apple Silicon 晶片；Windows 版本則提供 x64 和 ARM64 兩種版本。</p>



<p>安裝過程非常簡單。macOS 用戶下載 DMG 檔案後，拖曳到 Applications 資料夾即可；Windows 用戶執行 Setup 安裝程式，按照提示完成安裝。首次啟動後，使用你的 Anthropic 帳號登入就能開始使用。</p>



<h3 class="wp-block-heading">全域快捷鍵設定</h3>



<p>Desktop App 最方便的功能之一就是全域快捷鍵。無論你正在使用任何應用程式，都能一鍵呼叫 Claude。macOS 的預設快捷鍵是 <code>Cmd + Shift + C</code>，Windows 則是 <code>Ctrl + Alt + Space</code>。你可以在 Preferences（偏好設定）中的 Shortcuts 區段自訂這個快捷鍵。</p>



<p>這意味著你可以在寫文件、看網頁、寫程式的時候，隨時呼叫 Claude 來幫忙，不需要切換視窗或打開瀏覽器。這種無縫體驗是 Web 版無法提供的。</p>



<h2 class="wp-block-heading">Desktop App 的核心功能</h2>



<h3 class="wp-block-heading">Chat 模式：對話式互動</h3>



<p>Chat 模式是最基本的使用方式，功能上和 Web 版幾乎相同。你可以與 Claude 進行自然語言對話、上傳檔案、使用 Projects 組織對話內容。Desktop App 的 Chat 模式額外支援拖曳本地檔案到對話視窗中，省去了手動上傳的步驟。</p>



<h3 class="wp-block-heading">Cowork 模式：自主代理執行</h3>



<p>Cowork 是 Desktop App 的殺手級功能，也是它和 Web 版最大的差異。Cowork 讓 Claude 不再只是回答問題，而是能夠自主執行多步驟的複雜任務。</p>



<p>啟動 Cowork 的方式很簡單：打開 Claude Desktop，在頂部的模式選擇器中切換到 Cowork 分頁，就能進入任務模式。在這裡，你可以描述想要完成的任務，Claude 會自動分析需求、拆解步驟、協調子代理並行執行，最終把成果直接輸出到你的檔案系統中。</p>



<p>Cowork 的主要能力包括以下幾個方面。首先是<strong>本地檔案存取</strong>，Claude 可以直接讀取和寫入你電腦上的檔案，不需要手動上傳下載。其次是<strong>子代理協調</strong>，Claude 能將複雜工作拆分成多個子任務，並行處理以提高效率。第三是<strong>專業文件輸出</strong>，可以生成帶有公式的 Excel 試算表、PowerPoint 簡報、格式化的 Word 文件等。第四是<strong>排程任務</strong>，你可以設定週期性或一次性的自動化任務。最後是<strong>Projects 功能</strong>，可以把相關任務組織成持久的工作空間，包含共享檔案、指示和記憶。</p>



<h3 class="wp-block-heading">Cowork 的運作機制</h3>



<p>Cowork 在一個隔離的虛擬機器環境中執行任務，這代表它有獨立的安全沙箱，不會直接影響你的系統。當你授予檔案存取權限後，Claude 才能讀寫指定的資料夾。整個執行過程中，你可以看到進度指示、Claude 的推理過程，也可以隨時介入修正方向。</p>



<p>要注意的是，Cowork 執行任務時需要保持 Desktop App 開啟。如果關閉應用程式或電腦進入睡眠狀態，正在執行的任務會被終止。如果需要長時間執行的任務，可以考慮使用 Remote Sessions，它會在 Anthropic 的雲端基礎架構上運行，即使關閉應用程式也會繼續執行。</p>



<h3 class="wp-block-heading">Claude Code 整合</h3>



<p>Desktop App 將 Claude Code 直接整合進來，提供了一個完整的開發環境。你可以在同一個應用程式中切換 Chat、Cowork 和 Code 三種模式，不需要額外安裝 CLI 工具。Claude Code 在 Desktop App 中提供了環境選擇（Local、Remote、SSH）、專案資料夾設定、模型選擇和權限模式等進階功能。</p>



<h2 class="wp-block-heading">MCP Server 與 Desktop Extensions</h2>



<p>Model Context Protocol（MCP）是 Anthropic 開發的開放協議，讓 Claude 能夠連接外部資料來源和工具。Desktop App 完整支援 MCP Server，而且提供了兩種設定方式。</p>



<h3 class="wp-block-heading">Desktop Extensions（簡易方式）</h3>



<p>Desktop Extensions 是 2026 年推出的新功能，大幅簡化了 MCP Server 的安裝流程。就像安裝瀏覽器擴充套件一樣，你只需要到 Settings &gt; Extensions，瀏覽 Anthropic 審核過的擴充套件目錄，點擊安裝就完成了。不需要手動編輯 JSON 設定檔，也不需要管理相依套件。</p>



<h3 class="wp-block-heading">手動 JSON 設定（進階方式）</h3>



<p>如果你需要連接自訂的 MCP Server，可以手動編輯設定檔。設定檔的位置根據作業系統不同而異。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>作業系統</th><th>設定檔路徑</th></tr></thead><tbody><tr><td>macOS</td><td><code>~/Library/Application Support/Claude/claude_desktop_config.json</code></td></tr><tr><td>Windows</td><td><code>%APPDATA%\Claude\claude_desktop_config.json</code></td></tr></tbody></table></figure>



<p>設定檔的格式如下：</p>



<pre class="wp-block-code"><code class="">{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["-y", "@my-org/my-mcp-server"],
      "env": {
        "API_KEY": "your-api-key"
      }
    }
  }
}</code></pre>



<p>修改設定檔後，需要完全關閉 Claude Desktop（不只是關閉視窗）再重新開啟，MCP Server 才會生效。成功載入後，你可以在對話視窗底部的工具列中看到 MCP 指示器，點擊滑桿圖示可以查看可用的工具。</p>



<h2 class="wp-block-heading">排程任務與自動化</h2>



<p>Desktop App 支援排程任務功能，讓你能夠設定週期性或一次性的自動化工作流程。在 Cowork 模式中，你可以輸入 <code>/schedule</code> 來建立排程任務。</p>



<p>排程任務的常見應用場景包括：每天早上自動整理收件匣摘要、定期產生專案進度報告、每週自動備份特定資料夾的檔案清單、定時監控某些網站或 API 的變化等。</p>



<p>需要注意的是，排程任務只有在電腦處於喚醒狀態且 Claude Desktop App 保持開啟時才會執行。如果電腦在排定的執行時間處於睡眠或關機狀態，該次任務會被跳過。</p>



<h2 class="wp-block-heading">Projects 專案管理功能</h2>



<p>Desktop App 和 Web 版都支援 Projects 功能，但在 Cowork 模式下的 Projects 功能更為強大。</p>



<p>Web 版的 Projects 讓你可以組織對話、設定自訂指示（Custom Instructions），並在專案中共享知識庫檔案。這對於需要保持上下文一致性的系列對話非常有用。</p>



<p>Cowork 的 Projects 則更進一步，它是一個持久的工作空間，可以包含自己的檔案、連結、指示和記憶。在 Cowork Projects 中，Claude 能夠記住之前的對話脈絡，了解專案的特定規範和偏好，在多個任務之間保持一致的工作狀態。</p>



<h2 class="wp-block-heading">Dispatch：行動裝置與桌面的橋樑</h2>



<p>Dispatch 是 Anthropic 在 2026 年推出的新功能，讓你可以從手機上指派任務給 Claude，然後回到桌面電腦查看完成的結果。這個功能對於 Pro 和 Max 訂閱用戶開放。</p>



<p>使用場景很直覺：你在通勤路上用手機想到需要整理一份報告，可以直接在 Claude iOS 或 Android App 中描述任務，Claude 就會在你的桌面電腦上開始執行。等你到了辦公室，打開 Desktop App 就能看到完成的成果。</p>



<h2 class="wp-block-heading">Web 版（claude.ai）的優勢</h2>



<p>雖然 Desktop App 功能更強大，但 Web 版在某些場景下仍然有其優勢。</p>



<p><strong>零安裝使用</strong>是最大的優點。打開瀏覽器就能用，不需要下載安裝任何東西，也不受作業系統限制。無論你用的是 Linux、ChromeOS 還是任何有瀏覽器的裝置，都能存取 Claude。</p>



<p><strong>Artifacts 功能</strong>在 Web 版上的體驗更好。Artifacts 讓 Claude 能夠生成互動式的程式碼預覽、圖表、和可視化內容，直接在聊天視窗旁邊即時呈現。</p>



<p><strong>團隊協作</strong>方面，Web 版的 Team 和 Enterprise 方案提供了完整的管理功能，包括審計日誌、資料匯出、使用量分析等。而 Desktop App 的 Cowork 活動目前不會被記錄在審計日誌或資料匯出中，這對有合規需求的企業來說是需要考量的。</p>



<h2 class="wp-block-heading">如何選擇適合你的使用方式</h2>



<p>根據不同的工作需求和使用場景，以下是選擇建議。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>使用場景</th><th>建議方式</th><th>原因</th></tr></thead><tbody><tr><td>快速問答與對話</td><td>Web 版或 Desktop App</td><td>兩者皆可，看個人習慣</td></tr><tr><td>需要處理本地檔案</td><td>Desktop App</td><td>可直接存取檔案系統</td></tr><tr><td>自動化工作流程</td><td>Desktop App（Cowork）</td><td>支援排程和多步驟任務</td></tr><tr><td>軟體開發</td><td>Desktop App（Code）</td><td>整合 Claude Code 開發環境</td></tr><tr><td>團隊協作與管理</td><td>Web 版</td><td>完整的管理和審計功能</td></tr><tr><td>跨平台使用</td><td>Web 版</td><td>支援任何有瀏覽器的裝置</td></tr><tr><td>連接外部工具</td><td>Desktop App</td><td>MCP Server 和 Extensions</td></tr></tbody></table></figure>



<p>最佳的策略通常是兩者並用。Desktop App 作為日常主力工具，Web 版作為補充和備用。兩者使用同一個帳號，對話紀錄也會同步，所以可以無縫切換。</p>



<h2 class="wp-block-heading">Desktop App 常見問題與疑難排解</h2>



<h3 class="wp-block-heading">安裝與啟動問題</h3>



<p>如果安裝後無法正常啟動，可以先到 Anthropic 官方提供的相容性檢查工具（Readiness Checker）確認你的系統是否符合需求。macOS 和 Windows 各有對應的檢查工具可以下載使用。</p>



<p>如果看到「Setting up Claude&#8217;s workspace」的訊息，這是正常的初始化過程，代表應用程式正在更新或設定環境，等待一段時間即可。</p>



<h3 class="wp-block-heading">Cowork 任務中斷</h3>



<p>Cowork 任務中斷最常見的原因是 Desktop App 被關閉或電腦進入睡眠。確保在執行長時間任務時，調整電腦的睡眠設定，或改用 Remote Sessions 來避免這個問題。</p>



<h3 class="wp-block-heading">用量管理</h3>



<p>Cowork 模式由於涉及多步驟執行和子代理協調，會消耗比一般對話更多的資源。建議將 Cowork 保留給真正需要多步驟處理的複雜任務，簡單的問答用 Chat 模式就好。你可以在 Settings &gt; Usage 中查看使用量狀況，方便管理配額。</p>



<h2 class="wp-block-heading">企業部署與管理</h2>



<p>對於企業 IT 團隊來說，Claude Desktop App 支援透過 MDM（macOS）或 Group Policy（Windows）進行統一管理。管理員可以設定的政策包括：啟用或停用特定功能、控制自動更新行為、設定自訂部署 URL、管理 MCP Server 連接權限等。這讓企業能夠在確保安全性的前提下，大規模部署 Claude Desktop App。</p>



<h2 class="wp-block-heading">總結</h2>



<p>Claude Desktop App 不只是 Web 版的桌面包裝，它是一個具有深度系統整合能力的 AI 工作平台。Cowork 模式帶來了自主代理執行能力，MCP Server 讓 Claude 能連接你的工具生態系，全域快捷鍵和本地檔案存取則大幅降低了使用門檻。</p>



<p>如果你是重度 Claude 使用者，Desktop App 幾乎是必裝的。搭配 Web 版和行動版 App，你可以建立一個完整的跨裝置 AI 工作流程，在任何地方都能高效完成工作。</p>



<p>在後續的文章中，我們將深入探討 MCP 協議的技術細節，以及如何開發自己的 MCP Server 來擴展 Claude 的能力。</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-desktop-app-web-guide%2F&amp;linkname=Claude%20Desktop%20App%20%E8%88%87%20Web%20%E7%89%88%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97%EF%BC%9A%E5%BE%9E%E5%AE%89%E8%A3%9D%E5%88%B0%E9%80%B2%E9%9A%8E%E5%8A%9F%E8%83%BD%E5%85%A8%E6%94%BB%E7%95%A5" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-desktop-app-web-guide%2F&amp;linkname=Claude%20Desktop%20App%20%E8%88%87%20Web%20%E7%89%88%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97%EF%BC%9A%E5%BE%9E%E5%AE%89%E8%A3%9D%E5%88%B0%E9%80%B2%E9%9A%8E%E5%8A%9F%E8%83%BD%E5%85%A8%E6%94%BB%E7%95%A5" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-desktop-app-web-guide%2F&amp;linkname=Claude%20Desktop%20App%20%E8%88%87%20Web%20%E7%89%88%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97%EF%BC%9A%E5%BE%9E%E5%AE%89%E8%A3%9D%E5%88%B0%E9%80%B2%E9%9A%8E%E5%8A%9F%E8%83%BD%E5%85%A8%E6%94%BB%E7%95%A5" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fclaude-desktop-app-web-guide%2F&#038;title=Claude%20Desktop%20App%20%E8%88%87%20Web%20%E7%89%88%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97%EF%BC%9A%E5%BE%9E%E5%AE%89%E8%A3%9D%E5%88%B0%E9%80%B2%E9%9A%8E%E5%8A%9F%E8%83%BD%E5%85%A8%E6%94%BB%E7%95%A5" data-a2a-url="https://blog.che-ya.com/claude-desktop-app-web-guide/" data-a2a-title="Claude Desktop App 與 Web 版完整指南：從安裝到進階功能全攻略"></a></p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
