Skip to main content
Glama
martindzejky

agentmemory-mcp-gateway

by martindzejky

agentmemory-mcp-gateway

リモートクライアントに小規模な AgentMemory MCP ツール一式を公開する、シングルユーザー向け OAuth 2.1 ゲートウェイです。

MCP クライアントはこのサービスに対して認証します。このサービスは AgentMemory に対して認証します。AgentMemory のバックエンドシークレットがゲートウェイから出ることはありません。

機能

  • /mcp で Streamable HTTP によるリモート MCP を処理します

  • OAuth 認可サーバーおよび保護リソースとして動作します

  • 事前にシードされた 1 人の人間だけがサインインして同意を付与できます

  • 許可リストに登録された tools/list および tools/call トラフィックを AgentMemory REST に転送します

  • AgentMemory が利用できない場合はフェイルクローズします

想定クライアント: ChatGPT、Notion Custom Agents、Codex cloud、その他の標準準拠のリモート MCP クライアントです。

公開 URL の形式:

https://memory-mcp.example.com/mcp

Related MCP server: Remote MCP Server on Cloudflare

アーキテクチャ

MCP client
  -> HTTPS gateway (this service)
    -> private AgentMemory REST API

信頼境界:

  • MCP クライアントが見られるのは、公開 HTTPS オリジン、OAuth メタデータ、許可リスト登録済みツールのスキーマ/結果のみです。

  • AgentMemory は Railway のプライベートネットワーキング上に留まります。クライアントが AGENTMEMORY_URL や AGENTMEMORY_SECRET を受け取ることはありません。

  • 受信した Authorization ヘッダーは、クライアントアクセストークンの検証にのみ使用されます。ゲートウェイは常に新しい Authorization: Bearer ${AGENTMEMORY_SECRET} ヘッダーを構築してアップストリーム呼び出しを行います。

  • SQLite は認証情報と OAuth 状態のみを保存します。これはメモリデータベースではありません。

これは AgentMemory とは別の Railway サービスです。レプリカは必ず 1 つだけ実行してください。

@agentmemory/mcp ではなく REST を使う理由

@agentmemory/mcp はアップストリームに到達できない場合、ローカルのメモリデータベースにフォールバックできます。それはリモート個人用ゲートウェイとしては許容できません。

このサービスが呼び出すのは次のものだけです。

  • GET /agentmemory/mcp/tools

  • POST /agentmemory/mcp/call ({ "name": string, "arguments": object })

AgentMemory がダウン、不正な応答、タイムアウトのいずれの場合でも、ゲートウェイは安全な MCP エラーを返します。別のメモリストアを作成、オープン、書き込みすることはありません。

SQLite が存在する理由

DATABASE_PATH にある SQLite(デフォルト: /data/oauth.sqlite)には以下が保存されます。

  • 1 人のユーザーとパスワードハッシュ

  • セッションと同意

  • OAuth クライアント登録

  • 認可コード

  • アクセス/リフレッシュトークンと失効状態

  • 署名キー / JWKS

AgentMemory の観察情報や埋め込みを保存することはありません。

インメモリのレートリミッターも単一レプリカ専用です。このサービスを水平分散させないでください。

厳密なシングルユーザーモデル

  • メールアドレス / パスワードのみ

  • GitHub、ソーシャルログイン、マジックリンク、招待、パスワードリカバリはなし

  • 公開サインアップやユーザー管理 API はなし

  • クライアント登録(CIMD / DCR)は人間の登録ではありません

  • サインイン、同意の承認、使用可能な MCP トークンの取得ができるのは、シード済みユーザーの恒久的 ID のみです

  • 本番起動は、ユーザーテーブルがちょうど 1 行でない場合に失敗します

認証エラーは一般的な内容に統一されています。メールアドレスが存在するかどうかは明かされません。

環境変数

変数

必須

目的

PUBLIC_URL

はい

正式な公開オリジン。パス、クエリ、フラグメント、認証情報なし。ループバックを除き HTTPS。

BETTER_AUTH_SECRET

はい

Better Auth の署名/暗号化シークレット、32 文字以上

DATABASE_PATH

はい

SQLite ファイルのパス。例: /data/oauth.sqlite

AGENTMEMORY_URL

はい

AgentMemory のプライベートオリジン

AGENTMEMORY_SECRET

はい

AgentMemory へのバックエンド Bearer トークン、32 文字以上

ALLOWED_TOOLS

いいえ

デフォルト: memory_recall,memory_smart_search,memory_save

PORT

いいえ

待ち受けポート。Railway が設定します。デフォルト 8080

ADMIN_EMAIL

シード時のみ

管理者メールアドレス

ADMIN_PASSWORD

シード時のみ

強力な生成パスワード、20 文字以上

PUBLIC_URL は単一の issuer であり、/mcp のオリジンです。保護リソース識別子は ${PUBLIC_URL}/mcp です。

.env.example をコピーしてください。Placeholder しか含まれていません。

ローカル開発

nvm install
cp .env.example .env
# fill local loopback values, for example PUBLIC_URL=http://127.0.0.1:8080
npm install
npm run seed-admin
# remove ADMIN_PASSWORD from .env
npm run dev

便利なチェック:

npm run format
npm run lint
npm run typecheck
npm test
npm run build

安全な 1 回限りの管理者シーディング

railway run は ローカル コマンドにのみ変数を注入します。Railway ボリュームには書込めません。/data がマウントされた後、デプロイ済みコンテナ内でシーディングしてください。

ローカル

npm run seed-admin
# remove ADMIN_PASSWORD from .env

本番イメージ / Railway

イメージには dist/seed-admin.js が含まれており、node dist/start.js で起動します。

  1. 1Password で長いランダム・パスワードを生成します。git、SQLite、Docker、またはログに保存しないでください。

  2. サービスに ADMIN_EMAIL と ADMIN_PASSWORD(20 文字以上)を一時的に設定します。

  3. /data がマウントされた状態でコンテナが動くよう、デプロイまたは再起動します。

  4. それらの変数が設定された状態では、node dist/start.js は node dist/seed-amin.js をイン・プロセスで実行し、恒久的なユーザー ID を出力し、HTTP ポートを開かずに終了コード 0 で終了します。

  5. ADMIN_PASSWORD と ADMIN_EMAIL を削除して再起動します。するとプロセスが HTTP を提供します。

  6. ユーザーが存在する後も両方の変数が設定されたままの場合、起動はそれらを削除すべきと記録し、Railway がクラッシュループしないよう終了コード 0 で終了します。

  7. ADMIN_EMAIL または ADMIN_PASSWORD のどちらかだけが設定されている場合、起動はフェイルクローズし、HTTP を提供しません。

ボリュームの存在後にコンテナ内で手動実行するのと同等の手順:

railway ssh -- node dist/seed-admin.js

本番シーディングに railway run npm run seed-admin を使わないでください。そのコマンドは自分のマシン上で実行されます。

本番 HTTP プロセスは、その 1 人のユーザーが存在し、シーディング用変数が消えるまで起動しません。

Doーカー

docker build -t agentmemory-mcp-gateway .
docker run --rm -p 8080:8080 \
  -e PUBLIC_URL=http://127.0.0.1:8080 \
  -e BETTER_AUTH_SECRET=... \
  -e DATABASE_PATH=/data/oauth.sqlite \
  -e AGENTMEMORY_URL=http://127.0.0.1:3111 \
  -e AGENTMEMORY_SECRET=... \
  -v gateway-data:/data \
  agentmemory-mcp-gateway

エントリポイントはルートとして起動し、DATABASE_PATH が /data(または RAILWAY_VOLUME_MOUNT_PATH)配下の絶対パスであることを確認したうえで、そのディレクトリと SQLite/WAL/SHM ファイルだけを chown し、node を実行する前に UID/GID 10001 に権限を落します。 / や他の親ディレクトリを再帰的に chown することはありません。 /data に永続ボリュームをマウントしてください。

Railway

  1. このリポジトリから新規サービスを作成します。AgentMemory サービスにデプロイしないでください。

  2. リポジトリのルートにある Dockerfile / railway.json を使用します。

  3. /data にマウントする永続ボリュームを接続します。Railway はボリュームをルートとしてマウントし、イメージの /data ディレクトリを置き換えます。

  4. RAILWAY_RUN_UID=0 を設定し、エントリポイントが /data を chown したあとで UID 10001 に権限を落とせるようにします。プロセスをルートのままにするのはトレードオフですが、このイメージは起動後にルートを維持しません。

  5. レプリカは 1 に設定します。単一の SQLite ボリュームは安全に共有できません。

  6. 上記の環境変数を設定します。AgentMemory のプライベート URL、例えば http://<agentmemory-service>.railway.internal:3111 を使用します。

  7. 公開カスタムドメインを接続し、PUBLIC_URL をその正確な https:// オリジンに設定します。

  8. 上記のコンテナ内手順で管理者を一度シードし、そのあと一時的なパスワード変数を削除します。

  9. GET /healthz が {"ok":true} を返すことを確認します。

このフローでは AgentMemory をパプリック・インターネットに公開しないでください。ゲートウェイが唯一の公開 MCP エンドポイントです。

ChatGPT に接続する

  1. 安定した HTTPS オリジンと /mcp を用意してデプロイします。

  2. ChatGPT でリモート MCP / コネクタ URL として https://<your-domain>/mcp を追加します。

  3. ChatGPT が CIMD を提供している場合は CIMD を優先します。フォールバックとして DCR も有効のままです。

  4. シード済みユーザーとして、ホステッドのサインイン画面と同意画面を完了します。

  5. memory_recall、memory_smart_search、memory_save が表示されることを確認します。

ChatGPT は /.well-known/oauth-protected-resource と認可サーバーのメタデータを自動的に発見します。

Notion Custom Agents に接続する

  1. 必要に応じて、Notion ワークスペースでカスタム MCP サーバーを有効にします。

  2. カスタム MCP サーバー URL として https://<your-domain>/mcp を追加します。

  3. Notion は OAuth を使用し、クライアントが事前登録されていない限り通常は DCR を使用します。

  4. シード済みユーザーとしてサインインし、同意を承認します。

  5. そのエージェントが使用すべきツールだけを有効にします。

基本的なエンドツーエンドの検証

curl -sS https://<your-domain>/healthz
curl -sS https://<your-domain>/.well-known/oauth-authorization-server
curl -sS https://<your-domain>/.well-known/oauth-protected-resource
curl -sS -D- https://<your-domain>/mcp \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'

/mcp への呼び出しは、保護リソースのメタデータを指す WWW-Authenticate チャレンジとともに 401 を返す必要があります。実際のクライアントログイン後、tools/list は許可リストに登録されたツールだけを表示する必要があります。

クライアントとトークンの失効

SQLite は、OAuth クライアント、リフレッシュトークン、同意に関する正本です。

  • BETTER_AUTH_SECRET の削除またはローテーションは、署名マテリアルを無効化し、注意して再シーディングする場合だけにしてください。

  • oauthClient 行、関連するトークン、同意レコードを削除すれば、そのクライアントは失効します。

  • SQLite ファイルを置き換えると、すべてのクライアントがログアウトします。

管理 API はありません。特定のクライアントを失効させる必要があったら、ボリュームに対して 1 回限りの sqlite3 セッションを使用してください。

バックアップとリカバリ

サービスを停止した状態で /data/oauth.sqlite と -wal / -shm ファイルをまとめてコピーするか、sqlite3 .backup を使用してください。ボリュームを失うと、すべての OAuth クライアントが再接続し、管理者を再シードする必要があります。このバックアップは認証状態であり、AgentMemory の情報ではありません。

既知の制限

  • レプリカは 1 つのみ。レートリミットはインメモリです。

  • パスワードリセットはありません。パスワードを紛失した場合は、SQLiteをバックアップから復元するか、ユーザーテーブルを削除して再シードしてください。

  • ダッシュボードなし、マルチユーザー非対応です。

  • MCP ハンドラーは、ChatGPT と Notion が拒否されないよう、ステートレス・モードで公式 SDK のレガシー (2025) プロトコルサポートを維持しています。OAuth スタックは、CIMD を含み明示的な DCR も盛り込んだ現在の Better Auth MCP API に従います。

  • ChatGPT が告知する mTLS クライアント認証は、HTTPS エッジで意図変換され、このプロセス内では確認されません。

クラウドエージェント

Cursor Cloud は .cursor/environment.json を使用します:

  • Dockerfile — Ubuntu 24.04、Node 24 (nvm)、npm、および agentfiles

  • install — agentfiles を更新し、package-lock.json がある場合に npm ci を実行します

ローカル開発では、クラウドイメージの .nvmrc を使って同じ Node バージョンを利用します。ゲートウェイのランタイム自体は Node 22 をターゲットにしています。

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers