iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
AI Engineering

打造具備記憶與執行能力的常駐 AI Agent:Hermes Agent × Gemini × MCP 的 Harness 設計系列 第 23 篇

【Day 23】OAuth 的 client 換人當:接外部 MCP 之後組態少掉兩個區塊

  • 分享至 

  • xImage
  •  

前兩天那個 MCP server 是自己寫的,工具邊界、參數驗證與授權判定全部在自己手上。今天換成接一個別人寫好的 server,對象是 Google Workspace 的日曆與信箱。同一件事換一層來做,成本從實作移到授權與程序管理,組態檔的形狀也跟著變。


三種取得途徑,卡在資格的那一種先排除

Google 在 Cloud Next '26 開放的託管 MCP 裡,Workspace 側是八個遠端端點。實際要用的時候卡在資格:那組端點屬於 Workspace Developer Preview Program,要求持有 Google Workspace 帳號並通過審核,個人 Gmail 帳號不符。

剩下兩種途徑的差別:

官方託管 MCP 開源自架
帳號資格 Workspace 帳號並通過審核 任何 Google 帳號
執行位置 Google 託管的遠端端點 本機程序
OAuth client 是誰 agent 自己 MCP server 自己
agent 端組態 需要 auth: 與 oauth: 兩個區塊 一行 url:
信箱唯讀 強制要 gmail.compose 寫入權 --read-only 只申請 gmail.readonly

最後一列是選型的決定性差異。唯讀這件事放在 prompt 層是一句指示,模型可能照做也可能不照做,放在 OAuth scope 上,寫入類工具根本不會載入,模型在協定層就沒有那個選項。


服務識別碼跟產品名不一樣

建立 GCP 專案之後要啟用底層 API,日曆這一支的識別碼與直覺不同:

gcloud services enable gmail.googleapis.com
gcloud services enable calendar-json.googleapis.com

日曆的服務名是 calendar-json.googleapis.com。 兩者都是正式服務,與 Preview 資格無關,填成 calendar.googleapis.com 會在啟用那一步就失敗。

OAuth 同意畫面這一側,User Type 選 External、Publishing status 留在 Testing,測試使用者上限 100 人。--read-only 模式實際使用的 scope 有五個:

openid
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/calendar.readonly

這五個是兩組組合起來的。auth/scopes.py 裡 BASE_SCOPES 固定帶 openid 與兩個 userinfo,TOOL_READONLY_SCOPES_MAP 給 gmail 的是 gmail.readonly、給 calendar 的是 calendar.readonly。前三個用於識別身分,真正碰到資料的只有後兩個。

OAuth client 建成 Web application 類型,已授權的重新導向 URI 填 http://localhost:8000/oauth2callback。

產品名與服務識別碼各自獨立命名,啟用哪一支以 Console 列出的識別碼為準


四個旗標各自關掉一塊

啟動指令與環境變數:

export WORKSPACE_MCP_PORT="8000"
export GOOGLE_OAUTH_REDIRECT_URI="http://localhost:8000/oauth2callback"

uvx workspace-mcp --transport streamable-http \
  --tools gmail calendar --tool-tier core --read-only --single-user
旗標 作用
--transport streamable-http 以 HTTP 端點對外,取代 stdio
--tools gmail calendar 只載入這兩個產品的工具
--tool-tier core 每個產品只載入精簡工具集
--read-only 只申請唯讀 scope,寫入類工具不載入
--single-user 單人模式,省掉多使用者的 session 管理

--tool-tier core 的作用與前面量過的 context 預算直接相關。工具 schema 整份進 system prompt,掛得越多固定開銷越大,而工具數量上升時模型挑錯工具的機率也跟著上升。篩選後實際掛上來的是五個:

  • list_calendars:列出可存取的日曆
  • get_events:讀指定日曆的事件
  • search_gmail_messages:依查詢字串搜尋信件
  • get_gmail_message_content:讀單一信件全文
  • get_gmail_messages_content_batch:一次讀多封信件全文

五個全是讀取。--read-only 讓寫入那一側在工具清單裡就不存在。


agent 端只需要知道去哪裡連

掛載的指令是一行:

hermes mcp add workspace --url "http://127.0.0.1:8000/mcp"

執行後會問一句 Does this server require authentication? [Y/n],答 n。Google 的授權流程由 MCP server 自己跑完,agent 這端不是 OAuth client,因此組態裡既沒有 auth: 也沒有 oauth:,只剩下一個 URL。

授權責任放在哪一層,決定了另一層的組態需要寫幾行

與自建那兩天對照起來,同一件事的成本落在不同位置:

自建 MCP 外部 MCP
主要成本 實作工具、參數驗證、安全判定 申請憑證、登記 URI、管理程序生命週期
授權寫在哪 自己在工具裡實作確認閘門 OAuth scope,由服務端強制
壞掉時查哪 自己的程式碼 憑證、port、程序是否還活著

兩個組態錯誤與一個搶答

症狀 原因 處置
redirect_uri_mismatch WORKSPACE_MCP_PORT 與 Console 登記的 URI 不一致 兩邊改成同一個 port
掛載成功但連線時好時壞 同一個 port 上有第二個行程 查出來關掉它
回答提到 google_token.json 同名的內建 skill 搶答 停用那個 skill

第一個錯誤的成因單純,改了 port 就要回 Console 一起改。

第二個是 port 被占用,症狀是時好時壞。Docker Desktop 的後端行程會綁 0.0.0.0:8000,涵蓋所有介面,看起來像 MCP server 在監聽,實際連進去的是另一個程式。確認方式:

netstat -ano | findstr :8000

只有一個行程在這個 port 上才算乾淨。

第三件事與組態無關。agent 內建一個同名的 google-workspace skill,它會跟 MCP server 搶同一類問題,症狀是回答開始提到 google_token.json、google_client_secret.json,或把人導去 Console 建立 Desktop app 憑證。那是 skill 的流程,與 MCP server 無關。同一個領域同時有 skill 與 MCP 時,模型選哪一個由它自己決定,要讓 MCP 接手就得把 skill 停用。


維運這一側多了一條

workspace-mcp 是本機程序,跑在一個終端機視窗裡。終端機關掉程序就結束,agent 隨即連不上。 自建那個 MCP 包在容器裡,重開機之後容器自己起來,這一個要人再開一次終端機。

排錯順序因此固定成兩步:

  • 先確認程序還活著:curl http://127.0.0.1:8000/mcp 沒有回應就是程序沒在跑,與 Google 那一側無關
  • 再確認授權那一步:卡在 redirect_uri_mismatch 的話回去對 port 與登記的 URI

外部 MCP 的可用性綁在一個本機行程的壽命上,它的生命週期要自己管


心得

啟動腳本印出伺服器在 8000 監聽,掛載指令回報成功,問日曆問題卻連不上,重試幾次之後又通了一次。時好時壞這件事本身是線索,固定壞或固定好都比較好查。

netstat 列出來 8000 上有兩個行程,另一個是 Docker Desktop 綁的 0.0.0.0:8000。綁在萬用位址的行程涵蓋所有介面,兩邊各自以為自己拿到了這個 port,實際連進去的是哪一個要看作業系統怎麼派。

「伺服器說它在監聽」與「連進去的是它」是兩段不同的資訊。前者來自伺服器自己的輸出,後者要從系統這一側去看誰真的綁著那個 port。

服務自己印出來的監聽訊息,證明的是它呼叫了 bind,證明不了連線會進到它那裡


明天

工具掛上去之後,模型花了三分鐘查別的東西,一次都沒有呼叫它。


上一篇
【Day 22】已受理但還沒完成:長時操作在無狀態協定下怎麼做
下一篇
【Day 24】工具就在手上,模型查了三分鐘別的東西
系列文
打造具備記憶與執行能力的常駐 AI Agent:Hermes Agent × Gemini × MCP 的 Harness 設計 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言