记忆管理系统

Picard MCP是一个基于Model Context Protocol标准的完整记忆管理系统,提供安全的记忆存储、检索和管理服务,支持语义搜索和AI驱动的查询。

  • by hburgoyne
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 hburgoyne/picard_mcp

使用说明

Picard MCP服务器

概述

Picard MCP是一个完整的内存管理系统,建立在 模型上下文协议(MCP) 标准。它由两个主要组件组成:一个提供安全内存存储和检索服务的MCP服务器,以及一个演示如何与MCP服务器集成的Django客户端应用程序。该系统使用户能够存储、检索和管理他们的记忆,同时控制访问权限,并允许基于存储的记忆进行语义搜索和人工智能查询。

MCP合规性

此实现遵循模型上下文协议标准,该标准允许LLM应用程序以标准化的方式与服务器交互。MCP服务器公开:

  • 资源:向LLM提供数据(内存内容)的只读端点
  • 工具:执行操作(内存创建、更新、查询)的功能端点
  • 认证:OAuth 2.0实现,用于安全访问受保护的资源

关键组件

  1. MCP服务器:基于FastAPI的模型上下文协议实现,提供:

    • ✅ OAuth 2.0身份验证和授权,支持PKCE
    • ✅ 带有PostgreSQL和pgvector扩展的内存存储
    • ✅ 基于权限的内存访问控制(私有/公共)
    • ✅ 基于OpenAI文本嵌入3-small模型的语义搜索向量嵌入
    • 🔄 LLM集成用于基于内存的查询(框架就绪,计划提供高级功能)
  2. Django客户端:演示与MCP服务器集成的web应用程序:

    • 用户注册和身份验证
    • OAuth 2.0客户端实现
    • 内存创建、检索和管理UI
    • 基于Persona的查询界面

系统架构

总体架构

Picard MCP系统遵循客户端-服务器架构,包含以下组件:

  1. MCP服务器:处理内存存储、检索和AI操作的核心后端服务

    • 内置FastAPI(FastMCP),提供高性能和异步支持
    • 使用PostgreSQL和pgvector扩展进行向量存储和语义搜索
    • 为用户、内存(带向量嵌入)、OAuth客户端和令牌实现数据模型
    • 使用SQLAlchemy ORM和Alembic迁移进行数据库管理
    • 实施OAuth 2.0以实现安全身份验证和授权
    • 与OpenAI API集成,用于内存嵌入(text-embedding-3-small)
    • 在可用时使用LangChain进行LLM操作
    • 提供有状态和无状态操作模式
    • 支持流式HTTP传输,以实现更好的可扩展性
  2. Django客户端:演示与MCP服务器集成的Web应用程序

    • 提供用户注册、身份验证和配置文件管理
    • 实现OAuth 2.0客户端,用于与MCP服务器进行安全通信
    • 提供用户友好的内存管理和查询界面
    • 使用独立于MCP服务器的PostgreSQL数据库
  3. Docker基础架构:容器化部署,便于设置和扩展

    • MCP服务器(端口8001)、Django客户端(端口8000)和PostgreSQL数据库的单独容器
    • 已配置用于安全容器间通信的网络
    • 用于持久数据存储的卷装载
    • 兼容本地Docker部署和Render云部署

身份验证方法

该系统提供两种主要的身份验证方法:

1.与用户上下文令牌流直接连接(推荐)

这种简化的方法允许用户只在Django客户端进行一次身份验证,从而避免了单独的MCP服务器身份验证的需要:

  1. 客户注册:

    • Django客户端使用以下命令向MCP服务器注册 /api/admin/clients/register 端点
    • 注册需要管理员身份验证,包括客户端名称、重定向URI和请求的作用域
    • MCP服务器发布基于UUID的客户端ID和加密安全的客户端密钥
    • 客户端凭据应安全存储,不得在客户端代码中公开
  2. 用户身份验证流程:

    • 用户仅通过Django客户端进行身份验证
    • 当用户发起与MCP服务器的连接时,Django客户端向MCP的服务器端发出服务器端请求 /api/user-tokens/user-token 端点
    • 该请求包括:
      • 客户端凭据(Client_id和Client_secret)
      • 用户信息(用户名和电子邮件)
      • 如果不存在创建用户的选项
    • MCP服务器验证客户端凭据,并找到或创建相应的用户
    • MCP服务器为用户发放访问和刷新令牌
    • Django客户端安全地存储这些令牌,并将其用于API请求
  3. API访问:

    • 客户端在Authorization标头中包含访问令牌(Authorization: Bearer {token})用于所有API请求
    • MCP服务器验证令牌签名、过期和受众声明
    • MCP服务器对每个端点强制执行基于范围的权限
    • 当访问令牌过期时,客户端使用刷新令牌获取新令牌
  4. 安全特性:

    • 只有机密客户端可以使用此方法,提供服务器到服务器的安全性
    • 为每个令牌请求验证客户端凭据
    • 令牌在使用后被列入黑名单,以防止重放攻击
    • 刷新令牌使用轮换:每次使用都会生成一个新的刷新令牌,并使旧令牌无效

2.使用PKCE的标准OAuth 2.0授权代码流(传统)

该系统还支持符合RFC 6749和RFC 7636标准的标准OAuth 2.0授权码流和PKCE,以增强安全性。这种方法要求用户同时向客户端和MCP服务器进行身份验证:

  1. 授权流程:

    • 用户通过Django客户端发起登录
    • 客户端生成加密安全的随机 state CSRF保护参数
    • 客户端生成随机的PKCE code_verifier 并推导 code_challenge 使用SHA-256
    • 客户端重定向到MCP服务器 /authorize 端点具有:
      • response_type=code
      • client_id (UUID格式)
      • redirect_uri
      • scope (空格分隔的列表。, memories:read memories:write)
      • state (用于CSRF保护)
      • PKCE参数(code_challenge 和 code_challenge_method=S256)
    • MCP服务器对用户进行身份验证(如果尚未进行身份验证)
    • MCP服务器验证所有参数,并使用短期授权码重定向回客户端
  2. 代币交换:

    • 客户端验证返回的 state 参数与授权请求中发送的参数匹配
    • 客户端通过以下方式交换访问和刷新令牌的授权码 /token 端点
    • MCP服务器发出JWT访问令牌、刷新令牌、过期时间和授予的范围
  3. API访问:

    • 与直接连接方法相同

数据库模型

MCP服务器使用SQLAlchemy ORM和以下关键模型:

  1. 用户模型:

    • 使用电子邮件、用户名和哈希密码存储用户信息
    • 包括帐户状态的布尔标志(is_active、is_superuser)
    • 通过一对多关系与记忆相连
  2. 具有向量存储的内存模型:

    • 使用pgvector扩展来存储和查询向量嵌入(1536维)
    • 支持具有可选加密的文本内容
    • 包括权限控制(私有/公共)
    • 支持限时记忆的过期日期
    • 通过外键关系与用户关联
  3. OAuth模型:

    • OAuthClient:存储客户端应用程序详细信息,包括client_id、client_secret、重定向URI和授权范围
    • 授权码:使用PKCE支持管理临时授权码
    • 代币:存储具有过期跟踪功能的访问和刷新令牌

该系统使用Alembic进行数据库迁移,确保模式版本控制和易于更新。

内存管理系统

Picard MCP的核心功能围绕以下组件的内存管理展开:

  1. 记忆存储:

    • 内存存储为带有相关元数据的文本
    • 向量嵌入(使用文本嵌入3-small模型)实现了语义搜索功能
    • 权限控制谁可以访问每个内存
    • 时间戳跟踪创建、修改和过期
    • 内存文本在静止时被加密,而元数据仍然可以搜索
    • 所有标识符都使用UUID格式,而不是顺序整数,以实现可扩展性
    • 使用OpenAI的嵌入模型将每个内存转换为向量嵌入
    • 嵌入支持语义搜索和相似性匹配
    • 带有pgvector扩展的PostgreSQL提供了高效的向量存储和检索
  2. 权限管理:

    • 每个内存都有一个权限级别(私有或公共)
    • 私人记忆仅供所有者访问
    • 其他用户可以访问公共记忆进行人物角色查询
    • 系统设计为可扩展以适应未来的权限类型(例如,用于统计/聚合用途)
    • 特定用户或组可以访问共享内存
    • 内存所有者可以随时修改权限
  3. 记忆提取:

    • ✅ 用户可以通过过滤和排序选项检索自己的记忆
    • ✅ 基于语义的向量嵌入记忆语义搜索
    • ✅ 使用pgvector查找相关记忆的向量相似度(余弦)
    • ✅ 基于查询相关性和可配置相似度阈值的Top-N最相似记忆
    • ✅ 权限检查确保用户只能访问授权的内存
  4. LLM集成:

    • 内存可以用作LLM查询的上下文
    • 用户可以根据他们的公共记忆创建角色
    • 其他用户可以查询这些人物角色,以获得记忆中的响应
    • 系统自动处理上下文管理和提示工程

主要特点

MCP服务器功能

  • OAuth 2.0身份验证:

    • 使用PKCE的授权码流可增强安全性
    • 基于范围的权限系统(memories:read, memories:write, memories:admin)
    • 支持刷新令牌的令牌管理
    • 客户注册和管理
  • 内存管理:

    • 创建、读取、更新和删除记忆
    • 语义搜索的向量嵌入
    • 基于权限的访问控制
    • 批处理操作以实现高效的内存管理
  • 用户管理:

    • 用户注册和身份验证
    • 配置文件管理和设置
    • 活动跟踪和分析
    • 系统管理的管理员控制
  • ✅ 人工智能集成:

    • ✅ OpenAI API集成(v1.x),用于使用text-embedding-3-small模型的嵌入
    • ✅ 所有存储器的自动矢量嵌入生成(1536维)
    • ✅ 基于pgvector余弦相似度的语义搜索
    • ✅ 具有严格错误处理的异步嵌入生成
    • 📋 基于用户记忆的人物角色创建框架(计划中)
    • 📋 上下文感知查询处理架构(计划中)

Django客户端功能

  • 用户界面:

    • 桌面和移动设备的简洁、响应式设计
    • 直观的内存管理界面
    • 高级搜索和筛选选项
    • 人物角色创建和查询界面
  • OAuth客户端实现:

    • 安全的令牌存储和管理
    • 自动令牌刷新
    • 基于范围的功能可用性
    • 错误处理和恢复
  • 内存工具:

    • 支持富文本的内存创建
    • 批量导入和导出
    • 权限管理界面
    • 标记和分类

MCP接口

MCP资源

  • 存储器资源: memories://{memory_id}

    • 通过权限检查返回特定内存的内容
    • 参数:memory_id(UUID)
    • 响应:包含元数据的内存内容
  • 用户记忆资源: users://{user_id}/memories

    • 通过权限检查返回特定用户的内存列表
    • 参数:user_id(UUID),可选筛选器
    • 回复:记忆摘要列表

MCP工具

  • 提交内存工具:创建新内存

    • 参数:文本(字符串)、权限(字符串)
    • 返回:使用UUID创建内存详细信息
  • 更新内存工具:更新现有内存

    • 参数:memory_id(UUID),文本(字符串)
    • 返回:更新内存详细信息
  • 删除内存工具:删除内存

    • 参数:memory_id(UUID)
    • 返回:成功确认
  • 查询内存工具:对记忆执行语义搜索

    • 参数:查询(字符串)、限制(整数)、相似性阈值(浮点数)、权限过滤器(字符串)
    • 返回:按相似性得分排序的相关记忆列表
    • 用途:OpenAI嵌入和pgvector余弦相似度
  • 查询用户:根据记忆查询用户的角色

    • 参数:user_id(UUID),查询(字符串)
    • 返回:基于用户记忆的响应

API终点

OAuth端点

  • 客户注册: /register

    • 方法:POST
    • 说明:注册新的OAuth客户端
    • 请求:客户端详细信息(ID、机密、重定向URI、作用域)
    • 响应:客户端凭据和注册信息
  • 授权: /authorize

    • 方法:GET
    • 说明:启动OAuth授权流
    • 参数:response_type、client_id、redirect_uri、作用域、状态、code_challenge、code_chalenge_method
    • 响应:重定向到具有授权码的客户端
  • 代币交换: /token

    • 方法:POST
    • 说明:代币的交换授权码
    • 请求:grant_type、code、redirect_uri、client_id、client_secret、code_verifier
    • 响应:访问令牌、刷新令牌、过期和范围信息

内存端点

  • 获取记忆: /api/tools (工具: get_memories)

    • 方法:POST
    • 描述:使用可选过滤检索记忆
    • 身份验证:承载令牌
    • 请求:可选过滤器参数(user_id、权限、过期状态)
    • 响应:用户可访问的内存列表
    • 请求示例:
      {
        "tool": "get_memories",
        "data": {
          "user_id": "550e8400-e29b-41d4-a716-446655440000",
          "permission": "private"
        }
      }
      
  • 提交内存: /api/tools (工具: submit_memory)

    • 方法:POST
    • 说明:创建新内存
    • 身份验证:承载令牌
    • 请求:内存文本、权限级别和到期日期(ISO 8601格式,例如“2025-12-31T23:59:59Z”)
    • 响应:创建了包括UUID标识符在内的内存详细信息
    • 请求示例:
      {
        "tool": "submit_memory",
        "data": {
          "text": "This is my memory content",
          "permission": "private"
        }
      }
      
  • 找回记忆: /api/tools (工具: retrieve_memories)

    • 方法:POST
    • 描述:获取经过身份验证的用户的所有内存
    • 身份验证:承载令牌
    • 响应:具有UUID标识符的内存对象列表
    • 请求示例:
      {
        "tool": "retrieve_memories",
        "data": {}
      }
      
  • 更新存储器: /api/tools (工具: update_memory)

    • 方法:POST
    • 说明:更新现有内存
    • 身份验证:承载令牌
    • 请求:内存ID、更新的内容和可选更新的到期日期(ISO 8601格式)
    • 响应:更新了内存详细信息
    • 请求示例:
      {
        "tool": "update_memory",
        "data": {
          "memory_id": "550e8400-e29b-41d4-a716-446655440000",
          "text": "Updated memory content",
          "expiration_date": "2026-01-01T00:00:00Z"
        }
      }
      
  • 修改权限: /api/tools (工具: modify_permissions)

    • 方法:POST
    • 说明:更新内存权限级别
    • 身份验证:承载令牌
    • 请求:内存UUID和新的权限级别
    • 响应:更新了内存详细信息
    • 请求示例:
      {
        "tool": "modify_permissions",
        "data": {
          "memory_id": "550e8400-e29b-41d4-a716-446655440000",
          "permission": "public"
        }
      }
      
  • 查询内存: /api/tools (工具: query_memory)

    • 方法:POST
    • 描述:使用向量嵌入对用户的记忆进行语义搜索
    • 身份验证:承载令牌
    • 请求:在数据字段中搜索查询和可选参数
    • 响应:按相似性评分排序的记忆列表
    • 请求示例:
      {
        "tool": "query_memory",
        "data": {
          "query": "artificial intelligence thoughts",
          "limit": 10,
          "similarity_threshold": 0.5,
          "permission_filter": "private"
        }
      }
      
    • 示例响应:
      {
        "data": {
          "memories": [
            {
              "id": "550e8400-e29b-41d4-a716-446655440000",
              "text": "I think AI will revolutionize how we work...",
              "permission": "private",
              "similarity": 0.85,
              "created_at": "2024-01-15T10:30:00Z",
              "updated_at": "2024-01-15T10:30:00Z"
            }
          ]
        }
      }
      
  • 查询用户: /api/tools (工具: query_user)

    • 方法:POST
    • 描述:根据记忆查询用户的角色(对其他用户公开,对自己公开+私有)
    • 身份验证:承载令牌
    • 请求:用户UUID和查询提示
    • 响应:JSON包含未过期的内存,无论是所有有效内存还是与查询最相似的前N个内存
    • 响应:基于用户记忆的AI生成响应
    • 请求示例:
      {
        "tool": "query_user",
        "data": {
          "user_id": "550e8400-e29b-41d4-a716-446655440000",
          "prompt": "What are your thoughts on artificial intelligence?"
        }
      }
      

设置和部署

先决条件

  • Docker和Docker Compose
  • Python 3.10+
  • OpenAI API密钥

完整安装指南

  1. 克隆存储库:

    git clone https://github.com/yourusername/picard_mcp.git
    cd picard_mcp
    
  2. 为两个组件创建环境文件:

    # For MCP server
    cp mcp_server/.env.example mcp_server/.env
    
    # For Django client
    cp django_client/.env.example django_client/.env
    
  3. 编辑环境文件以设置配置:

    • 在 mcp_server/.env:设置数据库凭据、OpenAI API密钥和管理员凭据
    • 在 django_client/.env:设置数据库凭据和OAuth设置
  4. 使用Docker Compose启动服务:

    docker-compose up -d
    

    这将启动以下服务:

    • db-mcp:MCP服务器的PostgreSQL数据库
    • db-django:Django客户端的PostgreSQL数据库
    • mcp_server:MCP服务器正在运行http://localhost:8001
    • django_client:正在运行的Django客户端http://localhost:8000
  5. 为MCP服务器创建管理员用户:

    docker-compose exec mcp_server python scripts/create_admin_user.py
    

    这将使用环境变量中指定的凭据创建管理员用户。

  6. 在MCP服务器上注册Django客户端:

    docker-compose exec django_client python register_oauth_client.py
    

    这将在MCP服务器上注册Django客户端,并更新Django客户端的 .env 包含客户端凭据的文件。

  7. 访问应用程序:

    • MCP服务器:http://localhost:8001
    • Django客户端:http://localhost:8000
  8. 在Django客户端创建一个用户帐户并开始使用该应用程序。

初始测试

要验证您的设置是否正常工作,请运行以下测试:

  1. MCP服务器测试:

    docker-compose exec mcp_server python -m pytest
    

    这将运行MCP服务器的所有单元测试,包括OAuth端点、管理功能和内存管理。

  2. Django客户端测试:

    docker-compose exec django_client python manage.py test
    

    这将测试Django客户端与MCP服务器的集成。

  3. 手动测试:

    • 在Django客户端中创建一个用户帐户http://localhost:8000/register
    • 登录并通过OAuth连接到MCP服务器
    • 创建、检索和管理记忆
    • 测试语义搜索功能

安全考虑

数据保护

  • 内存文本内容在静止时使用Python的Fernet对称加密(CBC模式下的AES-128,带有PKCS7填充)进行加密,而元数据仍然可以搜索
  • 个人身份信息(PII)通过文本字段加密进行保护
  • 访问令牌的过期时间为1小时,以限制暴露
  • 刷新令牌寿命长,但使用轮换:每次使用都会生成一个新的刷新令牌,并使旧令牌无效
  • OAuth令牌安全地存储在Django客户端的PostgreSQL数据库中

UUID使用情况

系统中的所有标识符都使用UUID v4格式,而不是顺序整数,原因有几个:

  1. 安全:UUID不公开系统信息或记录计数
  2. 可扩展性:UUID可以在没有数据库协调的情况下生成,从而支持分布式系统
  3. 不可猜测:UUID几乎无法猜测,从而防止枚举攻击
  4. 一致性:在整个系统中使用UUID简化了与其他服务的集成

API中的所有id(user_id、memory_id、client_id等)都必须是UUID格式。

OAuth最佳实践

  • 所有OAuth通信必须在生产环境中使用HTTPS
  • 授权码是一次性使用的,期限短(最多5分钟)
  • 所有客户端,甚至是机密客户端,都需要PKCE进行深度防御
  • 刷新令牌是长期有效的,但可以由用户或管理员撤销
  • 系统为已撤销的令牌维护一个令牌黑名单

文档

API文档

MCP服务器包括所有端点的Swagger/OpenAPI文档:

  • 访问Swagger用户界面 /docs 服务器运行时
  • OpenAPI规范可在 /openapi.json
  • 所有API端点都有完整的请求/响应模式和示例文档

附加文档文件

  • 测试.md:测试应用程序的综合指南

    • 描述所有已实施的测试及其目的
    • 本地和CI/CD中运行测试的说明
    • 记录测试范围并确定需要额外测试的区域
  • DEBUGGING.md:跟踪问题及其解决方案

    • 记录尚未修复的已知错误
    • 以前解决的错误及其解决方案的文档
    • 为常见问题提供故障排除指导
  • 规划.md:跟踪实施网站所需任务的细分

    • 列出实施站点所需的任务和子任务
    • 使用复选框记录任务是否已完成

部署

该项目包括 docker-compose.yml 促进地方发展和 render.yaml 部署到Render的蓝图。相同的代码库既可以在Docker容器中本地运行,也可以在部署到Render云服务时运行。

MCP服务器部署

  1. Docker部署 (推荐用于生产):

    docker-compose up -d
    

    Docker Compose配置包括:

    • 集装箱间通信的网络配置
    • 用于持久数据存储的卷装载
    • 从.env文件配置环境变量
    • 端口映射(Django客户端8000,MCP服务器8001)
    • 服务依赖关系的健康检查
  2. 渲染云部署: 使用随附的 render.yaml 要部署到Render的蓝图。

许可证

麻省理工学院