1.1 快速開始

把MCP框架理解為“大模型插件”,并且你也可以很方便地編寫自己的“插件”功能。

配置如下:

1.2 Awesome MCP Clients 推薦

完整列表參考:https://github.com/punkpeye/awesome-mcp-clients

對比參考:https://modelcontextprotocol.io/clients

筆者推薦:

1.Cherry Studio

2.DeepChat

3.AIaW

4.Cursor

5.Continue

1.3.Awesome MCP Servers 推薦

完整列表參考:https://github.com/punkpeye/awesome-mcp-servers

文檔實例列表:https://modelcontextprotocol.io/examples

官方列表:https://github.com/modelcontextprotocol/servers

按需添加即可。

二、MCP Server for 阿里云可觀測2.0

2.1 可觀測2.0

過去一年,我們邁向了通用可觀測之路。從“監控”到“可觀測”,不僅是技術升級,更是對復雜系統認知的深化。通過因果推理的三個層級(關聯、干預、反事實),可觀測性能夠實現從被動觀測到主動預測的能力提升。企業數字化需要將黑盒系統轉化為白盒,通過采集、存儲和分析多模態數據(如Log、Trace、Metric等),優化運營效率。

隨著分布式系統和技術棧的復雜化,可觀測性成為確保系統穩定性和性能的關鍵。然而,許多企業面臨可觀測數據混亂的問題,如缺乏標準化、數據存儲分散、分析效率低及知識難以沉淀。為解決這些問題,我們提出了UModel——可觀測數據之魂,一種通用的可觀測“交互語言”。

UModel 基于本體論思想,通過 Set 和 Link 組成的圖模型描述IT世界,定義了EntitySet、LogSet、MetricSet 等核心類型,以及 EntitySetLink、DataLink 等關聯關系。它支持靈活擴展,引入 CommonSchema 降低使用門檻,并提供 Explorer、告警與事件集等功能提升易用性。UModel 不僅實現了數據的標準化和統一建模,還支持算法和大模型對數據的高效利用,助力構建全新的“可觀測2.0”體系。

2.2 融合 MCP 能力

在可觀測2.0中融合 MCP 能力,是一種很合適的嘗試,一定程度上可以通過對話的方式,讓用戶對可觀測2.0整體使用方式有更好的感知,并且可以協助用戶感知系統、分析問題——只用自然語言交流。

三、設計好 MCP Server 的親身實踐(血淚踩坑)

3.1 經驗一:Tools 接口精簡化、原子化

寫在前面:MCP Server ≠ SDK API,是和人打交道的接口。

這里的“和人打交道”,是全方面的,無論是接口的理解,參數,還是返回,都要求簡潔易懂。“三歲小孩都能懂”的 MCP Server Tools 才是好 Tools。

舉個例子:

SLS 的 getLogs SDK API 是這樣的

def get_logs(
ak: str,
sk: str,
region_id: str,
project: str,
logstore:str,
query: str,
from_timestamp: int,
to_timestamp: int,
topic: str,
line: int,
offset: int,
reverse: boolean,
powerSql: boolean
) -> list[Any]:

這個接口如果直接給到大模型作為 Tools,可以說調用的成功率為0,因為這是一個非常復雜的接口:

1.主要的瓶頸在 query 怎么寫,語法是怎樣的,對模型挑戰非常大。這種場景適合 A2A(Agent協作),生成可靠的 SLS query 作為一個 Agent,此處不過多展開。

2.假設我們解決了query的問題,API中的很多基礎信息需要多輪對話獲得:aksk、region、project、logstore,實際使用上這種環境變量級別的參數重復性非常高。

3.參數中帶了時間窗口,這一點需要謹慎,詳情見經驗二。

4.參數中帶了 topic、line、offset、reverse、powerSql 這種不常用參數,使用默認值能搞定大部分請求的參數就不帶。

對于這些問題,在整體的實踐后,認為在阿里云上,使用 MCP Server 和用戶交互的架構,可能需要做一些改變。

樸素想法:

真正適用的:

首先,這里的 MCP Server 的生命周期應該是在用戶進入到 Workspace 后,才創建。阿里云提供給用戶的 MCP 交互 Client + MCP Server 是非常輕量的,一個用戶、一次 Workspace 訪問就是一次生命周期。而此時 MCP Server 是帶上 aksk、Workspace name、region id 等環境變量信息的,里面的各種 Tools 無需關心這種基礎的參數了。

然后,隨著用戶業務的范圍,可以創建若干對應模塊的 Tools 以供用戶按需調用。

最后,需要把常用的操作封裝 MCP Tools,而不是給出一個萬能的 “query” 接口。\

因此,給出的 getLogs,優化過后的 MCP Server Tools 版本應該是這樣的:

A2A 模式:

def get_log_tool(
query: str,
from_timestamp: int = Field(
int(datetime.now().timestamp()) - 3600, description="from timestamp,unit is second"
),
to_timestamp: int = Field(
int(datetime.now().timestamp()), description="to timestamp,unit is second"
)
) -> list[Any]:

def gen_sls_query(
text: str,
) -> str:

功能模塊化模式(僅示例):

# 獲取logstore的index信息
def get_index():
pass

# 獲得fields字段聚合的統計信息
def get_fields_desc(
filter: str,
fields: List[str],
from_timestamp: int = Field(
int(datetime.now().timestamp()) - 3600, description="from timestamp,unit is second"
),
to_timestamp: int = Field(
int(datetime.now().timestamp()), description="to timestamp,unit is second"
)
) -> list[Any]:
# * and upstream_status >= 400 | SELECT request_uri, upstream_status, COUNT (*) AS cnt
# FROM log
# GROUP BY request_uri, upstream_status
# ORDER BY cnt DESC
# LIMIT 10

# 統計UV
def get_uv(
filter: str,
field: str
from_timestamp: int = Field(
int(datetime.now().timestamp()) - 3600, description="from timestamp,unit is second"
),
to_timestamp: int = Field(
int(datetime.now().timestamp()), description="to timestamp,unit is second"
)
) -> list[Any]:
# * | SELECT COUNT(DISTINCT client_ip) AS unique_visitors FROM log

這里不需要 ak、sk、project、logstore 信息的原因是,這里的 MCP 應該是在 logstore 打開的時候啟動的,因此已經知道基礎環境信息了。

這樣的功能模塊劃分僅為示例,僅作說明。

3.2 經驗二:Tools 接口參數默認化。慎用時間參數

案例:一個查詢 SQL Query的Tools,接口是這樣的:

def o11y_list_entities(
ctx: Context,
query: str = Field(default=None, description="query"),
from_timestamp: int = Field(
..., description="from timestamp,unit is second"
),
to_timestamp: int = Field(
..., description="to timestamp,unit is second"
)
) -> list[str]:

為了方便大模型使用,特意增加了一個 tool 用于調用時間相關的參數:

想法很好,現實很骨感,實際使用中,經常出現傳入并不合法的 from to 的情況:

導致接口直接報錯,因為傳入不合法的參數,這種場景甚至必須重啟 client 和Server。

有時也會傳入離譜的時間參數,導致后續的回答并不理想:

時間戳這里提供的是 2023-06-25 00:00:00。大模型對“現在的時間”概念模糊。提供的示例對于一個只保存30天的 LogStore 來說仍然查不出數據。

更好的方式:

def o11y_list_entities(
ctx: Context,
query: str = Field(default=None, description="query"),
from_timestamp: int = Field(
int(datetime.now().timestamp()) - 3600, description="from timestamp,unit is second"
),
to_timestamp: int = Field(
int(datetime.now().timestamp()), description="to timestamp,unit is second"
),
) -> list[str]:

直接給出最近1小時的默認值,極大概率都可以覆蓋期望的查詢,只需考慮 query 的傳入,不用糾結時間的細節設置。如果返回為空,模型會考慮是否是時間問題,并反饋。

3.3 經驗三:精簡輸出,避免過長的上下文輸出

一些不好的例子:查詢 workspace 的 list(返回500個workspace),查詢某個 workspace 下接入的 entity 類型(返回200個)

MCP Server 和 SDK API 的功能不能完全等價看待,MCP 本質上是給人作為終端顯示的,因此人眼看不過來(體感:大于20個的數量)都是意義不大的內容。每個接口的輸出都應該控制 limit。可以考慮通過加入篩選檢索,或者直接截斷輸出到10個。

除了體感之外,過長的 json response 會嚴重卡慢后續模型的輸出速度、影響上下文理解效果。

以上是一般 json 接口的經驗。在實踐中,我們還會遇到這類場景:希望 Tools 返回一幅圖(以 svg 或 png 的形式)。嘗試了幾種方案:

Args:
ctx: MCP上下文,用于訪問可觀測客戶端
workspace_name: Workspace 名稱,必須完全匹配Workspace

Returns:
![Schema](http://localhost:9688/xxx.svg})
Schema 的 markdown 內容,直接作為你的輸出打印并展示

效果:

3.4 經驗四:避免 Tools 和 Tools 輸入輸出的鏈式傳遞

好的實踐:Tool 原子能力,一個 Tool 做獨立一件事。

不好的實踐:Tool1 -> output -> Tool2 input -> output -> Tool3

實踐中鏈式傳遞也可以做到,但有一定概率傳入的參數不符合預期,且不好控制。

有一些還不錯的自我修復能力是,當大模型發現參數報錯的時候,會調用依賴的上一個 Tools 驗證一下參數正確性。這種情況有一定概率修復,但并非完全可以。有時會執拗地認為自己沒錯:

在同一次問題中,通常鏈式傳遞表現尚可。如果是在同一會話中第二次詢問,并不會獲得第一次詢問調用的接口的每一個信息,或者判斷錯誤。

Tool1:查詢 service 的關聯上下游,返回

[
{
"id": "apm@apm.service:dc7495605d8395b3788f9b54defcb826",
"type": "upstream",
"name": "gateway",
},
{
"id": "apm@apm.service:97cd7e28783143028d7e8e9c8dbce99c",
"type": "downstream",
"name": "checkout",
},
]

然后其他一些分析……省略

對話上下文中,第二次詢問,請幫我查詢 checkout 服務的信息。

模型會直接把checkout直接傳入 Tool2(參數只有一個 id,并在 Prompt 注釋中說明很詳細)

第二次對話必須復制

apm@apm.service:97cd7e28783143028d7e8e9c8dbce99c完整,才會正確傳遞參數。

有一個 Tool 返回 trace ids,返回了一個列表:

[
"93b9111f425a4b6cab6548aa68d18f04",
"e165fede431c4c178d1e7e399c92b70d",
"ce7d4e9f74634252969adfd62b509fd6",
"e824356ddf4f42d884abe7c6a2d55d66",
]

每一個值是 trace id。

期望的是模型使用每一個 trace id 調用分析的接口,但是模型會自己傳錯。

3.5 經驗五:在接口實現開工之前,首先以模擬數據作為嘗試

模型使用接口的方式,可能和預期不一樣。接口的設計可能需要大量改動,才能讓模型按照你想要的方式運作,尤其涉及 Tools 鏈式調用的時候,更要謹慎。

在設計 MCP 接口的時候,首先定義 Tools 接口信息,然后編寫 Tools 的注釋說明(引導 Prompt),接著按照預期實現的返回數據,mock 一些假數據直接返回。在交互的過程中不斷調整接口信息、注釋信息,直到假數據可以按照預期正常工作,最后再開始接口的開發,否則如果先實現接口,返工率極高,十分心痛。

3.6 經驗六:有時模型會“盲目自信”、“假裝工作”。適當調低 temperature

這個 case 里面,trace id 傳錯是第一個問題,之前(經驗四)已經講過。

在之后,又遇到了時間的坑。(經驗二)

在發生錯誤之后,模型并不會提示問題,而是結合一些正確的接口輸入輸出數據,自己悄悄生成假模假樣的數據……像不像論文里瞎編數據的無良大學生[狗頭]。

這里上下游的數據也是假的,從 id 也能看出來。

這個問題調低 tempreture 可以緩解,但是并非可以完全解決,MCP 本質上還是依賴生成模型,而生成模型是否適合一些嚴肅嚴格場景的接口,這里稍稍打一個問號。

除此之外,觀察到如果在同一對話上下文中多次問類似實體,但id不同的實體,模型似乎并不會真正調用接口了,而是直接生成 tools 的輸入參數,建議用戶去調(誰是老板??)。

還有一種場景是受上下文影響過大,會參考上次的輸出,然后新實體的關聯、上下游也和上次調用的實體關聯、上下游一樣(糊弄我是吧??

四、總結

MCP 是標準化 LLM 上下文交互的開放協議,包含主機、客戶端、服務器及數據源組件,支持連接本地/遠程服務。用戶需配置支持 MCP 的客戶端(如Cherry Studio)和 LLM API(如阿里云百煉),并可擴展官方/自定義 MCP 服務器。阿里云可觀測2.0通過 UModel 統一多模態數據交互,解決系統復雜性帶來的觀測難題,實現從被動監控到主動預測的升級。

4.1 MCP Server 設計注意事項和思考

MCP 作為人、LLM、業務場景融合的媒介和工具,是新一代交互工具的萌芽,但仍然存在很多設計場景上的注意點。

如果判斷下來都是“是”,則非常適合 MCP 場景。

一些不適合的場景,通過某種轉化,可以變成適合的場景。比如股票交易系統不提供交易接口,只提供股票代碼查詢的能力,規避安全性問題。提供股票查詢后,規避返回股票信息具體細節,而引導模型輸出報告,模型會輸出對這支股票的看多看空思路和依據,提升寬容性。

同時也可以發現,MCP 天生適合理解業務短平快的需求場景,如果想解決一個非常復雜的任務,MCP 接口可能還不夠,需要 A2A + 更高級的協作、超長上下文的理解。

4.2 一些優秀的 MCP 應用場景

1.bing 搜索、Github搜索、網盤搜索等各類搜索引擎 MCP

理由:獨立、簡潔(返回 Top5 相關)、寬容(一定程度上)、魯棒、安全。

2.高德地圖 MCP 生成旅游路線

理由:獨立、寬容(每次不同甚至有新鮮感)、魯棒(有高德地圖穩定的系統為支持)、安全。

3.Web 瀏覽器自動化,相關爬取、統計、分析

理由:獨立、簡潔(輸出約束一下)、寬容、魯棒。

4.FileSystem

理由:獨立、簡潔、寬容(理由是 linux 命令行 llm 非常懂,不太可能寫錯)、安全(不提供 rm 能力)

5.Redis

理由:獨立、簡潔、寬容(非嚴肅 Redis 數據庫)

4.3 可觀測2.0 + AI的未來展望

MCP 適用于短平快的獨立接口能力,對于復雜需求,更適合 A2A 或更強大的模式。更多結合AI的能力,不僅僅有 MCP,可觀測2.0 + AI,還有更多可能。

文章轉載自: MCP for 可觀測2.0,6個讓MCP開發更高效的小妙招

上一篇:

面對MCP安全風險,我們該如何應對

下一篇:

Java調用MCP客戶端教程
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費