Skip to main content
Glama
pnaskardev

Batcave-MCP

by pnaskardev

Batcave — MCP-сервер для проверки резюме

MCP-сервер, который принимает два документа — резюме и описание вакансии — и прогоняет их через трехэтапную проверку. Каждый этап служит входом для следующего: нельзя переписывать, пока нет отчета о соответствии, и нельзя запускать проход ATS, пока нет переписанной версии.

Конвейер

Инструмент

Что делает

start_review

Прием. Принимает резюме и описание вакансии в виде обычного текста или пути к файлу .pdf / .docx / .txt / .md, извлекает текст и открывает сессию.

resume_match_report

Этап 1. Старший рекрутер в целевой компании: оценка соответствия из 100, топ-5 недостающих ключевых слов, 3 красных флага, которые менеджер по найму замечает менее чем за 10 секунд.

rewrite_experience_xyz

Этап 2. Переписывает раздел об опыте, чтобы включить ключевые слова этапа 1 и убрать его красные флаги, каждый пункт в форме Google XYZ — достиг X, измеряемый Y, путем выполнения Z.

ats_scroll_stopper_pass

Этап 3. Проход парсера ATS плюс менеджер по найму на резюме №147 из 200: какие разделы пропускаются, затем переписывает их, чтобы остановить прокрутку. Возвращает итоговое резюме.

session_status

Какие этапы завершены, ожидают результата или не начаты, и что вызывать дальше.

list_sessions

Сохраненные сессии, сначала самые недавно обновленные.

export_dossier

Возвращает всю проверку — все три этапа плюс итоговое резюме — в виде одного markdown-документа.

delete_session

Удаляет сессию и все, что с ней связано. Ничто не истекает само по себе.

Related MCP server: ats-resume-writer

Как работает этап

Сервер не вызывает модель. Он составляет бриф, хранит состояние и обеспечивает порядок; модель подключенного клиента выполняет рассуждения. Поэтому каждый инструмент этапа вызывается дважды:

  1. { session_id } — возвращает аналитический бриф для этого этапа, с уже встроенными резюме, описанием вакансии и результатами всех предыдущих этапов.

  2. { session_id, result } — записывает ответ. result проверяется по схеме этапа, поэтому отчет с четырьмя ключевыми словами вместо пяти отклоняется, а не сохраняется.

Этап 2 читает записанный отчет этапа 1. Этап 3 читает updated_resume из этапа 2, а не оригинал. Этап, вызванный не по порядку, завершается ошибкой с именем инструмента, который нужно вызвать первым.

Два правила, заложенные в брифы

  • Никаких выдуманных метрик. Если в исходном резюме нет числа, переписанная версия выдает [QUANTIFY: what to measure] и перечисляет его в placeholders_needing_user_input.

  • Никакого набивания ключевыми словами. Ключевое слово включается только там, где его поддерживает реальный опыт; остальные возвращаются в keywords_not_addressed с указанием причины.

Транспорты

Две точки входа, одни и те же инструменты:

Вход

Транспорт

Для

index.ts

stdio

Клиент на той же машине — Claude Code, IDE

serve.ts

Streamable HTTP на /mcp

Удаленный клиент — именно это работает в контейнере

stdio — это канал между двумя процессами на одной машине; по сети до него не добраться. Контейнер, обслуживающий stdio, не принимал бы никаких соединений, поэтому путь EC2 использует serve.ts.

serve.ts требует две переменные и отказывается запускаться без каждой из них:

  • 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

Две таблицы вместо одного документа, поэтому запись этапа добавляет одну строку, а не переписывает оба резюме, и list_sessions вообще не выбирает текст документа. Таблицы имеют префикс модуля, а миграции выполняются лениво при первом запросе этого модуля — запуск сервера не будит базу данных.

Миграции являются append-only и записываются в schema_migrations, поэтому каждая выполняется ровно один раз на базу данных. 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 и test, выполняет миграции и обслуживает MCP на http://127.0.0.1:3000/mcp с токеном dev-token-not-a-secret. Редактирование чего-либо в 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

Две команды базы данных, ни одна из которых не требует работающего сервера:

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 и удаляют свои таблицы при завершении. Они читают TEST_DB_URL, намеренно не DB_URL, поэтому указание серверу на реальную базу данных не может активировать удаление — а dev-стек поставляет отдельную базу данных batcave_test, так что запуск тестов никогда не мешает работающему серверу.

.mcp.json в этом каталоге регистрирует stdio-сервер для Claude Code. Для другого клиента:

{ "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 при каждом деплое, который включает новую миграцию; это no-op, когда применять нечего.

Compose отказывается запускаться, если какая-либо переменная не задана. Храните их в профиле оболочки или в секрете инстанса — не в файле в этом репозитории.

Опубликованный порт — 127.0.0.1:3000, намеренно. Конечная точка говорит по открытому HTTP и аутентифицируется с помощью bearer-токена: в открытом интернете этот токен может прочитать любой на пути. Поставьте перед ним TLS — ALB, завершающий HTTPS и пересылающий на инстанс, или nginx/Caddy на той же машине, проксирующий на 127.0.0.1:3000. Тогда группа безопасности должна разрешать 443 от ваших клиентов и ничего больше; порт 3000 остается закрытым для мира.

Ротация токена — это export MCP_AUTH_TOKEN=... && docker compose up -d, что перезапускает контейнер. Токен один для всех — он никого не идентифицирует, поэтому не может отличить ваши сессии от сессий друга. Доступ для каждого пользователя требует настоящей аутентификации и колонки владельца в resume_sessions; ни того, ни другого пока нет.

resume_path разрешается внутри контейнера, поэтому удаленный вызывающий не может его использовать — пути на его ноутбуке ничего не значат для сервера. По HTTP передавайте resume_text и job_description_text. Смонтируйте том, если хотите, чтобы форма пути работала для файлов на машине.

docker-compose.yml — это только продакшн-стек. Локальная разработка использует docker-compose.dev.yml, который поднимает собственный Postgres и не разделяет ни одной из этих конфигураций.

Структура

Сервер является хостом для модулей. Модуль — это самодостаточное семейство инструментов, которое владеет своими таблицами и своим словарем. Проверка резюме — единственный такой модуль на сегодня; второй, не связанный, — это папка в src/features/ и одна запись в списке в index.ts.

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

Два правила поддерживают структуру:

  • src/platform никогда не импортирует из src/features. Все, что может понадобиться второму модулю, принадлежит платформе; все, что нужно только проверке резюме, остается в функциональности.

  • Ни один модуль не импортирует другой модуль. Два модуля, которым нужно знать друг о друге, — это один модуль.

stage-tool.ts намеренно живет внутри функциональности, а не в платформе. Форма «сначала бриф, затем запись» может оказаться переиспользуемой, но сегодня у нее ровно один потребитель, а угадывание общего случая до появления второго — это то, как гниет слой платформы.

Добавление модуля

// 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]);

Это весь контракт. Миграции применяются по одному разу, отслеживаются для каждого модуля в schema_migrations и выполняются лениво при первом обращении модуля к базе данных — неиспользуемый модуль не стоит ни одного запроса. tests/modules.test.ts проверяет стык с помощью заглушечного модуля, не имеющего отношения к резюме.

Участие в разработке

См. CONTRIBUTING.mdbun run dev — это вся настройка. Проблемы безопасности отправляются через SECURITY.md, а не через публичные issues.

Лицензия

MIT.

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

View all related MCP servers

Related MCP Connectors

  • Tailor resumes, generate cover letters, render CVs as PDF, and browse 22+ templates.

  • Search 6.3M+ live jobs from companies' own career pages, plus resume tailoring & cover letters.

  • Search AI-native jobs, inspect application forms, and fetch free interview-prep resources.

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/pnaskardev/Batcave-MCP'

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