mcpField
T
Tenant Pair

Tenant Pair

本地服务
matthiasmeyer.tech开发工具01 周前更新

关于 Tenant Pair

Tenant Pair 是面向伴侣、家庭和小组共享状态场景的 TypeScript 库及参考 MCP 服务,支持身份隔离。它提供双时态存储、可配置冲突处理,以及 SQLite 和 Postgres 适配器。

主要功能

  1. 01创建关系组并邀请成员
  2. 02区分成员状态与共享状态
  3. 03记录双时态状态历史
  4. 04可插拔的冲突处理
  5. 05SQLite 和 Postgres 存储适配器

适用场景

  1. 01为消费类 MCP 服务加入多成员状态
  2. 02追踪共享状态的时间变化
  3. 03选择策略处理并发更新

MCP 相关

参考实现通过 stdio 暴露 12 个工具,涵盖关系组管理、成员偏好和共享状态操作。该库本身不依赖传输方式。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"tenant-pair": {
"command": "npx",
"args": [
"-y",
"mcp-tenant-pair-cli"
]
}
}
}
启动命令npx -y mcp-tenant-pair-cli

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmmcp-tenant-pair-cli

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

属于 StudioMeyer MCP Stack 的一部分 — 在 Mallorca 🌴 构建 · 如果你在使用,欢迎点 ⭐

mcp-tenant-pair

npm version npm downloads License Last commit GitHub stars 面向消费级 MCP 服务中多用户租户管理(伴侣、家庭、小型群组)的基础库和参考 MCP 服务。支持身份隔离状态、双时态存储和冲突解决器接口。

规范: MCP 2025-06-18 许可证: MIT 仓库布局: monorepo(npm workspaces)

packages/
  lib/        mcp-tenant-pair          (TypeScript library)
  cli/        mcp-tenant-pair-cli      (commander CLI)
  demo/       mcp-tenant-pair-demo     (reference Low-Level MCP server, stdio)

我们想说的话

过去两年,我们一直在为自己构建工具和系统。这个仓库规模小、星标少,并不是因为它刚刚诞生,而是因为我们最近才决定分享自己的成果。这不是一次全新的实验,而是一段漫长历程的最新提交。

我们喜欢构建和分享东西,但不喜欢社交媒体策略、增长技巧,也不热衷于追逐星标和关注者。所以这个仓库规模不大。代码是真实的,也有人在用,问题也会得到回复。请自行判断。

如果它对你有帮助,分享、测试和反馈都会给我们带来帮助。如果你觉得它还有改进空间,提一个 issue 会更有用。如果你用它构建了什么,请发邮件告诉我们:[email protected]。这真的会让我们开心一整天。

来自 Palma de Mallorca 的一家小型工作室。

为什么要做这个

如今大多数 MCP 服务都是单用户的。一旦你想要在两个或更多人(伴侣、家庭、小型群组)之间共享状态,就会一次又一次遇到同样的五个子问题:创建配对、邀请流程、身份隔离状态、冲突解决、自愿退出 / 移除成员。这个库一次性解决这些问题,让下游 MCP 服务(Pet-Platform、食谱共享、家庭管理、日历)无需重复造轮子。

5 分钟快速入门

库
import { TenantPair, SqliteTenantStore, LWWResolver } from "mcp-tenant-pair";

const tp = new TenantPair({
  store: new SqliteTenantStore({ path: "./tenant-pair.sqlite" }),
  resolver: new LWWResolver(),
});

const { pairId, inviteToken } = await tp.createPair({ creatorMemberId: "alice" });
await tp.acceptInvite({ inviteToken, memberId: "bob" });

await tp.setMemberPreference(pairId, "alice", "allergy", ["nuts"]);
await tp.setSharedState(pairId, "alice", "tonight", "pizza");

const aliceConstraints = await tp.getMemberConstraints(pairId, "alice");
const shared = await tp.getSharedState(pairId);
命令行界面
npx mcp-tenant-pair-cli pair create --member-id alice
npx mcp-tenant-pair-cli pair invite --pair-id <id> --member-id alice
npx mcp-tenant-pair-cli state set --pair-id <id> --member-id alice --key tonight --value pizza
npx mcp-tenant-pair-cli state get --pair-id <id>
演示 MCP 服务
node packages/demo/dist/server.js
# or via stdio in your MCP client config

读取 MCP_TENANT_PAIR_DB 环境变量(默认值为 :memory:)。

工具(12 个)

工具readOnlyHintdestructiveHint
create_pairfalsefalse
invite_memberfalsefalse
accept_invitefalsefalse
list_memberstruefalse
set_member_preferencesfalsefalse
get_member_constraintstruefalse
get_shared_statetruefalse
set_shared_statefalsefalse
resolve_conflictsfalsetrue
kick_memberfalsetrue
leave_pairfalsetrue
forget_memberfalsetrue

兼容性矩阵

方面支持情况
MCP 规范2025-06-18
Node使用需要 >= 20.0.0。构建此仓库需要 20.19+ 或 22.12+(Vite 8)。
存储SQLite(默认)、Postgres(peer-dep)
冲突解决器LWWResolver(默认)、ManualResolver、自定义(接口)
传输方式stdio(演示版),库不依赖传输方式

存储适配器

  • SqliteTenantStore — 默认选项,嵌入式,单进程。使用 better-sqlite3 和 WAL 模式。传入 { path: "./pair.sqlite" } 或 :memory:。
  • PostgresTenantStore — 支持多进程、多租户。接受任何形状符合 pg.Pool 的客户端({ query<R>(text, params): Promise<{rows: R[]}>, end?(): Promise<void> })。pg 是同级依赖。

冲突解决

ConflictResolver 是一个接口。提供了两种实现:

  • LWWResolver — 选择 validFrom 最新的行;若相同,则选择 version 最高的行。候选列表为空时抛出异常。
  • ManualResolver — 不返回任何解决结果;冲突会保持待处理状态,直到由外部人员解决。

实现 { name: string; resolve(conflicts: Conflict[]): Resolution[] } 即可注入自定义实现。

双时态模型

每次覆盖 (pairId, namespace, key) 三元组时,都会为之前的活动行设置 valid_to,并插入一条具有新 valid_from 的新行。version 在每个键内单调递增。这样即可重放历史记录(getPairStateHistory),并以确定性的方式检测并发写入。

身份隔离

member_state 按成员划分(仅该成员可通过 get_member_constraints 读取)。 pair_state 为共享状态(所有活跃成员均可通过 get_shared_state 读取)。

成员离开或被移出后,其写入仍会保留在共享状态中。

安全说明

  • 邀请令牌格式为 <uuid v4>.<XXXX-XXXX> — uuid v4(通过 node:crypto 提供 122 位 CSPRNG 熵),加上便于语音读取的 base32 短码(默认 RNG 为 node:crypto.randomInt,可注入以便测试)。
  • 每个 pair 的待处理邀请数量上限(默认为 25,可通过 maxPendingInvites 配置)。
  • 仅所有者可以移出成员。所有者不能移出自己;请改用离开操作。
  • DSGVO 第 17 条擦除路径:forgetMember(pairId, memberId) 会硬删除该成员的 member_state 行(过敏信息、饮食偏好),并将 display_name 设为 null。成员关系记录(left_at)会保留以供审计。
  • Postgres 适配器在构造时会拒绝不匹配 /^[a-z_][a-z0-9_]{0,62}$/ 的 schema 名称(防止通过集成方提供的 schema 字符串进行 SQL 注入)。
  • acceptInvite 具备竞态安全性 — 两种适配器都使用原子事务(better-sqlite3 即时事务;pg BEGIN + SELECT ... FOR UPDATE)。
  • 时间可注入(now: () => Date),以便进行确定性测试。

开发

npm install
npm run build
npm test

测试覆盖(142 项 + 1 项条件测试):

  • Pair 创建(8)
  • 邀请流程(10)
  • 邀请过期边界(6)— 在 expires_at 的精确时刻,两种适配器的 accept/pending 结果一致
  • 成员偏好(8)
  • 共享状态(8)
  • 冲突解决(13)
  • 解决器(11)
  • 错误处理(17)— 全面覆盖 TenantPairError 代码
  • 存储适配器(6)
  • Postgres 适配器(26)— schema 标识符验证、原子事务、回退路径(模拟池,无实时数据库)
  • 适配器一致性(6 + 1)— 对 SQLite 和 Postgres 执行相同操作会产生相同结果;仅当 TENANT_PAIR_TEST_PG_URL/DATABASE_URL 指向可连接的数据库时才会运行 Postgres 部分,否则跳过(绝不会误报失败)
  • Demo 服务集成(9)
  • 第一轮回归修复(14)— SQL 注入 schema 验证、TOCTOU acceptInvite 竞态、冲突解决胜者标记、asOf 时钟、DSGVO 擦除、CSPRNG 默认值

针对真实 Postgres 运行跨适配器一致性测试套件:

TENANT_PAIR_TEST_PG_URL=postgres://user:pass@host:5432/db npm test

状态

基础版本构建。已审核(Cold-Cross-Review + MCP Factory Reviewer + Tester)— 所有 HIGH/MEDIUM 级问题均已修复。tsc 检查通过(strict),142 项测试通过(+1 项 Postgres 条件跳过)。生产依赖树中没有已知安全公告(npm audit --omit=dev)。

关于 StudioMeyer

StudioMeyer 是一家位于马略卡岛帕尔马、服务全球客户的 AI 与设计工作室。我们为中小型企业打造定制网站和 AI 基础设施。生产技术栈基于 Claude Agent SDK、MCP 和 n8n,并使用 Sentry、Langfuse 和 LangGraph 实现可观测性,同时配备自研防护层。

评论

支持 Markdown

第一次接触 MCP?

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

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