mcpField
P
plexus

plexus

远程服务
github.com/pcas-io记忆与知识126 周前更新
代码仓库

关于 plexus

plexus 是面向 AI Agent 的可自托管知识图谱,将信息保存为带类型的实体和有时效的关系。人类可通过仪表板查看,Agent 则通过 MCP 创建、更新和关联内容,适用于跨会话或团队共享记忆。

主要功能

  1. 01带类型的实体与关系
  2. 02基于 MCP 写入图谱
  3. 03全文搜索与关系遍历
  4. 04时效关系与历史查询
  5. 05用户、令牌和权限范围管理
  6. 06图谱检查与技能加载

适用场景

  1. 01保存跨会话的 Agent 记忆
  2. 02在不同 Agent 间交接工作
  3. 03追溯决策及其来源
  4. 04将研究资料整理为关联知识

MCP 相关

plexus 通过 MCP 暴露 15 个工具,供 Agent 搜索、读取、创建、更新实体并管理关系;访问范围由令牌权限控制。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://{plexus_host}/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

plexus (_graph)

面向 AI Agent 的类型化本地知识图谱。人类只读,Agent 只写,通过 Model Context Protocol 进行交互。

属于 pcas.io 产品系列。

许可证 Node CI

plexus 图谱视图 — 阿波罗计划演示图谱


TL;DR

二十年来,知识管理一直是一场围绕文档展开的运动——文件夹、笔记、Wiki、编辑器之争。plexus 颠覆了这一模式。

在 plexus 中,每条信息都是一个类型化实体——concept、decision、fact、project、task、document、skill,……——实体之间通过严格且有时间效力的边连接。没有自由格式文本,没有被遗忘的标签,也没有“我以后再整理”。写入和链接只能通过 MCP,由你的 Agent 完成。仪表板展示图谱;没有编辑按钮。

这样你就能获得三项优势:

  1. 你的 Agent 不必询问你——它可以直接构建,并严格遵守类型和关系规范。
  2. 图谱永不过时,因为 lint、取代和来源记录都属于工作流的一部分。
  3. 你可以分享单个想法,而不是整个图谱——通过通行密钥保护的一次性链接,首次点击后即失效。

可在你自己的硬件上通过 Docker Compose 运行。采用 Apache-2.0 许可证。

可以把它看作面向大模型的 Wiki

传统 Wiki 是为人类读者构建的:自由格式的文字、手工整理的链接,以及一棵只要停止维护就会腐朽的页面树。在 Wiki 前面放一个大模型,它做的第一件事就是让你总结内容。

plexus 颠倒了受众。大模型既是读者,也是写作者。每个页面都是一条类型化记录,而不是一段文字;每条链接都是一种具名关系,而不是超链接;每次编辑都是一次原子化的 MCP 调用,而不是 Markdown 差异。界面向你展示 Agent 所见的同一张图谱——但由你的 Agent 负责整理。

这与 Andrej Karpathy 在其 "The LLM wiki" gist(2026 年 4 月,5000+ 星标)中勾勒的模式相同:大模型不必每次查询都针对原始文档进行无状态 RAG,而是一次性将知识编译成结构化、交叉引用的 Wiki,并持续更新。plexus 将这一模式落实到基础设施中:

Karpathy 的 LLM wikiplexus
原始来源(不变)Agent 使用 web_fetch、文件 I/O 等读取的外部文档
Wiki(类型化 Markdown,经过整理)Agent 通过 MCP 写入图谱的类型化实体和具名边
架构(CLAUDE.md / AGENTS.md 中的约定)list_kinds + list_relations 注册表,在 MCP 边界强制执行
ingest → compile → reflect → query → lintsearch_entities → save_entity / update_entity → link_entities → get_related → lint_graph

Karpathy 将这个 gist 称为“想法文件”——一种与供应商无关的提示词模式。plexus 为它提供了生产级后端:类型化存储、乐观锁、时间边、多用户身份验证和审计日志。

由此你可以获得:

  • 跨会话的单一事实来源。 你的 Agent 会在每次对话开始时加载上下文。你不必反复解释自己。
  • 跨 Agent 的单一事实来源。 Claude web、Claude Code、Claude Desktop、Le Chat、Gemini——无论谁连接进来,使用的都是同一张图谱。
  • 跨用户的单一事实来源。 开箱即用的多用户支持、每人独立的作用域令牌、共享的 project 容器和审计日志。

目录

了解它

运行它

将 Agent 接入它

参考

运维


使用场景

持久化 Agent 记忆。 每次对话都会从 context_load 开始,因此助手会记住你已经做过哪些 ADR、哪些项目正在进行,以及你昨天完成了哪些任务。无需通过提示词工程来让它说“如你所忆……”

跨 Agent 交接。 Claude Code 完成功能后,会写入一条交接事实。第二天早上,Claude 网页版会接续同一上下文,知道哪些提交已发布、还有哪些事项未完成。无需重新介绍情况。

小团队的团队记忆。 启动一个实例,为每个人发放范围受限的个人令牌,并共享一个 project 容器。所有人都可以使用只读仪表板,Agent 为所有人写入内容。不用 Notion、维基,也不必翻查 Slack 考古。

决策考古。 每个 ADR 都是一个一等 decision 实体,并带有 supersedes / derived_from 边。一年后,你可以追溯 F-1 引擎为何保留、Apollo 13 事后分析引发了什么,以及哪些设计取代了哪些设计。通过 get_related(as_of: "2026-01-01") 进行时光回溯查询。

事件 → 修复闭环。 生产事件会成为一条带有 severity: high 的 fact。缓解措施 ADR 通过 triggered_by 关联到该事实。操作手册会 documents 该 ADR。六个月后新员工入职时,他们只需沿图谱遍历一次,无需翻看十二条 Slack 讨论串。

文献 / 研究摘要。 Agent 摄取论文,为来源创建一条 note,提取 concept 和 fact 实体,并附加 mentions 边。你可以按主题查询图谱;每条主张都有来源,可追溯到一条 derived_from 笔记。

Agent 真正会使用的私人“第二大脑”。 使用 inbox_item 捕捉内容,在每周回顾时将其提升为 task / concept / fact,再通过 supersedes 归档。笔记会自动结构化,无需你填写表单。


快速入门

# 1. Clone
git clone https://github.com/pcas-io/plexus.git
cd plexus

# 2. Configure — generates .env from the template with fresh 32-byte
#    secrets for all four required fields:
#      PLEXUS_ADMIN_TOKEN      ← you'll use this once, to bootstrap
#      PLEXUS_OAUTH_SECRET     ← OAuth state signing
#      PLEXUS_COOKIE_SECRET    ← dashboard session cookie signing
#      PLEXUS_SURREAL_PASS     ← SurrealDB root password
scripts/bootstrap_env.sh

# 3. Start
docker compose up -d

# 4. Open the dashboard
open http://localhost:8787

首次登录时需要用到的管理员令牌位于 .env 中:

grep '^PLEXUS_ADMIN_TOKEN=' .env

复制该十六进制值——下一节将介绍一次性引导流程。

完整配置参考见 .env.example。下文还提供 Coolify、纯 Docker 和 Kubernetes 的部署说明。


创建管理员用户(首次运行)

plexus 在空数据库上启动时没有用户。你将使用 PLEXUS_ADMIN_TOKEN 一次来创建首个管理员账户,之后该令牌便不再使用。

1. 查找管理员令牌

你在快速入门中运行的 scripts/bootstrap_env.sh 脚本已将令牌写入 .env。读取该令牌:

grep '^PLEXUS_ADMIN_TOKEN=' .env
# PLEXUS_ADMIN_TOKEN=<64-char-hex>

复制 = 后面的十六进制值。你只需将它粘贴到仪表板中一次;完成引导后,plexus 会拒绝在 MCP 和常规登录中使用管理员令牌。

2. 走一遍流程
#操作plexus 的响应
1打开 http://localhost:8787显示登录表单
2粘贴管理员令牌,点击 Continue识别到“管理员令牌 + 不存在管理员用户”→ 重定向到 /bootstrap
3输入管理员名称(字母、数字、_、-、.),点击 Create admin创建管理员用户,并仅显示一次新的个人令牌 pt_…。请复制该令牌。
4点击 Continue to login返回 /auth/login,并设置待处理身份验证 Cookie
5粘贴 pt_ 令牌显示通行密钥注册界面
6点击 Register passkey now,使用 Touch ID / Face ID / Windows Hello / YubiKey 确认保存通行密钥,然后轮换 pt_ 令牌,并仅显示一次新令牌。请覆盖密码管理器中的原有记录。
7点击 Sign in with new token,粘贴新令牌并轻触通行密钥进入 /home

从此以后,管理员令牌仅用于管理平面端点(备份、重置)。它在 MCP 中以及普通仪表板登录时都会被拒绝。

为什么要轮换?

初始令牌(管理员令牌和第一个 pt_)是一次性邀请码。如果它们被截获——例如通过邮件、聊天或屏幕共享——轮换令牌会在你登录的那一刻让截获的令牌失效。对于你通过 /users 创建的其他用户,同样的管理员→用户交接流程和首次注册时的令牌轮换也能提供相同保护。

接下来可以做什么

仪表板中的 /help 页面介绍了其他所有内容:MCP 集成、令牌范围、通行密钥管理、共享链接和图谱视图。

plexus 帮助页面——首次运行引导文档


连接 Agent

plexus 通过 POST /mcp 使用 Model Context Protocol。任何支持 MCP 的客户端都可以连接。

Claude.ai(网页)

设置 → 集成 → 添加自定义集成 → https://<your-plexus-host>/mcp。plexus 会自动处理 OAuth——你只需查看一次同意界面。

Claude Code(命令行)
claude mcp add plexus --transport http \
  --header "Authorization: Bearer pt_YOUR_TOKEN" \
  https://<your-plexus-host>/mcp
Claude Desktop

在 ~/Library/Application Support/Claude/claude_desktop_config.json 中:

{
  "mcpServers": {
    "plexus": {
      "type": "http",
      "url": "https://<your-plexus-host>/mcp",
      "headers": { "Authorization": "Bearer pt_YOUR_TOKEN" }
    }
  }
}

MCP 工具

plexus 提供 15 个工具。

工具用途范围
save_entity创建新实体写入
get_entity按 ID 获取单个实体读取
list_entities按条件筛选并列出实体(类型、上下文、状态)读取
search_entities按 BM25 排序的全文搜索,可选择高亮读取
update_entity使用乐观锁(expected_version)更新实体写入
archive_entity软删除(状态 → 已归档)写入
link_entities在两个实体之间创建时间边写入
unlink_entity使边失效(valid_to = now)写入
get_related按方向和时间点筛选遍历边读取
list_kinds查询类型注册表读取
list_relations查询关系注册表读取
context_load会话预热——最近的 20 个实体 + 注册表读取
lint_graph检查孤立实体和重复标题读取
list_skills所有技能的精简索引读取
load_skill按名称、触发短语或 BM25 回退方式加载一项技能读取

每个工具都会在处理程序边界强制执行范围检查:requireWrite()、checkContext()、checkKind() 和 rejectSecret()。通过 MCP 无法访问 kind=secret,且所有读取响应都会过滤掉此类内容。

plexus 仪表板主页——项目、活动动态、上下文筛选器

Agent 系统提示词模板

将此代码块粘贴到任何支持 MCP 的 Agent 中(Claude 网页版自定义集成、Claude Code CLI、Claude Desktop、Le Chat、自定义 SDK 测试框架)。它特意写得很精炼——每一行都有其用处。与模型无关;适用于任何支持 MCP 工具调用的大模型。

# Plexus is your long-term memory

You have access to **plexus**, a persistent on-prem knowledge graph,
over MCP. Treat it as authoritative memory across sessions. Never
re-derive what the graph already knows; never let the graph drift.

## Every session

1. **Start:** call `context_load` once. Read the 20 most recent
   entities and the kinds/relations registries. No other lookups
   until you know what's already there.
2. **Before writing:** call `search_entities` (BM25, 2–4 keywords) to
   avoid duplicates. If you find a close match, `update_entity` with
   `expected_version`; do not create a new one.
3. **Writing new knowledge:** `save_entity` with the right `kind`.
   Pick deliberately — kind drives how other agents will query it.
   - `concept` — pattern, idea, domain term
   - `decision` — an ADR (see "ADR discipline" below)
   - `fact` — atomic statement, incident, milestone
   - `project` — container that other entities are `part_of`
   - `task` — actionable item (`attributes.is_milestone: true` for
     milestones)
   - `document` — runbook, post-mortem, design doc
   - `note` — provenance anchor for an external source (URL, paper)
   - `config` / `secret` — URLs, env vars, credentials. Secrets are
     MCP-unreadable by design; do not attempt to read them.
   - `inbox_item` — GTD quick capture to triage later
4. **Linking:** pick a named relation, not `relates_to`:
   `part_of`, `depends_on`, `blocks`, `supersedes`, `documents`,
   `derived_from`, `triggered_by`, `implements`, `produces`,
   `consumes`, `mentions`, `owned_by`, `has_version`, `variant_of`.
5. **Traversal:** prefer one `get_related` over multiple
   `get_entity` calls. Use `as_of` for point-in-time queries.
6. **Graph hygiene:** at the end of a substantial session, call
   `lint_graph` and fix orphans and duplicate titles.

## ADR discipline

Every `kind=decision` MUST carry at least one edge —
`derived_from`, `triggered_by`, `supersedes`, or `part_of`. A
free-floating decision is a bug; the next agent won't find it.

## Session handoff

At the end of every non-trivial session, save a handoff-fact:

- `kind: "fact"`
- `attributes.session_type: "handoff"`
- `attributes.session_date: "<ISO date>"`
- `attributes.session_id: "<short slug>"`
- `attributes.agent_id: "<model id>"`
- `attributes.git_branch: "<branch>"` if applicable
- `part_of: "<project-entity-id>"` (required for handoffs, not
  optional — server enforces this)

Title format: `"<Project> Handoff <Date> — <Core topic>"`.

## Optimistic locking

Every `update_entity` requires `expected_version`. On
`version_conflict`, re-fetch with `get_entity` and retry; never
blindly overwrite.

## Versioning, not deletion

Never delete by hand. Supersede: create the new entity, link
`supersedes <old>` (1:1), then `archive_entity` the old one.

## Memory routing — when plexus, when local scratchpad

**Goes in plexus (the default):**
- Anything team-, project-, architecture- or decision-relevant.
- Incidents, milestones, post-mortems, ADRs.
- Anything an agent in another session will want to know.

**Keep in a local scratchpad instead:**
- Per-session ephemera (current file paths, interim REPL output).
- Host-local gotchas with no team value (a specific IDE's template
  literal trap, one machine's firewall oddity).

**When in doubt, plexus wins.** You can always archive a noisy
entity; you cannot recover one you never wrote.

## Trigger phrases

If the user says any of these, load the matching skill via
`load_skill` before acting:

| Phrase | Skill |
|---|---|
| "ADR" / "decision" | entscheidung / adr |
| "post-mortem" | post-mortem |
| "pre-mortem" | pre-mortem |
| "5 whys" / "root cause" | 5-whys |
| "runbook" | runbook |
| "STRIDE" / "threat model" | stride |
| "weekly review" | weekly-review |
| "meeting notes" | meeting-protokoll |

Skills are `kind=skill` entities in the graph with a trigger-phrase
attribute. `list_skills` gives you the index; `load_skill` returns
the full markdown body.

根据 Agent 角色收紧权限。 签发范围受限的独立个人令牌,而不是一个无所不能的令牌:

  • Writer Agent(Claude Code CLI):permission=write,所有上下文、所有类型。
  • Reader 小组件(仪表板、监控任务):permission=read,仅限单个 contexts: [dev],不含机密信息。
  • 特定领域 Agent(例如研究摘要 Agent):permission=write,仅限 kinds: [note, concept, fact]。

仪表板的 /tokens 页面只需两次点击即可生成上述任意令牌。


示例:摄取来源

以下是 Agent 实际使用 plexus 时,Karpathy 风格的摄取循环。用户提交一篇文章;Agent 仅使用 plexus 工具,按 LLM-wiki 模式完成五个阶段,并在不到一分钟内丰富知识图谱。

用户:“把这篇内容加进来:https://example.com/engineering/feature-flags-at-scale”

1 — 分类与定位。 Agent 获取来源,将其分类为 article,并检查已有内容,以免重复:

search_entities({ query: "feature flags progressive rollout", limit: 10 })
// → 2 concepts, 1 ADR, 1 fact in the dev context

2 — 提取。 对于文章,Agent 会提取关键论点、新事实、决策,以及任何与现有实体相矛盾的内容。

3 — 写入带类型的实体。 每种意图对应一种类型;更新现有实体,而不是创建重复项。

// New concept — the specific rollout pattern the article introduces
save_entity({
  kind: "concept", context: "dev",
  title: "Shadow-flag pre-rollout (Acme pattern)",
  body: "# Shadow flag pre-rollout\n..."
})
// → entities:ab12...

// New atomic fact with provenance-grade attributes
save_entity({
  kind: "fact", context: "dev",
  title: "Acme reduced rollout-related incidents by 62% after adopting shadow flags",
  attributes: { severity: "info", category: "benchmark", source_year: 2026 }
})
// → entities:cd34...

// Existing concept gets enriched, not duplicated
update_entity({
  id: "entities:prev-concept-id",
  expected_version: 3,
  body: body + "\n\n## Update 2026-04-17\n..."
})

4 — 标注来源。 每次摄取都会恰好创建一个作为来源锚点的 note,且每个提取出的实体都会通过 derived_from 链接回该笔记:

save_entity({
  kind: "note", context: "dev",
  title: "Source: Acme — Feature flags at scale",
  body: "## Metadata\nURL, date, author.\n\n## Summary\n2–3 sentences.\n\n## Derived entities\n- Shadow-flag pre-rollout (Acme pattern)\n- Acme reduced rollout-related incidents by 62% ..."
})
// → entities:ef56...

link_entities({ from_id: "entities:ab12...", to_id: "entities:ef56...", relation: "derived_from" })
link_entities({ from_id: "entities:cd34...", to_id: "entities:ef56...", relation: "derived_from" })
link_entities({ from_id: "entities:prev-concept-id", to_id: "entities:ef56...", relation: "mentions" })

5 — 双重输出。 回复用户并更新知识图谱——两者在同一轮中完成,而不是留待以后处理。

Agent 的回复:

已摄取 Acme 的功能标志文章。新增 2 个实体,丰富了 1 个现有概念,并创建了 3 条指向新来源笔记(entities:ef56…)的 derived_from / mentions 边。影子标志的预发布阶段与现有的发布 ADR 并不矛盾——两者相辅相成。

六个月后,有人问你的 Agent:“我们当初为什么选择影子标志?”你的 Agent 会执行 search_entities({ query: "shadow flag rollout" }),再对命中的实体调用 get_related,以获取来源笔记和引用该笔记的 ADR,并依据汇总后的知识图谱作答,而不是重新阅读原始 HTML。无需重新总结,也不用说“如你可能还记得”。答案早已在知识库中。


知识图谱的内容

类型
类型含义
concept抽象知识、模式
decision架构决策记录
fact原子陈述、事件、里程碑
project容器
task工作项(里程碑使用属性 is_milestone)
document设计文档、运行手册、事后分析、协议
note来源、来源锚点
template可复用模式
configURL、环境变量
secret凭据——MCP 无法访问,仅限仪表板使用并需通过升级验证的通行密钥
inbox_itemGTD 快速记录
user用户引用
tag分类标签
skill带有触发短语的 Markdown 技能,通过 load_skill 加载
关系

contains / part_of · relates_to · depends_on / blocks · supersedes / superseded_by · documents / documented_by · implements · produces / produced_by · consumes · mentions · derived_from · triggered_by · has_version · variant_of · executed_by · owned_by

每条边都带有 valid_from、valid_to、confidence 和 source(manual / llm-inferred / computed / imported)。unlink_entity 会将 valid_to 设为 now;该边仍会作为历史记录保留。get_related(as_of: …) 可以提供过去任意时间点的知识图谱状态。

plexus 实体详情——包含 Markdown 正文、属性和带类型的关系的 ADR


身份验证

面向人类:通行密钥

控制面板仅支持通行密钥。首次登录时使用令牌 + 通行密钥,令牌会自动轮换——初始令牌是一次性邀请码,注册通行密钥后即失效。每位用户最多可添加 3 个通行密钥(笔记本电脑、手机、硬件密钥);最后一个通行密钥无法删除。

面向 Agent:个人令牌和 OAuth

个人令牌(pt_…)是通过控制面板签发的第一方自助令牌,并具有明确的作用域:permission × contexts × kinds × expires_in_days。可将它们用于 claude code、CLI 自动化,或任何你愿意授予长期凭证的 MCP 客户端。

OAuth 2.1 令牌(ot_…)适用于第三方 MCP 客户端。plexus 提供完整的授权服务器:

  • 通过 RFC 8414(授权服务器元数据)和 RFC 9728(受保护资源元数据)进行发现。
  • 动态客户端注册(RFC 7591)。
  • 必须使用 PKCE 和 S256;架构和代码都会拒绝 plain。
  • 授权端点和令牌端点均支持资源指示符(RFC 8707)。
  • 以恒定时间进行重定向 URI 精确匹配比较。
  • 刷新时轮换令牌——签发新刷新令牌的同时立即撤销旧刷新令牌,以便检测凭证泄露。

管理员令牌在 /mcp 上会被拒绝,并返回硬性 403。不存在“直接使用管理员令牌”的变通方式。


分享

你可以将单个实体分享为只读的一次性链接,无需交出整个图谱。

  1. 在控制面板中打开该实体。点击 分享。
  2. 通过与用途绑定的通行密钥进行提权验证(stepup:share:<userId>)——分享质询无法被重放为重置质询。
  3. plexus 会签发一个 32 字节的 st_ 令牌。系统只存储 SHA-256 哈希值。URL 仅显示一次。
  4. 接收者打开 GET /share/:token——无需登录,受到速率限制,且为只读。
  5. 第二次调用会返回 410 Gone。你可以随时撤销。

一个分享 URL,三种格式:

URLContent-Type用途
/share/:tokentext/html浏览器
/share/:token?rawtext/markdown管道传输给大模型或 glow
/share/:token?raw=jsonapplication/json适用于 jq 的自动化

kind=secret 的实体无法分享——检查会在创建令牌之前进行。


搜索

search_entities 基于 SurrealDB BM25 索引运行,并使用自定义分析器(plexus_text):

  • blank + class 分词器,lowercase + ascii 过滤器(Unicode 到 ASCII 折叠——ü 可匹配 u,ß 可匹配 ss)。
  • 两个索引:entities_title_search 和 entities_body_search。
  • 排名:search::score(0) * 2 + search::score(1)——标题权重为两倍。
  • 可选的高亮功能会用 <mark> 标签包裹匹配项。
  • 可选的 body_preview_chars(0–2000)用于限制响应大小——宽泛查询时建议使用。

plexus 实体浏览器 — BM25 搜索与匹配项高亮


架构

┌──────────────────────────────────────────────┐
│  agents (Claude web / CLI / Desktop / ...)   │
└───────────────┬──────────────────────────────┘
                │ MCP over HTTPS + Bearer token
                ▼
┌──────────────────────────────────────────────┐
│  plexus worker (Hono + TypeScript, Node 22)  │
│  ├─ POST /mcp      — MCP tool dispatcher     │
│  ├─ /oauth/*       — OAuth 2.1 AS + PRM      │
│  ├─ /auth/*        — WebAuthn passkey flow   │
│  ├─ /share/:token  — one-shot read links     │
│  ├─ /dashboard     — read-only human UI      │
│  └─ /admin/backup  — portable JSON export    │
└───────────────┬──────────────────────────────┘
                │ SurrealQL
                ▼
┌──────────────────────────────────────────────┐
│  SurrealDB v2 (RocksDB, persistent volume)   │
│  entities · edges · registries · activity    │
└──────────────────────────────────────────────┘
源码目录结构
src/
├── index.ts              # HTTP bootstrap, CSP, security headers
├── auth/                 # passkeys, sessions, CORS allow-list
├── db/                   # SurrealDB client, repositories, util
├── mcp/                  # MCP tool handlers, skill tools, dispatcher
├── routes/               # dashboard, oauth, shares, admin, well-known
├── ui/                   # layout, styles, pages, markdown renderer
├── backup.ts             # portable JSON export
└── version.ts            # build-embedded version string
migrations/               # SurrealDB schema in migration order
scripts/                  # one-off admin / ops helpers

文件大小软上限:约 700 行。超过上限的文件会按职责拆分。


配置

所有配置均通过环境变量完成。完整列表及默认值请参阅 .env.example。

变量必需描述
PLEXUS_ADMIN_TOKEN✓引导管理员令牌。在生产环境中请使用密钥管理器。
PLEXUS_OAUTH_SECRET✓用于签署授权码和 OAuth 状态。
PLEXUS_COOKIE_SECRET✓用于签署仪表板会话 Cookie。
PLEXUS_SURREAL_URL✓SurrealDB 端点——在 compose 网络内默认为 http://surrealdb:8000。
PLEXUS_SURREAL_USER✓SurrealDB 根用户。
PLEXUS_SURREAL_PASS✓SurrealDB 根密码。
PLEXUS_SURREAL_NS命名空间(默认为 plexus)。
PLEXUS_SURREAL_DB数据库(默认为 main)。
PLEXUS_RP_IDWebAuthn 依赖方 ID——必须与主机名匹配。默认为 localhost。
PLEXUS_RP_NAME通行密钥提示中显示的名称。
PLEXUS_BASE_URLOAuth 元数据使用的规范基础 URL。
PLEXUS_PORTHTTP 监听端口(默认为 8787)。
PLEXUS_LOG_LEVELdebug / info / warn / error。

生成高熵密钥:

openssl rand -hex 32

自托管

Docker Compose(推荐)

随附的 docker-compose.yml 会同时启动 plexus 工作进程和 SurrealDB。工作进程仅发布在 127.0.0.1:8787 上,也就是仅限 localhost 访问,因此即使公共 DNS 记录有误,也不会意外暴露仪表板。若要从本机以外的设备访问,请在前面配置反向代理。

docker compose up -d
docker compose logs -f plexus

对于 Coolify 主机,在其上叠加 Coolify 覆盖配置,以附加外部 coolify Traefik 网络并固定路由标签:

docker compose -f docker-compose.yml -f docker-compose.coolify.yml up -d
位于反向代理之后

plexus 在生产环境中要求使用 TLS。仪表板会设置 Secure Cookie,在 localhost 之外通过纯 HTTP 访问时会出现异常。请使用 Caddy、Traefik 或 nginx 等代理;最精简的 Caddy 配置见 Caddyfile。

CSP 标头会为 D3 固定 cdn.jsdelivr.net(并使用 SRI 哈希)。如果通过其他 CDN 提供仪表板,请相应更新 src/index.ts 中的 CSP。

备份
curl -H "Authorization: Bearer $PLEXUS_ADMIN_TOKEN" \
  https://<your-plexus-host>/admin/backup \
  > plexus-backup-$(date +%Y-%m-%d).json

导出内容包含实体、边、类型、关系和用户(不含令牌哈希)。它不包含会话、通行密钥、OAuth 令牌、个人令牌或共享令牌——凭据和会话状态绝不会备份。传入 ?include_audit=1 可将最近 1000 条活动日志记录包含在单独的文件中(默认不包含,因为这些记录含有个人数据)。


开发

npm ci
docker compose up -d surrealdb
cp .env.example .env        # fill in required fields
npm run dev                 # live reload on :8787

质量检查:

npm run typecheck
npm run build
npx vitest run
npm audit --omit=dev --audit-level=moderate

有关提交规范、PR 要求以及我们在审查期间坚持的设计原则,请参阅 CONTRIBUTING.md。


安全

  • Markdown 通过允许列表 URL 解析器进行渲染;链接带有 rel="noopener nofollow ugc"。
  • 属性载荷上限为 64 KB,并会在 Zod 边界处被拒绝;原型键(__proto__、constructor、prototype)会被递归剥除。
  • 令牌生成采用 base62 拒绝采样,以避免模运算偏差。
  • 敏感操作的 WebAuthn 挑战会通过用途绑定进行增强验证。
  • 无论(用户、通行密钥、速率限制)中的哪一项验证失败,登录错误路径都会统一返回 LOGIN_FAIL——不会泄露用户是否存在。
  • kind=secret 无法通过 MCP 访问、不可共享,并且仅限管理员在仪表板中通过增强验证的通行密钥操作。

请私下报告漏洞——参阅 SECURITY.md。请勿公开提交安全问题。


许可证

Apache License 2.0。请参阅 LICENSE。

plexus 和 pcas.io 是 pcas.io 项目的商标。Apache 许可证适用于代码;不授予商标权。


致谢

plexus 基于 SurrealDB、Hono、the Model Context Protocol SDK、SimpleWebAuthn、Zod 和 D3 构建。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。