@backendx/mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +196 -0
  2. package/README.md +550 -0
  3. package/dist/index.js +7895 -0
  4. package/package.json +45 -0
package/README.md ADDED
@@ -0,0 +1,550 @@
1
+ # backendx-mcp
2
+
3
+ BackendX API를 AI 에이전트가 사용할 수 있도록 MCP(Model Context Protocol) 서버로 래핑한 프로젝트입니다.
4
+ 프로젝트 인터뷰 → 코드 생성 → 로컬 실행 → 배포 → 운영 → 구독 관리까지, backendx-frontend가 제공하는
5
+ 워크플로우를 터미널 에이전트가 수행할 수 있도록 하는 도구들을 제공합니다.
6
+ 도구 수와 전체 목록은 아래 "등록된 MCP 도구" 절이 정본입니다.
7
+
8
+ ## 기술 스택
9
+
10
+ - **MCP SDK**: `@modelcontextprotocol/sdk` v1.29.0
11
+ - **입력 검증**: `zod` v4
12
+ - **빌드**: `tsup` (ESM, ES2022)
13
+ - **런타임**: Node.js >= 18
14
+ - **언어**: TypeScript
15
+
16
+ ## 등록된 MCP 도구 (76종)
17
+
18
+ ### 인증 · 계정
19
+
20
+ | 도구 | 설명 |
21
+ | -------------------- | --------------------------------------------------------- |
22
+ | `authenticate` | Google 토큰으로 BackendX 인증 |
23
+ | `get_account` | 계정 정보 조회 — 연결된 로그인 제공자, legacy 크레딧, 인트로·쿠폰 플래그(`held_coupons` 파생) |
24
+ | `get_github_account` | 연결된 GitHub 계정 조회 (소스 레포 collaborator 등록용) |
25
+ | `link_github` | GitHub PAT로 계정 연결 (OAuth 대안, 소스코드 접근에 필요) |
26
+ | `unlink_github` | GitHub 연결 해제 (`confirm=true` 필요 — 모든 미러 레포의 collaborator 권한 즉시 회수) |
27
+
28
+ ### 프로젝트 생명주기 (인터뷰 → 생성)
29
+
30
+ | 도구 | 설명 |
31
+ | ----------------------- | -------------------------------------------------------------------- |
32
+ | `get_consent_questions` | 생성 전 동의 질문지 정의 조회 (프로젝트·인증 불요, `stage` 필터) |
33
+ | `create_project` | 새 프로젝트 생성 (직후 project_start 5종 답변 적재가 정본 순서) |
34
+ | `list_projects` | 프로젝트 목록 조회 |
35
+ | `get_project_status` | 프로젝트 상태 조회 (+ 구독 요약·첨부 허용량·내 역할, `has_failed_stage` 로 요구사항 단계의 **입력 대기 vs 멈춤** 판정) |
36
+ | `rename_project` | 프로젝트 이름(label) 변경 |
37
+ | `get_deletion_preview` | 프로젝트 삭제 가능 여부·차단 사유·**즉시 정산될 금액** 미리보기 (revision 발급, TTL 15분) |
38
+ | `delete_project` | 프로젝트 영구 삭제 (`confirm=true` + `preview_revision` 필요, 구독 즉시 해지·미청구분 즉시 결제) |
39
+ | `send_message` | 메시지 전송 및 AI 응답 수신 (변경 한도 402 는 사유별 분기) |
40
+ | `get_messages` | 대화 이력(인터뷰 문답 + progress) 조회, 최신 우선 (부모 리비전 포함) |
41
+ | `upload_attachment` | 로컬 파일을 요구사항 첨부로 업로드 (비동기 SRS 반영, 플랜별 한도) |
42
+ | `download_attachment` | 첨부 파일 다운로드 (id 는 `get_messages` 의 attachment 메시지에서, 410 = 보존기간 만료) |
43
+ | `list_revisions` | SRS 리비전 이력(변경 요약) 조회 |
44
+ | `wait_for_pipeline` | 코드 생성 파이프라인 완료 대기 (현재 단계 실측 평균 소요 동반) |
45
+ | `retry_pipeline` | 멈추거나 실패한 파이프라인 재시도 (`restart_point` 로 재시작 지점 구분 — `interview` 는 SRS 를 비우고 인터뷰 재개, 점검 대기 중엔 `MAINTENANCE_PENDING`) |
46
+ | `get_system_status` | 플랫폼 health + 점검 대기 여부 (파라미터·인증 불요 — 새 실행이 보류되는 이유를 가르는 유일한 조회) |
47
+ | `get_progress` | 단계별 파이프라인 진행 메시지 조회 (페이지네이션) |
48
+
49
+ ### 문서 · 산출물
50
+
51
+ | 도구 | 설명 |
52
+ | ------------------- | ------------------------------------------------------------------------------------------------------------ |
53
+ | `get_docs` | 프로젝트 문서 조회 — SRS, 아키텍처, DB 스키마, Dockerfile, API 문서, 스케줄 작업(`tasks`), 도커 이미지, 소스 저장소 URL |
54
+ | `purchase_docs` | 문서 접근 가능 여부 판정 + GitHub 소스 미러 개설(`repo`) — 문서 접근은 플랜이 결정하며 개별 구매는 없다 |
55
+ | `get_api_clipboard` | 프론트·클라이언트 앱 구현용 완성형 프롬프트 조회 — API 문서를 연동 지시문에 얹어 그대로 붙여넣을 수 있게 준다 (웹 콘솔 "AI 프롬프트 복사"와 동일 경로). 배포된 프로젝트의 실 base URL 을 기본으로 싣는다(`include_deployed_base_url` 기본 true — 원 API 기본값을 뒤집음). `link=true`는 문서를 미인증 공개 URL 로 대체해 응답을 수 KB 로 줄이지만, **사용자 확인 후에만** 켠다 |
56
+ | `download_source` | 생성된 소스코드 ZIP 다운로드 및 추출 (Builder 플랜 이상, 받는 시점의 스냅샷 — `type` 으로 env 버킷 선택, **아카이브에 실제 시크릿 동봉**) |
57
+ | `get_er_diagram` | ER 다이어그램 조회 — `format="mermaid"` 는 **텍스트를 응답으로** 돌려주므로 에이전트가 스키마를 읽는 경로다. 이미지(svg/png/pdf/zip)는 `output_directory` 지정 시 파일 저장, 생략 시 presigned URL 메타데이터. DB 스키마와 같은 플랜 게이트 |
58
+
59
+ ### 로컬 실행
60
+
61
+ | 도구 | 설명 |
62
+ | ----------------------- | ----------------------------------------------------------------------------- |
63
+ | `configure_environment` | 환경변수 조회·저장·초기화 (`local`/`deployment` 버킷 분리, `reset_keys` 지원) |
64
+ | `download_project` | 로컬 실행 설정 ZIP 다운로드 및 추출 |
65
+ | `get_project_file` | 단일 파일을 텍스트로 조회 (파일명은 `get_project_status` 의 `files_available`). `env.txt` 는 `env_type=deployment` 로 배포 버킷까지 — 웹 콘솔에는 없는 경로. credential 파일은 플레이스홀더 |
66
+ | `verify_local_run` | 로컬 컨테이너 기동 확인용 health check URL 조회 |
67
+
68
+ ### 배포 (게이트 → 실행 → 수명주기)
69
+
70
+ | 도구 | 설명 |
71
+ | -------------------------------- | ----------------------------------------------------------------------------------------- |
72
+ | `get_deploy_readiness` | 배포 가능 여부 진단 — 요금 동의 + 배포 설문 게이트를 한 번에 조회 |
73
+ | `accept_pricing_consent` | managed-hosting 요금 정책 동의 기록 (`confirm=true` 필요, 정책 5개 조항 제시 후 매 배포마다) |
74
+ | `submit_deploy_questionnaire` | 배포 설문 답변 저장 (법적 고지 기록, blocking 선택지는 `confirm_blocking=true` 필요) |
75
+ | `get_deployment_data_categories` | 파이프라인이 도출한 개인정보 카테고리 정본 조회 (`data_categories_confirmed` 답변의 근거) |
76
+ | `get_privacy_block` | 처리방침 게시 본문 생성·조회 (첫 호출이 본문과 `block_hash` 를 고정) |
77
+ | `deploy_project` | 완성된 프로젝트(ReadyToRun)를 managed-shared 풀에 배포 (리비전 지정 가능) |
78
+ | `get_deployment_status` | 배포 상태·엔드포인트(URL)·배포 가능 리비전 조회 |
79
+ | `pause_deployment` | 배포 일시정지 — 스택만 내리고 도메인·데이터·secrets 유지 (`resume_deployment` 로 복구) |
80
+ | `resume_deployment` | 일시정지한 배포 재기동 (추가 과금 없음) |
81
+ | `stop_deployment` | managed-shared 배포 삭제 (`confirm=true` 필요, 배포 DB 영구 삭제) |
82
+
83
+ ### 운영 대시보드
84
+
85
+ | 도구 | 설명 |
86
+ | ----------------------------- | --------------------------------------------------------------------- |
87
+ | `get_ops_summary` | 배포 운영 요약(KPI) 조회 — `server_status` 는 실측이 아닌 고정값 |
88
+ | `list_incidents` | 운영 인시던트 목록 조회 (`category` **필수**, range 는 1h~72h) |
89
+ | `get_incident` | 단일 인시던트 상세(타임라인·triage 판정·autofix 진행·뮤트 상태) 조회 |
90
+ | `get_incident_ai_prompt` | 4xx 인시던트의 클라이언트 수리 프롬프트 조회 (409 = 대기·플랫폼 수리·비대상 분기) |
91
+ | `update_incident_status` | 인시던트 상태 전이 (전진 3종만, `resolved` 는 되돌릴 수 없음) |
92
+ | `mute_incident_notifications` | 인시던트 단위 알림 뮤트·해제 (프로젝트 전체 설정과 별개) |
93
+ | `get_ops_usage` | 사용량(트래픽 게이지·일별 막대) 조회 — 한도 초과는 차단이 아니라 과금 |
94
+ | `get_usage_by_date` | 특정일(YYYY-MM-DD) API 호출 분석 조회 (당일 수치는 집계 중) |
95
+ | `get_ops_resources` | 컨테이너 자원(CPU/메모리/네트워크) 조회 — 절댓값 합산, 디스크는 없음 |
96
+ | `configure_hard_stop` | API 호출 하드 스톱 조회·변경 (API 호출 한정 — DB 초과는 막을 수 없다) |
97
+ | `configure_ops_notifications` | 운영 알림 preference 조회·변경 (부분 머지) |
98
+
99
+ ### 결제 · 구독 · 좌석
100
+
101
+ | 도구 | 설명 |
102
+ | --------------------------- | ----------------------------------------------------------------------------------- |
103
+ | `get_plan` | 프로젝트 구독·엔타이틀먼트·좌석/변경횟수/업로드 허용량 조회 — **체험 판정(`is_trialing`)의 단일 출처**, 다음 청구서는 플랜(`next_invoice`)·좌석(`seat_invoice`) 둘로 나뉜다 |
104
+ | `list_invoices` | 청구 내역 조회 (최신순, owner 전용 — overage 실청구 확인 경로) |
105
+ | `list_members` | 멤버·대기 초대·좌석 요청 현황 조회 (좌석 회계 상세) |
106
+ | `preview_seats` | 좌석 추가(delta) 금액 미리보기 — 부작용·과금 없음 (`prorated_now` 는 **오늘 결제될 금액**) |
107
+ | `set_seats` | 총 좌석 수 설정 (`confirm=true` 필요, **절대값** — 증가는 **오늘 즉시 청구**, 감소는 다음 좌석 주기 예약) |
108
+ | `purchase_seats_and_invite` | 좌석 추가 + 초대 (`confirm=true` 필요, 좌석은 **즉시 청구**, 부분 롤백 없음) |
109
+ | `create_seat_request` | admin 의 좌석 부족 초대 — 여유분 즉시 초대 + 초과분을 owner 승인 대기로 큐잉 (과금 없음) |
110
+ | `resolve_seat_request` | 좌석 요청 승인·반려 (owner 전용, `approve` 는 좌석 구매라 `confirm=true` 필요) |
111
+ | `purchase_change_runs` | 요구사항 변경 횟수 추가 구매 (`confirm=true` 필요, **구매 시점 즉시 결제** — 402 는 아무것도 적립 안 됨) |
112
+ | `cancel_subscription` | 구독 취소 (`confirm=true` 필요, 사유 선택 — 평시엔 기간말 예약·철회 가능, **체험 중이면 즉시·철회 불가**) |
113
+ | `preview_plan_change` | 플랜·주기 변경 시 **오늘** 청구액 미리보기 — 부작용 없음 (`mode=immediate` 일 때만 금액, `proration_date` 를 `change_plan` 에 되돌려야 표시가=청구가) |
114
+ | `change_plan` | 플랜·주기 변경 (`confirm=true` 필요, 업그레이드는 **즉시 청구**, 다운그레이드는 기간말 예약 — **기능 호환이 가격에 우선**해 Pro→Builder 는 예약·배포 회수, 체험 중 변경은 체험 소멸) |
115
+ | `withdraw_scheduled_plan_change` | 예약된 플랜 변경·기간말 취소 철회 (`confirm=true` 필요, 주기를 건드리지 않음) |
116
+ | `get_billing_portal_url` | Stripe 고객 포털 링크 발급 (결제수단 변경·구독 재개 경로, 링크만 반환) |
117
+ | `get_upgrade_url` | 플랜 업그레이드 화면 딥링크 조립 (백엔드 호출 없음) |
118
+ | `get_pricing` | legacy 크레딧 단가 조회 (현행 가격 모델 아님 — `get_plan` 참조) |
119
+ | `get_credits` | 잔여 크레딧 조회 (legacy 계정 잔액 — 산출물 접근을 결정하지 않는다) |
120
+ | `redeem_coupon` | 사전신청 프로모 코드 등록 (계정당 1개 — 혜택은 다음 Pro 월간 결제에 자동 부착) |
121
+
122
+ ### 멤버 · 권한 · 공유
123
+
124
+ | 도구 | 설명 |
125
+ | --------------------- | ---------------------------------------------------------------------------------------- |
126
+ | `get_role_matrix` | 역할↔capability 매트릭스 조회 (본문 없는 403 의 사유를 역산하는 기준점, custom 역할 포함) |
127
+ | `manage_invite` | 초대 발송·취소·재발송 (과금 없음 — 발송 시 좌석 **선점**, 좌석 부족은 배치 전체 거부) |
128
+ | `manage_member` | 멤버 역할 변경·좌석 변경·제거 (`remove` 와 접근 차단 좌석 변경에 `confirm=true` 필요) |
129
+ | `transfer_ownership` | 소유권 이전 (`confirm=true` 필요, **되돌리려면 새 owner 가 호출해야 함** — 기존 owner 는 admin 강등) |
130
+ | `leave_project` | 스스로 프로젝트 나가기 (`confirm=true` 필요 — owner·admin 은 불가, 좌석 없어도 호출 가능) |
131
+ | `claim_invite` | 초대 토큰·링크로 멤버십 수락 (`project_uuid` 를 받지 않는 유일한 도구, 이미 멤버면 성공) |
132
+ | `manage_share_link` | 공유 링크 목록·발행·회수 (`get_api_clipboard(link=true)` 공개 URL 의 **유일한 회수 경로**, public 발행에 `confirm=true`) |
133
+
134
+ ## 대표 워크플로우
135
+
136
+ ### 인터뷰 → 생성 → 배포
137
+
138
+ ```
139
+ authenticate
140
+ → get_consent_questions (stage="project_start" 5종 질문지 — 생성 전에 사용자에게 제시)
141
+ → create_project
142
+ → submit_deploy_questionnaire (5종 답변 적재 — 반드시 첫 send_message 이전)
143
+ → send_message ⇄ get_messages (요구사항 인터뷰)
144
+ → wait_for_pipeline (SRS → 아키텍처 → 코드 → 도커 이미지)
145
+ → get_docs / download_source … (산출물 확인)
146
+ → 배포 게이트 통과 (아래 "배포 전제조건 체인")
147
+ → deploy_project → get_deployment_status
148
+ ```
149
+
150
+ ### 플랜 변경 · 취소 · 철회
151
+
152
+ ```
153
+ get_plan (현재 플랜·pending_state: active | scheduled | canceled)
154
+ → preview_plan_change (mode=immediate 면 amount_due_now 를 사용자에게 제시)
155
+ → change_plan(confirm) (업그레이드 즉시 청구 / 다운그레이드·주기 단축은 기간말 예약)
156
+ → cancel_subscription(confirm) (기간말 취소 — 예약된 변경·좌석 감소도 함께 해제)
157
+ → withdraw_scheduled_plan_change(confirm) (예약·취소 되돌리기 — 주기를 건드리지 않음)
158
+ ```
159
+
160
+ Sandbox → 유료 최초 구독만 브라우저(`get_upgrade_url`)가 필요하다.
161
+
162
+ ### 프로젝트 삭제
163
+
164
+ ```
165
+ get_deletion_preview (can_delete · blocker · 즉시 정산액 · revision)
166
+ → (deployment_blocker 면) stop_deployment(confirm) → get_deletion_preview 재호출
167
+ → delete_project(preview_revision, confirm) (구독 즉시 해지 + 미청구분 즉시 결제)
168
+ ```
169
+
170
+ ### 인시던트 대응
171
+
172
+ ```
173
+ list_incidents(category)
174
+ → get_incident (ai_prompt_available · triage_verdict · fix.state)
175
+ → get_incident_ai_prompt (4xx 클라이언트 수리 프롬프트 — 409 는 대기·플랫폼 수리·비대상)
176
+ → (fix.state=ready, auto_redeploy=false 면) deploy_project
177
+ → update_incident_status(resolved)
178
+ ```
179
+
180
+ ### 로컬 테스트
181
+
182
+ ```
183
+ configure_environment(type:"local") (환경변수 채우기 — 배포용은 type:"deployment", 별개 저장소)
184
+ → download_project (docker-compose 실행 설정 ZIP)
185
+ → 컨테이너 기동 (docker compose up)
186
+ → verify_local_run (health check URL 로 기동 확인)
187
+ ```
188
+
189
+ ### 소스코드 접근 (Builder 플랜 이상)
190
+
191
+ ```
192
+ get_plan (플랜에 source_code 포함 여부 확인)
193
+ → link_github / get_github_account (GitHub 계정 연결)
194
+ → purchase_docs(docs:["repo"]) (미러 개설 — 플랜 포함이어도 이 POST 없이는 repo 404)
195
+ → get_docs(doc:"repo") (레포 URL) 또는 download_source (ZIP)
196
+ ```
197
+
198
+ ### 배포 후 운영·비용 방어
199
+
200
+ ```
201
+ get_ops_summary / list_incidents / get_ops_usage (모니터링)
202
+ → configure_hard_stop(api_hard_stop:true) (quota 초과 시 차단 — 켜지 않으면 초과분 자동 과금)
203
+ → configure_ops_notifications (장애·사용량 이메일 알림)
204
+ → pause_deployment / resume_deployment (일시정지·재개)
205
+ ```
206
+
207
+ ### 배포 전제조건 체인
208
+
209
+ `deploy_project` 는 두 게이트를 모두 통과해야 수락된다. 실패 시 412 가 오는데, MCP 는 이를
210
+ `PRICING_CONSENT_REQUIRED` 와 `QUESTIONNAIRE_INCOMPLETE` 로 구분해 해소 도구를 안내한다.
211
+
212
+ ```
213
+ get_deploy_readiness (막힌 이유 한 번에 진단)
214
+ ├─ accept_pricing_consent (요금 동의 — confirm=true 필요)
215
+ └─ submit_deploy_questionnaire
216
+ ├─ get_consent_questions (항목·선택지 정의 — 프로젝트 없이도 조회 가능)
217
+ ├─ get_deployment_data_categories (data_categories_confirmed 의 key 정본)
218
+ └─ get_privacy_block (privacy_block_embedded 가 pin 할 block_hash)
219
+
220
+ deploy_project → get_deployment_status
221
+ ```
222
+
223
+ 설문은 `stage` 축으로 두 시점에 나뉘어 수집되지만 게이트 판정은 통합이다(전부 필수).
224
+ `stage: project_start` 5종(`restricted_services_ack` · `end_user_jurisdictions` ·
225
+ `minors_in_scope` · `age_gating_measures` · `sensitive_data_in_scope`)은 배포가 아니라
226
+ **프로젝트 생성 직후·첫 `send_message` 이전**에 받는 것이 정본 순서다 — 이 답이 인터뷰
227
+ 컨텍스트로 주입되어 첫 SRS 초안에 반영되고, 없으면 인터뷰가 같은 질문을 대화로 되묻는다
228
+ (대화형 답변은 법적 기록으로 쓰이지 않아 결국 두 번 답하게 된다).
229
+ `get_deploy_readiness` 응답의 `questionnaire.stages` 로 `missing` 항목이 어느 시점 것인지
230
+ 가를 수 있다. 요금 동의는 웹 콘솔이 **배포할 때마다** 새로 받으므로, `consented: true` 는
231
+ 과거 기록이지 이번 배포를 건너뛸 근거가 아니다.
232
+
233
+ MCP 로 생성한 프로젝트는 설문 답변이 하나도 없는 상태로 시작하므로, 이 체인을 거치지 않으면
234
+ 배포가 412 로 막힌다.
235
+
236
+ ### 플랜 게이팅과 과금
237
+
238
+ 구독 모델에서 **소스 접근·배포·요구사항 변경·첨부 업로드는 전부 프로젝트 플랜이 결정**한다.
239
+ 크레딧(`get_credits`)은 계정 단위 legacy 잔액이라 이 판정과 무관하다 — 402/403 을 받으면
240
+ `get_plan` 을 먼저 본다.
241
+
242
+ - **402 는 두 사유가 공유한다**: 요구사항 변경 횟수 소진(`CHANGE_RUN_LIMIT_REACHED`)과
243
+ 첨부 업로드 한도 소진(`FILE_UPLOAD_LIMIT_REACHED`). 상태 코드가 아니라 응답 body 의
244
+ `error` 코드로만 갈린다 — 판별자는 `src/billing-errors.ts` 한 곳에 있다.
245
+ - **403 도 두 사유가 공유한다**: 역할 권한 부족과 플랜 미포함(`PLAN_UPGRADE_REQUIRED`).
246
+ body 판별 없이 잠금으로 읽으면 역할이 부족한 멤버에게 결제를 권하게 된다.
247
+ - **한도 초과는 차단이 아니라 과금이다.** API 호출·DB 용량이 플랜 quota 를 넘어도 서비스는
248
+ 계속 돌아가고 초과분이 다음 청구서에 합산된다(에러 없음). `configure_hard_stop` 이 이를
249
+ 막는 유일한 스위치이며, 켜면 quota 소진 시 트래픽이 차단되므로 양방향으로 위험하다.
250
+ - **과금 쓰기는 즉시 결제가 아니라 다음 청구서 이연이다 — 단 하나의 예외가 `change_plan` 이다.**
251
+ 좌석 추가·변경 횟수 구매는 `create_prorations` 로 다음 renewal invoice 에 실린다 — 카드가
252
+ 그 자리에서 긁히지 않는다. `preview_seats` 의 `prorated_now` 도 "지금 청구액"이 아니라 그
253
+ 청구서에 실릴 잔여 기간 일할분이다. 반면 **플랜 업그레이드(`change_plan`)는 `always_invoice`
254
+ 로 차액을 즉시 청구**하므로 반드시 `preview_plan_change` 의 `amount_due_now` 를 사용자에게
255
+ 보인 뒤 호출한다. 다운그레이드·주기 단축은 기간말 예약(청구 없음)이다. 청구가 확정되는
256
+ 구속력 있는 조작은 전부 `confirm=true` 가드를 유지한다.
257
+ - **프로젝트 삭제는 즉시 정산이다.** `delete_project` 는 구독을 그 자리에서 해지하고 미청구분
258
+ (구매한 변경 횟수 잔여·미납 인보이스)을 즉시 결제한다. `get_deletion_preview` 가 그 금액과
259
+ 차단 사유를 먼저 보여주며, 그 `revision` 없이는 삭제를 호출할 수 없다.
260
+ - **금액은 전부 minor units 정수 + currency** 로 전달한다. 포맷하지 않는다 —
261
+ KRW 같은 zero-decimal 통화를 1/100 로 표시하는 사고를 막기 위함이다.
262
+ - **브라우저가 필수인 결제는 이제 둘뿐이다**: Sandbox 프로젝트의 **최초** 유료 구독(hosted
263
+ checkout, `get_upgrade_url`)과 결제수단 변경(`get_billing_portal_url`). 이미 구독 중인
264
+ 프로젝트의 플랜·주기 변경(`change_plan`), 취소(`cancel_subscription`), 예약·취소 철회
265
+ (`withdraw_scheduled_plan_change`)는 API 로 완결된다. 링크를 받은 것이 작업 성공은 아니다.
266
+
267
+ ## 프로젝트 구조
268
+
269
+ ```
270
+ src/
271
+ ├── index.ts # 진입점 (stdio transport)
272
+ ├── server.ts # MCP 서버 생성 및 도구 등록
273
+ ├── state.ts # 인메모리 상태 관리 (토큰)
274
+ ├── client.ts # BackendX API 클라이언트
275
+ ├── polling.ts # 폴링/재시도/복구 로직
276
+ ├── constants.ts # 워크플로우 상태, 임계값
277
+ ├── types.ts # API 응답 타입 정의
278
+ ├── analytics.ts # GA4 Measurement Protocol 계측
279
+ ├── version.ts # package.json 의 version 을 읽어 MCP 서버 버전·버전 체크 헤더로 사용
280
+ ├── tool-utils.ts # MCP 도구 공용 유틸리티
281
+ └── tools/ # 워크플로우 도구
282
+ tsup.config.ts # 번들 설정 — 빌드 시 GA 키 내장 (아래 "배포 빌드")
283
+ ```
284
+
285
+ ## 요구 사항
286
+
287
+ - **Node.js 18 이상** — 전역 `fetch`·`AbortController` 를 사용한다.
288
+ - **`unzip` 명령** — `download_project`·`download_source` 가 내려받은 zip 을 풀 때 외부
289
+ `unzip` 바이너리를 호출한다. macOS·대부분의 Linux 에는 기본 탑재되어 있으나
290
+ **Windows 에는 없다** (해당 2종만 영향, 나머지 도구는 정상 동작).
291
+
292
+ ## 설치
293
+
294
+ ### npm (배포 후 권장 경로)
295
+
296
+ ```bash
297
+ claude mcp add -s user backendx -- npx @backendx/mcp
298
+ ```
299
+
300
+ > npm 배포는 아직 진행 전이다(BETA3-32). 배포 전까지는 아래 로컬 빌드 방식을 쓴다.
301
+
302
+ 이 패키지는 오픈소스가 아니라 **BackendX 서비스 이용 목적의 설치·실행만 허용하는 proprietary
303
+ 소프트웨어**다. 설치·실행은 패키지에 동봉된 [`LICENSE`](LICENSE) 의 이용 조건에 동의하는 것으로
304
+ 본다. 기동 시 외부 통신(버전 체크)과 사용 계측이 있으며 자세한 내용은 아래
305
+ "라이선스와 고지 사항" 절과 `LICENSE` §4·§5 를 참고한다.
306
+
307
+ ### 로컬 빌드 (개발용)
308
+
309
+ ```bash
310
+ npm install
311
+ npm run build
312
+ claude mcp add -s user backendx -- node /path/to/backendx-mcp/dist/index.js
313
+ ```
314
+
315
+ ### 인증 유지 범위
316
+
317
+ 인증 토큰은 **프로세스 메모리에만** 보관하고 디스크에 저장하지 않는다.
318
+ 따라서 MCP 서버가 재시작될 때마다 `authenticate` 를 다시 호출해야 한다.
319
+
320
+ ### 버전 게이트와 업데이트
321
+
322
+ MCP 서버는 **기동할 때마다** `{BACKENDX_FRONTEND_URL}/api/mcp/version-check` 에 자기 버전을 보내
323
+ 판정을 받고, 그 결과를 프로세스가 살아 있는 동안 캐시한다.
324
+
325
+ | 판정 | 동작 |
326
+ | --- | --- |
327
+ | `ok` | 정상 |
328
+ | `update_recommended` | 정상 동작. stderr 에 `[version-check] update_recommended: …` 한 줄만 남긴다 |
329
+ | `update_required` | **모든 tool 이 `UPDATE_REQUIRED` 로 차단**되고 `authenticate` 도 426 으로 거절된다 |
330
+ | `fail` — 판정 불가(네트워크·타임아웃·서버 미구성) | **모든 tool 이 `VERSION_CHECK_FAILED` 로 차단**된다 (fail-closed) |
331
+
332
+ 차단 응답에는 `current_version`·`latest_version`·`min_supported_version`·`update_url` 과 함께
333
+ 조치 방법(`how_to_update` / `how_to_fix`)이 실려 있어 에이전트가 그대로 사용자에게 안내한다.
334
+
335
+ **업데이트 방법:** `npx @backendx/mcp` 는 기동 때마다 레지스트리의 latest 를 확인하므로
336
+ **MCP 서버를 재시작**하면 된다 (Claude Code: `/mcp` 재연결 또는 재시작). 버전을 고정했거나
337
+ 전역 설치했다면 `npm install -g @backendx/mcp@latest` 후 재시작한다.
338
+
339
+ **사용자 고지:** 기동 시 BackendX 서버로 버전을 전송한다는 것과 지원 종료 버전·판정 불가 시
340
+ 전체 도구가 차단된다는 것은 배포 패키지의 `LICENSE` §4 에 이용 조건으로 명시되어 있다
341
+ (BETA3-524). 이 동작을 바꾸면 `LICENSE` §4 와 이 절을 함께 고친다.
342
+
343
+ 환경변수:
344
+
345
+ - `BACKENDX_API_URL` (기본값: `https://api.backendx.ai`)
346
+ - `BACKENDX_FRONTEND_URL` (기본값: `https://www.backendx.ai`)
347
+ - `GA_MEASUREMENT_ID` (선택): GA4 측정 ID. npm 배포본에는 프로덕션 키가 **빌드 시 내장**되어 있어 평소엔 설정할 필요가 없다. 설정하면 내장값을 덮어쓴다 — 스테이징 속성으로 보내거나 로컬 개발에서 바꿀 때 쓴다. `GA_API_SECRET` 와 **함께** 있어야 계측이 활성이며, 둘 중 하나라도 비면(내장값도 env 도 없음) 완전 비활성(no-op).
348
+ - `GA_API_SECRET` (선택): GA4 Measurement Protocol API secret. 위와 같은 우선순위(런타임 env > 내장값). GA4 콘솔 → 관리 → 데이터 스트림 → Measurement Protocol API secrets 에서 발급.
349
+ - `DO_NOT_TRACK` (선택): `1`·`true`·`yes` 중 하나면 GA 키가 설정돼 있어도 계측을 보내지 않는다. CLI 생태계의 사실상 표준 스위치.
350
+ - `BACKENDX_TELEMETRY_DISABLED` (선택): 위와 동일하게 동작하는 제품 전용 스위치.
351
+
352
+ ## 사용 계측 (GA4, 서버사이드)
353
+
354
+ 브라우저가 없는 MCP 는 gtag 대신 GA4 **Measurement Protocol**로 프론트와 동일한 GA4 속성에 이벤트를 보낸다(`origin: "mcp"` 파라미터로 브라우저 트래픽과 구분). 전송은 fire-and-forget — 실패해도 tool 응답에 영향이 없다.
355
+
356
+ **npm 배포본은 계측이 기본으로 켜져 있다.** GA 키가 배포 빌드 때 번들에 내장되기 때문이며(아래 "배포 빌드" 참고), 사용자는 환경변수 하나로 끌 수 있다. 키가 내장되지 않은 로컬 빌드는 env 로 키를 주지 않는 한 아무것도 보내지 않는다.
357
+
358
+ | 이벤트 | 발화 시점 | 주요 파라미터 |
359
+ | --------------- | ---------------------------------------- | ------------------------------------- |
360
+ | `mcp_started` | 서버 기동(버전 체크 직후) 1회 | `version_status`, `mcp_version` |
361
+ | `mcp_tool_used` | 모든 tool 호출(단일 길목 `registerTool`) | `tool_name`, `outcome`(success/error), 실패 시 `error_code`(fail code, 예: `UPDATE_REQUIRED`/`AUTH_FAILED`) |
362
+
363
+ **사용자 단위 식별자는 보내지 않는다.** 페이로드의 최상위 키는 프로세스마다 새로 발급하는
364
+ 무작위 `client_id` 와 `events` 둘뿐이고, `authenticate` 성공 후에도 GA4 `user_id` 는 설정하지
365
+ 않는다 — 이메일은 원문은 물론 해시 형태로도 계측에 넘기지 않는다(BETA3-555,
366
+ `tests/analytics.test.ts` 가 페이로드 모양을 고정). 이벤트는 프로세스 단위 `client_id` ·
367
+ `session_id` 로만 묶이므로 GA 의 활성 사용자·리텐션 리포트는 "MCP 프로세스" 단위로 읽어야 한다.
368
+
369
+ **끄는 방법:** `DO_NOT_TRACK=1` 또는 `BACKENDX_TELEMETRY_DISABLED=1` 을 설정하면 GA 키가
370
+ 내장·설정돼 있어도 아무것도 전송하지 않는다.
371
+
372
+ ```bash
373
+ claude mcp add -s user backendx -e DO_NOT_TRACK=1 -- npx @backendx/mcp
374
+ ```
375
+
376
+ **프론트엔드와의 차이:** 웹(backendx-frontend)은 쿠키 동의 배너로 GA 를 opt-in 게이트하고
377
+ GPC 신호가 있으면 gtag 자체를 로드하지 않는다. MCP 는 브라우저가 없어 동의 배너도 GPC
378
+ 신호도 받을 수 없으므로 위 opt-out 스위치로 대체한다. 수집 범위는 웹과 같다 — 둘 다 GA 에
379
+ 사용자 단위 식별자를 보내지 않는다. BETA3-524 법무 검토는 옵트아웃 방식과 api_secret 내장을
380
+ 현행 유지해도 되되, 이메일 해시 `user_id` 전송만은 제거하라고 결론냈고(BackendX 가 원문
381
+ 이메일을 보유하므로 해시는 익명정보가 아닌 가명정보), 그 제거가 BETA3-555 다. 수집 항목·
382
+ 옵트아웃 방법의 사용자 고지는 `LICENSE` §5 가 담당한다. **`LICENSE` §5 는 실제 전송 항목의
383
+ 사용자 고지이므로 코드와 항상 붙어 다녀야 한다** — 수집 항목을 바꾸면 `src/analytics.ts`·
384
+ 이 절·`LICENSE` §5 를 같은 PR 에서 함께 고친다. §5 의 문언 자체를 손보는 게 아니라 수집
385
+ 항목을 좁히는 동기화라면 그대로 진행하고, 조항의 취지나 범위를 넓히는 변경이면 법무 검토를
386
+ 먼저 받는다.
387
+
388
+ GA4 콘솔에서 `tool_name`·`outcome`·`origin`·`version_status` 를 맞춤 측정기준(이벤트 범위)으로 등록해야 표준 리포트에 축으로 나온다(비소급).
389
+
390
+ ### 배포 빌드 (GA 키 내장)
391
+
392
+ `npx` 로 실행되는 사용자 환경에는 우리 GA 키가 env 로 없으므로, `tsup.config.ts` 가 빌드 시
393
+ `GA_MEASUREMENT_ID`·`GA_API_SECRET` 를 번들 상수(`__GA_MEASUREMENT_ID__` 등)로 치환해 내장한다.
394
+ `src/analytics.ts` 는 "런타임 env > 내장값" 순으로 읽으므로 내장 후에도 env 로 덮어쓸 수 있다.
395
+
396
+ | 빌드 | 명령 | 키 출처 | 키가 비면 |
397
+ | --- | --- | --- | --- |
398
+ | 개발 | `npm run build` | 셸 env > `.env`(gitignore, `.env.example` 참고) | 경고 후 계측 비활성 번들 |
399
+ | 배포 | `npm run build:release` (= `npm publish` 의 `prepublishOnly`) | **셸 env 만** — `.env` 는 읽지 않는다 | **빌드 실패** |
400
+
401
+ 배포 빌드가 `.env` 를 무시하는 이유: 로컬 `.env` 에는 보통 스테이징 키가 활성돼 있어, 그대로
402
+ publish 하면 스테이징 키가 프로덕션 패키지에 들어간다. 프로덕션 키는 publish 시점에 셸로 넘긴다.
403
+
404
+ ```bash
405
+ GA_MEASUREMENT_ID=G-XXXXXXXXXX GA_API_SECRET=xxxxxxxx npm publish
406
+ ```
407
+
408
+ 빌드 로그의 `[build] GA 키 내장: measurement_id=G-...` 줄로 어느 속성이 들어갔는지 확인한다
409
+ (api_secret 은 출력하지 않는다). Measurement Protocol 의 api_secret 은 공개 패키지에 내장되면
410
+ 읽을 수 있지만, 노출 시 영향은 제3자가 우리 GA 속성에 가짜 이벤트를 보낼 수 있는 정도이며 GA4
411
+ 콘솔에서 즉시 회전할 수 있다(Angular CLI 등 CLI 계측의 통상 관행). 그래도 내장이 불가하다는
412
+ 결론이 나면 BE 프록시 방식으로 전환한다(BETA3-524 법무 검토 항목 5-ⓔ).
413
+
414
+ ## 라이선스와 고지 사항
415
+
416
+ 외부 사용자에게 이용 조건이 전달되는 공식 경로는 레포 루트의 [`LICENSE`](LICENSE) 파일이다.
417
+ `npm publish` 는 `package.json` 의 `files` 화이트리스트와 무관하게 `LICENSE` 를 항상 패키지에
418
+ 포함하므로, 사용자는 `node_modules/@backendx/mcp/LICENSE` 와 npmjs.com 패키지 페이지에서 볼 수
419
+ 있다. `package.json` 의 `license` 필드는 `"SEE LICENSE IN LICENSE"` 로, "조건은 LICENSE 파일을
420
+ 보라"는 npm 표준 표기다(BETA3-524 항목 3).
421
+
422
+ `LICENSE` 의 구성과 이 README 의 대응 절:
423
+
424
+ | `LICENSE` 절 | 내용 | 코드·README 대응 |
425
+ | --- | --- | --- |
426
+ | §1–§3 | proprietary 고지, 설치·실행 허용, 수정·재배포·경쟁 목적 사용·과금 우회 금지 | — |
427
+ | §4 | 기동 시 버전 체크 외부 통신, 지원 종료 버전·판정 불가 시 전체 도구 차단(fail-closed) | `src/client.ts` `checkVersion`, "버전 게이트와 업데이트" 절 |
428
+ | §5 | 사용 계측: 기본 활성, 수집 항목·미수집 항목, `DO_NOT_TRACK`/`BACKENDX_TELEMETRY_DISABLED` 옵트아웃 | `src/analytics.ts`, "사용 계측" 절 |
429
+ | §6 | AI 에이전트가 자율 호출하는 삭제·과금 도구에 대한 사용자 책임 | `delete_project`, `purchase_*`, `change_plan`, 배포 조작 도구 |
430
+ | §7–§8 | 보증 부인, 책임 제한 | — |
431
+ | §9 | 서드파티 의존성은 별도 라이선스(번들에 미포함) | `tsup` 기본 external 처리 |
432
+ | §10–§12 | 종료, 준거법(대한민국), 일반 조항 | — |
433
+
434
+ **변경 규칙:** 외부 통신 대상, 계측 수집 항목, 옵트아웃 방법, 과금·삭제 도구의 동작 중 하나라도
435
+ 바뀌면 `LICENSE` 의 해당 절을 같은 PR 에서 고친다. `LICENSE` 문구의 확정·변경 이력은 BETA3-524
436
+ 가 정본이다.
437
+
438
+ ## 배포 절차 (npm publish)
439
+
440
+ "버전" 은 두 곳에 있고 역할이 다르다.
441
+
442
+ | 위치 | 값 | 역할 |
443
+ | --- | --- | --- |
444
+ | 이 레포 `package.json` → `version` | **패키지 버전** | 배포물이 몇 버전인지. `src/version.ts` 가 런타임에 읽어 MCP 서버 버전·`X-MCP-Version` 헤더·기동 시 버전 체크 요청에 쓴다 |
445
+ | backendx-frontend `backend/docker-compose.yaml` → `MCP_MIN_VERSION` / `MCP_LATEST_VERSION` | **지원 정책** | FE(`lib/mcp-version.ts`)가 클라이언트 버전을 판정하는 기준. `MIN` 미만이면 `update_required` → **모든 tool 차단**·인증 426. `LATEST` 미만이면 `update_recommended` → stderr 경고만 |
446
+
447
+ 패키지는 스스로 최신 여부를 알 수 없고, 한 번 publish 된 버전은 고칠 수 없다. 그래서 옛
448
+ 클라이언트를 밀어내는 기준(정책)은 서버 쪽에 둔다. 두 값이 서로 다른 레포에 있으므로
449
+ **순서가 중요하다** — FE 값을 먼저 올리면 npm 에 아직 없는 버전을 요구하게 되어, 사용자
450
+ 전원이 `update_recommended`(LATEST) 또는 tool 차단(MIN)을 본다. 항상 **npm 먼저, FE 나중**.
451
+
452
+ ### 순서
453
+
454
+ 1. **검증.** 워킹 트리가 깨끗해야 `npm version` 이 동작한다.
455
+
456
+ ```bash
457
+ git status # clean 이어야 한다
458
+ npm test
459
+ npm run build && npm pack --dry-run # 타르볼: README.md · dist/index.js · package.json 3개뿐인지
460
+ ```
461
+
462
+ 2. **버전 올림.** `package.json` 갱신 + 커밋 + `v{version}` git 태그를 한 번에 만든다.
463
+
464
+ ```bash
465
+ npm version patch -m "chore: 배포 버전 %s (BETA3-xx)" # patch | minor | major
466
+ ```
467
+
468
+ | 단계 | 언제 |
469
+ | --- | --- |
470
+ | `patch` | 버그 수정, 문구·설명 변경 |
471
+ | `minor` | 도구 추가, BE 계약 동기화 등 옛 버전도 계속 동작하는 변경 |
472
+ | `major` | FE·BE 계약이 바뀌어 옛 버전이 더 이상 동작하지 않을 때 (→ 5단계에서 `MIN` 도 올린다) |
473
+
474
+ 3. **publish.** `prepublishOnly` 가 `build:release` 를 돌리므로 프로덕션 GA 키를 셸로 넘긴다
475
+ (위 "배포 빌드"). 키가 없으면 빌드가 실패해 publish 되지 않는다.
476
+
477
+ ```bash
478
+ GA_MEASUREMENT_ID=G-XXXXXXXXXX GA_API_SECRET=xxxxxxxx npm publish
479
+ git push && git push --tags
480
+ ```
481
+
482
+ 4. **전파 확인.** 새 버전은 현재 FE 정책(`MIN` ≤ 새 버전) 아래서 그대로 `ok` 판정이므로,
483
+ FE 를 건드리기 전에 실제 배포본으로 기동을 확인한다.
484
+
485
+ ```bash
486
+ npm view @backendx/mcp version # 방금 올린 버전
487
+ npx -y @backendx/mcp@latest # stderr 에 [version-check] 경고가 없어야 한다 (Ctrl+C 로 종료)
488
+ ```
489
+
490
+ 5. **FE 정책 갱신.** backendx-frontend `backend/docker-compose.yaml` 의 `MCP_LATEST_VERSION` 을
491
+ 새 버전으로 올리고 배포한다. 이 compose 는 서버에서도 쓰이며, 값을 바꾼 뒤
492
+ `docker compose up -d nextjs` 로 컨테이너를 다시 만들어야 반영된다.
493
+
494
+ `MCP_MIN_VERSION` 은 **옛 버전을 실제로 막아야 할 때만** 올린다 — 올리는 순간 그 미만
495
+ 사용자는 tool 이 전부 막히므로, `LATEST` 를 먼저 올려 경고를 내보낸 뒤 시차를 두고 올린다.
496
+
497
+ ### 사용자에게 반영되는 시점
498
+
499
+ `npx @backendx/mcp` 는 기동 때마다 레지스트리의 latest 를 확인하므로, 사용자는 MCP 서버가
500
+ **재시작될 때**(Claude Code 재시작 또는 `/mcp` 재연결) 새 버전을 받는다. 이미 떠 있는
501
+ 프로세스는 옛 버전 그대로다. 버전 판정도 기동 시 1회 받아 프로세스 수명 동안 캐시하므로,
502
+ 그 사이 FE `MIN` 이 올라가도 재시작 전까지는 tool 이 막히지 않는다(단 `authenticate` 재호출은
503
+ 인증 라우트가 헤더를 새로 판정해 426 으로 거절한다).
504
+
505
+ ### 롤백
506
+
507
+ publish 된 버전은 덮어쓸 수 없다(`npm unpublish` 는 72시간 제한이 있고 권장되지 않는다).
508
+ 문제가 있는 버전은 `latest` 태그를 이전 버전으로 되돌리고 deprecate 한 뒤, 고친 patch 를 새로 올린다.
509
+
510
+ ```bash
511
+ npm dist-tag add @backendx/mcp@1.0.0 latest # latest 를 이전 버전으로
512
+ npm deprecate @backendx/mcp@1.0.1 "1.0.2 로 올려주세요"
513
+ ```
514
+
515
+ FE `MCP_LATEST_VERSION` 을 이미 올렸다면 같이 되돌린다. `MIN` 을 되돌린 버전보다 높게
516
+ 올렸다면 되돌린 버전 사용자가 전부 막히므로 `MIN` 도 반드시 낮춘다.
517
+
518
+ ## 로컬 개발
519
+
520
+ 기본값이 운영 서버(prod)로 설정되어 있으므로, 로컬 개발 시에는 환경변수로 로컬 URL을 오버라이드해야 합니다.
521
+
522
+ 사전 준비: 백엔드 서버(`localhost:8000`)와 프론트엔드 서버(`backendx-frontend`, `localhost:3000`)를 먼저 실행해주세요.
523
+
524
+ ### 방법. 설정 파일 직접 편집 (env 변경 시 편리)
525
+
526
+ `~/.claude.json`의 최상단 `mcpServers.backendx.env` 값을 직접 수정합니다. user scope(최상단)에 두면 모든 경로에서 동일하게 적용됩니다.
527
+
528
+ ```json
529
+ {
530
+ "mcpServers": {
531
+ "backendx": {
532
+ "type": "stdio",
533
+ "command": "node",
534
+ "args": ["/path/to/backendx-mcp/dist/index.js"],
535
+ "env": {
536
+ "BACKENDX_API_URL": "http://localhost:8000",
537
+ "BACKENDX_FRONTEND_URL": "http://localhost:3000"
538
+ }
539
+ }
540
+ }
541
+ }
542
+ ```
543
+
544
+ > 주의: `projects.*.mcpServers`에 같은 이름의 항목이 있으면 user scope를 덮어씁니다. 전역으로 쓰고 싶다면 project scope의 동일 항목은 제거해주세요.
545
+
546
+ 편집 후 Claude Code에서 `/mcp`로 재연결하거나 재시작해야 반영됩니다.
547
+
548
+ ### 코드 수정 후
549
+
550
+ 코드를 수정한 뒤에는 `npm run build`로 재빌드해야 변경 사항이 반영됩니다.