LangGraph接入MCP
- 一、MCP快速上手
- [二、 详细梳理MCP工作机制](#二、 详细梳理MCP工作机制)
- 三、拆解MCP的两种实现方式:SSE和STDIO
- 四、Agent接入MCP服务
- 五、手写实现一个MCP服务
- 六、章节总结
在2024年底,claude大模型的开发公司Anthropic提出了一个MCP(ModeIContext Protocol)协议。通过MCP协议,可以让应用程序以一种统一的方式向LLM模型提供工具调用。
而随着几千个MCP服务突然冒出,百度、阿里等厂商也开始大规模接入MCP,这个协议也迅速在互联网上引起轩然大波。按照那些流量派见风就是雨的性子, MCP也着实被大吹特吹了一波。随着MCP服务越来越火爆,LangGraph的AgeNnt中也提供了MCP的集成。这次我们就分几个部分,逐步深度拆解MCP服务。
- MCP快速上手
- 理解MCP的stdio和sse两种实现模式
- LangGraph的Agent接入MCP服务
- 补充:自己开发一个MCP服务
一、MCP快速上手
MCP最神奇的地方就要做下简单的配置,就能完成很多复杂的工作。那这次,我们就先不来介绍MCP那些花里胡哨的概念,直接上手来玩玩MCP。首先,我们需要使用一个支持MCP的客户端工具。这类工具现在有很多,以后肯定也会越来越多。这次我们使用一个免费的。在VSCode中有一个开发插Cline。通过这个插件可以快速和AI大模型交互。



到这里,我们就完成了MCP服务的初体验。只需要算单配置一个JSON文件就可以给大模型提供更多扩展的功能。
当然,除了这里演示到的高德地图的MCP服务外,还有很多五花八门的MCP服务。甚至还有很多MCP的信息聚合网站。比如 https://mcp.so 上,目前就聚合了好几千个各种各样的MCP服务。通过这些服务,我们可以让AI大模型完成聊天以外的各种各样的功能。包括发送邮件、浏览网页等。甚至直接操作本地文件也可以。还有阿里云百炼平台 bailian.console.aliyun.com
更是将各种MCP服务聚合成了很多独立的服务。只要开通对应的服务后,就可以在阿里云百炼的智能应用中,用图形化的方式直接集成这些MCP服务。
通过MCP服务,可以让大模型不再只是扮演一个大脑的角色,而是拥有了四肢,直接替代人的工作能力。这样看起来,MCP确实给大模型带来一次质的飞跃是,事实情况真的是这样吗?
作为纯小白,或许你只能跟在别人身后,听风就是雨。但是,作为程序员,
我们是有能力更全面的去理解MCP的。
二、 详细梳理MCP工作机制
MCP协议,全程Model Context Protocol,中文翻译是模型上下文协议。MCP协议是由Anthropic公司提出的,是一个专门用于与AI大语言模型进行交互的是本质上,MCP协议只是允许应用程序以一种统一的方式向大语言模型提供Function call函数调用。而Function call是很多大语言模型自身就提供的一种功能。
例如,通过下面的案例,我们就可以很简单的给大模型提供路线规划的能力,
MCP协议虽然极具大模型的应用特色,但是本质上,MCP协议本身不包含任何具体的工具实现。他只是用协议的形式规定了应用程序如何向大模型提供函数能力。
至于为什么MCP服务使用起来这么简单单,其实是Cline这样的工具封装了客户端的实现能力,这是工具的一种简化实现,和MCP协议本身是没有太大关系的。这个关系就好像我们以往使用HTTP协议访问各种各样的网站一样的.我们这些普通人,可以在完全不用了解HTTP协议是什么东东,只要简单的使用浏览访问网站.但是,这并不意味着HTTP就是一个简单的协议.在HTTP协议层面,要考虑的问题也肯定不能只是简单的保证数据传输,还需要对网络传输的安全性等等各个方面做出很多的设计。
从这个功能层面上来说,MCP协议和HITTP协议本质上是相同的.他基于大模型的Function Call工具实现,只不过是是通过协议的方式定义了这些工具要如何样可以极大的提升各种工具的复用能力.但是,作为一个协议,MCP要考虑的事情,同样不应该只是考虑这些工具功能如何实现,还需要在各个方面保证不会出乱子。
但是事实是怎样的呢?接下来我们再来梳理-一下MCP协议的两种实现方式SSE和STDIO。
三、拆解MCP的两种实现方式:SSE和STDIO
MCP还没听明白,怎么又冒出SSE和STDIO了?不用担心,还是老规矩,直接上实例。
还是以我们之前使用的高德地图的MCP服务为例。在高德地图开放平台的介绍中,提供了两种接入高德地图的MCP配置方式
一种是我们之前使用过的。配置一个网站地址。这就是典型的SSE实现机制。
json
{
"mcpServers":{
"amap-amap-sse":{
"url":"https://mcp.amap.com/sse?key=你在高德官网上申请的key"
}
}
}
另一种,没有使用过的STDIO的配置方式是这样的:
json
"amap-maps": {
"command":"npx"
"args":[
"-y"
"@amap/amap-maps-mcp-server"
],
"env":{
"AMAP_MAPS_API_KEY":"高德地图key"
}
}
这种方式配置方式需要在本地安装Nodejs。很显然是通过在本地执行npx指令,执行了一个应用程序,从而获得高德地图的数据。
至于这个数据是如何获得的? 是调用远端高德地图的服务获得的? 还是读取本地某个神秘文件获取的? 这就只有在高德地图提供的Nodejs源码@amap/ammcp-server中才能知道了。
从这个案例中我们就能理解出SSE和STDIO到底是怎样的工作机制。
-
SSE:其实是一种基于HTTP协议实现的长连接协议,只不过SSE协议是一种从服务端向客户端单向推送数据的长连接协议。也就是高德地图需要提供一个客户端就可以不断的访问高德地图的HTTP服务,获得高德地图的服务数据。这时候的工HTTP服务,然后客户端可以和这个HTTP服务建立一个长连接,这样只是服务端的性能压力会大一点而已。作机制其实和以往我们熟悉的基于HTTP的工作机制本质上是很像的。
-
STDIO:这种工作机制的本质是在客户端本地执行一个应用程序,然后通过应用程序获得对应的结果。这时候MCP的核心问题就出来了, MCP的服务提供者设计的,但是执行却是在客户端的机器执行 。也就是说,这给服务提供者提供了一种操作客户端机器的机会。这里会有什么问题?修改一下你本地的文件,或者给你植入一个病毒程序,或者。...。大家可以发挥一下自己的想象。
四、Agent接入MCP服务
LangChain中提供了一个新的功能模块langchain-mcp-adapters 来支持MCP服务
python
#安装对应依赖
pip install langchain-mcp-adapters
接下来接入MCP服务也相当简单,只要增加MCP的配置文件就行。
python
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from config.load_key import load_key
from langchain_community.chat_models import ChatTongyi
# 构建阿里云百炼大模型客户端
llm = ChatTongyi(
model="qwen-plus'
api_key=load_key("BAILIAN_API_KEY"),
#相比Cline客户端配置,只要增加transport属性即可。不过测试stremaable_http有问题。不知道是不是版本的原因。
client = MultiServerMCPClient(
{
# "amap-amap-sse":{
# "url": "https://mcp.amap.com/sse?key=451ad40d0e39453600f2a305e31eabe4",
# "transport":"streamable_http"
#}
"amap-maps":{
"comggnd":"npx",
"args":[
"-y",
"@amap/amap-maps-mcp-server"
],
"env":{
"AMAP_MAPS_API_KEY":"451ad40d0e39453600f2a305e31eabe4"
},
"transport":"stdio"
}
}
}
tools = await client.get_tools()
agent = create_react_agent(
model=llm,
tools=tools
)
response = await agent.ainvoke(
{"messages":[{"role":"user","content":"帮我规划一条从长沙梅溪湖到湾镇的自驾路线"}]}
)
response
五、手写实现一个MCP服务
如何实现一个MCP服务?MCP的官网上提供了一系列的SDK来辅助实现MCP的客户端和服务端。官网地址:https://modelcontextprotocol.io/introduction

首先需要安装MCP依赖
l
pip install mcp
然后,就可以参照官网案例,快速实现一个MCP服务
mcp_server.py
python
from mcp.server.fastmcp import FastMCP
mcp=FastMCP("roymcpdemo")
@mcp.tool()
def add(a: int,b:int)->int:
"""Add two numbers together."""
print(f"roy mcp demo called :add({a},{b})")
return a+b
@mcp.tool()
def weather(city: str):
"""获取某个城市的天气
Args:
city:具体城市
"""
return"城市"+city+",念天天气不错"
@mcp.resource("greeting://{name}")
def greeting(name: str)-> str:
"""Greet a person by name."""
print(f"roy mcp demo called : greeting({name})")
return f"Hello,{name}!"
if __name__ == "__main__":
#以sse协议暴露服务。
mcp.run(transport='sse')
#以stdio协议暴露服务。
#mcp.run(transport='stdio')
mcp_client.py
python
from mcp import StdioServerParameters, stdio_client, ClientSession
import mcp.types as types
server_params = StdioServerParameters(
command="python",
args=["/Users/wuyuanshun/PycharmProjects/LongchainDemo1/langGraph/mcp_server.py"],
env=None
)
async def handle_sampling_message(message: types.CreateMessageRequestParams) -> types.CreateMessageResult :
print(f"sampling message: {message}")
return types.CreateMessageResult(
role="assistant",
content = types.TextContent(
type="text",
text ="Hello,world! from model"
),
model = "deepseek-v4-flash",
stopReason = "endTurn"
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write, sampling_callback=handle_sampling_message) as session:
await session.initialize()
prompts = await session.list_prompts()
print(f"prompts:{prompts}")
tools = await session.list_tools()
print(f"tools: {tools}")
resources = await session.list_resources()
print(f"resources: {resources}")
result = await session.call_tool("weather", {"city":"北京"})
print(f"result: {result}")
if __name__== "__main__":
import asyncio
asyncio.run(run())
接下来,也可以用同样的方式尝试在LangGraph中接入服务。
当然,由于需要依赖服务端的代码实现,所以不能简单的配置一个python指令执行。需要打包成nodejs依赖启动。后续就不再做介绍了。
六、章节总结
通过深度演示MCP服务的客户端和服务端的交互过程,让大家对MCP服务有了初步的了解。在深度使用更多的MCP服务的同时,合理的看待MCP的安全问题。虽然MCP最大的意义在于简化客户端的调用过程,让我们以极小的代价快速接更多的外部服务,但是并不代表MCP服务就是安全的。