微信扫码
添加专属顾问
我要投稿
MCP协议为AI模型与外部数据源、工具通信提供了标准化解决方案,极大简化了开发流程。 核心内容: 1. MCP的概念和作用:标准化AI模型与外部系统的通信 2. MCP架构和功能:客户端-服务器模型,支持工具、资源和提示 3. MCP通信机制:基于JSON-RPC 2.0协议,支持Stdio和HTTP+SSE两种方式
MCP(模型上下文协议,Model Context Protocol)是一种开放标准,旨在标准化大型语言模型(LLM)与外部工具、数据源之间的通信方式。它采用客户端-服务器架构,支持多种通信协议和传输机制,以实现结构化、多轮次、可扩展的上下文交换。就像 AI 应用程序的 USB-C 端口一样,提供了一种标准化的方式将 AI 模型连接到不同的数据源和工具。
在 MCP 出现之前,开发人员必须为每个 AI 应用程序所需的数据源或工具构建自定义连接——这是一个非常耗时且重复的过程。
MCP 采用客户端-服务器架构,AI 模型作为客户端,通过 MCP 协议与 MCP 服务器进行通信。MCP 服务器负责与外部数据源或工具交互,并将获取的数据按照 MCP 协议规范格式化后返回给客户端。这种设计使得 AI 模型能够动态地获取所需的上下文信息,执行更广泛的任务 。大大缩短了开发时间,并降低开发复杂性。
MCP 遵循 客户端-服务器 架构,其中:
MCP 支持三种功能:
MCP 的通信基于 JSON-RPC 2.0 协议,这是一种轻量级的远程过程调用协议,使用 JSON 格式进行数据交换。该协议支持状态化连接,允许在一个会话中进行多次请求和响应,适用于多轮对话和复杂的工具调用流程。
MCP 支持以下两种主要的传输机制:
标准输入/输出(Stdio)
• 适用场景:客户端和服务器在同一台机器上运行的本地集成。
• 特点:使用标准输入输出流进行通信,适合访问本地文件系统或执行本地脚本的场景。 
HTTP + Server-Sent Events(SSE)
• 适用场景:客户端和服务器分布式部署的远程通信。
• 特点:客户端通过 HTTP POST 向服务器发送请求,服务器通过 SSE 向客户端推送实时消息,支持实时数据流和事件驱动的通信。
在 MCP 架构中,通信流程如下: 1. 客户端:位于主机应用(如聊天机器人、IDE 助手)中,负责构建请求并发送给 MCP 服务器。
服务器:提供外部数据源或工具的访问接口,接收客户端的请求,处理后返回结构化的响应。
通信协议:客户端和服务器之间通过 JSON-RPC 2.0 协议进行通信,传输机制可以是 Stdio 或 HTTP + SSE。
MCP 提供了一个统一的通信协议和多样的传输机制,支持大型语言模型与外部工具和数据源之间的高效集成。通过标准化的结构和灵活的传输方式,MCP 使得开发者能够构建更强大、可扩展的 AI 应用。
Function Calling(函数调用)是模型内部的函数调用机制,是由 LLM 提供商(如 OpenAI、Anthropic)实现的一种机制,允许模型根据用户输入,生成结构化的函数调用请求。 不同平台之间可能存在差异。 适合处理边界清晰、描述明确的任务,如数据提取、分类或外部 API 调用等。代码的适配性和复用性较差(我们需要把每个 Function 编码到程序中)。
而 MCP(模型上下文协议) 是模型与外部系统的通用通信协议。使得不同的 AI 模型和外部系统能够无缝集成,降低了适配成本。 更擅长处理复杂、多步骤的对话场景,尤其是在需要维持上下文连贯性和动态适应用户需求的场景中,其优势尤为明显。
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
# 初始化 FastMCP server
mcp = FastMCP("weather")
# 获取美国某个州的天气警报
@mcp.tool()
async def get_alerts(state: str)-> str:
"""Get weather alerts for a US state.
Args:
state:Two-letter US state code(e.g.CA,NY)
"""
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data =awaitmake_nws_request(url)
if not data or "features" not indata:
return"Unable to fetch alerts or no alerts found."
if not data["features"]:
return"No active alerts for this state."
alerts =[format_alert(feature)for feature in data["features"]]
return"\n---\n".join(alerts)
# 获取某个地点的天气警报
@mcp.tool()
async def get_forecast(latitude: float,longitude: float)-> str:
"""Get weather forecast for a location.
Args:
latitude:Latitudeof the location
longitude:Longitudeof the location
"""
# Firstget the forecast grid endpoint
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data =awaitmake_nws_request(points_url)
if not points_data:
return"Unable to fetch forecast data for this location."
# Get the forecast URLfrom the points response
forecast_url = points_data["properties"]["forecast"]
forecast_data =awaitmake_nws_request(forecast_url)
if not forecast_data:
return"Unable to fetch detailed forecast."
# Format the periods into a readable forecast
periods = forecast_data["properties"]["periods"]
forecasts =[]
for period in periods[:5]: # Only show next 5 periods
forecast = f"""
{period['name']}:
Temperature:{period['temperature']}°{period['temperatureUnit']}
Wind:{period['windSpeed']}{period['windDirection']}
Forecast:{period['detailedForecast']}
"""
forecasts.append(forecast)
return"\n---\n".join(forecasts)
使用 main
方法启动 Weather MCP Server
if __name__ =="__main__":
# Initialize and run the server
mcp.run(transport='stdio')
importasyncio
from typing importOptional
from contextlib importAsyncExitStack
from mcp importClientSession,StdioServerParameters
from mcp.client.stdioimportstdio_client
from anthropic importAnthropic
from dotenv import load_dotenv
load_dotenv() # load environment variables from.env
classMCPClient:
def __init__(self):
# Initialize session and client objects
self.session:Optional[ClientSession]=None
self.exit_stack=AsyncExitStack()
self.anthropic=Anthropic()
# methods will go here
async def connect_to_server(self,server_script_path: str):
"""Connect to an MCP server
Args:
server_script_path:Path to the server script(.py or .js)
"""
is_python = server_script_path.endswith('.py')
is_js = server_script_path.endswith('.js')
ifnot(is_python or is_js):
raise ValueError("Server script must be a .py or .js file")
command ="python"if is_python else"node"
server_params =StdioServerParameters(
command=command,
args=[server_script_path],
env=None
)
stdio_transport =await self.exit_stack.enter_async_context(stdio_client(server_params))
self.stdio, self.write= stdio_transport
self.session=await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))
await self.session.initialize()
# List available tools
response =await self.session.list_tools()
tools = response.tools
print("\nConnected to server with tools:",[tool.namefor tool in tools])
async def process_query(self,query: str)-> str:
"""Process a query using Claude and available tools"""
messages =[
{
"role":"user",
"content": query
}
]
response =await self.session.list_tools()
available_tools =[{
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
}for tool in response.tools]
# InitialClaudeAPI call
response = self.anthropic.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1000,
messages=messages,
tools=available_tools
)
# Process response and handle tool calls
final_text =[]
assistant_message_content =[]
for content in response.content:
if content.type'text':
final_text.append(content.text)
assistant_message_content.append(content)
elif content.type'tool_use':
tool_name = content.name
tool_args = content.input
# Execute tool call
result =await self.session.call_tool(tool_name, tool_args)
final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")
assistant_message_content.append(content)
messages.append({
"role":"assistant",
"content": assistant_message_content
})
messages.append({
"role":"user",
"content":[
{
"type":"tool_result",
"tool_use_id": content.id,
"content": result.content
}
]
})
# Get next response fromClaude
response = self.anthropic.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1000,
messages=messages,
tools=available_tools
)
final_text.append(response.content[0].text)
return"\n".join(final_text)
注意:不同 LLM 的 request 和 response 的结构是不一样的,DeepSeek 和千问模型遵循 OpenAI 的规范,而 Claude 与 Gemini 的 resposne 与 openai 不一样。 如:
Claude response.content[0].text
与 OpenAI response.choices[0].message.content
async def chat_loop(self):
"""Run an interactive chat loop"""
print("\nMCP Client Started!")
print("Type your queries or 'quit' to exit.")
while True:
try:
query = input("\nQuery: ").strip()
if query.lower()=='quit':
break
response = await self.process_query(query)
print("\n" + response)
except Exception as e:
print(f"\nError: {str(e)}")
async def cleanup(self):
"""Clean up resources"""
await self.exit_stack.aclose()
async def main():
iflen(sys.argv)<2:
print("Usage: python client.py <path_to_server_script>")
sys.exit(1)
client =MCPClient()
try:
await client.connect_to_server(sys.argv[1])
await client.chat_loop()
finally:
await client.cleanup()
if __name__ =="__main__":
import sys
asyncio.run(main())
python client.py./weather.py
# Relative path
uv run client.py./server/weather.py
# Absolute path
uv run client.py/Users/username/projects/mcp-server/weather.py
# Windowspath(either format works)
uv run client.pyC:/projects/mcp-server/weather.py
uv run client.pyC:\\projects\\mcp-server\\weather.py
MCP Server Github提供很多现成的MCP Server,GitHub MCP Server 是一个模型上下文协议 (MCP) 服务器,可与 GitHub API 无缝集成,为开发人员和工具提供高级自动化和交互功能。
使用 npx 直接运行 GitHub MCP Server。需要创建一个 GitHub 个人访问令牌
(https://github.com/settings/tokens)
npx -y @modelcontextprotocol/server-github
使用官方提供的 MCP Inspector 工具来测试和调试 MCP Server。
npx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-github
浏览器访问 http://localhost:5173
LLM 集成 MCP Server 有很多种方式,可以自定义,也可以直接使用已有的库。
使用mcp-use
进行 LLM 与 MCP 的集成,mcp-use
是一个开源的 Python 库,可以非常轻松地将任何 LLM 连接到本地和远程的任何 MCP 服务器。
import asyncio
importos
from dotenv importload_dotenv
from langchain_openai importChatOpenAI
from mcp_use importMCPAgent,MCPClient
"""
pip install mcp-use
"""
async def main():
# Load environment variables
load_dotenv()
# Create configuration dictionary
config ={
"mcpServers":{
"github":{
"command":"npx",
"args":["-y","@modelcontextprotocol/server-github"],
"env":{
"GITHUB_PERSONAL_ACCESS_TOKEN":"<GITHUB PERSONAL ACCESS TOKEN>"
}
}
}
}
# CreateMCPClientfrom configuration dictionary
client =MCPClient.from_dict(config)
# CreateLLM
llm =ChatOpenAI(api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com",
model="deepseek-chat")
# Create agent with the client
agent =MCPAgent(llm=llm, client=client, max_steps=30)
# Run the query
result =await agent.run(
"search ai-agent-demo repo",
)
print(f"\nResult: {result}")
if __name__ =="__main__":
asyncio.run(main())
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2025-06-06
Anthropic官方揭秘内部团队如何使用 Claude Code(附完整版手册)
2025-06-06
图像编辑模型SeedEdit 3.0发布!更强保持力,更高可用率
2025-06-05
如何构建AI Agent快速分析行业景气度
2025-06-05
MCP Server 之旅第 5 站:服务鉴权体系解密
2025-06-05
Cursor 1.0 正式发布!BugBot 自动代码审查,Background Agent 全面开放、MCP一键安装
2025-06-05
11张图全面总结 MCP、A2A、Function Calling 架构设计间关系
2025-06-05
一手实测地产首个Agent,实话说:不错!
2025-06-05
面向 Data+AI 的新一代数智开发平台
2024-08-13
2024-06-13
2024-08-21
2024-07-31
2024-09-23
2024-05-28
2024-08-04
2024-04-26
2024-07-09
2024-07-20
2025-06-05
2025-06-04
2025-06-04
2025-06-03
2025-06-02
2025-05-31
2025-05-29
2025-05-29