Skip to main content
Glama
pnaskardev

Batcave-MCP

by pnaskardev

Batcave — レジュメレビューMCPサーバー

2つのドキュメント — レジュメ と 求人情報 — を受け取り、3段階のレビューを実行するMCPサーバーです。各段階は次の段階に受け渡されます。マッチレポートができる前に書き換えはできず、書き換えができる前にATSパスは実行できません。

パイプライン

ツール

機能

start_review

受け付け。レジュメと求人情報を生テキストまたは .pdf / .docx / .txt / .md ファイルへのパスとして受け取り、テキストを抽出してセッションを開きます。

resume_match_report

ステージ1。 対象企業のシニアリクルーター: 100点満点のマッチスコア、不足しているキーワード上位5件、採用担当者が10秒以内に見つける3つのレッドフラグ。

rewrite_experience_xyz

ステージ2。 経験セクションを、ステージ1のキーワードを盛り込みレッドフラグを除去する形で書き換えます。すべての箇条書きはGoogle XYZ形式 — Xを達成し、Yで測定され、Zを行うことによって。

ats_scroll_stopper_pass

ステージ3。 ATSパーサーパスに加え、200件中147件目のレジュメを見る採用担当者: どのセクションがスキップされるかを特定し、スクロールを止めるように書き換えます。最終レジュメを返します。

session_status

どのステージが完了済みか、結果待ちか、未開始か、次に何を呼ぶべきかを示します。

list_sessions

保存済みセッションを、最近更新された順に表示します。

export_dossier

レビュー全体 — 3つのステージすべてと最終レジュメ — を1つのマークダウンドキュメントとして返します。

delete_session

セッションとそれに関連付けられたすべてのデータを削除します。自動的に期限切れになるものはありません。

Related MCP server: resume-fit-scanner

ステージの実行方法

サーバーはモデルを呼び出しません。ブリーフを構成し、状態を保持し、順序を強制します。推論を行うのは接続されたクライアントのモデルです。したがって、各ステージツールは2回呼び出されます:

  1. { session_id } — そのステージの分析ブリーフを返します。レジュメ、求人情報、およびそれ以前のすべてのステージの出力がすでに埋め込まれています。

  2. { session_id, result } — 回答を記録します。result はステージのスキーマに対して検証されるため、4つのキーワードしかないレポートは保存されずに拒否されます。

ステージ2は記録されたステージ1のレポートを読み取ります。ステージ3はオリジナルではなく、ステージ2の updated_resume を読み取ります。順序を無視して呼び出されたステージは、最初に呼び出す必要があるツール名とともに失敗します。

ブリーフに組み込まれた2つのルール

  • 捏造された数値は禁止。 元のレジュメに数値がない場合、書き換えは [QUANTIFY: 測定するもの] を出力し、それを placeholders_needing_user_input にリストします。

  • キーワードの詰め込みは禁止。 キーワードは実際の経験がそれを裏付ける場合にのみ入れられ、残りは理由とともに keywords_not_addressed に返されます。

トランスポート

2つのエントリーポイント、同じツール:

エントリー

トランスポート

用途

index.ts

stdio

同じマシン上のクライアント — Claude Code、IDE

serve.ts

/mcp 上のStreamable HTTP

リモートクライアント — コンテナ内で実行されるのはこちら

stdioは1台のマシン上の2つのプロセス間のパイプであり、ネットワーク経由で到達することはできません。stdioを提供するコンテナは接続を受け付けないため、EC2パスが serve.ts を使用するのはそのためです。

serve.ts は2つの変数を必要とし、どちらかがなければ起動を拒否します:

  • DB_URL — Postgres接続文字列

  • MCP_AUTH_TOKEN — 共有シークレット。すべてのリクエストに Authorization: Bearer <token> が必要です。

GET /healthz は認証不要の唯一のルートです。データベース接続を開かないため、それをポーリングするロードバランサーがPostgresを起動することはありません。

ストレージ

すべてはPostgresに保存されます。サーバーはローカルディスクに何も書き込みません — ローカルで読み取るのは、指定したレジュメと求人情報のファイルのみです。

resume_sessions(id, created_at, updated_at, company, role,
                resume jsonb, job_description jsonb)
resume_stages(session_id -> resume_sessions.id on delete cascade, stage, status,
              issued_at, completed_at, result jsonb, primary key (session_id, stage))
schema_migrations(module, id, applied_at)     -- shared, owned by src/platform/db.ts

1つのドキュメントではなく2つのテーブルを使用するため、ステージの記録は両方のレジュメを書き換えるのではなく1行を書き込むだけで済み、list_sessions はドキュメントテキストをまったく選択しません。テーブルにはモジュールのプレフィックスが付けられ、マイグレーションはそのモジュールの最初のクエリで遅延実行されます — サーバーの起動はデータベースを起動しません。

マイグレーションは追記のみで、schema_migrations に記録されるため、各マイグレーションはデータベースごとに正確に1回実行されます。bun run db:migrate は保留中のものを適用します。サーバーはフォールバックとして、モジュールの最初のクエリでも遅延実行します。

自動的に期限切れになるものはありません。セッションは delete_session が削除するまで蓄積されます。

実行方法

bun install
bun run dev        # Postgres + the server, hot reload, nothing to configure

これは docker compose -f docker-compose.dev.yml up --build です: Postgresを起動し、開発用とテスト用のデータベースを作成し、マイグレーションを実行し、トークン dev-token-not-a-secret で http://127.0.0.1:3000/mcp でMCPを提供します。src/ 配下の何かを編集すると、実行中のサーバーがリロードされます。

代わりにホスト上でサーバーを直接実行するには:

export DB_URL='postgres://postgres:postgres@localhost:55432/batcave'
bun start          # stdio, for a client on this machine
bun run serve      # HTTP on :3000, also needs MCP_AUTH_TOKEN

サーバーの実行を必要としない2つのデータベースコマンド:

bun run db:check      # can this machine reach DB_URL, and what is in it?
bun run db:migrate    # create or update the tables; safe to run repeatedly

db:check は、サービスを提供せずに接続を開く唯一のものです。両方のエントリーポイントは起動時に DB_URL を検証しますが、最初のクエリで遅延接続するため、クリーンな起動は何も証明しません。

チェック:

bun run check      # Biome format + lint  (check:fix to apply)
bun run typecheck
bun test           # unit tests; no database needed

TEST_DB_URL='postgres://postgres:postgres@localhost:55432/batcave_test' bun test

エンドツーエンドテストは、実際のPostgresに対して実際のワイヤープロトコルで通信し、ティアダウン時にテーブルを削除します。これらは DB_URL ではなく、意図的に TEST_DB_URL を読み取るため、サーバーを実際のデータベースに向けてもティアダウンを仕掛けることはできません — また、開発スタックには別の batcave_test データベースが同梱されているため、テストを実行しても実行中のサーバーを妨げることはありません。

このディレクトリの .mcp.json は、Claude Code用にstdioサーバーを登録します。別のクライアントの場合:

{ "command": "bun", "args": ["index.ts"], "cwd": "/path/to/Batcave" }

EC2での実行方法

export DB_URL='postgres://user:pass@host/db?sslmode=require'
export MCP_AUTH_TOKEN="$(openssl rand -hex 32)"

bun run db:check                       # confirm the instance is reachable from this box
docker compose run --rm mcp bun scripts/migrate.ts   # create the tables
docker compose up -d --build
docker compose logs -f mcp

サーバーがトラフィックを受ける前にマイグレーションを実行してください。 これをスキップすると、最初のツール呼び出しで自動的にマイグレーションされますが、その場合、壊れたマイグレーションはデプロイの失敗ではなくユーザーリクエストの失敗として表面化し、最初の呼び出し元がスキーマを待つことになります。新しいマイグレーションを同梱するデプロイのたびに db:migrate を再実行してください。適用するものがない場合は何もしません。

Composeは、どちらかの変数が未設定の場合、起動を拒否します。シェルプロファイルまたはインスタンスシークレットに保管してください — このリポジトリのファイルには入れないでください。

公開ポートは意図的に 127.0.0.1:3000 です。 エンドポイントは平文HTTPで通信し、ベアラートークンで認証します。オープンインターネット上では、そのトークンは経路上の誰にでも読み取られます。その前にTLSを配置してください — HTTPSを終端してインスタンスに転送するALB、または同じボックス上のnginx/Caddyが 127.0.0.1:3000 にプロキシする方法です。その後、セキュリティグループはクライアントからの443のみを許可し、それ以外は許可しないようにします。ポート3000は外部に閉じたままにします。

トークンのローテーションは export MCP_AUTH_TOKEN=... && docker compose up -d で、コンテナが再起動されます。全員に1つのトークンがあります — 誰も特定しないため、あなたのセッションと友人のセッションを区別できません。ユーザーごとのアクセスには、実際の認証と resume_sessions のオーナー列が必要ですが、どちらもまだ存在しません。

resume_path はコンテナ内で解決されるため、リモートの呼び出し元はそれを使用できません — 彼らのラップトップ上のパスはサーバーにとって意味がありません。HTTP経由では、resume_text と job_description_text を渡してください。ボックス上のファイルでパス形式を機能させたい場合は、ボリュームをマウントしてください。

docker-compose.yml は本番スタックのみです。ローカル開発では docker-compose.dev.yml を使用し、独自のPostgresを同梱し、この構成を一切共有しません。

レイアウト

サーバーはモジュールのホストです。モジュールとは、独自のテーブルと独自の語彙を持つ、自己完結型のツールファミリーです。レジュメレビューは今日のところ唯一のものであり、2つ目の無関係なモジュールは src/features/ 配下のフォルダーと、index.ts のリストの1エントリです。

index.ts                          stdio entrypoint
serve.ts                          HTTP entrypoint (the container runs this)
src/modules.ts                    the one list of mounted modules, shared by both entries
src/module.ts                     the ToolModule contract every feature implements
src/server.ts                     mounts modules onto an McpServer
src/http.ts                       Streamable HTTP handler, bearer auth, /healthz
src/platform/                     feature-agnostic; knows nothing about resumes
  db.ts                             lazy Postgres pool + per-module migration runner
  documents.ts                      text / pdf / docx extraction
  stored-document.ts                what an extracted document looks like
  tool-result.ts                    keeps `content` and `structuredContent` in step
src/features/resume-review/
  index.ts                          the ToolModule: name, migrations, register()
  migrations.ts                     this module's tables
  sessions.ts                       repository, domain types, stage gating
  briefs.ts                         the three briefs
  schemas.ts                        zod schema per stage result
  stage-tool.ts                     the brief-then-record tool shape
  dossier.ts                        markdown rendering
  tools/                            one file per group of registered tools
    intake.ts, stages.ts, dossier.ts, session-admin.ts

構造を支える2つのルール:

  • src/platform は src/features からインポートしません。 2つ目のモジュールも必要とするものはplatformに属し、レジュメレビューのみが必要とするものはフィーチャーに残ります。

  • モジュールは他のモジュールをインポートしません。 互いを知る必要がある2つのモジュールは、1つのモジュールです。

stage-tool.ts はplatformではなく、意図的にフィーチャー内に配置されています。ブリーフ→記録の形状は再利用可能になるかもしれませんが、今日のところ消費者は正確に1つであり、2つ目が存在する前に一般的なケースを推測することは、プラットフォーム層が腐る方法です。

モジュールの追加

// src/features/interview-prep/index.ts
export const interviewPrep: ToolModule = {
  name: "interview-prep",
  migrations,                       // its own tables, namespaced in schema_migrations
  register(server) {
    registerWhateverTools(server);
  },
};
// index.ts
const server = createServer([resumeReview, interviewPrep]);

これが契約のすべてです。マイグレーションはそれぞれ1回適用され、schema_migrations でモジュールごとに追跡され、そのモジュールが最初にデータベースに触れたときに遅延実行されます — 未使用のモジュールはラウンドトリップを消費しません。tests/modules.test.ts は、レジュメとは無関係のスタブモジュールでシームをテストします。

貢献

CONTRIBUTING.md を参照してください — bun run dev がセットアップ全体です。セキュリティの問題は公開イシューではなく、SECURITY.md を通じて報告してください。

ライセンス

MIT。

Related MCP Connectors

Related MCP Servers