hburgoyne
服务介绍
Picard MCP 服务器
概述
Picard MCP 是一个基于 Model Context Protocol (MCP) 标准构建的完整内存管理系统。它由两个主要组件组成:提供安全内存存储和检索服务的 MCP 服务器,以及展示如何与 MCP 服务器集成的 Django 客户端应用程序。该系统使用户能够存储、检索和管理他们的记忆,同时控制访问权限,并允许基于存储的记忆进行语义搜索和 AI 驱动的查询。
MCP 合规性
此实现遵循 Model Context Protocol 标准,允许 LLM 应用程序以标准化方式与服务器交互。MCP 服务器提供了以下功能:
- 资源:提供给 LLM 的只读端点(记忆内容)
- 工具:执行操作的功能端点(记忆创建、更新、查询)
- 认证:OAuth 2.0 实现,用于安全访问受保护的资源
关键组件
-
MCP 服务器:基于 FastAPI 的 Model Context Protocol 实现,提供:
- 支持 PKCE 的 OAuth 2.0 认证和授权
- 带有向量嵌入的记忆存储
- 基于权限的记忆访问控制
- 用于基于记忆查询的 LLM 集成
-
Django 客户端:演示与 MCP 服务器集成的 Web 应用程序:
- 用户注册和认证
- OAuth 2.0 客户端实现
- 记忆创建、检索和管理的用户界面
- 基于角色的查询界面
系统架构
整体架构
Picard MCP 系统采用客户端-服务器架构,包含以下组件:
-
MCP 服务器:处理记忆存储、检索和 AI 操作的核心后端服务
- 使用 FastAPI(FastMCP)构建,以实现高性能和异步支持
- 使用带有 pgvector 扩展的 PostgreSQL 进行向量存储和语义搜索
- 实现了用户、记忆(带向量嵌入)、OAuth 客户端和令牌的数据模型
- 使用 SQLAlchemy ORM 和 Alembic 迁移进行数据库管理
- 实现了 OAuth 2.0 以确保安全认证和授权
- 与 OpenAI API 集成以生成记忆嵌入(text-embedding-3-small)
- 在可用时使用 LangChain 进行 LLM 操作
- 提供有状态和无状态两种操作模式
- 支持可流式传输的 HTTP 传输以提高可扩展性
-
Django 客户端:演示与 MCP 服务器集成的 Web 应用程序
- 提供用户注册、认证和个人资料管理
- 实现了 OAuth 2.0 客户端,以确保与 MCP 服务器的安全通信
- 提供用户友好的记忆管理和查询界面
- 使用独立于 MCP 服务器的 PostgreSQL 数据库
-
Docker 基础设施:容器化部署,便于设置和扩展
- 分别为 MCP 服务器(端口 8001)、Django 客户端(端口 8000)和 PostgreSQL 数据库配置单独的容器
- 配置网络以确保容器间的安全通信
- 卷挂载以实现持久数据存储
- 兼容本地 Docker 部署和 Render 云部署
认证方法
系统提供了两种主要的认证方法:
1. 直接连接并使用用户上下文令牌流(推荐)
这种简化的方法允许用户仅通过 Django 客户端进行一次认证,避免了需要单独对 MCP 服务器进行认证的需求:
- 客户端注册:
- Django 客户端使用
/api/admin/clients/register端点在 MCP 服务器上注册 - 注册需要管理员认证,并包括客户端名称、重定向 URI 和请求的作用域
- MCP 服务器会颁发基于 UUID 的客户端 ID 和加密安全的客户端密钥
- 客户端凭据应安全存储,且不应在客户端代码中暴露- 用户仅通过Django客户端进行身份验证
- Django 客户端使用
- 当用户发起与MCP服务器的连接时,Django客户端向MCP服务器的
/api/user-tokens/user-token端点发起服务器端请求 - 请求包括:
- 客户端凭证(
client_id和client_secret) - 用户信息(用户名和电子邮件)
- 如果用户不存在则创建用户的选项
- 客户端凭证(
- MCP服务器验证客户端凭证,并查找或创建相应的用户
- MCP服务器为用户颁发访问令牌和刷新令牌
- Django客户端安全地存储这些令牌,并使用它们进行API请求
-
API访问:
- 客户端在所有API请求中将访问令牌包含在Authorization头部 (
Authorization: Bearer {token}) - MCP服务器验证令牌签名、过期时间和受众声明
- MCP服务器对每个端点实施基于范围的权限控制
- 当访问令牌过期时,客户端使用刷新令牌获取新的令牌
- 客户端在所有API请求中将访问令牌包含在Authorization头部 (
-
安全特性:
- 只有机密客户端可以使用此方法,提供服务器到服务器的安全性
- 每次令牌请求都会验证客户端凭证
- 使用后令牌会被列入黑名单以防止重放攻击
- 刷新令牌使用轮换机制:每次使用都会生成一个新的刷新令牌并使旧令牌失效
2. 标准OAuth 2.0授权码流与PKCE(遗留)
系统还支持遵循RFC 6749和RFC 7636标准的标准OAuth 2.0授权码流程与PKCE,以增强安全性。这种方法要求用户同时通过客户端和MCP服务器进行身份验证:
-
授权流程:
- 用户通过Django客户端启动登录
- 客户端生成一个用于CSRF保护的加密安全随机
state参数 - 客户端生成一个随机的PKCE
code_verifier,并通过SHA-256导出code_challenge - 客户端重定向到MCP服务器的
/authorize端点,携带以下参数:response_type=codeclient_id(UUID格式)redirect_uriscope(空格分隔列表,例如memories:read memories:write)state(用于CSRF保护)- PKCE参数 (
code_challenge和code_challenge_method=S256)
- MCP服务器验证用户身份(如果尚未验证)
- MCP服务器验证所有参数并将带有短期授权码的响应重定向回客户端
-
令牌交换:
- 客户端验证返回的
state参数与授权请求中发送的一致 - 客户端通过
/token端点用授权码换取访问令牌和刷新令牌 - MCP服务器颁发JWT访问令牌、刷新令牌、过期时间和授予的范围
- 客户端验证返回的
-
API访问:
- 与直接连接方式相同
数据库模型
MCP服务器使用SQLAlchemy ORM,其关键模型如下:
-
用户模型:
- 存储用户信息,包括电子邮件、用户名和哈希密码
- 包含账户状态标志(如
is_active,is_superuser) - 通过一对多关系关联记忆
-
带向量存储的记忆模型:
- 使用pgvector扩展来存储和查询向量嵌入(1536维)
- 支持文本内容及可选加密
- 包括权限控制(私有/公开)
- 支持时间限制的记忆到期日期
- 通过外键关系与用户关联
-
OAuth模型:
- OAuthClient: 存储客户端应用程序详情,包括
client_id、client_secret、重定向URI和授权范围 - AuthorizationCode: 管理临时授权码,并支持PKCE
- Token: 存储访问令牌和刷新令牌,并跟踪过期时间
- OAuthClient: 存储客户端应用程序详情,包括
系统使用Alembic进行数据库迁移,确保模式版本控制和易于更新。
记忆管理系统
Picard MCP的核心功能围绕记忆管理展开,主要包括以下几个组件:1. 内存存储:
- 记忆以带有相关元数据的文本形式存储
- 通过使用
text-embedding-3-small模型生成的向量嵌入,实现了语义搜索功能 - 权限控制谁可以访问每条记忆
- 时间戳跟踪创建、修改和过期时间
- 记忆文本在静止状态下被加密,而元数据保持可搜索性
- 所有标识符使用UUID格式而非顺序整数,以提高扩展性
- 每条记忆都使用OpenAI的嵌入模型转换为向量嵌入
- 嵌入支持语义搜索和相似度匹配
- PostgreSQL结合pgvector扩展提供了高效的向量存储与检索
-
权限管理:
- 每条记忆都有一个权限级别(私有或公开)
- 私有记忆仅所有者可访问
- 公开记忆可供其他用户用于角色查询
- 系统设计为可扩展,以支持未来的权限类型(例如,统计/聚合用途)
- 共享记忆可由特定用户或组访问
- 记忆所有者可以随时修改权限
-
记忆检索:
- 用户可以通过过滤和排序选项检索自己的记忆
- 语义搜索允许根据意义而不是仅仅关键词来查找记忆
- 向量相似度(余弦)能够在整个数据库中找到相关的记忆
- 根据查询的相关性返回最相似的前N条记忆
- 权限检查确保用户只能访问授权的记忆
-
大语言模型集成:
- 记忆可以用作大语言模型查询的上下文
- 用户可以根据他们的公开记忆创建角色
- 其他用户可以查询这些角色以获得基于记忆的信息响应
- 系统自动处理上下文管理和提示工程
主要特性
MCP服务器特性
-
OAuth 2.0认证:
- 使用PKCE增强安全性的授权码流程
- 基于范围的权限系统 (
memories:read,memories:write,memories:admin) - 支持刷新令牌的令牌管理
- 客户端注册与管理
-
记忆管理:
- 创建、读取、更新和删除记忆
- 用于语义搜索的向量嵌入
- 基于权限的访问控制
- 批量操作以实现高效的记忆管理
-
用户管理:
- 用户注册与认证
- 个人资料管理和设置
- 活动跟踪与分析
- 系统管理的管理员控制
-
AI集成:
- OpenAI API集成用于嵌入和大语言模型查询
- 基于用户记忆的角色创建
- 上下文感知的查询处理
- 可定制的AI参数和设置
Django客户端特性
-
用户界面:
- 清晰、响应式的桌面和移动设计
- 直观的记忆管理界面
- 高级搜索和过滤选项
- 角色创建和查询界面
-
OAuth客户端实现:
- 安全的令牌存储与管理
- 自动令牌刷新
- 基于范围的功能可用性
- 错误处理与恢复
-
记忆工具:
- 支持富文本的记忆创建
- 批量导入导出
- 权限管理界面
- 标签和分类
MCP接口
MCP资源
-
记忆资源:
memories://{memory_id}- 返回特定记忆的内容,并进行权限检查
- 参数: memory_id (UUID)
- 响应: 包含元数据的记忆内容
-
用户记忆资源:
users://{user_id}/memories- 返回特定用户的记忆列表,并进行权限检查
- 参数: user_id (UUID), 可选过滤器
- 响应: 记忆摘要列表
MCP工具
-
提交记忆工具: 创建新的记忆
- 参数: text (字符串), permission (字符串)
- 返回: 创建的记忆详情及UUID
-
更新记忆工具: 更新现有记忆- 参数: memory_id (UUID), text (字符串)
- 返回: 更新后的记忆详情
-
删除记忆工具: 删除一条记忆
- 参数: memory_id (UUID)
- 返回: 成功确认信息
-
查询记忆工具: 对记忆进行语义搜索
- 参数: query (字符串), limit (整数)
- 返回: 相关记忆列表
-
查询用户: 根据记忆查询用户的个性
- 参数: user_id (UUID), query (字符串)
- 返回: 基于用户记忆的响应
API 端点
OAuth 端点
-
客户端注册:
/register- 方法: POST
- 描述: 注册一个新的 OAuth 客户端
- 请求: 客户端详细信息(ID、密钥、重定向 URI、作用域)
- 响应: 客户端凭证和注册信息
-
授权:
/authorize- 方法: GET
- 描述: 初始化 OAuth 授权流程
- 参数: response_type, client_id, redirect_uri, scope, state, code_challenge, code_challenge_method
- 响应: 重定向到带有授权码的客户端
-
令牌交换:
/token- 方法: POST
- 描述: 用授权码换取令牌
- 请求: grant_type, code, redirect_uri, client_id, client_secret, code_verifier
- 响应: 访问令牌、刷新令牌、过期时间和作用域信息
记忆端点
-
获取记忆:
/api/tools(工具:get_memories)- 方法: POST
- 描述: 检索记忆,可选过滤
- 身份验证: Bearer 令牌
- 请求: 可选过滤参数 (user_id, permission, expiration status)
- 响应: 用户可访问的记忆列表
- 示例请求:
json
{
"tool": "get_memories",
"data": {
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"permission": "private"
}
}
-
提交记忆:
/api/tools(工具:submit_memory)- 方法: POST
- 描述: 创建新的记忆
- 身份验证: Bearer 令牌
- 请求: 记忆文本、权限级别和过期日期 (ISO 8601 格式,例如 "2025-12-31T23:59:59Z")
- 响应: 包括 UUID 标识符在内的创建的记忆详情
- 示例请求:
json
{
"tool": "submit_memory",
"data": {
"text": "这是我的记忆内容",
"permission": "private"
}
}
-
检索记忆:
/api/tools(工具:retrieve_memories)- 方法: POST
- 描述: 获取已认证用户的所有记忆
- 身份验证: Bearer 令牌
- 响应: 包含 UUID 标识符的记忆对象列表
- 示例请求:
json
{
"tool": "retrieve_memories",
"data": {}
}
-
更新记忆:
/api/tools(工具:update_memory)- 方法: POST
- 描述: 更新现有记忆
- 身份验证: Bearer 令牌
- 请求: 记忆 ID、更新的内容以及可选的更新过期日期 (ISO 8601 格式)
- 响应: 更新后的记忆详情
- 示例请求:
json
{
"tool": "update_memory",
"data": {
"memory_id": "550e8400-e29b-41d4-a716-446655440000",
"text": "更新后的记忆内容",
"expiration_date": "2026-01-01T00:00:00Z"
}
}
-
修改权限:
/api/tools(工具:modify_permissions)- 方法: POST
- 描述: 更新记忆的权限级别
- 身份验证: Bearer 令牌
- 请求: 记忆 UUID 和新的权限级别
- 响应: 更新后的记忆详情
- 示例请求:
json
{
"tool": "modify_permissions",
"data": {
"memory_id": "550e8400-e29b-41d4-a716-446655440000",
"permission": "public"
}
}
-
查询用户:
/api/tools(工具:query_user)- 方法: POST
- 描述: 根据记忆查询用户的个性(对其他用户公开,对自己公开+私有)
- 身份验证: Bearer 令牌
- 请求: 用户 UUID 和查询提示- 响应:包含未过期记忆的 JSON,可以是所有有效记忆或与查询最相似的前 N 条
- 响应:基于用户记忆生成的 AI 响应
- 示例请求:
json
{
"tool": "query_user",
"data": {
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"prompt": "你对人工智能有什么看法?"
}
}
设置和部署
先决条件
- Docker 和 Docker Compose
- Python 3.10+
- OpenAI API 密钥
完整设置指南
-
克隆仓库:
bash
git clone https://github.com/yourusername/picard_mcp.git
cd picard_mcp -
为两个组件创建环境文件:
bash对于 MCP 服务器
cp mcp_server/.env.example mcp_server/.env
对于 Django 客户端
cp django_client/.env.example django_client/.env
-
编辑环境文件以设置您的配置:
- 在
mcp_server/.env中:设置数据库凭据、OpenAI API 密钥和管理员凭据 - 在
django_client/.env中:设置数据库凭据和 OAuth 设置
- 在
-
使用 Docker Compose 启动服务:
bash
docker-compose up -d这将启动以下服务:
db-mcp:MCP 服务器的 PostgreSQL 数据库db-django:Django 客户端的 PostgreSQL 数据库mcp_server:运行在 http://localhost:8001 的 MCP 服务器django_client:运行在 http://localhost:8000 的 Django 客户端
-
为 MCP 服务器创建一个管理员用户:
bash
docker-compose exec mcp_server python scripts/create_admin_user.py这将使用您在环境变量中指定的凭据创建一个管理员用户。
-
将 Django 客户端注册到 MCP 服务器:
bash
docker-compose exec django_client python register_oauth_client.py这将把 Django 客户端注册到 MCP 服务器,并更新 Django 客户端的
.env文件中的客户端凭据。 -
访问应用程序:
- MCP 服务器:http://localhost:8001
- Django 客户端:http://localhost:8000
-
在 Django 客户端中创建一个用户帐户并开始使用应用程序。
初始测试
为了验证您的设置是否正确,请运行以下测试:
-
MCP 服务器测试:
bash
docker-compose exec mcp_server python -m pytest这将运行 MCP 服务器的所有单元测试,包括 OAuth 端点、管理员功能和记忆管理。
-
Django 客户端测试:
bash
docker-compose exec django_client python manage.py test这将测试 Django 客户端与 MCP 服务器的集成。
-
手动测试:
- 在 http://localhost:8000/register 处的 Django 客户端中创建一个用户帐户
- 登录并通过 OAuth 连接到 MCP 服务器
- 创建、检索和管理记忆
- 测试语义搜索功能
安全注意事项
数据保护
- 记忆文本内容在存储时使用 Python 的 Fernet 对称加密(AES-128 CBC 模式,PKCS7 填充)进行加密,而元数据保持可搜索性
- 个人身份信息 (PII) 通过文本字段加密得到保护
- 访问令牌的有效期为 1 小时,以限制暴露时间
- 刷新令牌是长期有效的,但使用轮换机制:每次使用都会生成一个新的刷新令牌并使旧令牌失效
- OAuth 令牌安全地存储在 Django 客户端的 PostgreSQL 数据库中
UUID 使用
系统中的所有标识符都使用 UUID v4 格式而不是顺序整数,原因如下:
- 安全性:UUID 不会泄露系统信息或记录数量
- 可扩展性:UUID 可以在没有数据库协调的情况下生成,支持分布式系统
- 不可猜测性:UUID 实际上是不可能被猜测的,防止枚举攻击
- 一致性:在整个系统中使用 UUID 简化了与其他服务的集成所有API中的ID(如user_id、memory_id、client_id等)必须采用UUID格式。
OAuth最佳实践
- 所有OAuth通信在生产环境中必须使用HTTPS
- 授权码是一次性的且有效期短(最长5分钟)
- 即使是保密客户端,也要求使用PKCE以实现深度防御
- 刷新令牌有效期长,但可以由用户或管理员撤销
- 系统维护一个已撤销令牌的黑名单
文档
API文档
MCP服务器为所有端点提供了Swagger/OpenAPI文档:
- 当服务器运行时,可以通过
/docs访问Swagger UI - OpenAPI规范文件位于
/openapi.json - 所有API端点都完全记录了请求/响应模式及示例
其他文档文件
-
TESTING.md:应用程序测试的全面指南
- 描述了所有已实现的测试及其目的
- 提供本地和CI/CD中运行测试的说明
- 记录测试覆盖率并指出需要额外测试的区域
-
DEBUGGING.md:跟踪问题及其解决方案
- 记录尚未修复的已知错误
- 文档化之前解决过的错误及其解决方案
- 提供常见问题的故障排除指导
-
PLANNING.md:跟踪实施站点所需任务的分解
- 列出实施站点所需的主任务和子任务
- 通过复选框标记任务是否已完成
部署
该项目包含用于本地开发的docker-compose.yml以及用于部署到Render的render.yaml蓝图。同一代码库既可以在Docker容器中本地运行,也可以部署到Render云服务上。
MCP服务器部署
-
Docker部署(推荐用于生产环境):
bash
docker-compose up -dDocker Compose配置包括:
- 容器间通信的网络配置
- 持久数据存储的卷挂载
- 来自.env文件的环境变量配置
- 端口映射(Django客户端8000端口,MCP服务器8001端口)
- 服务依赖项的健康检查
-
Render云部署:
使用随附的render.yaml蓝图部署到Render。
许可证
MIT