【AI】开发笔记:一文入门MCP开发,架起LLM与业务系统桥梁
1、什么是MCP协议?
MCP(Model Context Protocol,模型上下文协议) 是由 Anthropic 于去年11月正式提出的一种开放标准,旨在通过统一的客户端-服务器架构解决 LLM 应用与数据源连接的难题,MCP 使得 AI 应用能够安全地访问和操作本地及远程数据,为 AI 应用提供了连接万物的接口,提升了智能体Agent的开发效率。截止目前,已上千种MCP工具诞生,在强悍的MCP生态加持下,人人手搓Manus的时代即将到来。
2、MCP技术架构
MCP 遵循客户端-服务器架构(client-server),其中包含以下几个核心概念:
- MCP 主机(MCP Hosts):发起请求的 LLM 应用程序(例如 Claude Desktop、IDE 或 AI 工具)。
- MCP 客户端(MCP Clients):在主机程序内部,与 MCP server 保持 1:1 的连接。
- MCP 服务器(MCP Servers):为 MCP client 提供上下文、工具和 prompt 信息。
- 本地资源(Local Resources):本地计算机中可供 MCP server 安全访问的资源(例如文件、数据库)。
- 远程资源(Remote Resources):MCP server 可以连接到的远程资源(例如通过 API)。

3、MCP Client 工作流程
- MCP client 首先从 MCP server 获取可用的工具列表。
- 将用户的查询连同工具描述通过 function calling 一起发送给 LLM。
- LLM 决定是否需要使用工具以及使用哪些工具。
- 如果需要使用工具,MCP client 会通过 MCP server 执行相应的工具调用。
- 工具调用的结果会被发送回 LLM。
- LLM 基于所有信息生成自然语言响应。
- 最后将响应展示给用户。
4、MCP Server 关键组件
- 工具(Tools):定义允许 LLM 自动调用的函数(需要用户批准),包括查询和写入操作。
- 资源(Resources):定义 LLM 可以访问的只读数据源,为 LLM 提供上下文内容,如帮助文档、日志信息等。
- 提示(Prompts):定义可重用的提示模板,帮助用更好的引导 LLM 以标准化的方式完成任务。
这些功能使 MCP server 能够为 AI 应用提供丰富的上下文信息和操作能力,从而增强 LLM 的实用性和灵活性。
5、MCP 通信方式
-
标准输入输出(Standard Input/Output, stdio):客户端通过启动服务器子进程并使用标准输入(stdin)和标准输出(stdout)建立双向通信,一个服务器进程只能与启动它的客户端通信(1:1 关系)。stdio 适用于本地快速集成的场景,在本文中,我们将使用这种方式来编写 MCP 客户端。
-
服务器发送事件(Server-Sent Events, SSE):是一种基于 HTTP 协议的技术,允许服务器向客户端单向、实时地推送数据。服务器作为独立进程运行,客户端和服务器代码完全解耦,支持多个客户端随时连接和断开。
6、 本地Server(STDIO)开发实例
6.1、server端开发
创建server代码:server_stdio.py
from mcp.server.fastmcp import FastMCP
from utils.date import get_time
from utils.weather import get_weather, format_weather
# 初始化 FastMCP 服务器,命名为 “MyMCPServer”
mcp = FastMCP("MyMCPServer")
# 定义工具函数,获取指定城市的天气
@mcp.tool()
async def fetch_weather(city: str) -> str:
"""
输入指定城市的名称,返回今日天气查询结果。
:param city: 城市名称(需使用中文)
:return: 格式化后的天气信息
"""
data = await get_weather(city)
return format_weather(data)
# 定义工具函数,返回当前的日期和时间(ISO格式)
@mcp.tool()
def fetch_time():
"""返回当前的日期和时间。 """
return get_time()
# 定义只读资源,返回当前项目的README.md文件内容
@mcp.resource("file://README.md")
def get_file() -> str:
"""Return the contents of README.md file"""
with open("README.md", "r") as f:
return f.read()
# 定义提示词模板,结合用户入参生成预置格式的提示词
@mcp.prompt()
def role_prompt(role: str) -> str:
"""Create a prompt for role"""
return f"""You are a '{
role}' with 10-year experience and an elite expert with deep knowledge, you can helper user in your filed
"""
#运行服务器,使用标准输入输出传输
if __name__ == "__main__":
mcp.run(transport='stdio')
utils/date.py:
import datetime
def get_timezone():
"""返回服务器的时区设置"""
# 获取当前本地时间
now = datetime.datetime.now()
# 获取时区信息
timezone = now.astimezone().tzinfo
return(f"当前时区信息: {
timezone}")
def get_time():
"""返回服务器的日期和时间,格式为ISO 8601。 """
return datetime.datetime.now().isoformat()
#print(get_timezone())
utils/weather.py:
import json
import httpx
from typing import Dict, Any
import asyncio
async def get_weather(city: str):
"""返回指定城市的天气信息。"""
weather_api_url = "https://shanhe.kim/api/za/tianqi.php"
params = {
"city": city,
"type": "json" # json text
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(weather_api_url, params=params, timeout=30.0)
response.raise_for_status()
return response.json() # 返回字典类型
except httpx.HTTPStatusError as e:
return {
"error": f"HTTP 错误: {
e.response.status_code}"}
except Exception as e:
return {
"error": f"请求失败: {
str(e)}"}
def format_weather(data: dict[str, Any] | str) -> str:
"""
将天气数据格式化为易读文本。
:param data: 天气数据(可以是字典或 JSON 字符串)
:return: 格式化后的天气信息字符串
"""
# 如果传入的是字符串,则先转换为字典
if isinstance(data, str):
try:
data = json.loads(data)
except Exception as e:
return f"无法解析天气数据: {
e}"
# 如果数据中包含错误信息,直接返回错误提示
if "error" in data:
return f"⚠️ {
data['error']}"
# 提取数据时做容错处理
#city = data.get("name", "未知")
city = data.get("data", {
}).get("city", "未知")
#country = data.get("sys", {}).get("country", "未知")
temp = data.get("data", {
}).get

最低0.47元/天 解锁文章
328

被折叠的 条评论
为什么被折叠?



