🚀 文档“活”起来了:深度实战 MCP Resources 协议,打造具备语义感知能力的本地 RAG 动态知识库系统

📝 摘要 (Abstract)

本文深度探讨了 Model Context Protocol (MCP) 中 Resources 原语的设计哲学与实战应用。不同于传统的文件读取,MCP Resources 通过结构化的 URI 定位与动态模板,为 LLM 提供了一个标准化的“语义数据接口”。文章将通过构建一个集成向量数据库(ChromaDB)的本地 RAG Server,展示如何将海量文档转化为 AI 可感知的动态资源,并深入思考分块策略、语义检索精度以及在长上下文环境下的资源调度优化,旨在为企业构建高效的本地知识库助手。


一、 重新定义“数据访问”:为什么 MCP Resources 是 RAG 的最佳拍档? 📚

1.1 从“死文件”到“活资源”:语义化的跨越

在没有 MCP 之前,如果我们想让 AI 读取一个 PDF,通常是先解析全文,然后塞进 Prompt。这在文档量巨大时会导致 Context 爆炸。MCP Resources 引入了类似 Web 时代的 URI(统一资源标识符) 概念。每一个文档、每一张数据库表、甚至每一段实时日志,都可以被赋予一个唯一的地址(如 docs://internal/handbook.md)。AI 不再是被动接收,而是根据需要主动“点餐”。

1.2 Resource Templates:应对海量数据的“动态索引”

如果你有数万个文档,在 list_resources 中全部列出是不现实的。MCP 提供了 Resource Templates。它允许我们定义带参数的路径(如 docs://projects/{project_id}/spec)。当 AI 意识到它在讨论某个具体项目时,它会自动填充参数并请求对应的资源,这种“按需发现”机制极大提升了系统的扩展性。

1.3 核心组件对比:Resources vs. Tools

很多初学者会混淆这两者。我们可以通过下表进行清晰界定:

维度MCP ResourcesMCP Tools
性质声明式数据(只读为主)命令式动作(可读写、可执行)
交互模型“这是我知道的信息”“这是我能做的操作”
典型场景读取配置、查询文档、查看日志运行代码、发送邮件、修改数据库
AI 感知作为 Context(上下文)注入作为 Action(动作)执行

二、 实战演练:手把手教你撸一个“语义驱动”的本地知识库 Server 🛠️

2.1 环境准备:向量数据库的引入

为了实现真正的“语义感知”,我们不能只做简单的文件名匹配。我们将使用 ChromaDB 作为后端,将本地文档向量化。

2.2 代码实现:具备 RAG 能力的 MCP Server

以下代码展示了如何利用 MCP 协议封装一个基于语义搜索的资源服务器。

import asyncio
import chromadb
from mcp.server import Server
from mcp.server.stdio import stdio_server
import mcp.types as types

# 1. 初始化本地向量库
chroma_client = chromadb.PersistentClient(path="./mcp_knowledge_db")
collection = chroma_client.get_or_create_collection(name="enterprise_docs")

server = Server("semantic-library-server")

@server.list_resources()
async def handle_list_resources() -> list[types.Resource]:
    """列出顶层静态资源(如:知识库总览)"""
    return [
        types.Resource(
            uri="docs://summary",
            name="知识库概览",
            mimeType="text/plain",
            description="当前知识库包含的所有文档主题摘要"
        )
    ]

@server.list_resource_templates()
async def handle_list_templates() -> list[types.ResourceTemplate]:
    """定义动态资源模板:支持按关键词语义检索文档"""
    return [
        types.ResourceTemplate(
            uriTemplate="search://docs/{query}",
            name="语义文档检索",
            description="根据关键词在本地知识库中进行语义搜索并返回相关片段",
            annotations=types.ResourceAnnotations(priority=1.0)
        )
    ]

@server.read_resource()
async def handle_read_resource(uri: str) -> str:
    """处理资源读取请求:支持静态读取与动态语义检索"""
    if uri == "docs://summary":
        return "本知识库涵盖:财务制度、技术规范、入职指引等。"

    if uri.startswith("search://docs/"):
        # 提取查询参数
        query = uri.replace("search://docs/", "")
        
        # 2. 【核心逻辑】执行向量检索
        # 实际场景中,这里应调用 Embedding 模型,此处演示简化的检索流程
        results = collection.query(
            query_texts=[query],
            n_results=3
        )
        
        # 将检索到的分块拼接成 context 返回
        context_chunks = [res for res in results['documents'][0]]
        return "\n--- 检索到的相关内容 ---\n" + "\n".join(context_chunks)

    raise ValueError(f"Resource not found: {uri}")

async def main():
    # 模拟预填充一些数据
    collection.add(
        documents=["公司的年假制度是每年15天。", "技术栈要求使用 Python 和 MCP 协议。"],
        ids=["id1", "id2"]
    )
    
    async with stdio_server() as (read, write):
        await server.run(read, write, server.create_initialization_options())

if __name__ == "__main__":
    asyncio.run(main())

2.3 关键点:MIME Type 的重要性

read_resource 中返回内容时,mimeType 决定了 Host 侧(如 Claude)如何渲染这些数据。如果是 application/json,AI 会将其视为结构化数据进行逻辑解析;如果是 text/markdown,AI 则会更注重其文档排版结构。在专业开发中,务必准确声明 MIME 类型,以辅助 AI 更好地理解资源含义。


三、 专家级架构思考:如何在大规模 RAG 场景下优化 Resources 性能? 🧠

3.1 语义分块(Semantic Chunking)策略

简单的按字符数截断会导致语义碎片化。

  • 专业建议:在将文档写入 MCP Resources 后端的向量库前,应采用 RecursiveCharacterTextSplitter 或基于标题层级的拆分。确保每一个被读取的 Resource 片段都包含完整的逻辑单位。

3.2 资源感知的“分级加载”

当 AI 发起 search://docs/ 请求时,如果检索出的内容有 50MB,直接返回会导致 Stdio 通道阻塞或模型 Context 溢出。

  • 策略:在 Server 端实现“预览模式”。优先返回每个匹配项的标题和前 200 字,并为每个匹配项提供一个深入的 URI(如 docs://detail/{doc_id})。让 AI 决定是否需要读取某个特定文档的全文。

3.3 缓存与一致性挑战

如果本地文档发生了物理修改,MCP Server 如何同步?

  • 进阶设计:结合我们在 第六篇 讨论过的 Notifications 机制。当本地文件系统监控到文件变动时,Server 应主动发出 notifications/resources/updated。这能确保 AI 始终在基于最新的企业“图书馆”进行推理,避免产生基于旧知识的“幻觉”。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐