[TOOLS] 16 分鐘閱讀OraCore 編輯部

Foundry MCP 把工具收斂成一個端點

我拆 Foundry 的 MCP 接法、Toolboxes、授權與 approval 流程,最後給你一份可直接貼進專案的 Python 模板。

分享 LinkedIn
Foundry MCP 把工具收斂成一個端點

這篇可以直接抄走 Foundry MCP 的接法、approval 流程、Toolboxes 與 Python 模板。

我用 agent 工具接線這件事一陣子了,越用越火大。模型沒問題,prompt 也沒問題,SDK 看起來也都正常,然後整個系統就卡在工具邊界:GitHub 一套、內部服務一套、搜尋又一套,最後每個 agent 都長得像拼裝車。我最受不了的是,大家總把問題怪到模型身上,但真正難的是工具怎麼接、誰能用、誰要先按同意。工具邊界沒收好,agent 再聰明也只是會亂跑的自動化。

後來我看了 Microsoft Learn 這篇 Connect to MCP Server Endpoints for agents,腦袋才比較清楚。它不是在教你再寫一層客製 wrapper,而是把外部能力收進 Model Context Protocol 這條線裡。也就是說,Foundry agent 不必知道每個外部系統的怪脾氣,只要會講 MCP,就能把遠端工具當成標準端點來用。

別再把每個工具都當一次性專案

訂閱 AI 趨勢週報

每週精選模型發布、工具應用與深度分析,直送信箱。不定期,不騷擾。

不會寄垃圾信,隨時可取消。

Connect your Foundry agents to Model Context Protocol (MCP) servers by using the MCP tool.

翻譯一下就是:agent 不需要知道工具背後到底怎麼實作,它只要知道怎麼呼叫一個 MCP server。這個 server 把能力包成標準介面,agent 看到的是工具,不是你那坨自訂整合碼。

Foundry MCP 把工具收斂成一個端點

我以前最常掉進去的坑,就是每加一個外部服務就寫一個 wrapper,然後每個 wrapper 都有自己的 auth、retry、錯誤格式、回傳結構。第一個看起來很合理,第二個開始就會失控。MCP 的好處不是「多了一個新名詞」,而是它把工具邊界固定住了,讓你不用每次都重新發明整合方式。

實操上我會這樣做:凡是能被包成 MCP server 的服務,優先走 MCP。只有在真的需要非常客製的行為時,才退回去寫專用 wrapper。對 Foundry 來說,就是把 mcp tool 當成預設入口,而不是把外部 API 硬塞進 agent prompt 或業務邏輯裡。

  • 先判斷服務能不能變成 MCP server。
  • 能的話就不要急著寫客製 function wrapper。
  • 把 agent 只保留在「會呼叫工具」這層,不要把整合細節灌進去。

公網端點簡單,私網端點才是現實

這篇我最在意的是它把 public 和 private MCP endpoint 分開講,因為那才是實際上會卡住你的地方。公網端點很單純,server 能從網際網路被找到,Foundry Agent Service 就能連。私網端點就沒那麼好打發,Microsoft 明講要走 Standard Agent Setup、private networking,還要有專用的 MCP subnet。

翻譯一下就是:如果你的工具在內網,別幻想靠幾個設定值就混過去。你得先把網路拓樸、入口、子網、權限這些東西搞定,agent 才有機會真的碰到那個 server。Microsoft 也提到 Azure Container Apps 與 Microsoft.App/environments 這類網路設定,還有一個模板 19-private-network-agents-tools-setup,這種東西我都會先看,因為它通常比我自己瞎配快得多。

我以前就踩過這種雷:先把 agent 寫好,最後才發現工具在內網,然後整個專案開始補 subnet、補 ingress、補權限,補到大家都想裝死。這類問題不是 code 層可以救的,順序錯了就是錯了。

實操寫法很直接:

  • 公網 MCP:直接用可公開存取的 URL。
  • 私網 MCP:先定好 Standard Agent Setup 和網路隔離。
  • 先決定 endpoint 類型,再寫 agent,不要反過來。

如果你在企業環境,我會建議先把網路模板跑起來,再把 agent 接上去。順序顛倒,後面只會一直補洞。

Toolbox 才是我想要的「工具收斂層」

Foundry Toolboxes 這個設計,我是真的有點點頭。它不是單一工具,而是把多個工具包成一個 MCP-compatible endpoint,裡面可以放 MCP server、OpenAPI tools、search、file tools,甚至 agent-to-agent connection。也就是說,agent 對外只看見一個入口,後面那堆工具怎麼組,交給 Toolbox 管。

Foundry MCP 把工具收斂成一個端點
Foundry Toolboxes let you bundle multiple tools into a single MCP-compatible endpoint.

翻譯一下就是:你不用讓每個 agent 都知道每個工具的存在。Toolbox 變成中介層,把工具 sprawl 收起來。今天要換搜尋後端、明天要加內部 API、後天要拔掉一個舊服務,都可以在 Toolbox 這層處理,不用動每個 agent 定義。

我碰過最煩的狀況,就是三個團隊做同一類 agent,卻各自接五個工具,結果 auth 方法不一樣、endpoint 不一樣、工具名稱也不一樣。最後沒人在乎 agent 做得多好,大家只想知道「到底哪個版本能上線」。Toolbox 的價值就在這裡:把共用工具集中管理,減少每個 agent 自己長出一套工具世界。

實操上我會這樣落地:

  • 同一批共用工具,盡量集中到一個 Toolbox。
  • agent 端只維持最薄的設定,不要把工具列表散在每個專案。
  • 如果組織裡有多個 agent,先問能不能共用一個 Toolbox,而不是先寫三份設定。

Microsoft 也提到,只要 runtime 能吃 MCP server,通常也能吃 Toolbox。這點對 Foundry Agent ServiceMicrosoft Agent Framework 這類 client 特別有用,因為你不用每個地方都重配一次工具。

Auth 不該躺在 prompt 或 source code 裡

這篇對授權的態度我很認同,因為它很務實:很多 MCP server 需要 auth,而 Foundry Agent Service 應該把這些資訊放在 project connection 裡,不要硬寫在程式碼。這件事看起來像常識,但很多團隊就是會把 token、key、header 一路塞進 repo,然後再假裝自己有做安全。

Use a project connection to store authentication details instead of hard-coding credentials in your app.

翻譯一下就是:agent 的身份跟工具的身份要分開。agent 用自己的身分去跟 Foundry 溝通;工具要用的憑證,放在 connection 或 Toolbox 管理,不要混成一坨。Microsoft 也列了幾種常見方式,像 key-based auth、Microsoft Entra、OAuth identity passthrough,這些都比你自己手刻 token 字串穩得多。

我自己最討厭的是那種「先 demo 再說」的 auth 寫法。demo 跑得動不代表可維護,尤其當 token 失效、權限變動、或不同服務要不同驗證方式時,你就會開始在一堆 prompt 和 config 裡找答案。那種感覺很像在垃圾堆裡找鑰匙。

實操寫法:

  • API key、bearer token 一律放 project connection。
  • 能用 Microsoft Entra 就別自己發明一套驗證流程。
  • 多工具共用同一邊界時,優先讓 Toolbox 管 credential injection。

我會把規則寫死成一句話:agent 只負責證明自己是誰,工具連線的憑證不要進 source code。這樣你後面才有辦法換服務、換金鑰、換權限,不會整個專案一起爆。

Approval 不是裝飾,是安全閘門

Microsoft 在 approval 這段講得很直白,這也是我覺得最該被照抄的地方。他們建議用 allowed_tools 做白名單,然後對高風險操作要求 approval,尤其是會寫資料、改資源、或造成外部副作用的工具。這不是流程美化,這是防止 agent 幹蠢事。

Require approval for high-risk operations, especially tools that write data or change resources.

翻譯一下就是:工具呼叫不能默默在背景跑掉。我要看到工具名稱、參數、要做什麼,才會按同意。Microsoft 也明講要在批准前檢查 tool name 跟 arguments,並且把 approval 和 tool call 記錄下來,方便稽核跟除錯。這才像真的在做系統,不是做魔術。

我以前看過太多 demo,都是「看,agent 自己就把東西改好了」。聽起來很爽,直到它把測試資料刪掉、把錯的 ticket 關掉、或對外送出不該送的請求。你如果真的要讓 agent 動到 state,就不要把 approval 當成可有可無的選項。

實操上我會這樣設計:

  • 先用 allowed_tools 限制工具範圍。
  • 凡是 write、delete、update、external side effect,一律要求 approval。
  • approval 畫面要顯示工具名與參數,不要只顯示一段模糊描述。

我自己的底線很簡單:會改狀態的工具,不自動批准。真的要自動化,也要先有明確的風險分級,不然就是在等事故。

Python sample 其實是在示範完整生命週期

這篇的 Python 範例不只是「怎麼連上去」而已,它其實把整條流程都畫出來了:建立 AIProjectClient、建立 MCPTool、設定 server label 與 URL、把 require_approval="always" 打開,還把 project connection ID 接進去。後面還有建立 agent、開對話、處理 approval request、最後清掉版本。

tool = MCPTool(
    server_label="api-specs",
    server_url="https://api.githubcopilot.com/mcp",
    require_approval="always",
    project_connection_id=MCP_CONNECTION_NAME,
)

翻譯一下就是:這不是只示範「能不能連」,而是把 approval turn、狀態交接、資源清理都一起演給你看。這很重要,因為 MCP 真正麻煩的地方從來不是第一個 request,而是第二輪怎麼審、怎麼回、怎麼收尾。

我自己測 agent tool flow 時最常遇到的問題,就是第一輪看起來都很漂亮,第二輪才開始暴露出 tool call 內容不透明、approval request 結構不清楚、或 cleanup 沒做乾淨。這種問題不先看 sample 很容易踩。

實操寫法:先照 sample 跑通,再把它縮成你的真實需求。就算工具現在是 read-only,我也會保留 approval loop,因為 read-only 很常在下一版變成 write-capable。你現在省掉的那個流程,之後通常要加回來。

第三方 MCP server 不是免費午餐

Microsoft 對非 Microsoft 的 MCP server 說得很直接:你要遵守對方的條款、資料處理方式和收費規則,而且他們不會幫你驗證那些 server。這段雖然不帥,但很誠實。我反而比較喜歡這種講法,因為它逼你承認一件事:每個遠端 MCP server 都是 dependency,不是神諭。

翻譯一下就是:你接一個遠端工具,不只是接 API 而已,你是在接受它的信任邊界、log 方式、資料保留、以及它背後那堆你未必看得到的流程。Microsoft 也提到 custom headers 可以傳給遠端 MCP server,這很方便,但同時也是最容易把秘密搞漏的地方。

實操上我會給每個 MCP server 一份檢查清單:

  • 誰擁有這個 server。
  • 它用什麼 auth。
  • 會看到哪些資料。
  • log 存哪裡、留多久。
  • 是公開入口還是代理層。
  • 哪些操作需要 approval。

如果這些答案你一個都講不清楚,那就先不要把它接進 agent。工具不是越多越好,能被你管住才重要。

可抄的模板

# Foundry MCP 工具接法模板(我會這樣落地)

## 1) 先選 endpoint 類型
- Public MCP server:用可公開存取的 URL。
- Private MCP server:先把 Standard Agent Setup、private networking、dedicated MCP subnet 搞定。

## 2) 把 auth 放進 project connection
不要把 key、token、header 寫進 source code。
- API key
- Bearer token
- Microsoft Entra / OAuth(如果服務支援)

## 3) 定義 MCP tool
Python 範例:

from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition, MCPTool

PROJECT_ENDPOINT = "https://your-resource.ai.azure.com/api/projects/your-project"
MCP_CONNECTION_NAME = "your-mcp-connection"

project = AIProjectClient(
    endpoint=PROJECT_ENDPOINT,
    credential=DefaultAzureCredential(),
)

mcp_tool = MCPTool(
    server_label="your-server-label",
    server_url="https://your-mcp-server.example.com/mcp",
    require_approval="always",
    project_connection_id=MCP_CONNECTION_NAME,
)

agent = project.agents.create_version(
    agent_name="MyAgent",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions="Use MCP tools as needed.",
        tools=[mcp_tool],
    ),
)

## 4) 先鎖工具,再談自動化
- 用 allowed_tools 限制 surface area。
- 寫入、刪除、改資源,一律要求 approval。
- approval 畫面要顯示 tool name 和 arguments。
- 全部記錄 log,方便稽核。

## 5) approval loop 不要偷懶
當 agent 要求 approval 時:
- 檢查 server_label
- 檢查 tool name
- 檢查 arguments
- 決定 approve / deny
- 把 approval response 回傳

## 6) 多個 agent 共用工具時,優先用 Toolbox
把共用工具集中到一個 Foundry Toolbox:
- 集中 auth
- 集中 policy
- 減少每個 agent 的設定漂移

## 7) 每加一個 MCP server,就跑一次審查
確認:
- owner
- auth method
- data exposure
- logging / retention
- network exposure
- approval policy
- 是否可信 host,還是代理層

## 8) 最小 approval loop

for item in response.output:
    if item.type == "mcp_approval_request" and item.id:
        print("Server:", item.server_label)
        print("Tool:", getattr(item, 'name', ''))
        print("Arguments:", getattr(item, 'arguments', None))
        should_approve = input("Approve? (y/N): ").strip().lower() == "y"
        # send McpApprovalResponse back to continue

## 9) 我的預設規則
- 會改狀態的工具,不自動批准。
- 多團隊共用的工具,丟進 Toolbox。
- 第三方 server,先看 contract 再接。

這版我自己會直接丟給團隊。它把 agent code 保持乾淨,把 auth 從 source code 拿掉,也把 approval 放回 app 層,不讓工具呼叫偷偷變成背景魔法。

原始來源是 Microsoft Learn 的 Connect to MCP Server Endpoints for agents,另外我也參考了 MCP 官方網站Foundry Agent ServiceMicrosoft Agent FrameworkDefaultAzureCredential 文件。上面這篇的拆解、順序整理和實戰建議是我自己的,模板則是根據官方 sample 改成我會真的拿去用的版本。