mcpField
P
Patina

Patina

リモート
patinadata.xyzセキュリティ15 週間前に更新
リポジトリ公式サイト

Patina について

Patinaは、アカウント活動の日付から、オンラインアカウントの利用期間を示す持ち運び可能な証拠を作成します。アカウントの利用歴を評価するサービス向けで、スコアが示すのは利用期間であり、個人の一意性ではありません。

主な機能

  1. 018つの情報源からアカウント履歴の日付を集約
  2. 02経過年数、継続性、裏付けなどをスコア化
  3. 03アカウント内容を破棄し、月単位の日付を保存
  4. 04オフライン検証可能な署名付き証明を作成
  5. 05MCP サーバー経由でスコアを提供

活用シーン

  1. 01登録や利用資格の確認でアカウント歴を評価
  2. 02他のSybil耐性チェックと履歴証拠を併用
  3. 03Patinaへの問い合わせなしで署名付きスコアを検証
  4. 04ハンドルを使い、AIエージェントから利用期間を照会

MCP 対応

MCPサーバーは、会話中にAIエージェントがアカウント利用期間のスコアを取得できるようにします。ハンドル解決機能は、本人の身元を明かさずに利用期間を返します。

設定

リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。

エンドポイント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はいpatinadata.xyz/u/<username> に表示されている、その人の Patina ユーザー名。

詳細

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 はプライバシーを損ない、行動に関するシグナルの大半は簡単に買えてしまいます。

アカウントファームを運営する人は、フォロワーを買い、投稿を一括アップロードし、もっともらしいプロフィールを作成できます。しかし、10年分の履歴を買うことはできません。

Patina を選ぶ理由
KYCWorld ID/実在人物の証明Patina
長年にわたる履歴を証明いいえいいえはい
唯一無二の人物であることを証明一部はいいいえ
ウォレットなしで利用可能はいいいえはい
生体認証なしで利用可能はいいいえはい
ユーザーが後からアクセスを取り消せるいいえいいえはい
別のアプリで証明を再利用可能いいえはいはい

Patina が証明するのは一意性ではなく、利用期間です。唯一無二の人間であることが確認された人を今日生み出すことはできますが、16年にわたる裏付けのある活動を生み出すことはできません。この2つは互いを補完するものであり、ツールの説明でも、そうでないかのように示すのではなく、その点を明記しています。


特徴

所有者を推測ではなく証明

コレクションはVana Desktop経由で実行される想定です。Vana Desktopはユーザー自身のマシンでブラウザーを開き、サインインを求めます。認証情報がデバイスの外に出ることはなく、Patinaがパスワードを見ることもありません。

ただし、Vanaには2つのコレクション経路があり、どちらを使ったかは報告されません。もう一方は、プロフィール URL から公開ページを読み取ります。これでアカウントの存在は証明できますが、誰がそのアカウントを持っているかは証明できません。つまり、「デスクトップ限定」と求めるだけでは不十分で、強制する必要があります。

そのため、各ソースでは公開ページでは取得できないスコープを1つ必須とし、その情報が返ってこない場合は読み取りを拒否します。LinkedInではつながった日付、Spotifyでは保存したトラック、YouTubeでは「後で見る」リストが必要です。非公開情報を含むリクエストには公開プロフィールから回答できないため、ユーザーはDesktopに移り、ログインする必要があります。ソースを追加した際にこれが満たされていなければ、sources.test.tsが失敗します。

Steamも同じ理由で取り下げました。そのコネクターは誰にもサインインを求めません。Steam Web APIキーとSteam IDを受け取りますが、Steam IDは公開情報です。誰でも他人のアカウントの利用年数やフレンドになった日付を、自分のものとしてPatinaに渡せました。YouTubeとは違い、代わりに必須にできる非公開スコープもありませんでした。

Instagramは関連する理由で一時停止中です。証明スコープのinstagram.postsは、Vanaのサーバーが公開ページから収集するものです。そのため、読み取りで証明できるのはアカウントの存在だけで、誰がそのアカウントを持っているかは証明できません。また、Patinaが代わりに必須にできる非公開スコープもInstagramにはありません。Instagramは提供されず、Vanaのどちらの経路でも費用が発生する前に拒否され、ハンドルリゾルバーも検索せず、すでに保存済みのInstagramデータもすべてのスコアから除外されます。スマートフォンアプリによるサインイン済みの証明が実現したら、再開します。

8つのソース、17のスコープ

GitHub、LinkedIn、Spotify、YouTube、Amazon、Uber、DoorDash、Shopです。各ソースのスコープはすべて1回の承認にまとめられるため、マニフェスト全体で承認は17回ではなく8回です。

タイムスタンプのみを取得し、コンテンツは破棄

各スコープでは日付を取得します。キャプション、住所、メールアドレス、トラック名、ゲームタイトル、他人の名前などは、保存する前に破棄されます。これらがストアに届いた場合はテストが失敗します。

署名付き、ポータブル、期限付き

暫定スコア以外のすべてのスコアには、誰でもオフラインでPatinaの公開アドレスを照合して検証できるEIP-191アテステーションが付与されます。キー不要、OAuth不要、CORSはオープンです。

アテステーションには30日で期限が切れます。期限は署名メッセージの外側ではなく内側に含まれるため、有効期間の確認もオフラインで行えます。失効リストを使えば同じ問題を解決できましたが、そうするとすべての検証者がPatinaに問い合わせる必要があり、これはユーザーが連携を避けるためにまさに解消しようとしている依存関係です。スコアの署名にはエスクロー残高を保持するキーとは別のキーを使うため、一方が漏えいしても、もう一方まで漏えいすることはありません。

自身について回答可能

/api/healthはデータベースへの実際の書き込みと読み取り、およびエスクロー残高のライブ読み取りを実行します。デプロイ環境が次のユーザーに対応できない場合は503を返すため、通常の稼働監視で、何を確認すべきか事前に教えなくても障害を検出できます。パスワードで保護された/adminでは、ファネル、ユーザー数、残高であと何件の連携に資金を提供できるかを確認できます。ファネルの集計はサーバー側で行います。サードパーティのスクリプトも、Cookieバナーも、プライバシーページの内容と矛盾するものもありません。

エージェントから読み取り可能

MCP サーバーが会話の途中でAIエージェントにスコアを公開します。また、本人を特定せずに利用期間を返すハンドルリゾルバーを備えています。


スコア

6つの要素で構成され、それぞれの重みは金額ではなく、かかる時間に基づいています。

要素最大点測定する内容
経過年数30接続されたすべてのソースを通じて証明できる最も古い日付です。12年で満点になります。
継続性25実際に本人が利用していた月の数に、カバー率を掛けた値です。
裏付け15日付が独立したソース間で一致する度合いです。各ソースの経過年数に応じて重み付けします。
推薦12他の人がつながりを選んだ「時期」であり、人数ではありません。どれだけ前のことかに応じて重み付けします。
深さ10実際に作成したものを測定します。短期間にまとめて作成された場合は割り引かれます。
幅広さ8互いに裏付け合う独立したアカウントの数です。

経過年数と2つの時間要素は、そのまま得点になります。深さ、推薦、幅広さには条件があります。攻撃者は午後のうちに活動量や友人、幅広さを捏造できるため、実際に経過した期間による裏付けがある範囲でのみ加点されます。最低点を15%にすることで、本当に若い人が19歳であるというだけでゼロにされるのを防ぎます。

score.test.ts で定義された参照プロフィールに対するスコアです。

プロフィールスコア
4つのアカウントで11年間活動95
一般的な例:11年間、2つのアカウント、実際の空白期間あり71
本当に若い人:3年間、2つのアカウント、実際の活動26
アカウントファーム:購入したフォロワー3,900人、1週間で投稿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 アプリの ID
  • 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_scorePatina ユーザー名の詳細な内訳を取得します
check_threshold年数、スコア、またはソース数を基準に信頼性を可否判定します
resolve_identityGitHub または LinkedIn のハンドルからスコアを取得します。本人の特定につながる情報は開示しません。Instagram の検索は一時停止中です
verify_attestation署名が本当に Patina のものかを検証します

テスト結果

174 passing
スイートテスト数対象
normalize.test.ts30エンベロープの形式、破棄の保証、冪等性
score.test.ts27各コンポーネント、ゲーティング、参照プロフィール
store.test.ts26デバイス間の ID、ユーザー名、ソースの個別削除、削除処理
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 は、実在しそうなメールアドレス、自宅住所 2 件、キャプション、同僚の氏名と 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
エージェントModel Context Protocol(mcp-handler)
不正利用対策ALTCHA プルーフ・オブ・ワーク、セッションごとのレート制限
テストnode:test、フレームワーク不使用

ライセンス

MIT。詳細は LICENSE をご覧ください。


謝辞

Vana と、その Data Portability Protocol を基盤に構築されています。コネクターは PDP-Connect/data-connectors のものを使用しています。ブランドグリフは Simple Icons と Font Awesome の無料ブランドセットから取得し、アプリが外部にリクエストを送信しないよう、どちらもインライン化しています。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。