关于 Personae
Personae 是面向多账号浏览的桌面浏览器,将每个浏览器身份隔离,并允许 Agent 控制已打开的窗口。它通过 MCP 按身份定位页面,避免依赖标题或网址区分账户。
主要功能
- 01隔离各身份的 Cookie 与登录状态
- 02为身份提供独立浏览器窗口
- 03通过身份名称定位页面目标
- 04控制页面导航、点击与输入
- 05读取页面文本并捕获屏幕截图
- 06支持操作身份所属的弹出窗口
适用场景
- 01同时登录同一网站的多个账户
- 02让 Agent 操作已打开的特定身份窗口
- 03处理身份窗口中的 OAuth 弹出页
MCP 相关
MCP 服务将浏览器身份列表及页面导航、交互、读取和截图功能提供给客户端。每项工具按身份限定目标窗口,也可指定该身份下的弹出窗口。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
13收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| section | string | 否 | 可选:只关注某个方面时,填写关键词进行筛选,例如 snapshot / click / tab / eval / screenshot / batch。留空则返回全部语法。 |
详细介绍
Personae
多身份浏览器 · 每个身份都是彼此隔离的分区,每个窗口都可由 Agent 控制
内置 agent-browser 和 MCP 服务——无需安装 Node 或命令行工具
English · 中文
这是一款 Electron 桌面浏览器,结合了多账号隔离和让 AI Agent 操控浏览器两项功能。
- 每个浏览器身份都是独立的 Chromium
persist:分区——Cookie、localStorage 和登录状态完全隔离,因此你可以同时使用多个账号登录同一网站。 - 每个身份都有独立窗口,带有前进、后退按钮和地址栏,使用体验与普通浏览器无异。
- 内置 agent-browser 二进制文件,并通过 MCP 暴露这些窗口,因此 Codex / Claude Code 可以操控特定身份对应的页面。
用户无需预先安装 Node、Chrome for Testing 或任何命令行工具。
MCP Registry
Personae 在首次支持 Registry 的版本发布后,已发布到官方 MCP Registry,名称为 io.github.leek-emperor/personae。
Registry 软件包是一个小型 stdio 启动器,适用于已单独安装并正在运行的 Personae 桌面应用——它不会取代浏览器应用,也不会创建云端浏览器。
安装并启动 Personae 后,支持 npm MCP 软件包的客户端可以运行:
npx -y @leek-emperor/personae-mcp
启动器通过本地桥接发现 Personae,并将每次工具调用限定在请求中指定的身份范围内。它不需要 API 密钥,也不会开放公网监听端口。建议使用应用中的 Configure Codex 控件进行配置,因为它使用内置的 Electron 运行时,无需安装 Node。
解决的问题
现有的浏览器自动化工具都假定由 Agent 启动浏览器。但如果你的产品本身_就是_浏览器客户端,情况则正好相反:窗口已经打开,并且分别属于不同的账号身份。Agent 需要做的是连接到相应窗口,同时避免跨越身份边界。
这里采用的方案:
- 应用启动时开放一个 CDP 端口(由系统分配,且仅限环回接口)。
- 身份窗口打开时,主进程通过
Target.getTargetInfo获取其内容页面的权威 targetId。 - 本地桥接提供
identity → targetId映射。 - MCP 服务直接将该 targetId 用作标签页引用,一步即可命中目标。
因此,即使两个窗口打开了同一网站,且标题和 URL 完全相同,snapshot(identity: "Account A") 和 snapshot(identity: "Account B") 仍会始终定位到正确的窗口。
快速开始
需要 Node ≥ 20 和 pnpm(仅开发时需要;打包后的应用不依赖它们)。
agent-browser 必须为 ≥ 0.36。低于此版本时,tab list --json 不会输出 targetId,而它是将身份与窗口关联起来的唯一信息——所有工具都会因此无法找到目标。package.json 中已锁定所需版本;请勿降级。
pnpm install
pnpm bundle:ab # copy the agent-browser binary and core skill into resources/
pnpm dev
在界面中添加一个或两个浏览器身份,然后点击身份以打开其窗口。
界面默认使用英文。使用右上角的 EN / 中 切换按钮切换到中文;所选语言会被记住,也会应用到每个身份窗口内的工具栏,以及你复制的 Agent 提示词中。
测试
那些棘手且几乎没有文档说明的决策,封装在小型纯模块中,以便通过测试固定下来。它们使用 node:test 运行,不需要额外依赖:
pnpm test
测试覆盖:window.open / 弹出窗口决策(window-open.ts)、代理输入解析(proxy.ts)、地址栏 URL 规范化(url-input.ts)、Codex 配置 TOML 拼接(toml.ts)以及身份配色方案(colors.ts)。
打包:
pnpm build:mac # or build:win
默认采用 临时签名(identity: '-'),无需 Apple Developer 证书,也能在构建机器上正常运行。但临时签名的应用无法分发——Gatekeeper 会在其他人的 Mac 上拦截它。若要正式分发,请通过环境变量提供证书,并将 notarize 设为 true:
CSC_LINK=/path/to/cert.p12 CSC_KEY_PASSWORD=... \
APPLE_ID=... APPLE_APP_SPECIFIC_PASSWORD=... APPLE_TEAM_ID=... \
pnpm build:mac
连接 Codex / Claude Code
最快的方法:让 Agent 自行连接
界面中有一个**“让 Agent 自行连接”**区块,会生成一段可直接发送的提示词。复制后粘贴到 Codex 或 Claude Code 中,Agent 就会编写自己的 MCP 配置、重启,并通过调用 list_identities 验证连接。
这段提示词不只是配置片段——它还会告诉 Agent 这 13 个工具的用途,以及需要避免哪些错误(过期的引用、猜测 agent-browser 语法、试图通过页面标题区分身份)。它根据实时运行时值生成,因此其中的路径始终适用于当前运行的机器。
或者点击一个按钮
同一面板还提供一键安装功能,会将 MCP 服务写入 ~/.codex/config.toml(支持幂等操作,并会先自动备份)。路径会在运行时根据 process.execPath 解析,因此不会出错。
或者手动配置
在 macOS 上:
[mcp_servers.personae]
command = "/Applications/Personae.app/Contents/MacOS/Personae"
args = ["/Applications/Personae.app/Contents/Resources/mcp-server.mjs"]
[mcp_servers.personae.env]
ELECTRON_RUN_AS_NODE = "1"
Contents/MacOS/ 下的可执行文件遵循 productName,因此名称为 Personae。请注意,electron-builder 的 executableName 仅适用于 Windows。
command 指向应用自身的二进制文件;ELECTRON_RUN_AS_NODE=1 会使其退化为纯 Node 运行时。因此无需安装 Node(已验证:将 PATH 设为 /usr/bin:/bin 后,完整流程仍可正常运行)。
Claude Code:
claude mcp add personae \
--env ELECTRON_RUN_AS_NODE=1 \
-- /Applications/Personae.app/Contents/MacOS/Personae \
/Applications/Personae.app/Contents/Resources/mcp-server.mjs
MCP 工具
每个工具都需要一个 identity 参数(名称或 ID)。
| 工具 | 用途 |
|---|---|
load_skill | 获取捆绑的 agent-browser 版本的实际命令语法(默认返回章节索引;传入 section 可获取特定章节) |
list_identities | 列出所有 identity 的打开状态和当前 URL |
open_identity | 打开 identity 的窗口 |
snapshot | 返回可访问性树快照,其中包含 [ref=eN] 元素引用 |
navigate | 导航到某个 URL |
click / fill / press | 交互;click 接受引用或可见文本 |
act | 在一个 agent-browser 进程中运行多条命令 |
get_text / get_url | 读取内容 |
screenshot | 截取屏幕截图 |
eval_js | 执行 JavaScript |
当 click / fill 接收到 @eN 引用时,会先自动获取快照,因为引用仅在单个 agent-browser 进程内有效——在多个进程间重复使用引用总会失败并提示 Unknown ref。进行多步交互时,请将操作放在同一个 act 批处理中。
操作弹出子窗口。 当页面打开弹出窗口(OAuth 登录、分享对话框等)时,该弹出窗口会成为同一 identity 所属的子窗口(参见弹出窗口和 OAuth)。它是单独的 CDP 目标,会在 list_identities 中作为 children 列在 identity 下。每个操作/读取工具都接受可选的 target 参数——传入子窗口的 targetId(或其索引)即可操作弹出窗口,而不是主窗口;省略该参数则仍像之前一样操作主窗口。
架构
┌─────────────────────────────────────────────────────────┐
│ Electron main process │
│ │
│ ├─ CDP server (port 0 → system-assigned, 127.0.0.1 only)│
│ ├─ IdentityManager storage / window lifecycle / target │
│ └─ Agent Bridge local HTTP, exposes identity↔target │
└───────────┬─────────────────────────────────┬────────────┘
│ │
┌─────────▼──────────┐ ┌───────────▼───────────┐
│ Identity window │ │ Discovery file │
│ (one per identity) │ │ userData/ │
│ │ │ agent-bridge.json │
│ BrowserWindow shell│ │ (port changes every │
│ ├ WebContentsView │ │ launch; found via │
│ │ chrome.html │ │ a fixed path) │
│ └ WebContentsView │ └───────────┬───────────┘
│ content │ │
│ ↑ agent acts │ │
└────────────────────┘ │
│
┌─────────────────────────────────▼───────────┐
│ scripts/mcp-server.mjs (stdio JSON-RPC) │
│ read discovery → get targetId → run CLI │
└───────────────────┬─────────────────────────┘
│
┌───────────▼────────────┐
│ Codex / Claude Code │
└────────────────────────┘
为什么每个 identity 窗口都是“一个外壳加两个 WebContentsViews”
目标是将第三方页面包裹在我们自己的导航 UI 中,而不使用 <webview> 标签。因此:
- 外壳
BrowserWindow仅用作容器,并加载about:blank; - 顶部栏是本地的
chrome.html,带有专用预加载脚本,仅公开六种导航方法; - 内容区域是一个应用了分区的
WebContentsView,并且刻意不加载任何预加载脚本,以保持第三方页面原样。
嵌套的 BrowserWindow 和 BrowserView 也都可行,Agent 能操作这三者(均已验证)。选择 WebContentsView 是因为 BrowserView 在 Electron 的类型定义中标记为 @deprecated,也因为在 macOS 上,嵌套窗口是单独的原生窗口——拖动、调整大小和最小化都需要手动同步边界,始终无法真正呈现为“一个浏览器窗口”。
弹出窗口和 OAuth
页面可以通过 window.open(url, name, features) 打开弹出窗口,例如 OAuth 登录、“分享到…”对话框等。这些必须是真实窗口:OAuth 弹出窗口依赖 window.opener 和 postMessage/window.close() 将结果传回,因此不能将其简化为页面内导航,否则会破坏流程。
这里采用的方式是将弹出窗口视为其所属身份的一等子窗口,而不会尝试猜测“这是不是 OAuth 窗口”:
- 同窗口还是子窗口。 普通的
<a target="_blank">或不带特性的window.open会保持为窗口内导航(没有 opener,也不会创建新目标)——这样是安全的,并且保持“一个身份,一个主目标”的约束。只有以new-window方式打开的窗口(即带窗口特性的window.open)才会成为真实子窗口。 - 属于该身份。 子窗口创建时会将
parent设为该身份的外壳窗口,并使用相同的分区,因此会显示在正确的窗口上方,Cookie 也会存入正确的账户。window.opener会保留,因此适用于各种 OAuth 方式。outlivesOpener: false表示关闭身份时也会关闭其弹出窗口。 - 弹出窗口拦截器(默认开启)。 唯一区分“应该打开”和“不应该打开”的条件是用户激活——过去一秒内是否发生过真实的点击或按键?这正是主流浏览器弹出窗口拦截器的工作方式:它绝不会检查域名或内容。没有前置输入、由脚本驱动的弹出窗口会被拦截,并以不打扰用户的提示消息告知;你可以在顶部栏关闭拦截器。
- Agent 可以控制子窗口。 每个子窗口都是独立的 CDP 目标,会解析为其权威
targetId,并以children的形式列在身份之下。每个 MCP 工具都可以通过可选的target指定要操作的弹出窗口。这不会破坏面向外部的“每个身份一个主目标”约定,而是将其如实扩展为“一个主目标加已跟踪的子窗口”。
该判断逻辑(same-window / allow-child / ignore)位于纯函数 src/main/window-open.ts 中,并经过单元测试。
按身份设置代理
每个身份都可以通过自己的代理路由——适用于希望同一网站的账号来自不同地区,或测试地理位置行为的场景。代理由你自行提供(从 IPRoyal / Webshare / Bright Data 等服务商购买);Personae 仅提供设置并负责接入。
- 适用范围。 代理通过
session.setProxy设置在身份的persist:分区上,因此是真正按身份单独设置的——身份 A 可以通过美国 IP 出口,而身份 B 可以通过日本 IP 出口。不设置代理则直接连接。 - 支持的类型。 HTTP、HTTPS 和 SOCKS5。你可以分别填写各字段,也可以将
socks5://user:pass@host:port这样的完整字符串粘贴到主机输入框中。 - 身份验证。 支持使用用户名和密码的代理。凭据绝不会写入代理规则字符串(Chromium 会拒绝其中的
user:pass@);身份验证通过 Electron 的login事件处理。 - 密码在静态存储时会加密。 密码通过
safeStorage存储(macOS 上使用 Keychain,Windows 上使用 DPAPI),保存在userData/proxy-secrets.json中,绝不会写入identities.json,也绝不会发送回渲染进程。如果safeStorage不可用,则会回退到明文存储,界面也会说明这一点。 - 测试连接。 点击按钮后,会通过该身份的会话获取 IP 回显服务,并显示实际的出口 IP,以便确认代理确实生效。
- WebRTC 泄漏防护。 对任何使用代理的身份,都会应用
setWebRTCIPHandlingPolicy('disable_non_proxied_udp'),防止 WebRTC 绕过代理并泄露真实 IP。
这不是反检测浏览器。 它只会更改你的网络出口,不会做其他处理。除上述 WebRTC 防护外,它不会进行指纹伪装(Canvas / WebGL / UA / 时区 / 字体……),因此同一台机器上的多个身份仍会共用相同的浏览器指纹。如果平台根据指纹关联账号,单靠代理无法隐藏这一点。
代理解析(parseProxyInput / buildProxyRules)是 src/main/proxy.ts 中的纯函数,并经过单元测试,包括验证凭据不会泄露到规则字符串中。
遇到的问题
记录在这里,因为其中大多数问题没有任何文档说明。
CDP 端口按浏览器进程设置。 --remote-debugging-port 是进程级开关,没有对应的 webPreferences 设置,因此一个 Electron 应用恰好只有一个 CDP 服务端;无法为每个窗口分配独立端口。使用端口 0 让系统自动分配,然后从 userData/DevToolsActivePort 读取分配的端口——该文件会在成功绑定之前写入,因此还要探测 /json/version 以确认服务是否正常。
在 Electron 上,--pin-tab 会直接失败。 它会触发 Target.createTarget,而 Electron 会返回 Not supported。更糟的是,固定标签页的状态会持续保留:会话一旦使用过该功能,状态就会被持久化,即使执行 close --all 也无法清除,导致后续所有命令都无法正常工作。因此,每次调用都要显式传入 --no-pin-tab。
标题为空的页面目标会让 agent-browser 卡住。 如果 shell 窗口从未调用 loadURL,它在 CDP 中就会显示为 url 和标题均为空的页面目标;连接到该目标会一直卡住(tab list 不返回任何内容,甚至不会超时)。因此,shell 必须加载 about:blank 并设置一个易读的标题。
使用 about:blank,不要使用 data:text/html,<title>...——后者中的非 ASCII 标题会按 latin-1 解码,导致乱码。
设置标题也存在竞态:about:blank 加载速度很快,did-finish-load 可能会在监听器绑定之前触发;当多个身份同时打开时,标题就会停留在 about:blank。解决方法:同步调用一次 setTitle,加载后再调用一次。
绝不要通过标题、url 或标签页索引识别窗口。 多个身份打开同一网站时,标题和 URL 都相同;而且 CDP 目标的顺序与 agent-browser 的标签页索引顺序不匹配,因此也无法推算索引。只能使用 targetId。
**agent-browser 的技能内容会随版本变化——不要照抄网上的语法。**其自身的 SKILL.md 明确说明,其中不包含任何命令语法,必须通过 CLI 使用 skills get 获取。本项目就证明了这一点:网上找到的 tab --url "*settings*" 和 --pin-tab 在早期版本中并不存在,而 tab list --json 输出 targetId 是较新的功能——本项目的整套目标定位方案都基于它。
agent-browser 会从二进制文件所在位置向上搜索 skills/ 目录,这可能会与其他项目中同名的目录冲突。请显式传入 AGENT_BROWSER_SKILLS_DIR。
打包的二进制文件不能只依赖 asarUnpack。asarUnpack 会将文件放在 app.asar.unpacked/resources/bin/ 下,而 process.resourcesPath 指向 Contents/Resources——两者位置不同,因此打包后找不到二进制文件。使用 extraResources 使路径保持一致,并将 asarUnpack 限定为实际通过 ?asset 导入的文件,否则同一个二进制文件会被打包两次。
在 macOS 上,不能直接“跳过签名”。将 identity: null 设为 null 会让 electron-builder 完全跳过签名;应用包会保留 Electron 原有的 adhoc 签名,但资源已被修改,因此签名与内容不一致,应用会悄无声息地拒绝启动(没有错误,也没有日志;spctl 会报告 code has no resources but signature indicates they must be present)。正确做法是使用 identity: '-' 进行 adhoc 签名,并在 entitlements 中加入 com.apple.security.cs.disable-library-validation——entitlements 和 entitlementsInherit 都要设置,因为前者涵盖主进程。
**userData 目录取决于 package.json 的 name,而可执行文件取决于 productName。**这是两个不同的字段,而且 executableName 仅适用于 Windows——因此,如果它们不一致,你就会去错误的位置查找。本项目有意将两者都设为 Personae,以避免这种情况。(注意,在 Linux 上,文件系统区分大小写,因此以旧的小写名称创建的目录将无法被找到。)
**使用占位 URL 配置 publish: generic 会在打包的最后一步崩溃。**electron-builder 的模板将 provider: generic 和 url: https://example.com/auto-updates 配在一起。改用 provider: github 后,它会在打包结束时尝试推断发布渠道;由于缺少 owner/repo 上下文,会抛出 TypeError: Cannot read properties of null (reading 'channel')——构建其实已经完成,却仍以失败状态退出。本项目通过 CI 中的 gh release upload 发布,因此将 publish 设为 null 即可。
GitHub Actions 中作业级别的 if 无法访问 matrix 上下文。使用 if: inputs.platforms == matrix.name 来筛选平台会悄无声息地失败(actionlint 会提示 context "matrix" is not allowed here,但 GitHub 本身不会报错),因此无论输入是什么,都会构建所有平台。请在上游作业中生成矩阵 JSON,并通过 fromJSON 将其传给 strategy.matrix。
**使用 Electron 渲染 SVG 时,请抑制 window-all-closed。**图标脚本会循环执行“创建窗口 → 捕获 → 销毁 → 创建下一个窗口”,而每次 destroy() 都会将窗口计数降至零,默认情况下这会退出整个应用——表现为只处理完第一个尺寸就崩溃,子进程报告 No rendezvous client, terminating process (parent died?)。这看起来像是时序问题,但重试并无帮助。请注册一个空的 window-all-closed 处理程序。
另外还有两点:在 Retina 显示器上,capturePage 会按 devicePixelRatio 输出(请求 512 会得到 1024),因此要固定 zoomFactor / deviceScaleFactor;将中等长度的 SVG 内联到 data:text/html;base64,... 会超出 URL 长度限制,导致 loadURL 失败并返回 ERR_FAILED (-2),因此请使用临时文件并通过 file:// 引用。
已知限制和安全说明
- 隔离是一种约定,而非架构边界。 CDP 端口没有访问控制。它只在回环地址上使用随机端口进行监听,但任何连接到该端口的本地进程都能操控所有身份,跨越分区边界。这是允许外部 Agent 接入所付出的直接代价。请勿在共享设备上处理敏感账户。
- 普通链接会在当前窗口内导航。
setWindowOpenHandler会将window.open和target="_blank"链接转换为当前窗口内导航,以确保一个身份始终对应一个主目标。真正的弹出窗口(例如使用带功能参数的window.open打开的 OAuth 窗口)是例外——它们会作为受跟踪的子窗口打开;请参阅弹出窗口和 OAuth。 - 每个身份至少占用 3 个 CDP 页面目标(shell + 顶栏 + 内容),每个打开的弹出子窗口还会额外占用一个,因此规模大致会按身份数量的 3 倍增长。
- 捆绑的 agent-browser 版本在构建时固定;上游修复不会自动纳入。
- 运行时行为仅在 macOS(arm64)上经过验证,包括打包后的版本。Windows 打包可在 CI 中成功完成(macOS 和 Windows 均会构建并生成安装程序),但该应用从未在 Windows 上实际运行过,因此其运行时行为未经验证。Linux 不是构建目标。
bundle:ab仅为当前平台打包。 - 临时签名的构建版本不可分发:它们只能在构建机器上运行,在其他设备上会被 Gatekeeper 拦截。正式分发需要你自己的证书并进行公证。
- Codex 端尚未使用真实客户端验证:MCP 流程通过一个模拟客户端的脚本进行了测试(包括在无 Node 环境中测试打包后的版本),但从未使用实际的 codex 运行进行测试。
- 代理支持只会更改网络出口,不会更改指纹。 请参阅按身份设置代理——它不是反检测浏览器。
项目结构
src/main/
cdp.ts CDP port setup/discovery, targetId resolution
identity.ts identity storage, window lifecycle, nav-bar IPC, proxy
window-open.ts pure decision for window.open / target=_blank (unit-tested)
proxy.ts proxy input parsing → proxyRules (unit-tested)
secret-store.ts safeStorage-backed proxy password storage
url-input.ts address-bar input → URL normalization (unit-tested)
toml.ts TOML section splice for the Codex config (unit-tested)
agent-bridge.ts local HTTP bridge + discovery file
mcp-setup.ts one-click Codex configuration
index.ts main entry and IPC registration
src/shared/
colors.ts identity palette — imported by BOTH main and renderer,
so a window's top-bar dot always matches its list entry
src/preload/
index.ts main-window API
chrome.ts top-bar preload (navigation methods only)
src/renderer/
chrome.html navigation-bar UI
src/App.tsx identity management and connection panel
src/ProxyPanel.tsx per-identity proxy settings UI
src/agent-prompt.ts builds the copy-and-paste prompt for agents
src/assets/fonts/ self-hosted latin subsets (the CSP blocks
external font CDNs; CJK falls back to the system)
scripts/
mcp-server.mjs MCP server (stdio JSON-RPC)
bundle-agent-browser.mjs bundles the binary and core skill
make-icons.mjs SVG → PNG / icns / ico
test/
*.test.ts node:test unit tests for the pure modules above
design/logo/
icon.svg icon source (edit this, then run pnpm icons)
concept*.svg alternative concepts from the design pass
.github/workflows/
release.yml build and publish a GitHub Release (manual)
check.yml lint / typecheck / packaging smoke test (manual)
resources/bin/ 和 resources/skills/ 由 pnpm bundle:ab 生成,不纳入版本控制。
图标
源文件为 design/logo/icon.svg——三张互不重叠的彩色卡片代表三个隔离的身份,指针则代表 Agent 控制。编辑 SVG 后,请为所有平台格式重新生成图标:
pnpm icons
这会生成 build/icon.png(1024)、build/icon.icns、build/icon.ico 和 resources/icon.png(512,即运行时窗口图标)。
图像通过Electron 内置的 Chromium渲染,因此无需 rsvg-convert / Inkscape / ImageMagick——这些工具在干净环境中通常并不存在,而 Electron 本来就是本项目的依赖项。.icns 由系统的 iconutil 组装;.ico 则逐字节写入。
发布
这两个工作流都只能手动运行(workflow_dispatch),不会在推送或标记时运行。
在 GitHub 上进入 Actions,选择一个工作流,然后点击 Run workflow:
| 工作流 | 用途 | 输入 |
|---|---|---|
| Build & Release | 构建 macOS + Windows,创建发布 | version(可选)、platform(all / macos / windows)、create release、prerelease |
| Check | lint + 类型检查 + 打包冒烟测试 | 是否运行打包 |
创建的发布为草稿;请检查各项资源,然后自行点击 Publish。如果标记已存在,资源会追加到该标记(--clobber 会覆盖同名文件),因此重新运行不会直接失败。
发布不会使用 electron-builder 自带的发布步骤(electron-builder.yml 中的 publish: null);而是由单个汇总作业使用 gh release upload 上传所有内容,因为如果三个平台并行运行,它们都会尝试创建同一个发布并互相覆盖。
当 Build & Release 工作流创建发布时,它还会将版本匹配的 @leek-emperor/personae-mcp stdio 启动器发布到 npm,然后使用官方 mcp-publisher CLI 发布 server.json。首次发布前,请设置仓库的 NPM_TOKEN 密钥(具有发布该公开软件包权限的 npm 自动化令牌);MCP Registry 身份验证使用 GitHub OIDC,无需单独的密钥。
CI 生成的 macOS 构件也会进行临时签名。如需正式签名,请将 CSC_LINK / CSC_KEY_PASSWORD 添加到仓库密钥,并在 electron-builder.yml 中将 notarize 设为 true。
许可证
MIT — 请参阅 LICENSE。
捆绑的 agent-browser 采用 Apache-2.0 许可证;版权归其作者所有。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。