STORIX 개발에 쓰는 도구들을 Claude 에 붙이는 MCP 서버.
API 스펙을 찾아 읽고, 배포마다 뭐가 바뀌었는지 되짚고, 에러가 났을 때 어느 쪽이 스펙과 어긋났는지 가리고, 지표를 조회한다. 스웨거 화면을 뒤지거나 DB 를 손으로 뽑던 일을 대화 중에 끝내려고 만들었다.
서버는 storix 하나이고 기능은 모듈로 나뉜다. 툴 이름이 <모듈>_<기능> 이라
이름만 보고 어느 모듈 것인지 안다.
| 모듈 | 하는 일 | 원격에서도 쓸 수 있나 |
|---|---|---|
swagger |
스펙 조회, 에러 코드, 배포별 변경 이력, 실제 호출 | 예 |
report |
어긋난 곳 판정, 슬랙 제보 | 예 |
metrics |
미리 정의한 집계 질의 | 예 |
auth |
관리자·테스터 로그인, 토큰 관리 | 아니오, 로컬 전용 |
flow |
사용자 흐름 시나리오를 API 로 돌리고 판정 | 예 |
mobile |
앱 화면 띄우기, Maestro 안내 | 아니오, 로컬 전용 |
빌드 단계가 없다. Node 18+ 만 있으면 된다.
패키지로 받아 쓰는 게 가장 간단하다. 클론도 설치도 필요 없다.
claude mcp add storix -- npx -y @team-storix/storix-mcp@latest자격증명은 각자 넣는다. SWAGGER_USER 를 넣거나, AWS 프로필만 주고 Parameter Store 에서 읽게 한다.
버킷까지 같이 주면 팀이 공유하는 배포 이력(swagger_history · swagger_diff_spec)도 잡힌다.
저장소를 받아서 각자 등록한다. 로컬 모드에서는 모든 모듈이 켜진다.
git clone https://github.com/Team-STORIX/STORIX-MCP.git
cd STORIX-MCP && npm install
claude mcp add storix --scope user \
-e SWAGGER_BASE_URL=https://dev.storix.kr \
-e SWAGGER_USER='<계정 — 팀 시크릿 참고>' \
-e SWAGGER_PASSWORD='<비밀번호 — 팀 시크릿 참고>' \
-- node "$PWD/src/index.js"등록 후 Claude Code 를 재시작해야 툴이 잡힌다. claude mcp list 에 ✔ Connected 가
뜨면 된 것이다.
--scope user 는 어느 디렉터리에서 작업하든 잡히게 한다. claude mcp list 는 현재
디렉터리 기준이라, 프로젝트 스코프로 넣으면 그 프로젝트 밖에서는 아예 안 보인다.
--scope project 는 .mcp.json 을 저장소에 만들어 커밋되므로 쓰지 마라.
src/http.js 를 띄우면 /mcp 하나로 서비스된다. 받는 쪽은 URL 만 등록하면 된다.
claude mcp add --transport http storix https://<주소>/mcp \
--header "Authorization: Basic $(printf '%s' '<계정>:<비밀번호>' | base64)"아직 배포 전이다. 배포되면 이 방식이 기본이 된다. 이때 auth 모듈은 자동으로
꺼진다 — 아래 로컬 전용인 것 참고.
붙이는 방식과 쓰려는 모듈에 따라 필요한 것만 넣으면 된다.
공통 · swagger
| 변수 | 기본값 | 설명 |
|---|---|---|
SWAGGER_BASE_URL |
https://dev.storix.kr |
대상 서버 |
SWAGGER_SPEC_PATH |
/v3/api-docs |
OpenAPI 문서 경로 |
SWAGGER_USER / SWAGGER_PASSWORD |
(없음) | 스펙 조회용 basic auth. 없으면 Parameter Store 에서 읽는다 |
STORIX_PARAM_PREFIX |
/storix/dev |
자격증명을 둔 Parameter Store 경로 앞부분 |
AWS_REGION |
ap-northeast-2 |
Parameter Store 를 읽을 리전 |
SWAGGER_CACHE_TTL_MS |
60000 |
스펙 캐시 유효시간 |
SWAGGER_SNAPSHOT_DIR |
~/.storix-mcp/swagger/snapshots |
fs 백엔드의 스냅샷 저장 위치. 컨테이너로 띄우면 볼륨으로 빼라. 안 그러면 재배포마다 변경 이력이 통째로 날아간다 |
SWAGGER_SNAPSHOT_S3_BUCKET |
(없음) | 넣으면 스냅샷을 S3 에서 읽는다. 팀이 공유하는 배포 이력이 여기 쌓이므로 swagger_history · swagger_diff_spec 을 쓰려면 필요하다 |
SWAGGER_SNAPSHOT_S3_PREFIX |
swagger-snapshots |
위 버킷 안의 경로 앞부분 |
SWAGGER_MCP_ALLOW_WRITE |
(꺼짐) | true 여야 swagger_call_api 가 POST/PUT/PATCH/DELETE 를 보낸다 |
STORIX_DEV_TOKEN |
(없음) | 호출에 붙일 JWT. auth_login 을 쓰면 필요 없다 |
자격증명을 Parameter Store 에 두면 SWAGGER_USER / SWAGGER_PASSWORD 를 적지 않아도 된다.
읽을 권한은 AWS 프로필(환경변수 AWS_PROFILE 또는 기본 프로필)로 정해지며,
IAM 에서 해당 파라미터 경로만 열어주면 된다.
auth (로컬 전용)
| 변수 | 기본값 | 설명 |
|---|---|---|
STORIX_MCP_HOME |
실행 디렉터리 | .storix-mcp.json 을 둘 위치 |
report
| 변수 | 기본값 | 설명 |
|---|---|---|
STORIX_SLACK_WEBHOOK_URL |
(없음) | 없으면 보내지 않고 올릴 내용만 보여준다 |
STORIX_SLACK_CHANNEL |
#오류-제보 |
표시용 채널명 |
STORIX_MCP_REPORTER |
(없음) | 제보자 이름. 툴 인자로도 넘길 수 있다 |
metrics
| 변수 | 기본값 | 설명 |
|---|---|---|
STORIX_DB_HOST / STORIX_DB_PORT |
· 3306 |
DB 주소 |
STORIX_DB_USER / STORIX_DB_PASSWORD |
(없음) | 읽기 전용 계정만 쓸 것 |
STORIX_DB_NAME |
(없음) | 스키마 이름 |
STORIX_DB_TIMEOUT_MS |
5000 |
이 시간을 넘는 질의는 서버가 죽인다 |
flow
| 변수 | 기본값 | 설명 |
|---|---|---|
STORIX_FLOWS_DIR |
저장소의 flows/ |
시나리오를 둘 위치 |
mobile (로컬 전용)
| 변수 | 기본값 | 설명 |
|---|---|---|
STORIX_APP_SCHEME |
storixfe21 |
딥링크 스킴. FE 의 app.json 과 같아야 한다 |
STORIX_APP_IOS_BUNDLE_ID |
kr.storix.app |
시뮬레이터에 앱이 깔렸는지 볼 때 쓴다 |
STORIX_APP_ANDROID_PACKAGE |
kr.storix.android |
위와 같다 |
dev_server (로컬 전용)
| 변수 | 기본값 | 설명 |
|---|---|---|
STORIX_DEV_INSTANCE_NAME |
Dev Server |
dev 인스턴스의 Name 태그. Env 태그가 dev 인 것만 다룬다 |
EC2 는 각자 AWS 프로필로 부른다. 그 계정이 IAM developers 그룹에 들어 있어야 한다.
HTTP 모드
| 변수 | 기본값 | 설명 |
|---|---|---|
MCP_PORT |
8090 |
3000 은 프론트 dev 서버가 쓰므로 피했다 |
MCP_BASIC_USER / MCP_BASIC_PASSWORD |
SWAGGER_* 값 |
접속 계정 |
MCP_ALLOWED_ORIGINS |
(비어 있음) | 허용할 Origin, 쉼표 구분 |
툴 이름을 외울 필요는 없다. 말로 하면 Claude 가 고른다. 아래는 무슨 말을 하면 무엇이 도는지에 대한 안내다.
서버가 슬래시 커맨드도 같이 내려준다. 파일을 깔 필요 없이 연결만 하면 뜬다.
/mcp__storix__swagger swagger 툴 쓰는 법
/mcp__storix__report 오류 제보 절차
"토픽룸 생성 화면 만들 건데 API 스펙 좀"
swagger_list_endpoints 로 찾고 swagger_get_endpoint 로 요청·응답 스키마를
$ref 까지 펼쳐서 본다. 경로는 목록이 준 형태 그대로 쓴다.
스키마를 안 보고 swagger_call_api 부터 부르지 마라. 바디 모양을 지어내게 된다.
"이 API 에러 뭐 나와?"
swagger_errors 는 에러만 추린다. 같은 엔드포인트가 swagger_get_endpoint 로는
7천 자인데 여기서는 1천 자다. 에러 분기만 짤 때는 이쪽을 쓴다.
swagger_errors {method, path} 이 API 에러만
swagger_errors {tag: "토픽룸"} 기능 단위
swagger_errors {code: "USER_ERROR_007"} 이 코드가 어디서 나가는지 거꾸로
swagger_errors 전체 목록
인증 공통 에러는 개별 API 응답에 안 실리고 문서 상단 표에만 있다.
swagger_errors 는 그것도 같이 붙여준다.
전체 목록은 내 코드의 에러 분기와 대조할 때 쓴다. 코드에는 있는데 스펙에 없으면
죽은 분기, 스펙에는 있는데 코드에 없으면 처리 안 된 에러다. 지우기 전에
swagger_errors {code} 로 이름만 바뀐 건 아닌지 확인해라.
"어제 배포된 거 뭐 바뀌었어?" "토픽룸 쪽 최근 변경 좀"
swagger_history 가 배포 시점마다 찍힌 스냅샷을 이웃끼리 비교해 시간순으로 보여준다.
인자 없이 부르면 최근 배포 1건.
swagger_history 최근 배포
swagger_history {tag: "토픽룸"} 기능 단위
swagger_history {path} 엔드포인트 하나
swagger_history {since: "1w"} 기간
tag 가 기본 탐색축이다. 새로 생긴 엔드포인트는 경로를 모르니 path 로는 찾을 수 없고,
경로가 바뀐 것도 태그로 묶어야 "제거 + 추가" 가 나란히 보인다.
8/22 14:03 PR #251 · 719c0d0 · 에러 스펙 추가
+ POST /api/v1/topic-rooms/{roomId}/pin 새 엔드포인트
~ POST /api/v1/topic-rooms
[breaking] 응답 200 result 타입 변경: integer → string
결과에 붙는 PR 번호는 출처 표시다. 더 알아볼 게 있으면 그걸로 백엔드에 물어보면 된다.
스냅샷을 찍을 때 pr·commit·title 을 같이 넣으면 여기에 따라붙는다.
스냅샷이 없으면 이력도 없다. 배포마다 swagger_snapshot_spec 이 한 번 돌아야 쌓인다.
로컬이면 auth_setup 으로 계정을 한 번 넣고 auth_login 하면, 이후
swagger_call_api 가 토큰을 자동으로 붙이고 만료되면 알아서 재발급한다.
admin auth_setup {as: "admin", email, password} → auth_login
tester auth_signup_tester {nickName, favoriteGenreList}
→ 슬랙에서 사람이 승인 (10분 안에)
→ auth_login {as: "tester"}
계정은 작업 중인 프로젝트의 .storix-mcp.json 에 저장되고 .gitignore 에 자동 등록된다.
토큰은 프로세스 메모리에만 두고 파일로 남기지 않는다.
테스터의 pendingId 는 승인 대기용 임시값이 아니라 승인 후에도 계속 쓰는 로그인 키다.
한 번 승인받으면 다른 컴퓨터에서도 auth_setup {as: "tester", pendingId} 로 바로 쓴다.
쓰기 메서드는 기본으로 막혀 있다. 열려면 서버 설정에 SWAGGER_MCP_ALLOW_WRITE=true
가 있어야 한다. 툴 인자로는 못 켠다 — 인자였으면 AI 가 스스로 켤 수 있어 관문이 못 된다.
"이거 왜 안 되지" "이거 누구 문제야"
report_check 가 스펙과 대조해 어느 쪽이 어긋났는지 가린다. 서로 넘겨짚기 전에 먼저 돌린다.
요청이 스펙과 다름 프론트
응답·상태값·에러 코드가 스펙과 다름 백엔드
가리지 못하는 경우엔 단정하지 않는다 — 401/403 인증 문제, 문서화된 에러가 그대로 나온 경우(정상 동작일 수 있다), 스펙에 아예 없는 경로(미배포이거나 제거됐을 수 있다).
진짜 문제로 보이면 report_send 로 슬랙에 올린다. 형식이 고정돼 있어 채널에 같은 모양으로
쌓인다. 보내기 전에 dryRun 으로 내용을 확인받는 편이 낫다.
🔴 [백엔드] POST /api/v1/topic-rooms
──────────────────────────────
[증상] 생성 누르면 400 뜨는데 코드가 처음 보는 거임
──────────────────────────────
[판정 근거]
• [백엔드] TOPIC_ROOM_ERROR_099 는 스펙 어디에도 없는 코드입니다.
──────────────────────────────
판정이 "확인필요" 로 나와도 올릴 수 있다. 스펙으로 못 가린다는 뜻이지 문제가 없다는 뜻이 아니다.
"어제 가입자 몇 명이야?" "출석 이벤트 참여율"
metrics_list 로 무엇을 셀 수 있는지 보고 metrics_query 로 돌린다.
signups 일별 가입자 (역할별)
withdrawals 일별 탈퇴
accounts 계정 상태 분포
active_users 일별 접속자
attendance 출석 이벤트 참여
story_card 오늘의 스토리 카드 참여
event_rate 이벤트별 참여율
자유 SQL 은 받지 않는다. 미리 정의한 집계만 나가므로 개인을 특정하는 값이 응답에
담기지 않는다. users 에는 비밀번호 해시와 이메일이 있다.
각 지표에는 해석 주의점이 붙어 있다. 예를 들어 active_users 는 마지막 로그인 시각
기준이라 정확한 DAU 가 아니고, event_rate 는 분모가 현재 계정 수라 과거 이벤트일수록
비율이 낮게 잡힌다. 숫자만 보고 판단하지 마라.
연결은 읽기 전용 세션·5초 타임아웃·락 대기 2초·조회 기간 180일 상한으로 묶여 있다. dev 와 운영이 같은 인스턴스를 스키마로만 나눠 쓰기 때문이다. 여기 날린 질의가 운영 자원을 쓴다.
사용자 흐름 한 벌을 flows/<이름>.md 에 적어두고, 같은 파일을 두 가지로 쓴다.
설명은 사람이 읽고 실행기는 yaml 블록만 본다. api 는 flow 가, route 는 mobile 이 쓴다.
flow_list 어떤 시나리오가 있나
flow_check {name} 호출 없이 경로가 아직 스펙에 있는지만
flow_run {name} 실제로 호출하고 스펙과 대조해 판정
mobile_doctor 지금 환경에서 어디까지 되나
mobile_open {route} 앱에서 그 화면 띄우기
flow_run 은 auth_login 으로 받아둔 토큰을 쓴다. 앞 스텝에서 뽑은 값을 다음 스텝에 넣으므로
한 스텝이 실패하면 거기서 멈춘다. 쓰기 스텝은 SWAGGER_MCP_ALLOW_WRITE 가 꺼져 있으면 건너뛴다.
판정은 상태 코드, has 로 적은 필드가 있는지, 그리고 응답 최상위를 스펙과 대조해서 한다.
스펙의 필수 필드가 빠졌으면 실패, 스펙에 없는 필드가 오면 참고로만 적는다.
mobile_open 은 화면을 띄우기만 하고 버튼을 누르지는 못한다. 눌러야 하는 구간은 Maestro 를 쓴다.
Maestro 가 없어도 나머지는 그대로 된다. 자세한 건 mobile 프롬프트에 있다.
앱을 띄우면 앱이 스스로 dev API 를 부른다. 우리가 고른 요청만 나가는 게 아니라 analytics, 푸시 기기 등록, 미리 받아두기까지 따라 나가고 dev 데이터가 실제로 쌓인다.
CD 에서 부를 수 있게 진입점을 둘 뒀다. MCP 서버와 같은 모듈을 쓰므로 판정이 갈라지지 않는다.
node src/cli.js snapshot --label v2.4.2
node src/cli.js changelog --label "dev-abc1234" --commit "$SHA"
changelog 는 지금 스펙을 뜨고 직전 스냅샷과 비교해 변경 내역을 출력한다.
STORIX_SLACK_WEBHOOK_URL 이 있으면 슬랙으로도 보낸다. 첫 실행이라 비교 대상이 없으면
기준점만 잡고 끝낸다.
기본은 알리기만 하고 종료코드 0 으로 끝난다. dev 는 배포가 잦아 breaking 마다 실패시키면
금방 무시하게 되기 때문이다. 막고 싶으면 --fail-on-breaking 을 붙인다.
배포 파이프라인에서는 같은 일을 Lambda(src/lambda.js)가 한다. dev EC2 를 더 줄일 계획이라
그 서버의 메모리를 잠깐이라도 쓰지 않게 떼어냈다. VPC 밖에 두므로 NAT 도 EIP 도 필요 없다.
aws lambda invoke --function-name storix-spec-changelog \
--payload '{"label":"dev-abc1234","commit":"<sha>"}' /dev/null
Lambda 는 호출 주소가 따로 생기지 않는다. lambda:InvokeFunction 권한을 가진 주체만 부를 수 있고,
배포 역할 하나로 좁혀 둔다. Function URL 은 만들지 않는다 — 만드는 순간 공개 엔드포인트가 된다.
리소스를 만드는 명령은 scripts/aws-setup.sh 에 모아 뒀다.
dev 서버는 비용 때문에 평소 꺼 둔다. 쓰려면 켜고, 켠 뒤 4시간이 지나면 다음 정각에 자동으로 꺼진다. 쓰다가 꺼져도 다시 켜면 된다.
dev 서버 켜져 있어?
dev 서버 켜줘
dev 서버 2시간만 더 쓸게
켜고 나서 앱이 응답하기까지 1~2분 걸린다. dev_server_status 가 앱 응답 여부와 꺼지는 시각을 같이 보여준다.
퍼블릭 IP 는 켤 때마다 바뀌지만 dev.storix.kr 주소는 그대로다.
더 써야 하면 dev_server_extend 로 미룬다. 지금부터 정한 시간만큼 인스턴스의 extend-until 태그에 적고,
그 시각이 지난 뒤 처음 오는 정각에 꺼진다.
끄기는 다른 사람이 쓰고 있을 수 있어 확인을 받고 실행한다.
develop 에 머지되면 배포가 dev 를 알아서 켠다. 배포가 켠 서버는 30분만 두고 다음 정각에 끈다.
아무도 안 쓰는데 배포 때문에 4시간씩 도는 것을 막기 위해서다. 그 사이에 쓰려면 dev_server_start 를 부르면
직접 켠 것과 같이 4시간을 확보한다. 배포는 켤 때 인스턴스에 deploy-started-at 태그를 적고,
그 시각이 서버가 켜진 시각과 붙어 있으면 배포가 켠 것으로 본다.
자동 종료는 매시 정각에 도는 Lambda dev-server-auto-stop 이 한다. 코드는 scripts/dev-autostop-lambda.mjs 이고,
4시간과 30분은 Lambda 환경변수와 src/modules/devserver/index.js 두 곳에 같이 적혀 있다.
바이트를 읽고 쓰는 부분만 백엔드로 갈라 뒀다. 라벨 규칙과 색인 병합은 그대로다.
| 백엔드 | 언제 | 고르는 법 |
|---|---|---|
fs |
각자 찍어 보는 로컬 이력, 그리고 나중에 EFS 를 붙일 때 | 기본값 |
s3 |
Lambda, 그리고 팀이 공유하는 배포 이력을 볼 때 | SWAGGER_SNAPSHOT_S3_BUCKET 이 있으면 |
EFS 도 결국 POSIX 마운트라 fs 백엔드가 그대로 동작한다. SWAGGER_SNAPSHOT_DIR 만 바꾸면 된다.
이력은 CD 가 배포 때마다 S3 에 쌓는다. 그래서 버킷을 주지 않으면 비어 있는 fs 를 보게 되고
swagger_history 는 "스냅샷이 없다"고 답한다. 읽기 권한은 AWS 프로필로 정해지며, 쓰기는 주지 않는다 —
스냅샷을 찍는 것은 CD 의 몫이다.
스냅샷이 사라지면 직전 배포와 비교할 수가 없다. 컨테이너로 띄운다면 반드시 볼륨으로 빼라.
로컬에서 쓰는 다른 MCP 서버를 storix 하나에 묶을 수 있다. 등록을 여러 개로 늘리지 않고
한 자리에서 들고 있게 하려는 것이다.
.storix-mcp.json 에 bridge 를 넣는다. auth_setup 이 만드는 그 파일이다.
{
"bridge": [
{ "alias": "notion", "command": "npx", "args": ["-y", "@notionhq/notion-mcp-server"] },
{ "alias": "mine", "command": "node", "args": ["/Users/me/tools/my-mcp/index.js"] }
]
}툴은 별칭_툴이름 으로 올라온다. 위 예라면 notion_search, mine_doctor 처럼 된다.
무엇이 붙었는지는 bridge_list 로 본다.
여기 적은 것은 npm 으로 나가지 않는다. .storix-mcp.json 은 .gitignore 에 있고
package.json 의 files 는 src · flows · skills 만 싣는다. 각자 붙인 것이 패키지에
섞일 길이 없다.
몇 가지 정해둔 것:
- 로컬 전용이다. 원격 HTTP 모드에서는 꺼진다 — 자식은 그 사람 컴퓨터에서 뜨는 프로세스다
- 자식이 죽어도 storix 는 뜬다. 10초 안에 안 붙으면 건너뛰고
bridge_list에 이유를 남긴다 (STORIX_BRIDGE_TIMEOUT_MS로 조절) - 별칭이
swaggerauthreportmetricsmobileflow면 건너뛴다 — 이름이 겹친다 - 툴 목록은 세션 시작 때 정해진다. 설정을 고쳤으면 Claude Code 를 다시 켜야 잡힌다
| 툴 | 용도 |
|---|---|
swagger_list_endpoints |
엔드포인트 찾기. keyword/tag/method 필터 |
swagger_get_endpoint |
요청·응답 스키마를 $ref 까지 펼쳐서 |
swagger_get_schema |
DTO 하나. 이름 생략하면 전체 목록 |
swagger_errors |
에러 코드만. code 로 역방향 조회 |
swagger_call_api |
실제 요청 |
swagger_snapshot_spec |
스펙 스냅샷 저장. 라벨 생략하면 목록 |
swagger_history |
배포 시점별 변경 이력 |
swagger_diff_spec |
두 스냅샷 비교 |
swagger_refresh_spec |
캐시 버리고 재조회 |
report_check |
어느 쪽이 어긋났는지 판정 |
report_send |
판정을 붙여 슬랙에 제보 |
metrics_list |
지표 목록과 해석 주의점 |
metrics_query |
지표 조회 |
auth_setup |
계정 저장 (로컬) |
auth_login |
토큰 발급 (로컬) |
auth_signup_tester |
테스터 가입 요청 (로컬) |
auth_status |
로그인 상태 |
auth_logout |
토큰 폐기 (로컬) |
flow_list |
시나리오 목록 |
flow_check |
호출 없이 경로가 스펙에 있는지만 |
flow_run |
시나리오 실행과 판정 |
mobile_doctor |
도구·기기 점검, 지금 되는 것 (로컬) |
mobile_open |
딥링크로 앱 화면 띄우기 (로컬) |
dev_server_status |
dev 서버 상태, 앱 응답, 자동으로 꺼지는 시각 (로컬) |
dev_server_start |
dev 서버 켜기 (로컬) |
dev_server_extend |
자동 종료 미루기. 기본 2시간, 최대 12시간 (로컬) |
dev_server_stop |
dev 서버 끄기 (로컬) |
auth 모듈은 원격(HTTP) 모드에서 auth_status 만 남기고 꺼진다.
공유 서버에 한 사람의 자격증명을 두면 접속한 모두가 그 권한으로 API 를 호출하게 된다.
그게 관리자 계정이면 아무나 제재를 걸 수 있다는 뜻이다. 원격에서 실제 호출이 필요하면
swagger_call_api 의 token 인자에 각자 자기 JWT 를 넘긴다.
mobile 은 원격에서 통째로 꺼진다. 기기를 만지는 일이라 그 사람 컴퓨터에서만 뜻이 있고,
공유 서버에서 남의 기기를 열 수 있게 둘 이유가 없다.
dev_server 도 원격에서 통째로 꺼진다. 각자 AWS 프로필로 EC2 를 직접 불러야
누가 켜고 껐는지가 CloudTrail 에 사람별로 남는다. 공유 서버에 EC2 권한을 두면 그 구분이 사라진다.
metrics 는 원격에서도 켜둔다. 미리 정의한 집계만 나가서 개인정보가 응답에 안 담기기
때문이다. 자유 SQL 을 열지 않은 이유가 여기에 있다.
- basic auth —
initialize부터 인증을 요구한다 - Origin 검사 — DNS 리바인딩 방어.
Origin헤더가 있는데 허용 목록에 없으면 403. CLI 클라이언트는Origin을 안 보내므로 통과한다 Mcp-Session-Id는 인증에 쓸 수 없다. 서버가initialize응답으로 발급하는 값이라 누구나 요청만 하면 받아간다. 세션은 상태 연속성용이지 자격증명이 아니다/mcp/healthz만 인증 없이 200 (로드밸런서용)
스모크 검사는 node smoke-http.mjs — 무인증 401, 낯선 Origin 403, healthz 200,
툴 개수, 쓰기 차단을 확인한다.
- 경로 변경은 rename 을 못 알아본다. "제거 + 추가" 로 나온다. 태그로 묶어 보면 사람이 알아본다
- description·example 변경은 일부러 무시한다
- 스키마 펼치기는 기본 깊이 8 에서 자른다 (비교는 24 까지 본다). 순환 참조는
$circular로 표시 - 태그 이름이 바뀌면 그 시점 앞뒤로 이력이 끊긴다. 스냅샷에 그때의 태그가 박히기 때문이다
- 응답 content-type 은 springdoc 이
*/*로 내보내는 경우가 많아 json 우선, 없으면 첫 content 를 쓴다
swagger_diff_spec 이 breaking 으로 분류하는 것: 엔드포인트·필드·응답 상태코드 제거,
필드 타입 변경, 필수 파라미터 추가, 요청 필드가 선택→필수, 응답 필드가 필수→선택,
응답이 nullable 로 전환, 요청에서 enum 값 제거, 인증 요구 변경.
그 외로 빼는 것: 엔드포인트·필드 추가, enum 값 추가, format 변경, deprecated 표시, 반대 방향의 완화.
src/
index.js stdio 진입점
http.js HTTP 진입점
server.js storix 서버 하나를 만들고 모듈을 등록
shared/
mcp.js 응답 헬퍼, 이름 접두사
session.js 발급받은 토큰 (메모리)
modules/
index.js 등록할 모듈 목록
swagger/ spec · diff · snapshots · history · errors · guide
auth/ credentials
report/ verdict · slack · guide
metrics/ db · queries
devserver/ ec2
모듈을 추가하려면 src/modules/<이름>/index.js 에 NAMESPACE 와
register(server, { local }) 을 내보내고 src/modules/index.js 에 한 줄 넣는다.
local 이 false 면 여러 사람이 함께 쓰는 원격 모드다.
{ "env": { "AWS_PROFILE": "storix", "SWAGGER_SNAPSHOT_S3_BUCKET": "<스냅샷 버킷 — 팀 시크릿 참고>" } }