Skip to main content
Glama

img.png

recall.select

最小限のエージェント記憶システム - 任意のエージェントに1つのURLを与えるだけで、ほぼゼロセットアップで長期記憶を獲得できます。Qdrant + FastMCP + FastAPI/Bootstrap 上に構築されています。

完全な設計と段階的なビルド計画については docs/specs/initial_specification.md を、注目すべき変更の実行記録については docs/specs/changelog.md を参照してください。

仕組み

記憶はベクトルとして保存されます。各記憶ストアは Qdrantコレクション であり、(user, project) ペアに 1対1 でマッピングされます。これらのベクトルに関するメタデータ(ユーザー、APIキー、プロジェクト、コレクションごとの使用量/制限統計)は MongoDB に保存されます。

flowchart LR
    agent[Agent] --> web[FastAPI / MCP]
    web <-->qdrant[Qdrant]
    web <--> mongo[MongoDB]
    web <--> embed[Embedding API]

Qdrantコレクションは 遅延的に 作成されます。最初の記憶が (user, project) ペアに保存されるまで、Qdrantには何も触れません。

Related MCP server: LedgerMem MCP Server

アーキテクチャ

  • app/main.py - FastAPIアプリ。Bootstrapのランディングページを提供し、起動時にMongoのインデックスが存在することを確認します(コールド/リモートDBに対して耐性があります)。

  • app/mcp_server.py - メモリリンクの背後にあるMCPサーバー。エージェントのMCPクライアントは {PUBLIC_BASE_URL}/m/{key} を指します(Streamable HTTP、ステートレス、JSONレスポンス)。パス内のAPIキーが完全な認証情報であり、ツールをキー所有者のデフォルトプロジェクトにスコープします。基本ツール: store_memory / recall_memory / delete_memory。セマンティックレイヤーツール(vector_semantics.py を参照): link_memories / unlink_memories / annotate_memory / memory_connections / recall_connected - 接続されたエージェントはクライアント側で関係推論を行い(明示的な要求があった場合のみ)、これらは結果を取り込むかトラバースします。同じキーは、キーレスな /mcp エンドポイントに対して Authorization: Bearer として送信することもでき、シークレットをURL/ログから隠すことができます。{...}/m/{key}.mdapp/api/connect.py 内)は、対応するセットアップ手順(両方の形式)を提供します。

  • app/dependencies.py - コアDIコンテナ(injector)。共有シングルトン(Qdrantクライアント、Mongoクライアント/DB、リモートエンベッダー)を構築します。FastAPIの依存関係(app/api/deps.py)と起動時は、クライアントを自分で構築するのではなく、app_container から解決します。

  • app/services/ - サービスレイヤー(HTTP/ルートコードはなく、I/Oのみ):

    • qdrant_store.py - Qdrantクライアント + ensure_collection/upsert_memory/search/delete_memory、およびセマンティックレイヤーが必要とするポイントレベルのプリミティブ(neighborsscroll_pointsretrieve_pointsset_payload)。

    • vector_semantics.py - ベクトルメモリユーティリティレイヤー: ストアを意味のグラフとして扱います。各ポイントのペイロード内の予約済み _semantics 名前空間には、deixisアンカー(所有者、保存時刻。保存時に書き込まれる)、クライアントが抽出したエンティティ、およびクライアントが宣言した型付き関係(upsert_relations はそれらを検証して保存します - サーバー側でLLM呼び出しはありません)が保持されます。宣言された関係には2つの品質ヘッジがあります: confidence(0-1]、エッジのトラバーサル強度をスケーリング)と valid_till(ISO 8601; 期限切れのエッジはすべての読み取りパスで無視されるため、古い構造は自動的に廃止されます)。衛生管理: remove_relations は間違ったエッジを削除し(upsert_relations の修正版)、memory.delete_memoryprune_relations_to を呼び出すため、メモリの削除後もぶら下がったエッジは残りません。 プラグイン可能な レンズtopical/temporal/entity/declared)は型付きエッジを導出します。その上に semantic_graph(マルチグラフ)、spreading_activation(接続による検索)、concept_clusters(創発的オントロジー)、infer_relation(宣言された真実が優先され、その後に幾何学的ヒューリスティック)が配置されます。パフォーマンスメモ: 入力エッジのルックアップ(relations_of(include_incoming=True))は現在、境界付きスクロールアンドスキャンです。逆トラバーサルがホットになった場合の修正は、Qdrantの ペイロードインデックス_semantics.relations[].target に作成し(create_payload_index、キーワードスキーマ)、スキャンの代わりにフィルタリングクエリを使用することです - 同じストア、インデックスのみ。スキーマは何も変わりません。

    • mongo.py - Mongoクライアント、get_db()、および ensure_indexes()(一意の複合インデックスで1対1の (user, project) ルールを強制)。

    • users.py - add_userget_userget_user_by_emailupdate_user

    • api_keys.py - ユーザーにバインドされたキー。SHA-256ハッシュとして保存(平文は add_api_key から一度だけ返され、永続化されません): add_api_keydelete_api_keydelete_user_keyslist_api_keysget_labeled_keyget_by_key(提示されたトークンをハッシュ化し、ダイジェストと照合; MCP認証ゲートで record_use=True とすると last_used_at がスタンプされます)。保存時、各キーは非秘密の表示ヒントも保持します - key_prefix + key_last4masked() によって rs_ab12…wxyz としてレンダリングされるため、シークレットを再公開することなくキーをリスト表示して区別できます。

    • projects.py - add_projectget_projectlist_projectsupdate_projectdelete_project

    • collections.py - (user, project) ↔ Qdrantコレクション のレジストリ。collection_name(user_id, project_id) は内部命名標準(rs_{user}_{project})です。制限と統計のために points_count/calls_count を追跡します。

    • collection_provisioning.py - 両面の create_collection / destroy_collection ステップ。コレクションは、Mongoレジストリ行 そのバッキングQdrantコレクションの両方が存在する場合にのみ存在します。これは collections レジストリと qdrant_store を1つのアトミックで冪等な操作に構成し、2つのストアが同期しなくなることがないようにします。作成は遅延的であるため、唯一の作成呼び出し元は最初のメモリ書き込み(memory.store_memory)です。コレクションAPIの削除は destroy_collection を使用します。

    • embeddings.py - Embedder 抽象化; embeddings_remote.py - 具体的なテキスト→ベクトルバックエンド(リモート埋め込みAPI、例: DeepInfra)。

    • monobank.py - 最小限のMonobankアクワイアリングクライアント(create_invoicefetch_invoice_status)とWebhook認証(fetch_pubkey / verify_signature、生のボディに対するECDSA-SHA256)。mcp-api.netのマーチャントトークンを再利用します。recall.selectは独自の請求書/リダイレクト/Webhookを所有します。

    • billing.py - プランカタログと、Monobankの invoiceId をキーとする支払い記録。チェックアウト時に record_pendingapply_webhook は、success 時に購入者の tier1回だけ 切り替えます(リトライ/重複に対して冪等)。reconcile はWebhookが見逃したものを解決します(以下参照)。ティアは 時間制限付き です: grant_tier はエンタイトルメントが付与される唯一の場所(支払い済み請求書または所有者の好意)であり、tier_expires_attier_grants の監査行を書き込みます。effective_tier(user) はすべてのチェックが読み取る必要があるものです。保存された paid_2x の日付が過ぎている場合は無料アカウントになります。また、ティアごとの許容量の単一の真実の情報源でもあります: call_allowance(tier) / project_allowance(tier)None = 無制限; 未知のティアは無料にフォールバック)。

    • usage.py - 月間呼び出しメーターと価格モデルゲート。受け入れられた store/recall/delete のたびに、(user, カレンダー月) ごとの usage 行にカウントされます。check_call_allowed は、ティアの月間 call_allowance が使い果たされると呼び出しを拒否し、QuotaExceeded を発生させます。memory.py で強制され(MCPツールとHTTPメモリAPIの両方がカバーされます)、app/main.py によって HTTP 429 にマッピングされます。MCPトランスポートはツールエラーとして表面化します。全期間の collections.calls_count とは別です。

    • account.py - サインインした /account ページが表示する読み取り専用スナップショット(プラン、月間使用量、プロジェクトごとの保存数、マスクされた形式と作成日/最終使用日付のAPIキーリスト)。billing/usage/projects/collections/api_keys から構成されます。

    • docs.py - 公開 /docs 統合ガイドのコンテンツ。MCPクライアント設定を1か所で構築します(mcp_config / mcp_config_json)。ドキュメントページ app/api/connect.py のキーごとの .md の両方で再利用されるため、2つがずれることはありません。INTEGRATIONS はガイドレジストリです(エントリを追加することでページを追加)。

公開ページ(app/main.py から提供、Bootstrap + Jinja、app/translations/*.yml によるi18n): / ランディング、/plans/account(サインイン済み)、および /docs/integrations ガイド。FastAPIの組み込みAPIドキュメントは /docs から /api/docs/api/redoc/api/openapi.json)に移動され、公開サイトが /docs を所有します。

支払いはHTTPレイヤーを介して app/api/payments.py で処理されます: POST /api/me/checkout(サインイン済み)は請求書を作成し、Monobankの pay_url を返します。検証済みの POST /webhooks/monobank はティアを付与します。GET /payment/success|fail は化粧的なブラウザ戻りページです(エンタイトルメントはWebhook駆動であり、これらではありません)。

エンタイトルメントはWebhookだけに依存しません。 Monobankは各ステータス変更を1回だけ送信し、再送信しないため、再起動やプロキシの不具合でコールバックが失われると、支払った顧客が古いティアのままになり、こちら側で気付く手段がありません。そのため、アプリはプルも行います: PAYMENT_RECONCILE_MINUTES ごとにバックグラウンドスイープ(billing.reconcile_with_monobankapp/main.py のライフスパンで開始)が、5分経過してもまだ処理中の各支払いの実際のステータスを取得し、それを 同じ apply_webhook 遷移にプッシュします。プッシュとプルは互いに冪等です - どちらかが先に到達するとティアが付与され、もう一方は何もしません。payments の行はチェックアウトが 開始 されたときに書き込まれるため、created は「支払いページを開いた」ことを意味し、「支払った」ではありません。/admin/payments はその区別を明示的に表示します。

購入は1か月分SUBSCRIPTION_DAYS)であり、永久ではありません: grant_tiertier_expires_at をスタンプし、同じバックグラウンドループは期限切れのアカウントを無料に戻します(downgrade_expired)。アカウントページにはプランの有効期限が表示されます。まだ自動更新はありません - ユーザーが再度購入し、クレジットが残っている間に購入すると、ウィンドウが 延長 され、再開されるわけではありません。エンタイトルメントは effective_tier を通じて読み取られるため、期限切れの付与は、スイープが保存されたフィールドを書き換える前でもすぐに支払いを停止します。

自動更新がないため、アプリは 尋ねます: billing.renewal_state(user)/account のプロンプトを駆動します - プランの最後の RENEWAL_WARNING_DAYS(7)日間の警告とワンクリック更新ボタン、および「プランが終了しました。更新してください」というプロンプトが LAPSED_PROMPT_DAYS(30)日間表示されます(ダウングレードスイープは lapsed_tier / tier_lapsed_at を記録するため、ページは何が期限切れになったかをまだ表示できます)。更新は、プランページが使用するのと同じ /api/me/checkout に投稿し、保持していたプランに事前設定されます。まだメールはありません - プロンプトは訪問したユーザーにのみ届きます。

すべてのCRUD関数はオプションの db=/client= 引数を取るため、ライブバックエンドなしでテストで駆動できます。

設定

環境変数で設定します(ローカルの .env は自動的に読み込まれます。コミットしないでください - .env.example を参照):

変数

デフォルト値

目的

MONGODB_URI

(必須)

リモートのマネージドMongoDB接続文字列。

MONGODB_DB

recall_select

データベース名。

QDRANT_URL

http://qdrant:6333

Qdrantエンドポイント(内部Composeネットワーク)。

QDRANT_API_KEY

(ローカルではなし、本番では必須)

アプリとQdrant間で共有されるシークレット。ComposeはQDRANT__SERVICE__API_KEYをこの値に設定し、アプリはすべてのリクエストでこれを送信します。これはqdrant.recall.selectダッシュボードへの唯一のゲートであり、ダッシュボード自体には認証がありません。

VECTOR_SIZE

768

すべてのコレクションのベクトル次元数。リモートの埋め込みAPIには(dimensionsパラメータ経由で)このサイズのベクトルを返すよう要求され、両者の同期が保たれます。

EMBEDDING_API_KEY

(必須)

リモート埋め込みAPIのAPIキー。

EMBEDDING_BASE_URL

https://api.deepinfra.com/v1

OpenAI互換の埋め込みAPIベースURL。

GOOGLE_CLIENT_ID

(サインインに必須)

Google OAuth 2.0 WebクライアントID。

GOOGLE_CLIENT_SECRET

(サインインに必須)

Google OAuth 2.0クライアントシークレット。

SESSION_SECRET

(開発用フォールバック)

セッションクッキーに署名します。本番環境では安定した値を設定してください。

PUBLIC_BASE_URL

http://localhost:8000

公開オリジン。メモリリンクとOAuthリダイレクトURIを構築します。

FORWARDED_ALLOW_IPS

172.25.0.0/16 (compose) / 127.0.0.1 (uvicorn)

uvicornが信頼するX-Forwarded-Proto/-Forヘッダーの送信元ピア。Composeではcaddy_netサブネットにデフォルト設定され、リダイレクトでhttpsスキームが維持され、ログに実際のクライアントIPが記録されるようにします。そのネットワークが再作成された場合はdocker network inspect caddy_netで確認してください。

MONOBANK_API_KEY

(支払いに必須)

Monobankアクワイアリングマーチャントトークン。mcp-api.netプラットフォームと共有 - 同一マーチャント、単一アカウント。請求書はreferenceで区別されます。

MONOBANK_REDIRECT_URL

{PUBLIC_BASE_URL}/payment/success

購入者が支払い後にブラウザがリダイレクトされるURL。

MONOBANK_WEBHOOK_URL

{PUBLIC_BASE_URL}/webhooks/monobank

サーバー間コールバックで、ティアを付与します。公開アクセス可能である必要があります。

MONOBANK_WEBHOOK_VERIFY

1

マーチャント公開鍵に対してWebhookのX-Signを検証します。金銭が絡む場合は有効にしておいてください。ローカル開発時のみ0に設定します。

PAYMENT_RECONCILE_MINUTES

15

Monobankから処理中の支払いの実際のステータスを取得する間隔(分)。これにより、Webhookが失われても支払い中の顧客が取り残されることを防ぎます。0でスイープを無効化します。

ADMIN_SECRET

(未設定 - エリア無効)

/adminのオーナー管理エリアをアンロックします。未設定の場合、すべての/adminルートは404を返します。

ADMIN_SESSION_HOURS

12

アンロックされた管理セッションが再ロックされるまでの時間。

オーナー管理エリア(/admin

サポートやユーザーの視点確認のために、任意のユーザーの個人エリアへの読み取り専用ウィンドウです。ADMIN_SECRETを設定し(生成: python -c "import secrets; print(secrets.token_urlsafe(32))")、Webコンテナを再作成した後、{PUBLIC_BASE_URL}/adminを開き、セッションごとに一度キーを入力します。/admin/usersはすべてのアカウントを一覧表示します(メール、名前、ユーザーIDで検索可能)。各行から、そのユーザーのプラン、今期間の使用量、メモリカウント付きのプロジェクト、マスクされた形式のメモリリンクを開くことができます。

境界は意図的に設定されています。キーはPOSTで送信され(URLパラメータではないため、履歴やアクセスログに残りません)、間違った推測を繰り返すとクライアントは5分間ロックアウトされます。セッションはADMIN_SESSION_HOURS後に自動的に再ロックされ、このエリアのルートは何も書き込まず、メモリテキストやキーシークレットを公開しません。オーナーはアカウントの構造を見ることができても、その内容は見ることができません。ADMIN_SECRETが未設定の場合、このエリアはまったく存在しません。

認証(Googleサインイン)

サインインはメモリリンクへのゲートです。ユーザーはGoogleでサインインし、メモリリンクをコピーをクリックしてデフォルトのプロジェクト、コレクション、APIキーをプロビジョニングし、エージェントに渡すURLを取得します。シークレットは一度だけ表示されます(ハッシュのみが保存されます)。その後、ランディングページはリンクをマスクして表示し(GET /api/me/link経由)、ボタンは明示的で確認が必要な「新しいリンクを取得」に変わります。再生成は古いリンクを無効にし、サイレントに行われることはありません。キーは/accountで管理されます。マスクされたリスト、作成日/最終使用日、ラベル付き作成(一度だけ表示)、取り消し。Google認証情報を設定するには:

  1. Google Cloud Console → APIs & Services → OAuth同意画面 - 設定します(外部。未検証の間はテストユーザーとしてメールアドレスを追加)。

  2. 認証情報 → 認証情報を作成 → OAuthクライアントID → Webアプリケーション。

  3. 承認済みのリダイレクトURIを追加: {PUBLIC_BASE_URL}/auth/callback - 例: ローカル開発ではhttp://localhost:8000/auth/callback、本番ではhttps://recall.select/auth/callback(ローカルでテストする場合は両方を追加)。

  4. クライアントIDクライアントシークレット.envにコピーします(GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET)。安定したSESSION_SECRETを設定します(python -c "import secrets; print(secrets.token_urlsafe(48))")。

ローカルでの実行

Docker Composeを使用したフルスタック(Web + Qdrant):

cp .env.example .env   # then fill in MONGODB_URI
docker compose up --build
# open http://localhost:8000

または、独自のQdrant/Mongoに対してアプリのみを実行:

pip install -e ".[dev]"
uvicorn app.main:app --reload

テスト

pip install -e ".[dev]"
pytest

CRUDテストはインメモリMongo(mongomock)に対して実行され、Qdrant/埋め込みクライアントは偽装されています。ライブバックエンドは不要です。

デプロイ

./deploy/deploy.sh

同じコマンドが2つの場所から機能します。実行された場所を検出します:

  • 開発マシンから(またはエージェントのボックスから): ローカルコミットをプッシュし、recall-server SSHエイリアス経由でサーバー上でデプロイを実行します。

  • サーバー上でsetti@setti-server:~/recall_select$ ./deploy/deploy.sh): その場でデプロイ。SSHホップはありません。

どちらのパスも同じワーカーを実行します - deploy/_server_deploy.sh: mastergit同期、Composeスタック(FastAPI web + Qdrant)の再ビルド、共有Caddyプロキシのリロード(recall.selectの自動HTTPS)、古いイメージの削除。MongoDBはリモート/マネージドであるため、認証/MONGODB_URI環境変数(.env参照)がサーバー上に存在している必要があります。

サーバー上で実行する人は、リポジトリへのGitHubプルアクセス~/.ssh内の認証済みSSHキー)とdockerグループのメンバーシップが必要です。これはclaude-agentsettiの両方で当てはまります。ワーカーはリポジトリをgitのsafe.directoryとして自動登録するため、リポジトリの所有者でないデプロイ担当者が「疑わしい所有権」によってブロックされることはありません。

自動デプロイ(CI)

masterへのすべてのプッシュは、GitHub Actions(.github/workflows/deploy.yml)を介して自動デプロイされます。上記と同じフローですが、人間ではなくCIによってトリガーされます。ジョブはサーバーにSSH接続し、deploy/_server_deploy.shを標準入力にパイプするため、プッシュされたコミット自身のデプロイロジックが実行されます。デプロイは直列化され(concurrency)、Run workflowボタン(workflow_dispatch)を使用してオンデマンドでデプロイすることもできます。

一度だけの設定 - Settings → Secrets and variables → Actionsの下に追加:

シークレット

必須

目的

DEPLOY_SSH_KEY

はい

公開鍵がデプロイユーザーの~/.ssh/authorized_keysにある秘密鍵。

DEPLOY_HOST / DEPLOY_USER

はい

サーバーアドレスとデプロイを実行するSSHユーザー。

DEPLOY_PORT

いいえ

SSHポート(デフォルト22)。

DEPLOY_KNOWN_HOSTS

いいえ

サーバーのホストキーを固定します。未設定の場合、CIはssh-keyscan経由で初回使用時に信頼します。

アプリのシークレット(MONGODB_URI、OAuthなど)はサーバーの.envに残ります。CIがそれらを見ることはありません。

ライセンス

GNU Affero General Public License v3.0 に基づいてライセンスされています。ネットワークサービスとして修正版を実行する場合、AGPL はそのソースコードをユーザーに提供することを要求します。Copyright © 2026 Sergii Setti.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides persistent, local-first AI memory across sessions via MCP tools for storing, searching, and retrieving context from past interactions.
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Provides persistent memory for AI agents via 10 MCP tools that map to the AgentRAM REST API, enabling store, retrieve, search, and share memories across personal and shared namespaces.
    10
    191
    MIT

View all related MCP servers

Related MCP Connectors

  • Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.

  • Shared long-term memory vault for AI agents with 20 MCP tools.

  • Your memory, everywhere AI goes. Build knowledge once, access it via MCP anywhere.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SergeySetti/recall_select'

If you have feedback or need assistance with the MCP directory API, please join our Discord server