Context Keeper (remote) について
Context Keeper (remote) は、プロジェクトの決定事項、パイプライン、制約を D1 に保存・検索する Cloudflare Workers 上の MCP サーバーです。Streamable HTTP で Claude のセッションに接続し、根拠を閲覧できる読み取り専用のモバイルビューも備えています。
主な機能
- 01プロジェクトコンテキストの記録と検索
- 02D1 による判断根拠の保存
- 03読み取り専用のモバイルビュー
- 04データベーススキーマの自動移行
活用シーン
- 01Claude のセッションでプロジェクトの決定事項を参照
- 02スマートフォンで判断根拠や制約を確認
MCP 対応
Streamable HTTP 経由で `record_entry`、`get_context`、`query_entries` などの context-keeper ツールを公開します。Claude のカスタムコネクターから接続できます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://context-keeper-remote.{account}.workers.dev/mcp/{token}claude mcp add --transport http jarmstrong158-context-keeper-remote https://context-keeper-remote.{account}.workers.dev/mcp/{token}{"mcpServers":{"jarmstrong158-context-keeper-remote":{"type":"http","url":"https://context-keeper-remote.{account}.workers.dev/mcp/{token}"}}}Cursor で開く{"servers":{"jarmstrong158-context-keeper-remote":{"type":"http","url":"https://context-keeper-remote.{account}.workers.dev/mcp/{token}"}}}VS Code で開く{"mcpServers":{"jarmstrong158-context-keeper-remote":{"type":"http","url":"https://context-keeper-remote.{account}.workers.dev/mcp/{token}"}}}{"mcpServers":{"jarmstrong158-context-keeper-remote":{"serverUrl":"https://context-keeper-remote.{account}.workers.dev/mcp/{token}"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
context-keeper-remote
xylem スタックの一部です。
Cloudflare Workers 上で動作するリモート MCP サーバーで、Streamable HTTP 経由で context-keeper の根拠ストア(決定事項、パイプライン、制約)を公開します。モバイルを含め、claude.ai のカスタムコネクターとして機能するため、PC を起動したままにしたりトンネルを使ったりせずに、あらゆる Claude セッションからプロジェクトの決定事項や制約を利用できます。
また、このストアをご自身で閲覧できる**スマートフォンアプリ**も提供します。一度ホーム画面にインストールすれば、ログインも URL 内のトークンも不要で開けます。最近のアクティビティ、プロジェクトごとの件数、cambium ナレッジ、ストアの状態を確認できるタブがあり、項目をタップするとタイトルだけでなく、根拠の全文を確認できます。これはオプションで、利用は任意です。また、専用の読み取り専用認証情報を使用します。
上のボタンから、数クリックでご自身のコピーをセルフホストできます。Cloudflare がこのリポジトリを GitHub アカウントにコピーし、新しい D1 データベースを作成して、Worker をデプロイします。その後、シークレットを 1 つ追加し、URL を Claude に貼り付けます。詳しい手順は以下をご覧ください。すべてクリックで進められ、コマンドライン操作は一切ありません。
メンテナー自身のインスタンスは
https://context-keeper-remote.jarmstrong158.workers.devで動作しています。デプロイ後は、ご自身のサブドメインで利用できます。
この構成にした理由
- トンネルではなく Worker — 「PC を起動しておく必要がある」という依存がありません。
- KV ではなく D1 — 行単位の書き込みと
WHEREクエリに対応しています。2 つの書き込み元(デスクトップとモバイル)が同時に使用しても、ファイル全体を JSON で読み取り・変更・書き込みする方式のように、互いの変更を上書きしません。 - Durable Objects を使わないステートレスなハンドラー — ツールは D1 に対するステートレスな RPC なので、Worker は Cloudflare の無料プランで動作します。
- シークレットをパスに含める認証 — claude.ai のカスタムコネクターはカスタムの bearer ヘッダーを確実に送信しないため、トークンを URL の最後のパスセグメントに含めています。URL が認証情報になります。
- 自動マイグレーション — Worker は実行時に自身の D1 スキーマを作成するため、新規の空のデータベースでも手動で SQL を実行する必要はありません(コールドスタートテストで検証済み)。
セルフホストする(ワンクリック、コマンドライン不要)
手順 1 — 「Deploy to Cloudflare」をクリックする
このページの上部にある Deploy to Cloudflare ボタンをクリックします。Cloudflare が次の処理を行います。
- GitHub の認証を求め、アカウントを選択すると、このリポジトリがご自身の GitHub アカウントにコピーされます(ご自身のリポジトリが作成されます)。
- Cloudflare アカウントに新しい D1 データベースを自動的に作成し、Worker にバインドします。(Worker の設定でデータベースバインディングが固定 ID なしで宣言されているため、Cloudflare が新しいデータベースを用意できます。)
- Workers Builds を設定し、新しいリポジトリへのプッシュごとに自動で再デプロイされるようにします。
- Worker をビルドしてデプロイします。
完了すると、Worker は
https://context-keeper-remote.<your-subdomain>.workers.dev で利用できるようになります。この URL を控えておいてください。手順 3 で必要になります。(ダッシュボードの Workers & Pages からいつでも確認できます。)
リポジトリで設定する項目はなく、実行する SQL もありません。データベースは空の状態で作成され、Worker が最初のリクエスト時にテーブルを作成します。
ステップ 2 — AUTH_TOKEN シークレットを追加する(Cloudflare ダッシュボード)
認証トークンが設定されるまで、Worker はすべてのリクエストを拒否するため、次の手順で設定します。
- Cloudflare ダッシュボード → Workers & Pages → context-keeper-remote Worker。
- Settings → Variables and Secrets → Add。
- 種類:Secret。名前:
AUTH_TOKEN。値:長いランダムな文字列(32 文字以上。 パスワードと同様に扱ってください)。保存してデプロイします。
この値はコネクターのパスワードです。安全な場所に保管してください。次のステップで貼り付けます。
連携する agentsync-remote Worker もデプロイしますか?
agentsync-remote も同じ AUTH_TOKEN 方式を使用し、さらに、この Worker の Variables and Secrets に次の設定が必要です。
- Secret(名前:
GH_PAT)— GitHub 個人アクセストークン - Variable(名前:
REPO)— 同期先のowner/repoを設定
この 2 つは context-keeper-remote(このリポジトリ)には適用されません。必要なのは AUTH_TOKEN だけです。詳しくは agentsync-remote の README を参照してください。
ステップ 3 — claude.ai にカスタムコネクターを追加する
-
claude.ai → Settings → Connectors → Add custom connector。
-
最後のパスセグメントにトークンを含めて、Worker URL を貼り付けます。
https://context-keeper-remote.<your-subdomain>.workers.dev/mcp/<AUTH_TOKEN><your-subdomain>を Worker のサブドメイン(ステップ 1)に、<AUTH_TOKEN>を設定した値そのもの(ステップ 2)に置き換えます。 -
保存します。ツール(
record_entry、get_context、query_entries、…)を Claude のセッションで利用できるようになります。
動作を確認するには: Claude に get_project_summary を呼び出すよう依頼します。応答があれば、一連の処理(デプロイ → D1 の自動プロビジョニング → 自動マイグレーション → 認証)が機能しています。
ステップ 4 — 既存のローカルデータを移行する(任意)
すでにローカル版の context-keeper を使用している場合は、コネクターを有効にした状態で Claude に import_entries を呼び出すよう依頼し、各ファイルの内容を貼り付けます。
decisions.json→import_entries(project, kind="decision", entries=[...])pipelines.json→import_entries(project, kind="pipeline", entries=[...])constraints.json→import_entries(project, kind="constraint", entries=[...])
受信した ID は保持されます。既存の ID は報告され、上書きされることはありません。
ステップ 5 — スマートフォン用ビューをインストールする(任意)
これまでの設定は、Claude が読み取るための MCP コネクターです。ステップ 5 では、あなたがスマートフォンから読み取るための設定を行います。このリポジトリのクローンと Node 22+ が必要です。コマンドラインを使うのはセットアップのこの部分だけで、コネクター自体では使用しません。
以下のスマートフォン用ビューを参照してください。
スマートフォン表示
/view は、すべてのプロジェクトの決定事項と制約を表示する、読み取り専用のサーバー描画ページです。ホーム画面に追加すれば、アプリのように開きます。ログインは不要で、URL にトークンが含まれることもなく、覚えておく必要もありません。
![]() | ![]() |
| 最近 — すべてのプロジェクトで何が変わったか | 任意のエントリー — タイトルだけでなく、その理由も確認できます |
![]() | ![]() |
| プロジェクト — プロジェクトごとの件数と、各ルールブックのうち強制可能な項目の割合 | 健全性 — 文字化け、根拠の不足、タグなし、古い項目 |
合成データです。上記のプロジェクトとエントリーはすべて架空のものです。データセットと再生成方法については docs/screenshots をご覧ください。
タブは 4 つあり、デスクトップダッシュボードと同じ構成です。
| タブ | 確認できる内容 |
|---|---|
| 最近 | すべてのプロジェクトで最近何が変わったか |
| プロジェクト | プロジェクトごとの件数:エントリー、有効な項目、制約、スコープ設定済み、置き換えリンク、古い項目、文字化け |
| ナレッジ | 接続されている場合の、cambium のチーム/組織の件数(下記参照) |
| 健全性 | 文字化け、根拠の不足、タグなし、古い項目を、割合とプロジェクトごとのランキングで表示 |
行をタップすると、エントリー全体を確認できます。問題、選択した理由、最初に試したこと、トレードオフ、却下した理由を含む代替案、そして制約の場合はスコープ、強度、適用方法が表示されます。検索対象は、通常答えが記されている根拠も含め、すべてのフィールドです。置き換えられたエントリーにも引き続きアクセスでき、各エントリーから置き換えた項目と置き換えられた項目にリンクできます。
インストール
1. 認証情報を作成します。 scripts/set-view-token.cmd をダブルクリックします
(macOS/Linux の場合は scripts/set-view-token.sh)。ターミナルから実行する場合は絶対パスを使用してください。リポジトリをカレントディレクトリにする必要があるため、npm run は使用しないでください。
powershell -NoProfile -ExecutionPolicy Bypass -File "/full/path/to/context-keeper-remote/scripts/set-view-token.ps1"
1 回の実行でトークンを生成してインストールし、ルートが 200 を返すまで待機した後、URL をコピーしてブラウザーで開き、QR コードを表示します。
2. スマートフォンで QR コードをスキャンしてから、インストールします。
- Android / Chrome — バナーに インストール が表示されます。または、⋮ → アプリをインストール を選択します。メニューに ホーム画面に追加 しか表示されない場合は、マニフェストが Chrome のインストール要件を満たしていません。よくある原因は 192x192 アイコンがないことです。その場合、Chrome は気づかれないまま通常のショートカットに切り替わり、ブラウザーのタブで開くようになります。
- iPhone — Safari が必須です(iOS 版 Chrome では Web アプリをインストールできません)。 共有 → ホーム画面に追加 を選択します。
通信できるうちに、最近、プロジェクト、ナレッジ、健全性を一度ずつ開いてください。オフラインキャッシュに保存されるのは、実際に開いたページのみです。
インストール以外の処理をすべて実行するには -DryRun を追加します。何かを変更する前にセットアップを確認する最も簡単な方法です。
オフラインでも動作し、タップするとすぐに開きます
サービスワーカーは、開いたページをすべてキャッシュし、キャッシュを優先しながらバックグラウンドで再検証します。稼働中のインスタンスでの測定結果:
| キャッシュからの配信 | 1 ms |
| ネットワークへの接続を強制 | 278–383 ms |
そのため、電波が届かない場所でも開き、タブの切り替えも往復通信を待たずにすぐ行えます。意思決定ログはライブフィードではありません。昨日の回答をすぐに表示して少し後に修正するほうが、300msのあいだ何も表示しないよりも優れています。また、ヘッダーには「8h ago」というタイムスタンプが表示されるため、古いデータが最新のものとして提示されることはありません。
キャッシュされるのは200番のレスポンスのみです。 認証されていない、またはローテーションされた認証情報に対して、このWorkerは404を返します。これをキャッシュすると、トークンをローテーションしたデバイスが、ネットワークを使わずに自身のディスクからサインアウト済みだと告げられ続け、しかもそれを消す明確な方法がなくなります。両方向で検証済みです。
トークンがJavaScriptに渡ることは、これまでどおりありません。 CookieはHttpOnlyなので、サービスワーカーは読み取れません。ブラウザーがCookieを付加する同一オリジンのリクエストを発行するだけです。手放したのは「クライアント側のJavaScriptを一切使わない」ことであり、認証情報の分離ではありません。CSPにはscript-src 'self'を追加し、意図的に'unsafe-inline'は追加していません。登録処理は専用ファイルに置かれているため、記録されたエントリがエスケーパーをすり抜けた場合を含め、ドキュメント全体に適用されるインラインスクリプトの許可は必要ありません。
ログイン状態を維持する仕組み
トークンURLへのアクセスは、日常的に行うものではなく、登録のための手順です。アクセスすると有効期間の長いHttpOnly Cookieが設定され、その後はそのデバイスからベースパスの/viewを使えます。ホーム画面のアイコンから開くのもこのパスです。
- 適用範囲は広がりません。 Cookieにはパスで使っていたものと同じシークレットが含まれ、同じ方法で比較されます。そのため、
VIEW_TOKENをローテーションすれば、すべてのデバイスが同時に無効になります。失効方法は1つで、セッションテーブルはなく、有効期限を追跡する必要もありません。 - 専用の認証情報です。 viewは
AUTH_TOKENを受け付けず、/mcpはVIEW_TOKENを受け付けません。view URLが漏洩しても、意思決定の概要が開示されるだけです。書き込み、非推奨化、削除はできません。 - 未設定なら利用できません。
VIEW_TOKENが設定されていない場合、/view/<anything>は本文のない404を返します。デプロイされたことのないルートと見分けがつきません。
npm run viewを実行すると、後から再び開けます(URLは.view-urlに保存され、gitignoreの対象です)。npm run view -- --qrを実行すると、トークンをローテーションせずに別のデバイスを登録できます。セットアップを再実行すると新しいトークンが生成され、すでに追加済みのすべてのデバイスが予告なく使えなくなります。
Knowledge タブを cambium-remote に接続する(任意)
cambium-remote も実行している場合にのみ関係します。
scripts/connect-cambium.cmd
ステータス専用の認証情報を生成し、cambium-remote に STATUS_TOKEN として設定します。実際の件数が返されることを確認してから、ここで CAMBIUM_STATUS_URL を設定します。調べたり、コピーして貼り付けたりする必要はありません。
**cambium のコネクター URL ではなく、別の認証情報を使う理由:**その URL は cambium-remote の AUTH_TOKEN であり、昇格済みのすべてのアイテムに対する recall 権限を付与します。TEAM_OWNER のチームスコープがすべてのリポジトリ(非公開のものも含む)に及ぶ Worker 上で使われます。この Worker から漏れると、cambium がアクセスできるすべての情報が開示される認証情報を、3 つの整数を表示するためだけにここへコピーすることになります。STATUS_TOKEN で読み取れるのは件数だけです。また、生成できる認証情報なので、セットアップを自動化できます。Cloudflare はシークレットを一方向で保存するため、AUTH_TOKEN は手動で再入力するしかありません。
セルフホストする場合はサービスバインディングを追加する必要があります。 Worker は workers.dev のホスト名にフェッチして別の Worker にアクセスできません。Cloudflare のエッジが 404 を返し、対象の Worker は実行されません。これはトークンが拒否された場合とまったく同じように見えます。wrangler.toml に次を追加してください。
[[services]]
binding = "CAMBIUM"
service = "cambium-remote"
このリポジトリでは、意図的に [env.production] の下だけで宣言しています。サービスバインディングには対象が指定されるため、トップレベルで宣言すると、アカウントに cambium-remote がないユーザーのワンクリックデプロイが失敗するからです。
パネルはエラーを許容するように動作します。cambium の応答が遅い(予算は 10 秒)、停止している、または接続されていない場合でも、ページは表示され、その旨を伝えます。この呼び出しを行うのは Knowledge タブだけなので、ほかのタブに影響することはありません。
API トークンなしで、プッシュ時にデプロイする
すでにログイン済みの wrangler を使えば、git push から Worker を直接デプロイできます。Cloudflare API トークン、GitHub シークレット、ダッシュボードは不要です。
scripts/install-deploy-hook.cmd
git の pre-push フックをインストールします。デプロイしてからプッシュします。デプロイに失敗するとプッシュは中止されるため、デプロイできなかったコミットが origin に送られることはありません。これは、置き換え前の失敗とは逆の動作です。cambium-remote の CI は、すべてのマージを受け入れてもデプロイを一度も行わず、main が実行中の Worker より先に進んでいることを示すものもありませんでした。
main のみを対象とし、ブランチの削除はスキップします。git push --no-verify で一度だけスキップでき、-Remove でアンインストールできます。
名前付き環境があるリポジトリでは、-Env を指定しないとインストールを拒否します。 この拒否は細かすぎる配慮ではなく、重要な安全策です。wrangler deploy をそのまま実行すると、トップレベルのプロファイルが使われます。このリポジトリではそれがセルフホスト用プロファイルであり、Cloudflare に新しい空のデータベースを作成させるため、意図的に database_id が省略されています。ここで -Env なしのフックをインストールすると、次のプッシュ時に稼働中の Worker が空の D1 に接続されてしまいます。そのため、次のようにしてください。
# cambium-remote -- no named environments, bare deploy is correct
scripts/install-deploy-hook.cmd
# a repo whose real deploy lives under [env.production]
scripts/install-deploy-hook.cmd -Env production
このリポジトリではフックは不要です。GitHub Actions によるデプロイが機能しており、フックを使うとプッシュごとに 2 回デプロイされます。
CI を修正するだけではいけないのでしょうか? その手順は実際に自動化できないからです。GitHub Actions には CLOUDFLARE_API_TOKEN が必要ですが、Cloudflare API を通じて Cloudflare API トークンを作成するには、既存のトークンに User API Tokens: Edit 権限が必要です。Wrangler の OAuth ログインにはその権限がありません。29 個のスコープは workers/d1/pages/queues の操作と account:read で、トークン管理に関するものはありません。お使いのマシン上に、その認証情報を作成できる認証情報はありません。 貼り付けが必要なのはツールの不足ではなく、Cloudflare の権限モデルによるものです。ローカルでデプロイすれば、この問題をまるごと回避できます。
GitHub Actions CI を使用する場合
connect-cambium は、ステータスルートが見つからない場合、既存の wrangler ログインを使って cambium-remote 自体をデプロイします。そのため、Knowledge タブを機能させるために、GitHub Actions によるデプロイが動作している必要はありません。
cambium-remote をプッシュのたびに自動デプロイしたい場合にのみ必要です。このワークフローには 2 つの Cloudflare シークレットが必要で、どちらかが空だと警告なしに失敗します。マージはすべて緑色に見えるのに、何もデプロイされません。
scripts/fix-cambium-ci.cmd
CLOUDFLARE_ACCOUNT_ID は wrangler whoami から読み取られ、自動的に設定されます。これは認証情報ではなく識別子で、すべてのダッシュボード URL に含まれています。
CLOUDFLARE_API_TOKEN は一度貼り付ける必要があります。この手順だけは本当に省略できません。Cloudflare API トークンの作成には、User API Tokens: Edit 権限を持つ既存のトークンが必要で、wrangler の OAuth ログインはその代わりになりません。お使いのマシン上にある認証情報では、その認証情報を作成できません。 それ以外はすべて自動化されています。ブラウザーは正しいページを開き、トークンは表示せずに読み取られ、保存前に Cloudflare の API で検証されます。両方のシークレットは argv ではなく stdin 経由で渡され、以前失敗した実行も再トリガーされるため、スクリプトの説明を信じるだけでなく、成功して緑色になるのを確認できます。
Worker URL の設定(セルフホストする場合)
workers.dev ホストを報告する wrangler コマンドはありません。whoami、deployments list、versions list、deployments status のどれにも表示されないため、package.json に記載されています。
node -e "const p=require('./package.json');p.contextKeeper.workerUrl='https://<worker>.<account>.workers.dev';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2)+'
')"
セットアップスクリプトは、何かをインストールする前にこの値を読み取り、設定されていなければ実行を拒否します。この順序は意図的なものです。URL の設定先がないままインストールされたトークンは復旧できません。Cloudflare はシークレットを読み戻せないためです。
プラットフォームの対応状況について
| スクリプト | Windows | macOS / Linux |
|---|---|---|
set-view-token | .cmd / .ps1 | .sh |
connect-cambium | .cmd / .ps1 | 未移植 — 下記を参照 |
install-deploy-hook | .cmd / .ps1 | 未移植 — 下記を参照 |
fix-cambium-ci | .cmd / .ps1 | 未移植 — 下記を参照 |
未移植の 3 つは、いくつかのコマンドを実行するだけの薄いラッパーなので、手動で行う場合の手順は簡単です。cambium の接続:
TOKEN=$(head -c 32 /dev/urandom | base64 | tr '+/' '-_' | tr -d '=
')
printf '%s' "$TOKEN" | (cd ../cambium-remote && npx wrangler secret put STATUS_TOKEN)
# wait ~60s for the new version to roll out, then check it answers with counts:
curl -s "https://cambium-remote.<account>.workers.dev/status/$TOKEN" | head -c 200
printf '%s' "https://cambium-remote.<account>.workers.dev/status/$TOKEN" | npx wrangler secret put CAMBIUM_STATUS_URL --env production
プッシュ時のデプロイ — 対象リポジトリに .git/hooks/pre-push を作成し、改行コードを LF に設定して chmod +x を実行し、npx wrangler deploy を実行するようにします。そのリポジトリに名前付き環境がある場合は --env <name> を追加してください。指定せずにデプロイすると、セルフホストプロファイルが対象になり、稼働中の Worker が新しく空のデータベースにバインドされます。
CI の修正 — リポジトリに対して gh secret set CLOUDFLARE_ACCOUNT_ID と gh secret set CLOUDFLARE_API_TOKEN を実行し、それぞれの値は stdin から読み取ります。
セットアップスクリプトの編集
このスクリプトは、Windows に標準で付属し、.cmd から起動されるバージョンである Windows PowerShell 5.1 を対象としています。次の 5 点は動作に不可欠ですが、最新化できそうに見えるかもしれません。
RandomNumberGenerator::FillではなくRNGCryptoServiceProviderを使います。前者は .NET Core 専用のため、例外が発生します。-SkipHttpErrorCheckではなく、WebExceptionのステータスを手動で抽出します。これは PowerShell 7 専用です。??、?.、三項演算子は使いません。すべて PowerShell 7 専用で、ここでは構文エラーになります。- すべての wrangler 呼び出しは
Invoke-Wrangler経由で行います。5.1 では、ネイティブコマンドに対する2>&1は各 stderr 行を ErrorRecord でラップします。また、$ErrorActionPreference = 'Stop'の場合、最初のエラーは終了エラーになるため、通常の wrangler の通知だけで実行が停止します。 - 確認処理では
[Environment]::UserInteractive(常に true)ではなく[Console]::IsInputRedirectedを使って判定し、比較の前にRead-Hostを[string]にキャストします。$null -notmatch '...'は$trueではなく empty と評価されるため、単純なガードでは誤って通過してしまいます。
実行のたびに、トークンをマスクしたサニタイズ済みログ(.view-setup.log、.cambium-setup.log)が書き込まれるため、ウィンドウを閉じた後でも失敗の内容を確認できます。
⚠️ セキュリティ:コネクター URL は認証情報です
Claude に貼り付ける URL には、末尾のパスセグメントとして AUTH_TOKEN が埋め込まれています。
…/mcp/<AUTH_TOKEN> の完全な URL を知っている人は、ストア全体の読み書きができます。パスワードとまったく同じように扱ってください。
- 共有したり、スクリーンショットを撮ったり、ログに記録される可能性のある場所に貼り付けたりしないでください。
- ほかのパスへのリクエストや、トークンが間違っているリクエストには、詳細を含まない単純な
404が返されます(有効なトークンを使用していても、POST 以外のメソッドでは405が返されます)。 - トークンをローテーションするには: Cloudflare ダッシュボード(ステップ 2)で
AUTH_TOKENを変更します。これにより、以前の URL はすべて即座に無効になります。新しい値を使って claude.ai(ステップ 3)で更新するまで、以前のトークンを使うコネクターには404が返されます。
このセクションの内容は閲覧用 URL にもすべて当てはまりますが、こちらには有利な違いがあります。VIEW_TOKEN でできるのは読み取りだけです。閲覧用 URL が漏れると、インスタンス上のすべてのプロジェクトの意思決定サマリーが漏洩します。こちらのほうが機密性の高い情報かもしれませんが、書き込み、非推奨化、削除はできません。これこそが、認証情報を 1 つにまとめず、2 つに分けている理由です。
トークンを URL パスに含める理由と、それによる代償
これは意図的な設計上の選択であり、見落としではありません。claude.ai のカスタムコネクターはカスタムヘッダーを確実に送信しないため、代替手段として明白な Authorization: ヘッダーには依存できません。認証情報をパスに含めることで、コネクターが機能します。
ヘッダーの場合とは異なるため、その代償を理解しておいてください。
- リクエストボディが記録されない場所にも、URL は記録されます。 ブラウザーの履歴、シェルの履歴、プロキシや CDN のアクセスログ、クラッシュレポート、バグレポート、スクリーンショット、「リンクをコピー」ボタン、そしてエージェントのセッショントランスクリプトです。このセクションのきっかけとなった監査では、これらの Workers のコネクター URL が、1 台のマシン上にある 13 件のローカルセッショントランスクリプトから約 54 か所見つかりました。意図的に貼り付けられたものは 1 つもなく、エージェントがそのまま出力したツール設定に含まれていただけでした。
- Worker 自体は URL をログに記録しません。 すべてのログ行では、ルートは
/mcp/***として記録されます。漏洩の可能性があるのは Worker の周辺すべてであり、まさに監査できない部分です。 - トークンが漏洩すると、追加認証も呼び出し元ごとの識別情報もなく、全面的なアクセスが可能になります。 失効させるにはトークン自体を変更するしかなく、誰が使用したかを知らせるログもありません。
実用上のガイダンス:
- 疑わしいときだけでなく、定期的にローテーションしてください。 管理できない場所に URL が記録されていると想定してください。ローテーションは簡単です。
AUTH_TOKENを変更して、コネクターを更新します。 - コネクターが設定されているマシンのターミナル録画、トランスクリプト、画面キャプチャ、バグレポートを共有した場合は、ただちにローテーションしてください。
- 長く、ランダムなトークン(32 バイト以上。例:
openssl rand -hex 32)を使用してください。内容と長さの両方について定数時間で比較されるため、長さは外部から判別できません。それでも、推測への唯一の防御手段はエントロピーです。 - ヘッダーや OAuth を使える機会があれば、必ず利用してください。このトレードオフはクライアントによって強いられるものであり、望ましいものではありません。
ツール
すべてのツールでは、project を省略できます。省略した場合は、設定済みの
default_project が使用されます(config — op='set'、キー default_project で一度設定します)。
統合ツール(config、record_entry)が現在のインターフェースです。既存の呼び出し元との互換性を保つため、古い操作別ツールも非推奨のエイリアスとして引き続き利用できます。新しい実装では統合ツールを優先してください。
| ツール | 用途 |
|---|---|
config | 設定の読み取りまたは書き込みを行います。op='get' はキーを読み取り、op='set' はキーに書き込みます(value が必須です)。呼び出し時に project が省略された場合に使用するプロジェクトを選ぶには、キー default_project(グローバルスコープ、project なし)を使用します。 |
set_config / get_config | config(op='set') / config(op='get') の非推奨エイリアスです。 |
record_entry | 統合書き込みツールです。decision、constraint、または pipeline を記録します。必須フィールドは種類によって異なります。decision には summary、constraint には rule、pipeline には name が必要です。 |
record_decision | record_entry(kind='decision') の非推奨エイリアスです。指定できるフィールドは summary、problem、why_chosen、what_we_tried、tradeoffs、tags です。 |
record_constraint | record_entry(kind='constraint') の非推奨エイリアスです。必ず守るべきルールを記録します。指定できるフィールドは rule、reason、tags です。 |
record_pipeline | record_entry(kind='pipeline') の非推奨エイリアスです。再利用可能なプロセスを記録します。指定できるフィールドは name、purpose、steps です(追加フィールドはそのまま保持されます)。 |
get_context | クエリに対する関連度順の取得を行います(キーワードスコアリングを使用し、include_deprecated が指定されない限り非推奨項目を除外します)。何かを置き換えた項目には、以前の項目の内容と変更理由を示す1行の predecessor が付きます。これはローカルサーバーのものとバイト単位で同一であり、どちらのトランスポートでも同じ履歴を確認できます。 |
query_entries | 構造化フィルターを使用します。id、kind、tags(すべて一致する必要があります)、status(active/deprecated/all)、自由形式の text、limit を指定できます。 |
get_project_summary | 1回の呼び出しで概要を確認できます。種類とステータス別の項目数、存在する ID、アクティブな制約(簡潔な形式)、直近の decisions を返します。 |
list_projects | 組織のレジストリです。項目を持つすべてのプロジェクトと、プロジェクトごとのアクティブ項目数(decisions/constraints/pipelines)、アクティブ/非推奨の合計数、最終更新時刻を返します。組織全体を1回の呼び出しで列挙できるため、推測するのではなく、大文字と小文字を区別する正確なプロジェクト名を確認できます。 |
update_entry | patch フィールドを項目のペイロードにマージし、必要に応じて status を変更します。 |
deprecate_entry | 非推奨としてマークし、必要に応じて superseded_by をリンクし、reason を記録します(この理由が predecessor の行で引用されます)。 |
reload_constraints | アクティブな制約の簡潔な一覧を返します。 |
prune_stale | 古い非推奨項目を削除します(デフォルトではドライランです。dry_run=false を渡してください)。 |
verify_quality | 根拠を示すフィールドが不足している項目を検出します。 |
export_markdown | 項目を DECISIONS.md 形式のドキュメントとして出力します。 |
import_entries | ローカル JSON ストア形式から一括インポートします(ID と superseded を含むライフサイクルステータスを保持し、競合を報告します。既存データは上書きしません)。 |
upsert_entries | ローカルストア形式で一括 upsert します(ミラー同期用の経路です)。新しい ID は挿入されます。既存の ID は、受信側の updated_at が厳密に新しい場合にのみ置き換えられます(タイムスタンプによる最終書き込み優先)。それ以外の場合はスキップされます。ミラー間で編集と非推奨化を反映します。削除は行いません。 |
項目の規約
- Decisions では
summary、problem、why_chosen、what_we_tried、tradeoffs、tagsを使用します。非推奨のrationaleフィールドも入力時に受け付けられ、why_chosenがない場合はwhy_chosenにマッピングされます。 - Constraints では
rule、reason、tagsを使用します。 - Pipelines では
name、purpose、stepsと、渡された追加フィールドを使用します。 - ID はプロジェクトと種類ごとに割り当てられます。例:
dec-001、pipe-003、con-012。同じ ID が複数のプロジェクトで使われるため、D1 の主キーは複合キー(project, id)です。
メンテナー/コントリビューター向け
上記はすべてセルフホストする方向けです。このセクションでは、コード自体の開発について説明します。
設定レイアウト:1 つのリポジトリでボタンと CI の両方に対応する方法
wrangler.toml には 2 つのプロファイルがあります。
- デフォルト(トップレベル) — D1 バインディングは
database_idなしで宣言されています。 これはデプロイボタン、wrangler dev、およびローカルテストスイートで使われます。ID を指定しないと、Cloudflare はセルフホストする各ユーザー向けに新しいデータベースを自動的にプロビジョニングします。 [env.production]— メンテナーの実際のdatabase_idと Worker のnameを固定します。メンテナーの CI はwrangler deploy --env productionでデプロイするため、同じデータベースと同じ URL に接続し続けます。セルフホストするユーザーはこの環境を使いません。
cambium サービスバインディングは [env.production] のみに存在します。この分離は単なる整理ではなく、必須です。サービスバインディングでは対象の Worker を指定するため、トップレベルに [[services]] service = "cambium-remote" を置くと、その Worker が存在しないアカウント(メンテナーのアカウント以外すべて)でワンクリックデプロイが失敗します。同じ理由から、別の Worker、ID で指定する別のデータベース、または別のアカウントを指定するものは、名前付き環境に配置します。
名前付き環境は何も継承しません。本番環境へのデプロイに必要なすべてのバインディングを、[observability] を含めて、[env.production.*] の下に重ねて記述する必要があります。トップレベルにしか存在しないバインディングは、CI が実際にデプロイする環境では何も通知されずに欠落します。
デプロイパイプライン(メンテナー専用)
.github/workflows/deploy.yml は main へのプッシュ時に実行され、フォークは失敗する Actions を実行しないように if: github.repository == 'jarmstrong158/context-keeper-remote' で制限されています(フォークは代わりに Workers Builds 経由でデプロイします)。手順:チェックアウト → Node 22(Wrangler には ≥ 22 が必要)→ npm ci → npm test → wrangler deploy --env production。テストに合格しないとデプロイされません。GitHub リポジトリシークレットの CLOUDFLARE_API_TOKEN(Workers Scripts: Edit が必要)と CLOUDFLARE_ACCOUNT_ID を読み込みます。これは Worker 自身の AUTH_TOKEN とは別のものです。
ローカル開発
ネットワークも Cloudflare の認証情報も不要です。テストは @cloudflare/vitest-pool-workers 経由でローカルの workerd D1 に対して実行されます。Node ≥ 22 が必要です。
npm install
npm test # vitest: migrations, cold-start, CRUD, id sequencing, auth, import, ...
npm run typecheck # tsc --noEmit
ライブスモークテスト
デプロイ後、ネットワークに接続できる任意のマシンから実行します。
WORKER_URL="https://context-keeper-remote.<subdomain>.workers.dev/mcp/<AUTH_TOKEN>" \
node scripts/smoke-test.mjs
ライブ Worker に対して initialize → tools/list → record_decision → query_entries を実行します。
レイアウト
src/index.ts fetch handler: token check -> MCP dispatch (schema ensured lazily on first tools/call, not on the handshake)
src/mcp.ts stateless Streamable HTTP MCP server (createMcpHandler)
src/db.ts D1 access + runtime migration runner + id generation
src/entries.ts payload normalization, insert-with-retry, keyword scoring
src/tools/*.ts one module per tool group
src/view.ts the phone view: shell, tabs, knowledge panel, dispatch on ?e/?p/?q/?t
src/detail.ts entry detail, project drill-down, search, supersession trail
src/health.ts quality flags + the Projects and Health tables
src/install.ts enrolment cookie, web app manifest, home-screen icon
src/icon-data.ts GENERATED by scripts/make-icon.mjs -- do not hand-edit
schema.sql reference copy of the DDL the migration runner embeds
wrangler.toml default (auto-provision) + [env.production] (pinned) config
.github/workflows/deploy.yml test-then-deploy on push to main (maintainer repo)
scripts/smoke-test.mjs live JSON-RPC round-trip check
scripts/set-view-token.* create VIEW_TOKEN, verify, QR, save the URL (.cmd = double-click)
scripts/connect-cambium.* generate STATUS_TOKEN on cambium-remote and wire it here
scripts/make-icon.mjs regenerate the home-screen PNG (npm run make-icon)
test/ vitest suite (local workerd D1, no network)
メンテナーのデプロイに関するトラブルシューティング
| Actions ログの症状 | 原因 | 対処方法 |
|---|---|---|
Wrangler requires at least Node.js v22.0.0 | Node < 22 | deploy.yml ではすでに Node 22 に設定されています。 |
it's necessary to set a CLOUDFLARE_API_TOKEN environment variable | デプロイ用シークレットが不足しています | GitHub リポジトリシークレットを両方追加してください。 |
No route for that URI [code: 7000] / object identifier is invalid [code: 7003] | API トークンに Workers 権限がないか、CLOUDFLARE_ACCOUNT_ID が間違っています | 「Edit Cloudflare Workers」トークンを使用し、アカウント ID を確認してください。 |
デプロイは成功するものの、すべての呼び出しが 404 を返す | Worker の AUTH_TOKEN が設定されていないか、URL のトークンが一致していません | Cloudflare ダッシュボードで AUTH_TOKEN を設定/確認してください。 |
関連項目
- context-keeper — この Worker がリモートトランスポートとしてホストする、ローカル stdio 版のオリジナルです。
- xylem — これが属するスタックです。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。



