大数跨境
0
0

AGI|基于FastMCP 2.0的MCP Server快速搭建指南

AGI|基于FastMCP 2.0的MCP Server快速搭建指南 AI实践工程院
2025-06-03
3
导读:一次性告别单打独斗☝


神州数码云基地

AGI专栏

基于FastMCP 2.0 开发MCP Server

MCP协议的登场为整个 Agent 生态注入新动力:它以标准化的消息格式和高效的路由机制,让分布式智能体之间能够跨平台、跨语言地无缝协作。


前文已为大家深入剖析了MCP与A2A协议的原理与优势,错过的伙伴可以回顾一下:

AGI|爆火的MCP背后,为何被称作 AI 模型的“万能适配器”?

AGI|详解Google A2A协议,谁才是Agent的未来标准?


接下来带你动手实操,手把手学习如何基于FastMCP 2.0快速搭建高性能、可扩展的MCP Server。



 作者 

李冠军 高级AI交付工程师

不是bug,是隐藏功能



Part1

介绍


模型上下文协议(Model Context Protocol,简称 MCP)是一种创新的通信协议,它允许应用程序以标准化的方式为大语言模型(LLM)提供上下文信息。通过 MCP,开发者能够将上下文提供与实际的 LLM 交互分离开来,这种解耦设计大大提升了系统的灵活性和可维护性。


MCP Server 可分为 Remote MCP Server 和 Local MCP Server 两种类型:


● Local MCP Server:Local MCP Server 架构是部署在用户本地设备上的 MCP 服务器。在这种架构模式中,MCP 客户端(例如 Claude Desktop 或 Cursor)通过本地进程通信(stdin/stdout)与 MCP 服务器进行交互,而 MCP 服务器则负责连接到互联网上的各种 API 和服务。这种架构设计简单直观,非常适合个人开发者使用,但同时也存在一些局限性。



● Remote MCP Server:Remote MCP Server 架构是部署在云端的 MCP 服务器,用户可以通过互联网进行访问。在这种模式下,MCP 客户端可以是各种网页应用或移动应用,它们通过 HTTP 协议与远程 MCP 服务器进行通信。Remote MCP Server架构 通常集成了认证授权、状态管理、数据库访问等企业级功能,能够为多个用户提供服务。




Part2

MCP开发框架


FastMCP


· 官网地址:https://gofastmcp.com/getting-started/welcome


· Github:https://github.com/jlowin/fastmcp


· MCP 官方SDK: https://github.com/modelcontextprotocol/python-sdk


MCP官方的Python SDK 基于 FastMCP 1.0,FastMCP 2.0 在 1.0 的基础上进行了显著扩展,引入了强大的客户端功能、服务器代理与组合、OpenAPI/FastAPI 集成以及更多高级功能。 FastMCP 2.0 是构建现代、强大的 MCP 应用程序的推荐途径。



核心概念


▶ 工具 - Tool


在 MCP Server 开发中,工具是将函数暴露给 MCP 客户端,使其成为可执行功能的关键组件。工具作为核心构建块,赋予了 LLM 与外部系统交互、执行代码以及访问训练数据之外信息的能力。在 FastMCP 中,工具本质上是通过 MCP 协议暴露给 LLM 的 Python 函数。


FastMCP 将常规 Python 函数转换为 LLM 在对话过程中可调用的功能。当 LLM 决定调用某个工具时,会按照以下流程执行:


  1. LLM 根据工具定义的模式,向服务器发送包含参数的请求;


  2. FastMCP 依据函数签名对传入的参数进行严格验证,确保参数的正确性和完整性;


  3. 经过验证的参数将作为输入,执行对应的 Python 函数;


  4. 函数执行结果返回给 LLM,LLM 可以在后续的响应中使用该结果。


通过这种机制,LLM 能够执行诸如查询数据库、调用 API、进行复杂计算或访问文件等多样化任务,从而突破训练数据的限制,极大地扩展了自身功能。


▶ 资源和模板 - Resources


资源和模板用于向 MCP 客户端公开数据源和动态内容生成器。资源代表了 MCP 客户端可以读取的数据或文件,而资源模板进一步扩展了这一概念,它允许客户端根据 URI 中传递的参数请求动态生成的资源。


在 FastMCP 中,主要使用@mcp.resource装饰器来简化静态和动态资源的定义过程。资源为 LLM 或客户端应用程序提供了对数据的只读访问权限。当客户端请求资源 URI 时,服务器会按以下步骤处理:


  1. FastMCP 查找与请求 URI 对应的资源定义。


  2. 如果是动态资源(由函数定义),则执行该函数生成相应内容。


  3. 将生成的内容(可以是文本、JSON 格式数据或二进制数据)返回给客户端。


借助资源和模板,LLM 可以访问与对话相关的文件、数据库内容、配置信息或动态生成的各类数据,满足不同场景下的需求。


▶ 提示 - Prompt


提示是为 MCP 客户端创建的可重复使用的参数化提示模板。它本质上是一种消息模板,能够帮助 LLM 生成结构化、具有明确目的性的响应。在 FastMCP 中,主要通过@mcp.prompt装饰器来简化提示模板的定义。


当客户端请求提示时,服务器的处理流程如下:


  1. FastMCP 找到与请求对应的提示定义。


  2. 如果提示包含参数,会根据函数签名对参数进行验证,确保参数符合模板要求。


  3. 使用经过验证的输入执行相关函数,生成提示消息。


  4. 将生成的消息返回给 LLM,用于指导其生成响应。


通过提示模板,开发者可以定义统一、可复用的消息模板,使 LLM 在不同客户端和环境中都能生成风格一致、符合预期的响应。


▶ 服务组合 - Server Composition


随着 MCP 应用程序的增长,您可能需要将工具、资源和提示组织到逻辑模块中,或重用现有的服务器组件。FastMCP 通过两种方法支持组合:


  • import_server:用于一次性复制带前缀的组件(静态组合)。


  • mount:用于创建主服务器将请求委托给子服务器的实时链接(动态组合)。


为什么要用Composition


  • 模块化:将大型应用程序分解为更小的、集中的服务器(例如,a WeatherServer、a DatabaseServer、a CalendarServer)。


  • 可重用性:创建通用实用程序服务器(例如TextProcessingServer)并将其安装在任何需要的地方。


  • 团队合作:不同的团队可以在单独的 FastMCP 服务器上工作,然后再合并。


  • 组织:将相关功能按逻辑分组。




Part3

快速搭建 MCP Server


1. 环境准备


# python 版本 要求 >= 3.10
# 使用 uv 来管理项目
# 初始化项目
uv init mcp-server-demo
cd mcp-server-demo

#
 创建并激活环境
uv venv
source .venv/bin/activate

#
 安装mcp 依赖
uv add "fastmap"


2. 代码实现


# server.py
# 引入 fastmcp 包
from fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("CalculatorServer")


# 定义工具,也就是实际执行的内容,类似于 RestAPI 中的 POST,mcp主要的能力都在这里体现。
# Add an addition tool
@mcp.tool()
defadd(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b


# 定义资源,资源为只读,类似于 RestAPI 中的 Get,可用于获取配置、版本等静态资源信息。
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
defget_greeting(name: str) -> str:
    """Get a personalized greeting"""
    returnf"Hello, {name}!"
    
    
if __name__ == "__main__":
    mcp.run(transport='stdio')


3.  测试验证


使用Cherry-Studio 中的MCP服务管理结合Chat对话使用我们开发的mcp server。




Part4

搭建一个多 MCP Server 组合的复杂应用


1. 示例说明


电商平台服务组合


▷ MainMCP 服务:可将其看作电商平台的主服务,负责管理各类子服务,像商品展示、用户管理、订单处理等。


▷ SubMCP 服务:商品推荐子服务,为用户提供个性化的商品推荐。


▷ SubMCP 服务:支付服务,为用户提供便捷的支付体验。


这里仅设置了一个SubMCP,大型服务可设置多个子MCP服务。


2. 代码实现


以下是实现电商平台多 MCP Server 组合的代码示例:


import asyncio
from fastmcp import FastMCP, Client

# --- 定义子服务器(商品推荐服务) ---
# 阿里西西商城
product_recommendation_mcp = FastMCP(name="商品推荐服务")


# 定义获取热门商品的工具函数
@product_recommendation_mcp.tool()
def get_popular_products():
    """List of popular products"""
    # mock data
    hot_products = ('[{"product_name":"iPhone 14 Pro Max", "price": 5999, "category": "Electronics"},'
                    '{"product_name":"小米SU7 Ultra", "price": 529999, "category": "Car"},'
                    '{"product_name":"红米K80", "price": 2399, "category": "Electronics"}]')

    return hot_products


# 定义为指定用户获取推荐商品的工具函数
@product_recommendation_mcp.tool()
def get_recommended_products(user_id):
    """Products recommended for users"""
    # mock data
    recommended_products = '{"product_name":"小米SU7 Ultra", "price": 529999, "category": "Car"}'
    return recommended_products


# --- 定义子服务器(支付服务) ---
pay_mcp = FastMCP(name="支付服务")


# 定义支付工具函数
@pay_mcp.tool()
def pay(product_name: str, amount: float):
    """Pay for a product"""
    # 这里可以是请求API或者是具体支付逻辑
    # 或者有没有可能未来的各种系统,都会实现一套 mcp 的接口,然后接收apikey等鉴权信息,类比于Restful API
    # 其实很多大厂已经这样做了
    returnf"恭喜您支付成功,商品名称:{product_name},支付金额{amount}元。"


# --- 定义主服务器(电商主服务) ---
ecommerce_main_mcp = FastMCP(name="阿里西西商城服务")

# --- 挂载子服务器(同步操作) ---
ecommerce_main_mcp.mount("recommendation", product_recommendation_mcp)
ecommerce_main_mcp.mount("pay", pay_mcp)

print("已将子服务挂载到电商主服务上。")


# --- 在挂载后为子服务器添加一个工具 ---
# 定义获取新上架商品的工具函数
@product_recommendation_mcp.tool()
def get_new_arrivals():
    """List of newly listed products"""
    # mock data
    new_arrivals = ('[{"product_name":"新款华为Mate 60 Pro", "price": 6999, "category": "Electronics"},'
                    '{"product_name":"新款小米平板", "price": 2999, "category": "Electronics"}]')
    return new_arrivals


print("已为商品推荐子服务添加 'get_new_arrivals' 工具。")


# --- 测试访问 ---
asyncdef test_dynamic_mount():
    # 从主服务器获取所有可用的工具
    tools = await ecommerce_main_mcp.get_tools()
    print("通过电商主服务可用的工具:", list(tools.keys()))

    asyncwith Client(ecommerce_main_mcp) as client:
        # 通过主服务器调用 'get_popular_products' 工具
        popular_products_result = await client.call_tool("recommendation_get_popular_products")
        print("调用 recommendation_get_popular_products 的结果:", popular_products_result[0].text)

        # 通过主服务器调用 'get_recommended_products' 工具
        recommended_products_result = await client.call_tool("recommendation_get_recommended_products",
                                                             parameters={"user_id""123"})
        print("调用 recommendation_get_recommended_products 的结果:", recommended_products_result[0].text)

        # 通过主服务器调用动态添加的 'get_new_arrivals' 工具
        new_arrivals_result = await client.call_tool("recommendation_get_new_arrivals")
        print("调用 recommendation_get_new_arrivals 的结果:", new_arrivals_result[0].text)


if __name__ == "__main__":
    # 需要异步上下文进行测试
    # asyncio.run(test_dynamic_mount())
    # 若要运行服务器本身:
    ecommerce_main_mcp.run()


3. 测试验证




4. 模块化MCP Server


在复杂的MCP Server 场景下,必然面临代码量增多,也必然有解耦以及模块化的需求,以下是一个模块化MCP Server的示例


########### 主程序 #################
from fastmcp import FastMCP
import asyncio

# Import the servers (see other files)
from modules.text_server import text_mcp
from modules.data_server import data_mcp

app = FastMCP(name="MainApplication")

# Setup function for async imports
asyncdef setup():
    # Import the utility servers
    await app.import_server("text", text_mcp)
    await app.import_server("data", data_mcp)

@app.tool()
def process_and_analyze(record_id: int) -> str:
    """Fetches a record and analyzes its string representation."""
    # In a real application, you'd use proper methods to interact between
    # imported tools rather than accessing internal managers
    
    # Get record data
    record = {"id": record_id, "value": random.random()}
    
    # Count words in the record string representation
    word_count = len(str(record).split())
    
    return (
        f"Record {record_id} has {word_count} words in its string "
        f"representation."
    )

if __name__ == "__main__":
    # Run async setup before starting the server
    asyncio.run(setup())
    # Run the server
    app.run()


########### 子程序-data_mcp #################
from fastmcp import FastMCP
import random
from typing import dict

data_mcp = FastMCP(name="DataAPI")

@data_mcp.tool()
def fetch_record(record_id: int) -> dict:
    """Fetches a dummy data record."""
    return {"id": record_id, "value": random.random()}

@data_mcp.resource("data://schema/{table}")
def get_table_schema(table: str) -> dict:
    """Provides a dummy schema for a table."""
    return {"table": table, "columns": ["id""value"]}
    
########### 子程序-text_mcp #################
from fastmcp import FastMCP

text_mcp = FastMCP(name="TextUtilities")

@text_mcp.tool()
def count_words(text: str) -> int:
    """Counts words in a text."""
    return len(text.split())

@text_mcp.resource("resource://stopwords")
def get_stopwords() -> list[str]:
    """Return a list of common stopwords."""
    return ["the""a""is""in"]


在这个示例中,将 MCP Server 拆分为主程序和两个子程序data_mcp、text_mcp。主程序负责导入子服务器并定义全局工具函数,子服务器分别实现数据处理和文本处理相关的工具和资源。通过这种模块化设计,提高了代码的可读性、可维护性和可扩展性。



Part5

总结思考


通过以上步骤,我们了解了如何开发 MCP 服务,从快速搭建单 MCP Server 到构建多 Server 组合的复杂应用。在开发过程中,我们深刻体会到 MCP 协议在模型通信中的优势,它为不同模型之间的协同工作提供了标准化的解决方案,有效提升了系统的整体性能和可扩展性。


思考点:


▷ MCP Server 是否可认为是 AI 版的 Restful API 对接方式?


▷ MCP Server 也可以通过组合和代理的方式实现鉴权等能力,那么还需要A2A吗?



相关链接:

1.https://gofastmcp.com/getting-started/welcome

2.https://github.com/jlowin/fastmcp

3.https://modelcontextprotocol.io/quickstart/server

4.https://github.com/mark3labs/mcp-go




Hello~

这里是神州数码云基地
编程大法,技术前沿,尽在其中
超多原创技术干货持续输出ing~


想要第一时间获取
超硬技术干货
快快点击关注+设为星标



- END -


往期精选




详解Google A2A协议




MCP详解:为何被称作 AI 模型的“万能适配器”




全面解读MCP协议:从技术原理到实践应用


了解云基地,就现在!

【声明】内容源于网络
0
0
AI实践工程院
我们致力于用数字技术重构企业价值,助力企业实现数字化转型升级。
内容 434
粉丝 0
AI实践工程院 我们致力于用数字技术重构企业价值,助力企业实现数字化转型升级。
总阅读115
粉丝0
内容434