How to build MCP server

前言

前陣子剛好處於職涯的轉換期,從 Software Engineer 轉變為顧問 Consultant 的角色。在適應新身份和不同工作節奏的過程中,部落格也跟著停更了一段時間。現在好不容易閒下來,是時候把這幾個月「搗鼓」的東西整理出來跟大家分享了~

還記得上一篇 教學:安裝 MCP 至 Claude Desktop,善用 AI 加速工作生產力 提到如何把現成的 MCP server 裝進 Claude 嗎?

今天我們不只要「用」,更要進一步「造」——自己動手建構一個本地的 MCP server,打造專屬於你的 AI 小工具。

為什麼想做這個?

這個靈感其實來自於我很日常的一個 idea。

每天早上醒來或通勤時,習慣做的第一件事大概就是滑手機看新聞。

但我通常只關注科技、娛樂與股市這類特定主題,現在的演算法雖然強大,但內容品質都不一定穩定,或者我需要瀏覽多個來源了解同個主題但不同解讀面向的新聞。

所以我產生了一個想法:能不能透過 API 把新聞抓下來,讓 LLM 幫我統整?

所以目標很明確:利用自定義的 MCP server 串接新聞 API,讓 Claude 能夠根據我的指令,直接調用、過濾並總結我真正想看的內容。

因此我抱持「想偷懶所以變勤勞」的想法,開始了這次的實作

技術架構

整個系統分為三層:

  1. Claude Desktop - 使用者介面,透過自然語言下指令
  2. News MCP Server - 我們要自己建的部分,使用 FastMCP 框架
  3. newsdata.io API - 外部新聞資料來源,支援 200+ 國家、40+ 語言
%%{init: {'theme':'dark', 'themeVariables': { 'darkMode': true, 'mainBkg': '#000000', 'clusterBkg': '#1A1A1A', 'primaryTextColor': '#E0E0E0', 'fontFamily': 'sans-serif' }}}%%
graph TB
    User[使用者] --> Claude[Claude Desktop
] Claude <-->|JSON-RPC| MCP[News MCP Server] MCP <-->|REST API| API[newsdata.io] subgraph "MCP Tools" MCP --> Tool1[get_latest_news] MCP --> Tool2[get_tech_news] MCP --> Tool3[get_taiwan_news] end API --> DB[newsdata.io news] style User fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#E0E0E0 style Claude fill:#254a7c,stroke:#60a5fa,stroke-width:3px,color:#E0E0E0 style MCP fill:#8b4011,stroke:#fcd34d,stroke-width:3px,color:#E0E0E0 style API fill:#5820a4,stroke:#c4b5fd,stroke-width:3px,color:#E0E0E0 style DB fill:#0a5e44,stroke:#34d399,stroke-width:3px,color:#E0E0E0 style Tool1 fill:#546274,stroke:#9ca3af,stroke-width:1px,color:#F0F0F0 style Tool2 fill:#546274,stroke:#9ca3af,stroke-width:1px,color:#F0F0F0 style Tool3 fill:#546274,stroke:#9ca3af,stroke-width:1px,color:#F0F0F0

環境準備

首先安裝Python 套件管理工具 uv

1
2
3
4
5
6
7
8
9
# 安裝 uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# 建立專案
mkdir news-mcp && cd news-mcp
uv init

# 安裝相依套件
uv add "mcp[cli]>=1.9.4" "requests>=2.32.4"

接著到 newsdata.io 註冊免費帳號,取得 API Key(免費版每日 200 次請求)。

核心程式碼

建立 src/mcp_news.py,核心概念就是用 @mcp.tool() decorator 把函數包裝成 MCP 工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from typing import Any, Optional
from mcp.server.fastmcp import FastMCP
import requests
import os

# 初始化 MCP server
mcp = FastMCP("news", dependencies=["requests"])

# API 設定
NEWSDATA_API_KEY = os.getenv("NEWSDATA_API_KEY")
BASE_URL = "https://newsdata.io/api/1"

@mcp.tool()
def get_latest_news(
country: Optional[str] = None,
category: Optional[str] = None,
language: str = "en",
query: Optional[str] = None,
max_results: int = 10
) -> dict[str, Any]:
"""
Get latest news articles

Args:
country: Country code (e.g., 'us', 'tw', 'jp')
category: News category (e.g., 'technology', 'business')
language: Language code (default: 'en')
query: Search keywords
max_results: Maximum results (default: 10)
"""
url = f"{BASE_URL}/news"
params = {
"apikey": NEWSDATA_API_KEY,
"language": language,
}

if country:
params["country"] = country
if category:
params["category"] = category
if query:
params["q"] = query

response = requests.get(url, params=params)
data = response.json()

articles = data.get("results", [])[:max_results]

return {
"total_results": len(articles),
"articles": [
{
"title": article.get("title"),
"description": article.get("description"),
"link": article.get("link"),
"source": article.get("source_id"),
"published_at": article.get("pubDate"),
}
for article in articles
]
}

@mcp.tool()
def get_tech_news(language: str = "en", max_results: int = 10) -> dict[str, Any]:
"""Get latest technology news"""
return get_latest_news(category="technology", language=language, max_results=max_results)

@mcp.tool()
def get_taiwan_news(category: Optional[str] = None, max_results: int = 10) -> dict[str, Any]:
"""Get latest news from Taiwan in Chinese"""
return get_latest_news(country="tw", category=category, language="zh", max_results=max_results)

if __name__ == "__main__":
mcp.run()

LLM 如何知道要用哪個 Function?

這裡的關鍵在於 FastMCP 會自動把 Python 函數轉換成 JSON Schema,讓 LLM 能理解。

當你用 @mcp.tool() decorator 標記一個函數時,FastMCP 會自動:

  1. 讀取函數簽名:從參數的型別標註(type hints)提取每個參數的資料型別
  2. 解析 docstring:從函數說明文件中提取工具的描述和參數說明
  3. 生成 JSON Schema:將這些資訊序列化成標準格式

例如我們的 get_latest_news 函數會被轉換成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"name": "get_latest_news",
"description": "Get latest news articles",
"inputSchema": {
"type": "object",
"properties": {
"country": {
"type": "string",
"description": "Country code (e.g., 'us', 'tw', 'jp')"
},
"category": {
"type": "string",
"description": "News category (e.g., 'technology', 'business')"
},
"language": {
"type": "string",
"description": "Language code (default: 'en')",
"default": "en"
}
}
}
}

當你向 Claude 下達指令時,背後的流程是這樣的:

  1. Claude 接收到你的自然語言指令:「Get me the latest technology news」
  2. 分析可用的工具列表:Claude 看到有 get_latest_newsget_tech_newsget_taiwan_news 等工具
  3. 判斷最適合的工具:根據描述和參數,判斷 get_tech_news 最符合需求
  4. 產生工具呼叫請求:Claude 產生類似這樣的 JSON:
    1
    2
    3
    4
    5
    6
    7
    {
    "tool": "get_tech_news",
    "parameters": {
    "language": "en",
    "max_results": 10
    }
    }
  5. MCP Server 執行函數:接收到請求後執行對應的 Python 函數
  6. 回傳結構化結果:函數執行完回傳 JSON 格式的新聞資料
  7. Claude 整理成自然語言:將結構化資料轉換成易讀的摘要給使用者

docstring 和參數說明越清楚,LLM 就越能準確判斷什麼時候該用哪個工具

這也是為什麼我們定義了 get_tech_news 這樣的函數——它的名稱和描述更明確,讓 LLM 能更快速地匹配使用者的意圖。

測試運行

設定環境變數後,可以直接測試:

1
2
export NEWSDATA_API_KEY="your_api_key_here"
mcp dev src/mcp_news.py

終端機會顯示一個 URL,點擊後會開啟 MCP Inspector,可以在瀏覽器中直接測試各個工具。

整合到 Claude Desktop

編輯 Claude 設定檔(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):

1
2
3
4
5
6
7
8
9
10
11
{
"mcpServers": {
"news": {
"command": "uv",
"args": ["run", "/path/to/news-mcp/src/mcp_news.py"],
"env": {
"NEWSDATA_API_KEY": "your_api_key_here"
}
}
}
}

重啟 Claude Desktop,在 Settings -> Developer -> Local MCP servers 就可以看到我的 MCP server 顯示 running 的狀態

檢查 Claude 連接到 local MCP server

實際使用

現在可以直接用自然語言跟 Claude 對話:

  • “Get me the latest technology news”
  • “Show me Taiwan technology news in Chinese”
  • “What’s happening with cryptocurrency?”

Claude 會自動判斷要呼叫哪個工具,幫你整理成易讀的摘要。

重要概念

MCP 的運作原理其實很簡單:FastMCP 會把你的函數轉換成 JSON Schema,讓 AI 知道有哪些工具可用、需要什麼參數。

當使用者下指令時,AI 判斷要用哪個工具,MCP server 執行後回傳結果,AI 再把結果轉成人類易懂的回應。整個過程都是自動的,你只需要專注在寫好工具函數本身。

實際運行範例

讓我們來看一個真實的使用案例。我在 Claude 中直接使用這個 News MCP Server,用自然語言向 AI 下指令:

指令:「Summarize me Gemini3 from latest news」

MCP 實際運行結果

可以看到整個流程運作:

  1. AI 理解我的意圖:我想知道 Gemini 3 的最新新聞摘要
  2. 自動選擇正確的工具:AI 判斷應該使用 search_news 函數
  3. 傳入適當參數
    1
    2
    3
    4
    {
    "keywords": "Gemini 3",
    "max_results": 10
    }
  4. 取得即時新聞:MCP Server 向 newsdata.io API 發送請求
  5. AI 整理成摘要:將結構化的 response (從 API 拿到的新聞資料)總結成易讀的內容

回傳的摘要包含

  • Google 最新發布 Gemini 3 的重點功能
  • 在 AI 領導力排行榜上的表現
  • 多模態推理能力的提升
  • “Nano Banana Pro” 圖片生成功能
  • 價格策略調整
  • 市場影響分析

透過 FastMCP 框架,就可以快速建立了一個實用的新聞 MCP server。

這個架構可以延伸到任何有 API 的服務:天氣、股價、待辦事項、內部系統等等。

下次當各位覺得「如果 AI 能幫我做這個就好了」,不妨花個半小時,自己動手打造一個專屬的 MCP 工具吧!!!

教學:安裝 MCP 至 Claude Desktop,善用 AI 加速工作生產力

隨著 OpenAI ChatGPT、Anthropic Claude 等 AI 服務的興起,運用這些工具來加速工作效率已經成為日常。

還記得 ChatGPT 剛問世時,我多半拿它來做翻譯、寫郵件草稿這種基礎應用。

但自從 Anthropic 在去年推出 MCP(Model Context Protocol) 後,AI 助理的能力又往前邁進了一大步——彷彿多了個小幫手,幫你處理繁瑣的日常工作瑣事,讓你能專注在更重要的任務上。

什麼是 MCP?

MCP(Model Context Protocol) 是 Anthropic 在 2024 年 11 月發表的開放標準協議,目的是讓 AI 助理安全地連接並使用各種第三方資料與工具

直接跟大家劇透他的功能 :
只要用戶授權,Claude 就能連結 Gmail、Google Drive、Atlassian、Asana 等常見工作工具,將 AI 從單純的對話夥伴,升級為真正能操作你日常工作平台的幫手。

這也解決了大語言模型長期面臨的資訊孤島問題。過去我們只能透過複製貼上的方式讓 AI 知道外部資訊,現在 Claude 可以直接「看到」並操作這些工具。

這些第三方服務會以 MCP Server 的形式提供功能(例如列出郵件、讀取專案資料等),用戶只要在 Claude 連接對應的 MCP Server,就能直接下指令使用這些功能,一氣呵成完成各種操作。

小提醒:根據 Anthropic 官方說明,部分第三方 MCP 服務需要特定付費方案才能使用(我自己是用 Pro 方案)。

MCP 的連接方式也很靈活,除了直接連接外部服務,也可以自己在本地搭建 MCP Server,客製化專屬功能。

不過今天這篇文章先聚焦如何在 Claude 上快速使用 MCP,至於如何用 Python 搭建本地 MCP Server,會變成下一篇文章跟大家說明(要填坑啦)

實戰示範:連接 Gmail 到 Claude Desktop

Step 1. 開啟 Claude Desktop → 前往 Settings → 點擊 Connectors

Claude 設定頁面

Step 2. 選擇要連接的第三方工具 → 點擊 Connect

接著會跳轉到 Google 的授權頁面,依照提示登入你的 Google 帳號並授權。完成後回到 Claude 的設定頁面,若顯示 Connected 或類似的連接成功狀態,就代表設定完成!

Claude 連接成功

Step 3. 測試 Gmail MCP 功能

重新啟動 Claude Desktop 並開啟新的對話視窗,記得確認 Gmail 連接已啟用(通常會在對話框下方看到相關圖示)。

接著就可以開始操作了

例如:我請 Claude 統計 過去一個月收到多少封來自 The Washington Post 的郵件,Claude 會自動透過 MCP 工具讀取 Gmail,並給出結果(數量讓我驚呆了 😅)。

結語

看吧!設定 MCP 其實很簡單~
而且 MCP 不只可以做資料讀取,還能處理更進階的寫入操作(例如建立 GitHub issue)。

不過還是要提醒大家使用 AI 工具要注意的事項:

  1. 只授權必要的權限給 AI,別把隱私或敏感資料也一併丟進去
  2. 無論 AI 幫你完成什麼操作,都務必檢查並審核結果,確保執行的動作正確哦

參考資料:

  1. Introducing Model Context Protocol
  2. Using the Gmail and Google Calendar Integrations