
2025年最新LangChain Agent教程:從入門到精通
這兩種技術(shù)都旨在增強 AI 模型與外部數(shù)據(jù)的交互能力,但 MCP 不止可以增強 AI 模型,還可以是其他的應(yīng)用系統(tǒng)。
這樣一個理想的“萬物互聯(lián)”生態(tài)系統(tǒng)看著很讓人著迷。
但是大家是不是擔(dān)心通過 MCP Server 暴露出來的數(shù)據(jù)會泄露或被非法訪問,這個頭疼的問題 MCP 也考慮到了。
MCP 通過標(biāo)準(zhǔn)化的數(shù)據(jù)訪問接口,大大減少了直接接觸敏感數(shù)據(jù)的環(huán)節(jié),降低了數(shù)據(jù)泄露的風(fēng)險。
還有,MCP 內(nèi)置了安全機制,確保只有經(jīng)過驗證的請求才能訪問特定資源,相當(dāng)于在數(shù)據(jù)安全又加上了一道防線。同時,MCP協(xié)議還支持多種加密算法,以確保數(shù)據(jù)在傳輸過程中的安全性。
例如,MCP 服務(wù)器自己控制資源,不需要將 API 密鑰等敏感信息提供給 LLM 提供商。這樣一來,即使 LLM 提供商受到攻擊,攻擊者也無法獲取到這些敏感信息。
不過,MCP 這套協(xié)議/標(biāo)準(zhǔn),需要大家一起來共建,這個生態(tài)才會繁榮,現(xiàn)在,只是測試階段,一切才剛剛開始,當(dāng)然,還會涌現(xiàn)出更多的問題。
MCP 協(xié)議采用了一種獨特的架構(gòu)設(shè)計,它將 LLM 與資源之間的通信劃分為三個主要部分:客戶端、服務(wù)器和資源。
客戶端負(fù)責(zé)發(fā)送請求給 MCP 服務(wù)器,服務(wù)器則將這些請求轉(zhuǎn)發(fā)給相應(yīng)的資源。這種分層的設(shè)計使得 MCP 協(xié)議能夠更好地控制訪問權(quán)限,確保只有經(jīng)過授權(quán)的用戶才能訪問特定的資源。
以下是 MCP 的基本工作流程:
MCP 遵循客戶端-服務(wù)器架構(gòu)(client-server),其中包含以下幾個核心概念:
MCP Client
MCP client 充當(dāng) LLM 和 MCP server 之間的橋梁,MCP client 的工作流程如下:
Claude Desktop 和Cursor都支持了MCP Server接入能力,它們就是作為 MCP client來連接某個MCP Server感知和實現(xiàn)調(diào)用。
MCP Server
MCP server 是 MCP 架構(gòu)中的關(guān)鍵組件,它可以提供 3 種主要類型的功能:
這些功能使 MCP server 能夠為 AI 應(yīng)用提供豐富的上下文信息和操作能力,從而增強 LLM 的實用性和靈活性。
你可以在 MCP Servers Repository 和 Awesome MCP Servers 這兩個 repo 中找到許多由社區(qū)實現(xiàn)的 MCP server。使用 TypeScript 編寫的 MCP server 可以通過 npx 命令來運行,使用 Python 編寫的 MCP server 可以通過 uvx 命令來運行。
MCP 協(xié)議支持兩種主要的通信機制:基于標(biāo)準(zhǔn)輸入輸出的本地通信和基于SSE(Server-Sent Events)的遠(yuǎn)程通信。
這兩種機制都使用 JSON-RPC 2.0 格式進行消息傳輸,確保了通信的標(biāo)準(zhǔn)化和可擴展性。
如果你還沒有嘗試過如何使用 MCP 的話,我們可以考慮用 Cursor(本人只嘗試過 Cursor),Claude Desktop 或者 Cline 來體驗一下。
當(dāng)然,我們并不需要自己開發(fā) MCP Servers,MCP 的好處就是通用、標(biāo)準(zhǔn),所以開發(fā)者并不需要重復(fù)造輪子(但是學(xué)習(xí)可以重復(fù)造輪子)。
首先推薦的是官方組織的一些 Server:官方的 MCP Server 列表。
目前社區(qū)的 MCP Server 還是比較混亂,有很多缺少教程和文檔,很多的代碼功能也有問題,我們可以自行嘗試一下 Cursor Directory 的一些例子,具體的配置和實戰(zhàn)筆者就不細(xì)講了,大家可以參考官方文檔。
MCP通過引入多樣化的MCP Server能力,顯著增強了AI工具的功能,例如我們常用的Cursor和Claude。以下是一些官方參考服務(wù)器,展示了MCP的核心功能和SDK的應(yīng)用:
數(shù)據(jù)與文件系統(tǒng):
文件系統(tǒng):提供安全文件操作,帶可配置的訪問控制。
PostgreSQL:提供只讀數(shù)據(jù)庫訪問,具備架構(gòu)檢查功能。
SQLite:支持?jǐn)?shù)據(jù)庫交互和商業(yè)智能功能。
Google Drive:實現(xiàn)Google Drive的文件訪問和搜索功能。
開發(fā)工具:
Git:工具用于讀取、搜索和操作Git倉庫。
GitHub:集成倉庫管理、文件操作和GitHub API。
GitLab:支持項目管理的GitLab API集成。
Sentry:從http://Sentry.io獲取并分析問題。
網(wǎng)絡(luò)與瀏覽器自動化:
Brave Search:利用Brave的搜索API進行網(wǎng)絡(luò)和本地搜索。
Fetch:為LLM優(yōu)化的網(wǎng)絡(luò)內(nèi)容獲取和轉(zhuǎn)換。
Puppeteer:提供瀏覽器自動化和網(wǎng)頁抓取功能。
生產(chǎn)力和通信:
Slack:支持頻道管理和消息功能。
Google Maps:提供位置服務(wù)、路線和地點詳情。
Memory:基于知識圖譜的持久記憶系統(tǒng)。
AI與專業(yè)工具:
EverArt:使用多種模型進行AI圖像生成。
Sequential Thinking:通過思維序列進行動態(tài)問題解決。
AWS KB Retrieval:使用Bedrock Agent Runtime從AWS知識庫檢索。
官方集成工具:
這些MCP服務(wù)器由公司維護,用于其平臺:
Axiom:使用自然語言查詢和分析日志、跟蹤和事件數(shù)據(jù)。
Browserbase:云端自動化瀏覽器交互。
Cloudflare:在Cloudflare開發(fā)者平臺上部署和管理資源。
E2B:在安全的云沙箱中執(zhí)行代碼。
Neon:與Neon無服務(wù)器Postgres平臺交互。
Obsidian Markdown Notes:讀取和搜索Obsidian知識庫中的Markdown筆記。
Qdrant:使用Qdrant向量搜索引擎實現(xiàn)語義記憶。
Raygun:訪問崩潰報告和監(jiān)控數(shù)據(jù)。
Search1API:統(tǒng)一的API用于搜索、爬蟲和網(wǎng)站地圖。
Tinybird:與Tinybird無服務(wù)器ClickHouse平臺交互。
集成工具:
Docker:管理容器、鏡像、卷和網(wǎng)絡(luò)。
Kubernetes:管理pod、部署和服務(wù)。
Linear:項目管理和問題跟蹤。
Snowflake:與Snowflake數(shù)據(jù)庫交互。
Spotify:控制Spotify播放和管理播放列表。
Todoist:任務(wù)管理集成。
目前支持的部分工具列表(更多見這里):
客戶端 | 資源 | 提示 | 工具 | 采樣 | 根目錄 | 備注 |
Claude 桌面應(yīng)用 | ? | ? | ? | ? | ? | 所有MCP 功能 |
Zed | ? | ? | ? | ? | ? | 提示以斜杠命令形式出現(xiàn) |
Sourcegraph Cody | ? | ? | ? | ? | ? | 通過OpenCTX 支持資源 |
Firebase Genkit | ?? | ? | ? | ? | ? | 支持資源列表和查找 |
Continue | ? | ? | ? | ? | ? | 支持所有MCP功能 |
GenAIScript | ? | ? | ? | ? | ? | 支持工具 |
Cursor | ? | ? | ? | ? | ? | 支持工具 |
以 Claude Desktop 為例,配置 MCP 客戶端的步驟如下:
添加所需的 MCP 服務(wù)器信息,例如:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
},
"git": {
"command": "uvx",
"args": ["mcp-server-git", "--repository", "path/to/git/repo"]
}
}
}
這里的@modelcontextprotocol/server-filesystem、mcp-server-git是對應(yīng)的一些MCP Server,可以是開源找來的,也可以是你自己開發(fā)的。
配置完后,在主界面對話題右下角就有個錘子出現(xiàn)了,有幾個錘子就是配置幾個,然后對話中如果涉及使用該工具的,claude就會自動調(diào)用。
Cursor工具中集成mcp server功能對開發(fā)增加效率非常明顯,配置入口在:文件—>首選項—>Cursor Settings—>Features—>MCP Server—>Add new MCP Server
配置完后,你需要畫圖的地方給它提要求就行了,它會自動感知,按上下文生成prompt并調(diào)用工具生成圖片:
生成的圖片質(zhì)量還不錯,符合開發(fā)需要的圖片
那我們來介紹一下 MCP 的工作原理。首先我們看一下官方的 MCP 架構(gòu)圖。
總共分為了下面五個部分:
整個 MCP 協(xié)議核心的在于 Server,因為 Host 和 Client 相信熟悉計算機網(wǎng)絡(luò)的都不會陌生,非常好理解,但是 Server 如何理解呢?
看看 Cursor 的 AI Agent 發(fā)展過程,我們會發(fā)現(xiàn)整個 AI 自動化的過程發(fā)展會是從 Chat 到 Composer 再進化到完整的 AI Agent。
AI Chat 只是提供建議,如何將 AI 的 response 轉(zhuǎn)化為行為和最終的結(jié)果,全部依靠人類,例如手動復(fù)制粘貼,或者進行某些修改。
AI Composer 是可以自動修改代碼,但是需要人類參與和確認(rèn),并且無法做到除了修改代碼之外的其它操作。
AI Agent 是一個完全的自動化程序,未來完全可以做到自動讀取 Figma 的圖片,自動生產(chǎn)代碼,自動讀取日志,自動調(diào)試代碼,自動 push 代碼到 GitHub。
而 MCP Server 就是為了實現(xiàn) AI Agent 的自動化而存在的,它是一個中間層,告訴 AI Agent 目前存在哪些服務(wù),哪些 API,哪些數(shù)據(jù)源,AI Agent 可以根據(jù) Server 提供的信息來決定是否調(diào)用某個服務(wù),然后通過 Function Calling 來執(zhí)行函數(shù)。
我們先來看一個簡單的例子,假設(shè)我們想讓 AI Agent 完成自動搜索 GitHub Repository,接著搜索 Issue,然后再判斷是否是一個已知的 bug,最后決定是否需要提交一個新的 Issue 的功能。
那么我們就需要創(chuàng)建一個 Github MCP Server,這個 Server 需要提供查找 Repository、搜索 Issues 和創(chuàng)建 Issue 三種能力。
我們直接來看看代碼:
const server = new Server(
{
name: "github-mcp-server",
version: VERSION,
},
{
capabilities: {
tools: {},
},
}
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "search_repositories",
description: "Search for GitHub repositories",
inputSchema: zodToJsonSchema(repository.SearchRepositoriesSchema),
},
{
name: "create_issue",
description: "Create a new issue in a GitHub repository",
inputSchema: zodToJsonSchema(issues.CreateIssueSchema),
},
{
name: "search_issues",
description: "Search for issues and pull requests across GitHub repositories",
inputSchema: zodToJsonSchema(search.SearchIssuesSchema),
}
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
if (!request.params.arguments) {
throw new Error("Arguments are required");
}
switch (request.params.name) {
case "search_repositories": {
const args = repository.SearchRepositoriesSchema.parse(request.params.arguments);
const results = await repository.searchRepositories(
args.query,
args.page,
args.perPage
);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
case "create_issue": {
const args = issues.CreateIssueSchema.parse(request.params.arguments);
const { owner, repo, ...options } = args;
const issue = await issues.createIssue(owner, repo, options);
return {
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
};
}
case "search_issues": {
const args = search.SearchIssuesSchema.parse(request.params.arguments);
const results = await search.searchIssues(args);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
default:
throw new Error(Unknown tool: ${request.params.name}
);
}
} catch (error) {}
});
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("GitHub MCP Server running on stdio");
}
runServer().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
上面的代碼中,我們通過 server.setRequestHandler
來告訴 Client 端我們提供了哪些能力,通過 description
字段來描述這個能力的作用,通過 inputSchema
來描述完成這個能力需要的輸入?yún)?shù)。
我們再來看看具體的實現(xiàn)代碼:
export const SearchOptions = z.object({
q: z.string(),
order: z.enum(["asc", "desc"]).optional(),
page: z.number().min(1).optional(),
per_page: z.number().min(1).max(100).optional(),
});
export const SearchIssuesOptions = SearchOptions.extend({
sort: z.enum([
"comments",
...
]).optional(),
});
export async function searchUsers(params: z.infer<typeof SearchUsersSchema>) {
return githubRequest(buildUrl("https://api.github.com/search/users", params));
}
export const SearchRepositoriesSchema = z.object({
query: z.string().describe("Search query (see GitHub search syntax)"),
page: z.number().optional().describe("Page number for pagination (default: 1)"),
perPage: z.number().optional().describe("Number of results per page (default: 30, max: 100)"),
});
export async function searchRepositories(
query: string,
page: number = 1,
perPage: number = 30
) {
const url = new URL("https://api.github.com/search/repositories");
url.searchParams.append("q", query);
url.searchParams.append("page", page.toString());
url.searchParams.append("per_page", perPage.toString());
const response = await githubRequest(url.toString());
return GitHubSearchResponseSchema.parse(response);
}
可以很清晰的看到,我們最終實現(xiàn)是通過了 https://api.github.com
的 API 來實現(xiàn)和 Github 交互的,我們通過 githubRequest
函數(shù)來調(diào)用 GitHub 的 API,最后返回結(jié)果。
在調(diào)用 Github 官方的 API 之前,MCP 的主要工作是描述 Server 提供了哪些能力(給 LLM 提供),需要哪些參數(shù)(參數(shù)具體的功能是什么),最后返回的結(jié)果是什么。
所以 MCP Server 并不是一個新穎的、高深的東西,它只是一個具有共識的協(xié)議。
如果我們想要實現(xiàn)一個更強大的 AI Agent,例如我們想讓 AI Agent 自動的根據(jù)本地錯誤日志,自動搜索相關(guān)的 GitHub Repository,然后搜索 Issue,最后將結(jié)果發(fā)送到 Slack。
那么我們可能需要創(chuàng)建三個不同的 MCP Server,一個是 Local Log Server,用來查詢本地日志;一個是 GitHub Server,用來搜索 Issue;還有一個是 Slack Server,用來發(fā)送消息。
AI Agent 在用戶輸入 我需要查詢本地錯誤日志,將相關(guān)的 Issue 發(fā)送到 Slack
指令后,自行判斷需要調(diào)用哪些 MCP Server,并決定調(diào)用順序,最終根據(jù)不同 MCP Server 的返回結(jié)果來決定是否需要調(diào)用下一個 Server,以此來完成整個任務(wù)。
本文轉(zhuǎn)載自:一文看懂:MCP(大模型上下文協(xié)議)