Batcave-MCP
Batcave — 이력서 검토 MCP 서버
두 문서, 즉 **이력서(resume)**와 **채용 공고(job description)**를 입력받아 3단계 검토를 수행하는 MCP 서버입니다. 각 단계는 다음 단계로 이어집니다. 매치 리포트가 있어야 재작성을 할 수 있고, 재작성이 있어야 ATS 패스를 실행할 수 있습니다.
파이프라인
Tool | 기능 |
| 입력 단계. 이력서와 채용 공고를 원시 텍스트 또는 |
| 1단계. 대상 회사의 시니어 리크루터: 100점 만점 매치 점수, 누락된 상위 5개 키워드, 채용 담당자가 10초 안에 발견하는 3가지 레드 플래그. |
| 2단계. 경력 섹션을 1단계의 키워드를 담고 레드 플래그를 제거하도록 재작성합니다. 모든 불릿은 Google XYZ 형식 — Z를 수행하여 Y로 측정되는 X를 달성 — 으로 작성합니다. |
| 3단계. ATS 파서 패스와 200개 중 147번째 이력서를 보는 채용 담당자: 건너뛰는 섹션을 찾아 스크롤을 멈추도록 재작성합니다. 최종 이력서를 반환합니다. |
| 완료된 단계, 결과 대기 중인 단계, 시작되지 않은 단계와 다음에 호출할 대상을 알려줍니다. |
| 저장된 세션을 최근 업데이트순으로 표시합니다. |
| 전체 검토(3개 단계와 최종 이력서)를 하나의 마크다운 문서로 반환합니다. |
| 세션과 그에 저장된 모든 것을 삭제합니다. 자동으로 만료되는 것은 없습니다. |
Related MCP server: ats-resume-writer
단계 실행 방식
서버는 모델을 호출하지 않습니다. 서버는 브리프를 구성하고 상태를 보관하며 순서를 강제합니다. 추론은 연결된 클라이언트의 모델이 수행합니다. 따라서 각 단계 도구는 두 번 호출됩니다:
{ session_id }— 해당 단계의 분석 브리프를 반환합니다. 이력서, 채용 공고, 그리고 이전 모든 단계의 출력이 이미 포함되어 있습니다.{ session_id, result }— 답변을 기록합니다.result는 해당 단계의 스키마에 대해 검증되므로, 키워드 5개 대신 4개인 리포트는 저장되지 않고 거부됩니다.
2단계는 기록된 1단계 리포트를 읽습니다. 3단계는 원본이 아닌 2단계의 updated_resume을 읽습니다. 순서에 어긋나게 호출된 단계는 먼저 호출해야 하는 도구 이름과 함께 실패합니다.
브리프에 내장된 두 가지 규칙
지어낸 지표 금지. 원본 이력서에 숫자가 없는 경우 재작성은
[QUANTIFY: what to measure]를 출력하고 이를placeholders_needing_user_input에 나열합니다.키워드 채워 넣기 금지. 키워드는 실제 경험이 뒷받침하는 곳에만 들어갑니다. 나머지는 이유와 함께
keywords_not_addressed에 반환됩니다.
전송 방식
두 개의 진입점, 동일한 도구:
진입점 | 전송 방식 | 용도 |
| stdio | 같은 머신의 클라이언트 — Claude Code, IDE |
|
| 원격 클라이언트 — 컨테이너에서 실행되는 것 |
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는 문서 텍스트를 전혀 선택하지 않습니다. 테이블은 모듈별로 접두사가 붙으며, 마이그레이션은 해당 모듈의 첫 번째 쿼리에서 지연 실행됩니다. 서버를 시작해도 데이터베이스는 깨어나지 않습니다.
마이그레이션은 추가 전용이며 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 데이터베이스를 만들고, 마이그레이션을 실행하고, http://127.0.0.1:3000/mcp에서 토큰 dev-token-not-a-secret으로 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서버 실행이 필요 없는 두 개의 데이터베이스 명령:
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 repeatedlydb: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에 대해 실제 와이어 프로토콜로 통신하며 teardown 시 테이블을 삭제합니다. 이 테스트는 의도적으로 DB_URL이 아닌 TEST_DB_URL을 읽으므로, 서버를 실제 데이터베이스에 연결해도 teardown이 작동하지 않습니다. 또한 dev 스택에는 별도의 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로 통신하고 bearer 토큰으로 인증합니다. 공개 인터넷에서는 경로상의 누구나 그 토큰을 읽을 수 있습니다. 앞에 TLS를 두세요. HTTPS를 종료하고 인스턴스로 전달하는 ALB, 또는 같은 박스에서 127.0.0.1:3000으로 프록시하는 nginx/Caddy를 사용하세요. 그러면 보안 그룹은 클라이언트의 443만 허용하고 그 외에는 아무것도 허용하지 않아야 합니다. 포트 3000은 외부에 닫혀 있어야 합니다.
토큰 교체는 export MCP_AUTH_TOKEN=... && docker compose up -d이며 컨테이너를 재시작합니다. 모두를 위한 토큰은 하나뿐입니다. 누구도 식별하지 않으므로 내 세션과 친구의 세션을 구분할 수 없습니다. 사용자별 접근에는 실제 인증과 resume_sessions의 owner 열이 필요합니다. 둘 다 아직 없습니다.
resume_path는 컨테이너 내부에서 해석됩니다. 따라서 원격 호출자는 이를 사용할 수 없습니다. 그들의 노트북에 있는 경로는 서버에 의미가 없습니다. HTTP에서는 resume_text와 job_description_text를 전달하세요. 박스의 파일에 대해 경로 형식을 사용하려면 볼륨을 마운트하세요.
docker-compose.yml은 프로덕션 스택 전용입니다. 로컬 개발은 자체 Postgres를 가져오고 이 구성 중 어떤 것도 공유하지 않는 docker-compose.dev.yml을 사용합니다.
구조
서버는 모듈의 호스트입니다. 모듈은 자체 테이블과 자체 용어를 소유하는 독립적인 도구 모음입니다. 현재 이력서 검토가 유일한 모듈입니다. 두 번째 무관한 모듈은 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에서 import하지 않습니다. 두 번째 모듈도 원할 만한 것은 platform에 속하고, 이력서 검토만 원하는 것은 feature에 남습니다.어떤 모듈도 다른 모듈을 import하지 않습니다. 서로를 알아야 하는 두 모듈은 하나의 모듈입니다.
stage-tool.ts는 의도적으로 platform이 아닌 feature 안에 있습니다. 브리프 후 기록(brief-then-record) 형태는 재사용 가능할 수도 있지만, 현재 소비자는 정확히 하나뿐입니다. 두 번째 소비자가 생기기 전에 일반적인 경우를 추측하는 것이 platform 계층을 썩게 만드는 방법입니다.
모듈 추가하기
// 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.md를 참조하세요. bun run dev가 전체 설정입니다. 보안 문제는 공개 이슈가 아닌 SECURITY.md를 통해 접수합니다.
라이선스
MIT.
This server cannot be installed
Maintenance
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
- FlicenseNot gradedqualityDmaintenanceAnalyzes resumes against job descriptions to identify missing skills, keywords, and improvement opportunities using AI. Provides structured feedback including gap analysis, ATS optimization suggestions, and actionable recommendations to improve job application success.
- AlicenseAqualityCmaintenanceRewrites resumes to beat ATS screening (Workday, Greenhouse, iCIMS, Taleo) against a specific job description, with strict truthfulness guardrails — never invents dates, metrics, titles, or seniority. Pay-what-you-want access codes ($0 works).2MIT
- FlicenseNot gradedqualityDmaintenanceAutomates ATS resume scanning via Jobscan, enabling AI to iteratively scan, analyze gaps, optimize, and rescan resumes against job descriptions to improve match rates.3
- FlicenseAqualityCmaintenanceEnables tailoring resumes to job descriptions by scraping JDs, applying rules, and generating optimized DOCX resumes.11
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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