持久性记忆服务器

一款为AI代理提供持久化、可搜索记忆的语义检索服务器,支持自优化检索和多代理授权。

  • by enochclaw-creator
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 enochclaw-creator/persistent-mcp-server

使用说明

持久MCP服务器

人工智能代理的语义记忆与自改进检索

A. 模型上下文协议(MCP) 服务器,为AI代理提供跨对话的持久、可搜索的内存。基于Supabase边缘函数和pgvector进行语义搜索。

为什么存在

人工智能助手在对话之间会忘记一切。此服务器修复了此问题。它将想法、决策和观察结果存储为向量嵌入,然后在相关时从语义上检索它们。内置的反馈循环随着时间的推移提高了检索质量。自我评估记分卡对你使用该系统的效率进行评分。

关键能力

  • 语义搜索 --通过pgvector嵌入按意义而不是关键字查找记忆
  • 自动提取元数据 --LLM在每次拍摄时都会提取主题、人物、行动项目和重要性
  • 多代理身份验证 --多个AI客户端使用范围权限(只读、仅捕获、完全访问)连接
  • 自我评估记分卡 --7维评分系统使用字母评分(S到F)
  • Spark智能引擎 --模式分析、差距检测、跨项目连接、研究简报
  • 检索反馈循环 --显式和隐式信号训练系统以获得更好的结果
  • 完整审计跟踪 --每个操作都记录了代理标识和时间戳
  • 电报通知 --Spark报告的可选推送警报

建筑

┌─────────────────────────────────────────────────┐
│  AI Clients (Claude, ChatGPT, custom agents)    │
│  Connect via MCP JSON-RPC over HTTPS            │
└──────────────────────┬──────────────────────────┘
                       │
         ┌─────────────▼─────────────┐
         │   Supabase Edge Function  │
         │   (Deno runtime)          │
         │                           │
         │  ┌─────────────────────┐  │
         │  │  Auth + Audit Layer │  │
         │  │  (SHA-256 key hash) │  │
         │  └────────┬────────────┘  │
         │           │               │
         │  ┌────────▼────────────┐  │
         │  │  9 MCP Tools        │  │
         │  │  capture, search,   │  │
         │  │  browse, stats,     │  │
         │  │  spark, update,     │  │
         │  │  delete, scorecard, │  │
         │  │  feedback           │  │
         │  └────────┬────────────┘  │
         │           │               │
         └───────────┼───────────────┘
                     │
    ┌────────────────┼────────────────┐
    │                │                │
    ▼                ▼                ▼
┌────────┐   ┌────────────┐   ┌───────────┐
│Supabase│   │ OpenRouter  │   │ Telegram  │
│Postgres│   │ (embeddings │   │ (optional │
│+pgvector│  │  + LLM)     │   │  alerts)  │
└────────┘   └────────────┘   └───────────┘

工具参考

工具 说明
capture_thought 存储具有自动嵌入和元数据提取功能的内存
search_thoughts 通过意义在记忆中进行语义搜索
browse_thoughts 使用项目/日期/类型筛选器列出最近的记忆
brain_stats 系统概述——按项目、活动、代理使用情况统计
spark 智能引擎——分析模式、研究简报、仪表板
update_thought 编辑内存(如果内容发生变化,会自动重新嵌入)
delete_thought 带有审计跟踪的软删除(不会永久删除任何内容)
scorecard 7个评分维度和字母等级的自我评估
feedback 对检索质量进行评级,以改善未来的搜索结果

部署指南

先决条件

你需要三件事:

  1. Supabase账户 — 网站 supabase.com (免费版作品)
  2. 一个OpenRouter API密钥 — openrouter.ai (用于嵌入和LLM调用)
  3. 已安装Supabase CLI — 安装指南

可选:

  • 电报机器人 --用于Spark报告的推送通知

第一步:创建一个Supabase项目

  1. 首选 suabase.com/dashboard
  2. 点击 新项目
  3. 选择一个名称并设置数据库密码
  4. 选择您附近的地区
  5. 等待项目完成配置(约2分钟)
  6. 注意你的 项目参考 (在URL中可见: supabase.com/dashboard/project/<YOUR_REF>)

步骤2:设置数据库

  1. 在您的Supabase仪表板中,转到 SQL 编辑器 (左侧边栏)
  2. 点击 新建查询
  3. 粘贴以下内容的全部内容 schema.sql 来自此repo
  4. 点击 跑

这将创建所有必需的表(thoughts, agents, agent_audit_log, thought_feedback, spark_reports, workflow_scores, build_sessions),功能(match_thoughts, increment_retrieval, project_health, mcp_raw_metrics),以及包括用于语义搜索的pgvector IVFFlat索引在内的索引。

注: 该架构启用 vector 和 pgcrypto 自动扩展。如果你在以下方面遇到错误 vector 不存在,请转到 数据库→ 扩展 在您的仪表板中,手动启用它。

步骤3:创建代理API密钥

每个连接的客户端都需要一个API密钥。在SQL编辑器中运行以下命令:

INSERT INTO agents (name, key_hash, scopes, active)
VALUES (
  'my-first-agent',
  encode(digest('replace-with-your-secret-key', 'sha256'), 'hex'),
  '{"master"}',
  true
);

替换 replace-with-your-secret-key 用你想要的任何字符串作为你的密钥。 保存此字符串 --数据库只存储SHA-256哈希,因此您以后无法恢复它。

要创建具有受限访问权限的代理,请执行以下操作:

-- Read-only agent (search and browse only)
INSERT INTO agents (name, key_hash, scopes, active)
VALUES (
  'readonly-agent',
  encode(digest('your-readonly-key', 'sha256'), 'hex'),
  '{"read-only"}',
  true
);

-- Capture-only agent (store memories and give feedback, no delete)
INSERT INTO agents (name, key_hash, scopes, active)
VALUES (
  'capture-agent',
  encode(digest('your-capture-key', 'sha256'), 'hex'),
  '{"capture-only", "feedback"}',
  true
);

步骤4:设置环境变量

在您的Supabase仪表板中:

  1. 首选 边缘函数 (左侧边栏)
  2. 点击 管理秘密 (您可能需要先在步骤5中部署该功能,然后再回来)
  3. 添加:
秘密名称 值
OPENROUTER_API_KEY 您的OpenRouter API密钥

可选(用于电报通知):

秘密名称 值
TELEGRAM_BOT_TOKEN Bot令牌来自 @植物学家
TELEGRAM_CHAT_ID 您的聊天ID(从获取 @用户信息机器人)

SUPABASE_URL 和 SUPABASE_SERVICE_ROLE_KEY 在边缘函数中自动可用——您不需要设置它们。

步骤5:部署

git clone https://github.com/YOUR_USERNAME/persistent-mcp-server.git
cd persistent-mcp-server

# Link to your Supabase project
supabase link --project-ref YOUR_PROJECT_REF

# Deploy
supabase functions deploy persistent-mcp --no-verify-jwt

这 --no-verify-jwt 标志是必需的,因为身份验证是通过API密钥处理的,而不是通过Suabase JWT令牌处理的。

您的服务器现在位于:

https://YOUR_PROJECT_REF.supabase.co/functions/v1/persistent-mcp

步骤6:验证

# Health check
curl https://YOUR_PROJECT_REF.supabase.co/functions/v1/persistent-mcp
# Expected: {"status":"online","version":"1.0.0","protocol":"mcp-jsonrpc"}

# Test a capture
curl -X POST \
  "https://YOUR_PROJECT_REF.supabase.co/functions/v1/persistent-mcp?key=your-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "capture_thought",
      "arguments": { "content": "Test memory — server is working!" }
    }
  }'

# Test a search
curl -X POST \
  "https://YOUR_PROJECT_REF.supabase.co/functions/v1/persistent-mcp?key=your-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "search_thoughts",
      "arguments": { "query": "test memory" }
    }
  }'

步骤7:连接到AI客户端

克劳德桌面

添加 ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)或 %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "memory": {
      "url": "https://YOUR_PROJECT_REF.supabase.co/functions/v1/persistent-mcp?key=your-secret-key"
    }
  }
}

Claude.ai

首选 设置→ 已连接的应用程序 并添加MCP服务器URL。

任何MCP客户端

服务器通过HTTP POST使用标准的MCP JSON-RPC 2.0。任何兼容的客户端都可以使用带有API密钥的URL作为查询参数或通过 x-api-key 头球


定制指南

更改项目

编辑 PROJECTS 数组输入 index.ts:

const PROJECTS: string[] = [
  "default",
  "personal",
  "work",
  "research",
  "infrastructure",
  // Add your own:
  "side-project",
  "health",
  "finances",
];

更改后重新部署:

supabase functions deploy persistent-mcp --no-verify-jwt

交换LLM模型

所有LLM电话都会接通 开放路由。在中更改这些常数 index.ts:

const EMBEDDING_MODEL = "openai/text-embedding-3-small";   // Must output 1536-dim vectors
const EXTRACTION_MODEL = "openai/gpt-4o-mini";             // Cheap + fast for metadata
const ANALYSIS_MODEL = "anthropic/claude-haiku-4-5";        // Smarter = better Spark insights
const NARRATIVE_MODEL = "openai/gpt-4o-mini";               // Scorecard personality

如果更改嵌入模型 将数据库更新为不同维度(例如,768而不是1536):

ALTER TABLE thoughts ALTER COLUMN embedding TYPE VECTOR(768);
-- Also update the match_thoughts function parameter type

代理范围参考

范围 授予的工具
master 所有工具
capture-only capture_thought, feedback
capture capture_thought, feedback
read-only search_thoughts, browse_thoughts, brain_stats, scorecard
read search_thoughts, browse_thoughts, brain_stats
search search_thoughts
browse browse_thoughts
stats brain_stats, scorecard
write update_thought, delete_thought, feedback
update update_thought
delete delete_thought
spark-only spark
spark spark, scorecard
scorecard scorecard
feedback feedback

自由组合范围:

INSERT INTO agents (name, key_hash, scopes, active)
VALUES (
  'custom-agent',
  encode(digest('my-key', 'sha256'), 'hex'),
  '{"capture", "read", "spark"}',
  true
);

调整语义搜索

两个参数控制搜索行为:

  • match_threshold (默认值0.65)--最小余弦相似度。越低捕获越多结果。越高越精确。
  • match_count (默认值10)--返回的最大结果数。

对于大型数据集(10000+个内存),重建IVFFlat索引:

DROP INDEX IF EXISTS idx_thoughts_embedding;
CREATE INDEX idx_thoughts_embedding
  ON thoughts USING ivfflat (embedding vector_cosine_ops)
  WITH (lists = 300);  -- target: sqrt(total_rows)

自定义元数据提取

在中编辑提示 extractMetadata() 功能。提取的JSON存储在 metadata JSONB列,因此您可以添加任何字段而无需更改模式:

// Example: adding an "urgency" field
const prompt = `Extract metadata. Return ONLY valid JSON.
{
  "type": "observation|decision|action_item|idea",
  "topics": ["topic1"],
  "urgency": "low|medium|high|critical",
  "importance": 5,
  "summary": "one-line summary"
}`;

添加自定义工具

在 registerTools 功能:

addTool(
  "my_tool",
  "What this tool does",
  {
    param1: z.string().describe("Description"),
    param2: z.number().optional().describe("Optional param"),
  },
  async ({ param1, param2 }) => {
    // Your logic here
    return {
      content: [{ type: "text", text: `Result: ${param1}` }],
    };
  }
);

然后将其添加到 toolScopeMap 在 agentCanUseTool:

my_tool: ["write", "my-custom-scope"],

禁用Telegram

不要设置 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID 秘密。当Telegram丢失时,该功能会自动跳过。


记分卡尺寸

尺寸 重量 测量内容
捕捉速度 25% 捕捉记忆的频率和一致性
检索精度 20% 搜索是否返回有用结果
项目覆盖率 15% 是否积极跟踪所有项目
行动完成 15% 行动项是否得到解决
Spark敬业度 8% 是否生成情报报告
内存新鲜度 10% 内容是最新的还是过时的
代理多样性 7% 是否有多个客户端为系统供电

分数: S (90+) → A. (75+) → B (60+) → C (45+) → D (30+) → F (<30)


成本估算

服务 免费等级 典型每月费用
Supabase 500MB数据库,500K边缘函数调用 大多数用户0美元
OpenRouter 按次付费 3-8美元(5-10次捕获+10-20次搜索/天)
电报 无限 0美元

替代部署选项

默认部署使用Supabase边缘功能+OpenRouter。但是,您可以根据需要在其他配置中运行此服务器。

选项A:本地开发(您的计算机)

在没有任何云服务的情况下,在本地运行服务器进行测试或个人使用。

您需要什么:

  • 德诺 已安装(curl -fsSL https://deno.land/install.sh | sh)
  • 带pgvector扩展的PostgreSQL
  • OpenRouter API密钥(或参见选项C了解本地嵌入)

步骤1:使用pgvector设置本地Postgres

# macOS (Homebrew)
brew install postgresql@16
brew install pgvector

# Ubuntu/Debian
sudo apt install postgresql postgresql-contrib
# Then install pgvector from source:
git clone https://github.com/pgvector/pgvector.git
cd pgvector && make && sudo make install

启动Postgres并创建数据库:

createdb mcp_memory
psql mcp_memory < schema.sql

步骤2:设置环境变量

export SUPABASE_URL="http://localhost:54321"  # or your local Postgres connection
export SUPABASE_SERVICE_ROLE_KEY="not-needed-locally"
export OPENROUTER_API_KEY="your-openrouter-key"

步骤3:使Supabase客户端适应本地Postgres

服务器使用Supabase JS客户端。对于纯本地设置,您有两个选择:

选项A1——在本地运行Supabase(最简单):

# Install Supabase CLI
npm install -g supabase

# Initialize and start local Supabase (includes Postgres + pgvector + API)
supabase init
supabase start

这为您提供了一个完整的本地Supabase堆栈 http://localhost:54321。服务器代码按原样工作——只需设置 SUPABASE_URL 到本地URL和 SUPABASE_SERVICE_ROLE_KEY 到由打印的密钥 supabase start.

然后直接运行该函数:

supabase functions serve persistent-mcp --no-verify-jwt --env-file .env

选项A2——将Supabase客户端替换为直接Postgres:

将Supabase客户端替换为直接的Postgres驱动程序,如 postgres (Deno兼容)。这需要更多的代码更改,但完全删除了Supabase依赖关系:

// Replace getSupabase() with:
import postgres from "https://deno.land/x/postgresjs/mod.js";

const sql = postgres({
  host: "localhost",
  port: 5432,
  database: "mcp_memory",
  username: "postgres",
  password: "your-password",
});

您还需要重写查询构建器调用(.from().select().eq())到原始SQL。这需要更多的工作,但会给你一个零依赖的本地服务器。

第四步:使用Deno跑步

deno run --allow-net --allow-env index.ts

服务器启动于 http://localhost:8000 (或Deno分配的任何端口)。


选项B:云部署(非Supabase)

您可以部署到任何运行Deno或Node.js的云。

Fly.io(为简单起见建议使用):

# Install flyctl
curl -L https://fly.io/install.sh | sh

# Launch
fly launch --name my-mcp-server
fly secrets set OPENROUTER_API_KEY=your-key
fly secrets set DATABASE_URL=your-postgres-connection-string
fly deploy

你需要一个带有pgvector的托管Postgres。选项:

  • 霓虹 --免费版,包括pgvector(新技术)
  • 铁路 --设置简单,pgvector可用(railway应用程序)
  • 渲染 --免费Postgres层(render.com)
  • Supabase --仅使用数据库,而不是边缘函数

对于Fly.io/Railway/Render,您需要调整服务器以使用 Deno.serve() 直接(已经在代码中)或将其包装在Node.js HTTP服务器中,稍作更改。

AWS EC2/任何虚拟专用服务器:

# SSH into your server
# Install Deno
curl -fsSL https://deno.land/install.sh | sh

# Install Postgres + pgvector
sudo apt install postgresql postgresql-contrib
git clone https://github.com/pgvector/pgvector.git
cd pgvector && make && sudo make install

# Set up the database
sudo -u postgres createdb mcp_memory
sudo -u postgres psql mcp_memory < schema.sql

# Set environment variables
export SUPABASE_URL="postgresql://postgres:password@localhost:5432/mcp_memory"
export OPENROUTER_API_KEY="your-key"

# Run with PM2 for persistence
npm install -g pm2
pm2 start "deno run --allow-net --allow-env index.ts" --name mcp-server
pm2 save

Docker:

FROM denoland/deno:latest
WORKDIR /app
COPY index.ts .
EXPOSE 8000
CMD ["run", "--allow-net", "--allow-env", "index.ts"]
docker build -t persistent-mcp .
docker run -p 8000:8000 \
  -e OPENROUTER_API_KEY=your-key \
  -e SUPABASE_URL=your-db-url \
  -e SUPABASE_SERVICE_ROLE_KEY=your-key \
  persistent-mcp

选项C:替换OpenRouter(本地或替代嵌入)

OpenRouter很方便,但需要花钱并需要互联网接入。以下是替代方案:

与Ollama的本地嵌入:

# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh

# Pull an embedding model
ollama pull nomic-embed-text

然后修改 generateEmbedding() 在 index.ts:

async function generateEmbedding(text: string): Promise<number[]> {
  const res = await fetch("http://localhost:11434/api/embeddings", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: "nomic-embed-text",
      prompt: text,
    }),
  });
  const data = await res.json();
  return data.embedding;
}

重要提示: nomic-embed-text 输出768个维度向量,而不是1536个。更新您的架构:

-- Change vector dimensions
ALTER TABLE thoughts ALTER COLUMN embedding TYPE VECTOR(768);

-- Update the match_thoughts function signature
-- Change VECTOR(1536) to VECTOR(768) in the function parameter

用于元数据提取的本地LLM:

修改 llmCall() 点击您当地的Ollama实例:

async function llmCall(
  prompt: string,
  model = "llama3.2",
  systemPrompt?: string
): Promise<string> {
  const messages = [];
  if (systemPrompt) messages.push({ role: "system", content: systemPrompt });
  messages.push({ role: "user", content: prompt });

  const res = await fetch("http://localhost:11434/api/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ model, messages, stream: false }),
  });
  const data = await res.json();
  return data.message.content;
}

替代托管提供商(而不是OpenRouter):

提供者 嵌入 LLM 注释
OpenAI直接 text-embedding-3-small gpt-4o-mini 需要OpenAI API密钥,将基本URL更改为 api.openai.com
直接人类学 -- claude-haiku-4-5 没有嵌入API-使用OpenAI或本地用于嵌入,使用Anthropic用于LLM
科恩 embed-english-v3.0 command-r 很好的嵌入免费层
Voyage AI voyage-3-lite -- 仅嵌入,高质量
谷歌顶点 text-embedding-004 gemini-2.0-flash 免费套餐可用

对于任何提供者交换,您只需更改 generateEmbedding() 和 llmCall() --服务器的其余部分并不关心向量和文本来自哪里。


选项D:完全离线(零云依赖)

对于没有外部API调用的完全自包含的设置:

  1. Postgres+pgvector --本地安装(见选项A)
  2. 奥拉玛 --本地嵌入+本地LLM(见选项C)
  3. 德诺 --在本地运行服务器

总成本:0美元。需要具有体面RAM的机器(Ollama型号为8GB+)。离线工作,气隙工作,在飞机上工作。

代价是质量——与OpenAI/Anthropic模型相比,本地嵌入模型和小型LLM产生的元数据提取效果较差,语义搜索精度较低。对于个人使用,这通常是可以的。对于有很多用户的生产来说,托管模型是值得的。


故障排除

问题 修复
Embedding failed: 401 OpenRouter API密钥丢失或无效-检查边缘功能机密
Invalid or inactive API key 您的密钥与任何代理都不匹配——请验证SHA-256哈希值
No matches found 更低 threshold 对于更广泛的结果,为0.4
记分卡显示零 先捕获一些记忆并运行搜索——需要数据
慢速首次请求 边缘功能冷启动(1-2s)——设置定时ping以保暖
vector 扩展错误 启用pgvector: CREATE EXTENSION vector; 或从源代码安装
Ollama连接被拒绝 请确保Ollama正在运行: ollama serve
向量维度错误 嵌入模型维度必须匹配 VECTOR(N) 在模式中

许可证

麻省理工学院——见 许可证.