【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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值