mcpField
P
Patina

Patina

远程服务
patinadata.xyz安全15 周前更新

关于 Patina

Patina 将账户活动日期转化为可携带的证据,用于说明一个人持有在线账户的时长。它面向需要评估账户年限的服务;分数反映历史时长,不代表一个人是否独一无二。

主要功能

  1. 01汇总八个来源的账户历史日期
  2. 02根据年限、连续性和相互印证等因素评分
  3. 03丢弃账户内容,仅保存按月归整的日期
  4. 04生成可离线验证的签名证明
  5. 05通过 MCP 服务提供分数

适用场景

  1. 01在注册或资格审核流程中评估账户年限
  2. 02将历史证据与其他 Sybil 抵抗检查结合
  3. 03无需联系 Patina 即可验证签名分数
  4. 04通过句柄让 AI Agent 查询账户年限

MCP 相关

MCP 服务向对话中的 AI Agent 提供账户年限分数。句柄解析器可在不披露身份的情况下返回账户年限。

配置

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

服务地址https://patinadata.xyz/api/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 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

4
参数类型必填说明
usernamestring是此人的 Patina 用户名,与 patinadata.xyz/u/<username> 中显示的一致。

详细介绍

Patina

Patina

证明用户对自己已有账户的持有时长
任何人都能创建新账户,但没人能创建旧账户。

在线应用 • 文档 • MCP 服务 • 验证评分

概览 • 评分 • 隐私 • 架构 • 快速开始 • 集成 • 测试结果


在线部署

界面URL
应用patinadata.xyz
文档patinadata.xyz/docs
MCPpatinadata.xyz/api/mcp
验证器patinadata.xyz/verify
注册表io.github.ramakrishnanhulk20/patina
签名地址0x3989bdFaf3BA242d27B4D0cEed98F446d0c52DAD

概览

Patina 会读取用户已有账户中的历史记录,并将其转化为可移植、可验证的证据,证明一个真实的人多年来一直在使用这些账户。它基于数据可移植协议 Vana 构建:数据存放在用户自己的个人服务器中,在用户可撤销的授权下读取一次,并且绝不会经由会保留数据的 OAuth 授权流程传递。

女巫攻击防护问题尚未解决,成本也很高。空投、二次方资助轮次、DAO 投票或免费试用,都需要知道面对的是一千个人,还是一个拥有一千个钱包的人。常见的解决方案效果不佳:生物识别会侵犯隐私,KYC 会破坏隐私,而大多数行为信号都能直接买到。

运营账户农场的人可以购买关注者、批量上传帖子,还能填出一份令人信服的个人资料。但他们买不到十年历史。

为什么选择 Patina?
KYCWorld ID / 人格证明Patina
证明多年历史否否是
证明你是独一无二的人部分是否
无需钱包即可使用是否是
无需生物识别即可使用是否是
用户之后可以撤销访问权限否否是
其他应用可以复用该证明否是是

Patina 证明的是持有时长,而非独特性。今天就能验证一个刚出现的独一无二的人;但无法凭空产生十六年的佐证活动记录。两者相辅相成,工具描述也会明确说明这一点,而不会暗示相反的结论。


功能

所有权有证据,而非凭空假定

数据采集通过 Vana Desktop 进行:它会在用户自己的设备上打开浏览器,并要求用户登录。凭据不会离开设备,Patina 也不会看到密码。

但 Vana 有两种数据采集路径,且不会报告使用了哪一种。另一种路径会通过个人资料 URL 读取公开页面,这只能证明账号存在,无法证明账号由谁持有。因此,不能只要求“仅限桌面端”,而必须强制执行。

所以,每个数据来源都必须要求一个公开页面无法提供的范围;如果没有返回该范围,就会拒绝读取。LinkedIn 必须返回建立联系的日期,Spotify 必须返回已保存的曲目,YouTube 必须返回“稍后观看”列表。公开个人资料无法提供私密信息,因此用户最终会使用 Desktop 并登录。如果添加数据来源时没有提供一个此类范围,sources.test.ts 就会报错。

Steam 因同样的原因被移除。它的连接器不会让任何人登录:它只需 Steam Web API 密钥和 Steam ID,而 Steam ID 是公开的。任何人都可以把陌生人的账号年龄和好友日期当作自己的信息交给 Patina;与 YouTube 不同,Steam 没有可要求提供的私密范围。

Instagram 因相关原因已暂停。它的证明范围 instagram.posts 是 Vana 的服务器从公开页面采集的,因此读取只能证明账号存在,无法证明账号由谁持有;Instagram 也没有 Patina 可以要求提供的私密范围。我们不会提供 Instagram;Vana 的两条路径都会在花费任何费用前拒绝它;句柄解析器不会查询它;已存储的 Instagram 数据也会从所有评分中排除。等手机应用的已登录证明功能上线后,它就会恢复。

八个数据来源,十七个范围

GitHub、LinkedIn、Spotify、YouTube、Amazon、Uber、DoorDash 和 Shop。每个数据来源的所有范围都会放在同一次授权中,因此整个清单需要进行八次授权,而不是十七次。

只保留时间戳,不保留内容

每个范围都会请求日期信息。说明文字、地址、电子邮件、曲目名称、游戏名称以及其他人的姓名都会在存储任何内容前被丢弃;如果其中任何内容进入存储,测试就会报错。

已签名、可移植且有时效

每个非临时评分都附带一份 EIP-191 证明,任何人都可以使用 Patina 公布的地址离线验证。无需密钥,无需 OAuth,CORS 开放。

证明会在三十天后过期;过期时间包含在签名消息中,而非单独存放,因此验证时效性也可以离线完成。撤销列表也能解决同样的问题,但这会要求每个验证者都调用 Patina,而这恰恰是人们集成它时想要避免的依赖。评分使用与持有托管余额的密钥分开的密钥签名,因此一个密钥泄露不会导致另一个也泄露。

能说明自身状态

/api/health 会对数据库进行真实的写入和读取,并实时读取托管余额;如果部署无法为下一位用户提供服务,就会返回 503。这样,常规运行时间监控无需了解具体检查内容,也能发现故障。受密码保护的 /admin 会显示转化漏斗、用户数量,以及余额还能支持多少次连接。转化漏斗统计在服务器端完成:没有第三方脚本,没有 Cookie 横幅,也没有任何与隐私页面相矛盾的内容。

便于 Agent 读取

MCP 服务可在对话过程中向 AI Agent 提供评分,并通过句柄解析器返回账号使用时长,而不泄露身份。


评分

六个组成部分,权重依据各项在时间而非金钱上的成本。

组成部分最高分衡量内容
资历30所有已连接来源中能够证实的最早日期。满分对应十二年。
连续性25此人实际活跃的不同月份数,按绝对数量乘以覆盖率计算。
佐证15独立来源对日期的认同,每个来源按其自身资历加权。
背书12其他人选择建立连接的时间,而非人数。按距今时间加权。
深度10实际创作的内容;如果内容量集中在一阵子内产生,则会折减。
广度8相互佐证的独立账号。

资历和两个时间组成部分直接计分。深度、背书和广度则受它们限制:攻击者可以在一个下午里伪造内容量、朋友和广度,因此只有在真实经历提供支撑的范围内,这些项目才计分。15% 的最低分可避免真正年轻的人仅仅因为十九岁就被压到零分。

根据参考档案进行评分,断言见 score.test.ts:

档案得分
跨四个账号活跃十一年95
普通情况:十一年、两个账号、确有空档期71
真正年轻:三年、两个账号、真实情况26
账号农场:3,900 个购买的关注者,一周内发布 120 条内容2

普通人与账号农场之间相差 69 分。这一差距正是本产品的价值所在。

诚实说明局限

这些说明会直接展示在网站上,而不是藏在这里:

  • 无法证明真人身份。 它报告的是能够看到多少真实经历。这是证据,不是证明书。
  • 低分不代表被指控。 年轻、私密或不活跃的账号得分较低,但这并不意味着他们做错了什么。
  • 老账号可以被购买。 这会把免费攻击变成昂贵攻击,且成本会随账号资历增长。这并不意味着攻击不可能。
  • 桌面应用能证明会话控制权,而非所有权。 买来的账号附带密码。门槛从“知道用户名”提升到“持有凭据”,这是很大的进步,但两者并非一回事。
  • 证明范围是底线,不是保证。 要求提供某些私密信息,能迫使用户真正登录;但真正登录仍然只是一次登录。这项要求排除的是有人给陌生人的公开档案打分,而这正是会让整个分数失去意义的问题。

读取和保留的内容

下面列出的每项权限范围都会因其时间戳而被请求。此表体现了我们的信任依据,因此隐私页面上也会以大致相同的形式呈现。

权限范围保留内容收到后立即丢弃
linkedin.connectionsdateConnected[]、数量姓名、标题、个人档案 URL
instagram.postsInstagram 暂停期间不接收新数据;已持有的数据不参与评分说明文字、图片、点赞、整个 who_liked[] 数组
spotify.savedTracksadded_at[]、总数曲目名称、艺人、专辑
github.historycreatedAt[]、哈希处理后的仓库、汇总后的互动量PR 和 issue 的标题及正文
linkedin.experience / education解析后的日期范围公司、职位名称、学校、成绩
uber.tripsrequestTime[]、数量上车和下车地址、费用、城市
amazon / doordash / shop 订单日期、数量商品、商家、总金额、配送地址
youtube.profilejoinedDate、数量电子邮箱地址
youtube.watchLater不保留任何内容所有内容;仅将其作为已登录会话的证明进行请求

时间戳在存储前会折叠为月份区间。评分器只会查询月份,因此保留更精细的数据毫无必要。


架构

连接流程
graph LR
    U[User] -->|1 Connect| P[Patina]
    P -->|2 createAccessRequest<br/>all scopes for one source| V[Vana Account API]
    V -->|3 approval URL| U
    U -->|4 Open in Vana Desktop| D[Vana Desktop]
    D -->|5 Playwright signs in<br/>on the user's machine| S[Source]
    S -->|6 import| PS[Personal Server]
    P -->|7 read every scope<br/>one grant| PS
    P -->|8 settle 402| E[Escrow Gateway]
    P -->|9 normalise, discard, score| R[(Redis)]
读取并结算
sequenceDiagram
    participant App as Patina
    participant PS as Personal Server
    participant GW as Escrow Gateway

    App->>PS: GET /v1/data/{scope}
    PS-->>App: 402 with accessRecord
    App->>GW: authorizeGrantPayment(accessRecord)
    GW-->>App: receipt
    App->>PS: GET /v1/data/{scope}
    PS-->>App: 200 payload
    Note over App: repeat per scope, same grant
    App->>PS: acknowledgeRead (once, at the end)

acknowledgeRead 会将请求移至 completed,这是终态,不再处于可读取状态。如果在第一个范围读取后就触发它,用户付费后,剩余内容就会因 Personal Server 不再提供服务而无法读取。

评分流程
graph LR
    RAW[Raw payload] -->|readScope| F[Fragment<br/>months + counts]
    F -->|stored by scope| DB[(Redis)]
    DB -->|evidenceFrom| EV[Evidence]
    EV -->|scorePatina| SC[Score]
    EV -->|buildStory| ST[Story]
    SC -->|buildAttestation| AT[Signed attestation]

片段按范围作为键存储,并在评分时合并。重试读取时会覆盖对应片段,而不是再次累加其中的月份,因此连接不稳定也不会虚增分数。


快速开始

前置条件
  • Node 20+
  • 从 account.vana.org/developers 获取的 Vana 应用身份
  • Upstash Redis 凭据(本地使用时可选;未提供时会回退到内存存储)
安装
git clone https://github.com/ramakrishnanhulk20/Patina.git
cd Patina
npm install
cp .env.example .env.local

填写 VANA_APP_PRIVATE_KEY 和 VANA_APP_URL,然后注册应用并为其托管账户注资:

npm run register:moksha
开发
npm run dev          # development server
npm test             # 118 tests
npm run typecheck    # types, ignoring generated route types
npm run verify       # typecheck + tests + production build

集成

REST

查询任何公开评分,无需密钥或 OAuth:

curl https://patinadata.xyz/api/verify/ramkumar
{
  "username": "ramkumar",
  "score": 71,
  "verdict": "Well established",
  "oldestYear": 2012,
  "yearsOfHistory": 13.6,
  "sourcesConnected": ["github", "linkedin", "spotify"],
  "provisional": false,
  "issuedAt": "2026-08-26T12:00:00.000Z",
  "expiresAt": "2026-09-25T12:00:00.000Z",
  "attestation": {
    "app": "0x...",
    "message": "Patina score attestation

username: ramkumar
score: 71/100
...
expiresAt: 2026-09-25T12:00:00.000Z
app: 0x...",
    "signature": "0x...",
    "expiresAt": "2026-09-25T12:00:00.000Z"
  }
}
离线验证证明
import { verifyMessage } from "viem";

const ok = await verifyMessage({
  address: "0x3989bdFaf3BA242d27B4D0cEed98F446d0c52DAD",
  message: attestation.message,
  signature: attestation.signature,
});
MCP
{
  "mcpServers": {
    "patina": {
      "type": "http",
      "url": "https://patinadata.xyz/api/mcp"
    }
  }
}
工具用途
get_patina_score获取 Patina 用户名的完整评分明细
check_threshold根据年数、评分或来源数量进行是/否信任判断
resolve_identity将 GitHub 或 LinkedIn 用户名映射到评分,同时不泄露身份。Instagram 查询已暂停
verify_attestation验证签名是否确实来自 Patina

测试结果

174 passing
测试套件测试数覆盖范围
normalize.test.ts30信封结构、丢弃保证、幂等性
score.test.ts27每个组成部分、门槛、参考档案
store.test.ts26跨设备身份、用户名、移除单个来源、删除
mcp-lookup.test.ts20解析器的隐私规则、签名、判定偏移
story.test.ts19时间线、活动、佐证材料、历史记录不足时的文案
routes.test.ts15真实 HTTP 请求:会话、签名下限、管理员门槛
device.test.ts12哪些设备可以完成连接
attest.test.ts10签名、过期、密钥隔离、已发布地址偏移
sources.test.ts9所有权不变量:不得通过公开页面查询任何来源
ratelimit.test.ts4托管账户滥用限制
altcha.test.ts2工作量证明机器人检查

最值得了解的一项测试是:nothing sensitive survives normalisation。它会输入一份包含看似真实的电子邮件地址、两个家庭住址、一段说明文字、一位同事的全名和 LinkedIn URL、一款游戏的名称、一家雇主、一首歌、一件产品和一家餐厅的载荷,然后断言这 13 项内容均不会出现在任何保存的数据中。


项目结构

src/
├── app/
│   ├── api/
│   │   ├── vana/          request + data: the connect spine
│   │   ├── patina/        me, username, data, restore, delete
│   │   ├── admin/         session, index rebuild
│   │   ├── verify/        public score lookup
│   │   ├── badge/         embeddable SVG badge
│   │   └── mcp/           MCP server
│   ├── connect/           the evidence board, and the phone handoff
│   ├── my-data/           see it, download it, remove any of it
│   ├── admin/             the funnel, the numbers, the money left
│   ├── u/[username]/      public page and story
│   ├── verify/            verifier, including an offline checker
│   └── docs/              integration reference
└── lib/
    ├── score.ts           the whole argument, weight by weight
    ├── normalize.ts       18 scopes in, timestamps out
    ├── sources.ts         the manifest, and the proof scope each source must return
    ├── device.ts          whether this device can finish a connection at all
    ├── vana.ts            app identity, one controller per source
    ├── vana-settle-read.ts  paid reads, escrow settlement
    ├── escrow-balance.ts  how many more connections the balance will fund
    ├── metrics.ts         the funnel, counted server-side and nowhere else
    ├── store.ts           profiles keyed on Personal Server identity
    ├── admin.ts           one operator, one password, fails closed
    ├── story.ts           evidence as a narrative, and exhibits
    ├── attest.ts          signed attestations, expiring, on their own key
    └── mcp-lookup.ts      what an agent is allowed to learn

src/lib/score.ts 是整套论证的核心。每个权重都有注释解释其设定依据。


技术栈

层选择
框架Next.js 16、React 19、App Router
语言TypeScript
样式Tailwind CSS 4、自定义令牌层
数据Vana Data Portability Protocol(@opendatalabs/vana-sdk)
存储Upstash Redis、内存回退方案
签名viem、EIP-191
AgentModel Context Protocol(mcp-handler)
滥用防护ALTCHA 工作量证明、按会话限流
测试node:test,无测试框架

许可证

MIT,详见 LICENSE。


致谢

本项目基于 Vana 及其 Data Portability Protocol 构建。连接器来自 PDP-Connect/data-connectors。品牌图标来自 Simple Icons 和 Font Awesome 的免费品牌图标集,均以内联方式提供,因此应用不会发出外部请求。

评论

支持 Markdown

第一次接触 MCP?

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

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