大模型(LLM)应用开发中,如何安全且结构化地让模型与外部世界进行交互是一项关键挑战。本文将深入探讨如何利用 MCP(Model Context Protocol)和 FastMCP 框架,结合 MongoDB 数据库,构建一个实时交互系统,使 LLM 能够在无需重新训练或修改代码的情况下,安全地执行数据库更新、库存管理和分析报告等任务。通过具体的案例和代码示例,我们将展示如何利用 @mcp.tool@mcp.resource@mcp.prompt 等装饰器,简化开发流程并提高系统的可维护性。

MCP:解决 LLM 与外部世界交互的难题

传统 LLM 应用面临的最大挑战之一是模型与外部系统通信的复杂性。受限于训练数据和孤立的运行环境,每个工具集成(例如 GitHub、Slack、Jira API)都需要定制化的协议和接口,导致架构复杂且难以实现。MCP(Model Context Protocol)旨在通过标准化工具调用、资源共享和 Prompt 管理来解决这一问题。简单来说,MCP 充当了 LLM 与外部世界之间的安全桥梁,允许模型通过安全的 JSON-RPC 流程触发代码中定义的动作(如“更新库存”、“更新价格”),并接收所需的数据。

MCP 的核心优势在于:

  • 安全性: 通过类型控制和运行时状态管理,确保 LLM 访问外部工具的安全性。
  • 灵活性: 无需重新训练或修改代码即可为 LLM 添加新的功能。
  • 标准化: 通过统一的协议简化了与各种外部系统的集成。

MCP 的关键组件包括:

  • Host(宿主): 承载 LLM 的应用程序环境(例如 Claude Desktop、VS Code 扩展),负责用户权限、安全管理以及 LLM 与工具调用之间的协调。
  • Client(客户端): 一个轻量级的桥梁,运行在 Host 内部,与每个 MCP Server 建立“有状态”连接。 它负责路由消息、处理请求/响应关联以及协商能力。
  • Server(服务器): MCP Server 以开放、类型安全和结构化的方式公开与外部系统交互所需的所有“能力”(即 Tools、Resources 和 Prompts)。

FastMCP:简化 LLM 应用开发流程

为了加速 MCP 的应用,我们选择了 FastMCP 框架。FastMCP 极大地简化了开发体验,并支持快速的生产部署。它的主要优势包括:

  • 基于装饰器的 API: 使用 @mcp.tool@mcp.resource@mcp.prompt 装饰器,只需一行代码即可向 MCP Server 引入能力。
  • 多传输协议支持: FastMCP 支持包括 stdio、HTTP(S) 和 Server-Sent Events (SSE) 在内的多种通信渠道,使其能够灵活地与各种系统集成。
  • 自动 JSON-Schema 生成: 与 Pydantic 天然集成,自动保证了每个定义结构的类型安全。

FastMCP 提供了一种简单而强大的结构,使我们能够快速且安全地构建兼容 MCP 的系统。例如,使用 @mcp.tool() 装饰器可以定义允许 LLM 对外部系统执行操作的函数:

from typing import Dict, Any, Optional
from fastmcp import tool

@tool()
def update_product(
    identifier: str,
    price: Optional[str] = None,
    stock: Optional[str] = None,
    category: Optional[str] = None,
    by_sku: bool = False
) -> Dict[str, Any]:
    """Update existing product with partial data"""

    # 假设 db_manager 是一个用于与 MongoDB 交互的类
    product = (db_manager.get_product_by_sku(identifier)
               if by_sku else db_manager.get_product_by_id(identifier))

    if not product:
        return {"success": False, "error": f"Product not found: {identifier}"}

    update_data = ProductUpdate()
    if price:
        update_data.price = float(price)
    if stock:
        update_data.stock = int(stock)
    if category:
        update_data.category = ProductCategory(category.lower())

    updated_product = db_manager.update_product(product.id, update_data)

    return {
        "success": bool(updated_product),
        "data": updated_product.dict() if updated_product else None,
        "message": f"Product {identifier} updated successfully"
    }

这个工具允许 LLM 通过 JSON-RPC 调用 update_product 函数,并使用 PATCH 语义以安全且类型控制的方式更新 MongoDB 中的产品信息。FastMCP 会自动验证传入的参数,确保数据的有效性。

Resource:为 LLM 提供实时上下文信息

@mcp.resource() 装饰器用于向 LLM 提供来自外部系统的只读数据。这些数据通常包括数据库状态、模式、文档或系统特定的配置信息。关键在于,这些资源是无副作用且确定性的:

  • 无副作用:函数仅提供数据,不修改数据库、文件系统或任何其他系统。
  • 确定性:对于相同的输入,总是产生相同的输出。

例如,可以使用 @mcp.resource 装饰器创建一个提供数据库状态信息的资源:

from fastmcp import resource

@resource("database://status")
def database_status() -> str:
    """Real-time database health and metrics"""
    health_data = db_manager.health_check()

    return f"""# Database Status
    **Connection**: {'✅ Connected' if health_data['connected'] else '❌ Disconnected'}
    **Total Products**: {health_data.get('total_products', 0):,}
    **Database Size**: {health_data.get('database_size', 0):,} bytes
    **Index Count**: {health_data.get('index_count', 0)}
    **Last Check**: {health_data['last_check']}
    """

LLM 可以通过 resources/get 端点将此资源包含在其上下文中。该函数运行,但不执行任何附加操作,仅提供字符串、JSON 或二进制数据。这样,LLM 就可以在不消耗 Token 的情况下,使用运行时上下文。

Prompt:指导 LLM 的行为和输出

@mcp.prompt() 装饰器用于提供预定义的、面向任务的可重用文本模板。通过这种方式,可以在预定义的上下文中确定模型应该如何思考以及应该产生什么样的输出。

from fastmcp import prompt

@prompt()
def executive_summary_prompt() -> str:
    """C-level business intelligence report"""
    return (
        "Create executive summary: total number of items, inventory value, "
        "top earning category, low stock alerts, and provide strategic recommendations."
    )

这种方法允许将 Prompt 定义为模块化的函数,并将其与代码分离。这意味着可以在不更改代码逻辑的情况下更新 Prompt。Prompt 工程人员无需后端部署即可进行更改。

MongoDB:数据存储和检索的核心

MongoDB 在该系统中扮演着关键的角色,用于存储和检索产品信息、库存数据以及其他相关数据。它提供了灵活的数据模型和强大的查询功能,能够满足 LLM 应用对数据处理的需求。通过 MCPFastMCPLLM 可以安全地查询和更新 MongoDB 中的数据,从而实现各种业务场景,例如:

  • 产品管理: 创建、更新和删除产品信息。
  • 库存控制: 跟踪库存水平、设置低库存警报和自动补货。
  • 分析报告: 生成销售分析、库存报告和业务摘要。

在实际应用中,可以利用 MongoDB 的聚合管道功能来生成复杂的分析报告。例如,可以使用以下聚合管道来计算每个类别的总销售额:

db.sales.aggregate([
  {
    $group: {
      _id: "$category",
      totalSales: { $sum: "$price" }
    }
  },
  {
    $sort: { totalSales: -1 }
  }
])

然后,LLM 可以通过 @mcp.resource 装饰器访问此报告,并将其包含在生成的业务摘要中。

真实场景:产品价格更新流程

让我们通过一个实际场景来了解 MCPFastMCPMongoDB 如何协同工作。假设用户希望将 SKU 为 ELEC-WH-001 的产品的价格更新为 100 元。以下是系统中的步骤:

  1. 用户查询: 用户告诉 Claude Desktop:“将 SKU 为 ELEC-WH-001 的产品的价格设置为 100 元。”

  2. LLM 理解需求: Host 环境中的 LLM 理解到该命令涉及数据库更新,并且它无法直接执行此操作。因此,它决定需要进行工具调用(函数调用)以与外部世界安全地通信。

  3. MCP Server 能力声明: 在用户查询到达之前,LLM 已经学习了通过 MCP Client 连接的 MCP Server 具有哪些工具和资源。MCP Server 之前向 LLM 声明了这些工具,例如:

    • create_product: 创建新产品
    • update_product: 更新产品字段,例如价格、库存、类别
    • get_inventory_summary: 库存摘要
  4. LLM 工具选择: LLMupdate_product 工具的描述中了解到,它可以通过 SKU 更新产品,并准备参数。

  5. JSON-RPC 请求: LLMMCP Server 发送以下格式的请求:

    {
      "method": "tools/call",
      "params": {
        "name": "update_product",
        "arguments": {
          "identifier": "ELEC-WH-001",
          "price": "100",
          "by_sku": true
        }
      }
    }
    
  6. 请求处理和验证: MCP Server 接收到此请求并首先对其进行解析。它根据使用 Pydantic 自动生成的 JSON Schema 验证包含的数据(例如,检查 price 字段是否为浮点数)。这保证了系统的类型安全操作。

  7. MongoDB 操作: 成功验证后,MCP Server 执行以下操作:

    # 1. 通过 SKU 获取产品
    product = db_manager.get_product_by_sku("ELEC-WH-001")
    
    # 2. 准备更新数据
    update_data = ProductUpdate(price=100.0)
    
    # 3. 在 MongoDB 中更新
    db.products.updateOne(
        {"_id": product.id},
        {"$set": {"price": 100.0, "updated_at": new Date()}}
    )
    
  8. 响应: 从 MongoDB 中检索更新的产品数据,并由 MCP Server 格式化后发送回,如下所示:

    {
      "success": true,
      "message": "Product 'Wireless Headphones' updated successfully",
      "data": {
        "id": "507f1f77bcf86cd799439011",
        "name": "Wireless Headphones",
        "sku": "ELEC-WH-001",
        "price": 100.0,
        "updated_at": "2024-01-15T10:30:00Z"
      }
    }
    
  9. 响应用户: LLM 使用接收到的数据向用户提供以下响应:“SKU 为 ELEC-WH-001 的 ‘Wireless Headphones’ 产品的价格已成功更新为 100 元。”

Prompt 链示例

Prompt 链是一种将多个 Prompt 连接在一起以实现更复杂任务的技术。例如,LLM 可以首先使用 inventory_overview_prompt 收集数据,然后在同一上下文中使用 executive_summary_prompt 生成 C 级报告。

这种方法提供了:

  • 模块化方法: 每个 Prompt 专注于单一职责。
  • 可重用性: 相同的 Prompt 可以在不同的场景中使用。
  • 可维护性: Prompt 更改不会影响后端代码。

结论

本文详细介绍了如何使用 MCPFastMCP 框架,结合 MongoDB 数据库,构建一个安全可控的 LLM 应用。通过装饰器简化开发流程,利用 资源(Resource)提供实时上下文信息,并使用 Prompt 指导 LLM 的行为,我们能够创建更强大、更灵活且更易于维护的 大模型 应用。 借助 JSON-RPC 协议,LLM 能够在运行时获得新的能力,而无需重新训练或手动干预。例如,一个基于 LLM 的客户服务系统,可以根据用户提出的问题,利用 FastMCP 调用 MongoDB 中的产品信息,并结合 Prompt 自动生成个性化的推荐信息。这种集成方式极大地提升了客户服务的效率和质量。 通过 FastMCP@mcp.tool@mcp.resource@mcp.prompt 等装饰器,我们可以极大地简化开发体验,并使 LLM 的行为清晰且可追溯。希望本文能帮助开发者更好地理解和应用 MCP,从而构建更智能、更高效的 LLM 应用。