MGC_MCP
# 메가MGC커피 앱 재고조회 MCP 재현 가이드
작성일: 2026-07-04 (KST)
대상 앱: 메가MGC커피 Android 앱 `co.kr.waldlust.megacoffee`
확인 버전: `2.0.7` / `versionCode=85`
기준 방식: ADB 연결 단말의 앱 화면 및 APK smali 분석, 앱 API 실호출
## 1. 목적
이 문서는 메가MGC커피 앱에서 사용하는 API를 바탕으로,
상품 검색, 매장 검색, 매장별 `sold_out` 재고 상태 조회를 재현하고 MCP 도구로 호출하는 절차를 정리합니다.
현재 MCP 서버는 다음 작업을 지원합니다.
- 메가MGC커피 매장 조회
- 앱 메뉴 검색
- 단일 매장 상품 재고 조회
- 전국 매장 대상 상품 재고 조회
- 지역 매장 대상 상품 재고 조회
- 전체 매장 리스트 캐싱 및 캐시 기반 지역 검색
## 2. 핵심 엔드포인트
베이스 URL:
- `https://app.annhouse.co.kr/api/`
APK 분석에서 확인된 추가 베이스 URL:
- `https://preview-app.mgcglobal.co.kr/api/`
- `https://devapp.annhouse.co.kr/api/`
현재 구현에서 사용하는 핵심 엔드포인트:
- 메뉴 목록: `POST /api/menu/general/list`
- 추천 메뉴 목록: `POST /api/menu/rcmnd/list`
- 메뉴 검색: `POST /api/menu/search`
- 메뉴 옵션: `POST /api/menu/option`
- 매장 목록: `POST /api/store/list`
재고 판정에 사용하는 필드:
- 상품 코드: `item_cd`
- 상품명: `item_nm`
- 가격: `price`
- 이미지: `img`
- 품절 여부: `sold_out`
- 매장 코드: `store_cd`
## 3. 공통 요청 조건
실측 기준 최소 헤더:
- `content-type: application/json`
- `accept: application/json`
- `user-agent: okhttp/4.12.0`
환경 변수로 API 베이스 URL과 User-Agent를 바꿀 수 있습니다.
- `MGC_APP_API_BASE_URL`
- `MGC_APP_USER_AGENT`
실행 인자로도 같은 값을 지정할 수 있습니다.
- `--app-api-base-url`
- `--app-user-agent`
- `--stock-api-url`
## 4. 재현 명령
### A. 전체 메뉴 목록 조회
```bash
curl -sS 'https://app.annhouse.co.kr/api/menu/general/list' \
-H 'content-type: application/json' \
-H 'accept: application/json' \
-H 'user-agent: okhttp/4.12.0' \
--data '{"store_cd":""}' \
| jq '.all.upper_ctg_list[0].ctg_list[0].item_list[0] | {item_cd,item_nm,price,sold_out,img}'
```
기대 결과:
- `item_cd`, `item_nm` 존재
- `sold_out` 값 확인 가능
### B. 특정 매장 기준 메뉴 목록 조회
```bash
curl -sS 'https://app.annhouse.co.kr/api/menu/general/list' \
-H 'content-type: application/json' \
-H 'accept: application/json' \
-H 'user-agent: okhttp/4.12.0' \
--data '{"store_cd":"001638"}' \
| jq '.. | objects | select(.item_cd? == "107350") | {item_cd,item_nm,price,sold_out}'
```
기대 결과:
- 해당 매장에서 상품이 노출되면 `item_cd: "107350"` 반환
- `sold_out: true`이면 품절
- `sold_out: false`이면 판매 가능
- 결과가 없으면 해당 매장 메뉴에 노출되지 않은 상태
### C. 매장 목록 조회
```bash
curl -sS 'https://app.annhouse.co.kr/api/store/list' \
-H 'content-type: application/json' \
-H 'accept: application/json' \
-H 'user-agent: okhttp/4.12.0' \
--data '{
"use_location": false,
"latitude": "0",
"longitude": "0",
"keyword": "",
"amenities_cd_list": [],
"page": 1,
"page_size": 20,
"item_list": []
}' \
| jq '.store_list[0] | {store_cd,name,addr,status,latitude,longitude}'
```
기대 결과:
- `store_cd`, `name`, `addr` 존재
### D. 위치 기반 근처 매장 조회
```bash
curl -sS 'https://app.annhouse.co.kr/api/store/list' \
-H 'content-type: application/json' \
-H 'accept: application/json' \
-H 'user-agent: okhttp/4.12.0' \
--data '{
"use_location": true,
"latitude": "37.4979",
"longitude": "127.0276",
"keyword": "",
"amenities_cd_list": [],
"page": 1,
"page_size": 10,
"item_list": []
}' \
| jq '.store_list[] | {store_cd,name,addr}'
```
기대 결과:
- 지정 좌표 주변 매장 목록 반환
### E. 전국 매장별 상품 노출 및 품절 상태 재현
전국 조회는 다음 절차를 반복합니다.
1. `POST /api/store/list`를 `page` 증가 방식으로 호출해 전체 매장 수집
2. 전체 매장 리스트를 `data/mgc-stores.json`에 캐싱
3. 지역 조건이 있으면 캐시된 매장명/주소 기준으로 필터링
4. 각 `store_cd`로 `POST /api/menu/general/list` 호출
5. `item_cd` 또는 상품명으로 메뉴 검색
6. 메뉴가 있으면 `sold_out`으로 판매 가능/품절 판정
7. 메뉴가 없으면 `notListed`로 분류
캐시 파일:
- 기본 경로: 패키지 내부 `data/mgc-stores.json`
- 기본 TTL: 720시간(30일)
- 환경 변수: `MGC_STORE_CACHE_PATH`
캐시 파일에는 다음 값이 저장됩니다.
- `refreshedAt`
- `count`
- `stores[].storeCode`
- `stores[].name`
- `stores[].address`
- `stores[].latitude`
- `stores[].longitude`
이전 방식처럼 매번 전체 매장을 새로 수집하는 대신, 기본적으로 패키지에 포함된 캐시를 우선 사용합니다.
GitHub 배포 사용자는 저장소에 포함된 `data/mgc-stores.json`을 바로 사용합니다.
`MGC_STORE_CACHE_PATH` 또는 `storeCachePath`를 지정하면 해당 경로를 사용자 실행 폴더 기준으로 사용합니다.
전국 재고 조회 내부 흐름:
1. 캐시가 없거나 만료되었으면 전체 매장 리스트 새로 수집
2. 각 `store_cd`로 `POST /api/menu/general/list` 호출
3. `item_cd` 또는 상품명으로 메뉴 검색
4. 메뉴가 있으면 `sold_out`으로 판매 가능/품절 판정
5. 메뉴가 없으면 `notListed`로 분류
실측 예시:
- 상품명: `와앙 핫 치즈스틱 & 딥`
- 상품 코드: `107350`
- 수집 매장: 4,286개
- 상품 노출 매장: 41개
- 판매 가능: 40개
- 품절: 1개
- 품절 매장: `001583` 송파나루역점
전체 실측 결과 파일:
- `mgc-cheesestick-national.json`
## 5. MCP 구현 매핑
### `refresh_mgc_stores`
전체 매장 리스트 캐시 갱신 도구입니다.
입력:
```json
{
"cachePath": "data/mgc-stores.json",
"maxStores": 5000
}
```
출력:
- `cachePath`
- `refreshedAt`
- `count`
- `sampleStores`
### `list_mgc_stores_by_region`
캐시된 전체 매장 리스트에서 지역 조건에 맞는 매장을 조회합니다.
입력:
```json
{
"regionQuery": "서울 종로구",
"resultLimit": 100
}
```
혜화/대학로권처럼 앱 주소에 행정동이 직접 들어가지 않는 경우:
```json
{
"city": "서울",
"district": "종로구",
"neighborhoods": ["혜화", "대학로"],
"resultLimit": 100
}
```
출력:
- `totalStores`
- `matchedStores`
- `storeCache.fromCache`
- `storeCache.cachePath`
- `storeCache.refreshedAt`
- `stores`
### `find_mgc_stores`
매장 검색 도구입니다.
입력:
- `latitude`
- `longitude`
- `sigungu`
- `limit`
소스:
- 앱 API: `POST /api/store/list`
- 보조 소스: 메가MGC커피 공개 웹 매장 조회
출력:
- `appStores[].storeCode`
- `appStores[].name`
- `appStores[].address`
- `appStores[].latitude`
- `appStores[].longitude`
### `search_mgc_menu`
메뉴 검색 도구입니다.
입력:
- `query`
- `limit`
소스:
- 앱 API: `POST /api/menu/general/list`
- 보조 소스: 메가MGC커피 공개 웹 메뉴 조회
출력:
- `appMenus[].itemCode`
- `appMenus[].name`
- `appMenus[].price`
- `appMenus[].soldOut`
- `appMenus[].imageUrl`
### `check_mgc_stock`
단일 매장 또는 기본 메뉴 기준 재고 조회 도구입니다.
입력:
- `productName`
- `storeCode`
- `storeId`
- `storeName`
- `sigungu`
- `latitude`
- `longitude`
소스:
- 기본: `POST /api/menu/general/list`
- 커스텀 연동: `MGC_STOCK_API_URL`
판정:
- `sold_out: false` -> `available`
- `sold_out: true` -> `sold_out`
- 메뉴를 찾지 못하면 공개 웹 근거만 반환하며 `unknown`
### `check_mgc_stock_nationwide`
전국 또는 지역 필터 기반 재고 조회 도구입니다.
입력:
```json
{
"itemCode": "107350",
"productName": "와앙 핫 치즈스틱 & 딥",
"regionQuery": "서울 종로구",
"refreshStores": false,
"storeCacheTtlHours": 720,
"maxStores": 5000,
"concurrency": 8,
"resultLimit": 100
}
```
지역 입력:
- `regionQuery`: 자유형 지역 문자열
- `city`: 시/도, 예: `서울`
- `district`: 시/군/구, 예: `종로구`
- `neighborhoods`: 동/도로명/역명/매장명 키워드 배열, OR 조건
- `regionKeyword`: 공백 토큰 전체가 매장명/주소에 포함되어야 함
- `regionKeywords`: 여러 지역 문구 중 하나라도 매칭되면 포함
- `refreshStores`: 재고 조회 전 매장 캐시 강제 갱신
- `storeCachePath`: 매장 캐시 파일 경로
- `storeCacheTtlHours`: 매장 캐시 TTL. 기본값은 720시간입니다.
`regionQuery` 해석 규칙:
- `서울 종로구` -> `서울 AND 종로구`
- `서울 종로구 이화동 혜화동` -> `서울 AND 종로구 AND (이화동 OR 혜화동)`
소스:
- 매장 수집: `POST /api/store/list`
- 매장별 메뉴 조회: `POST /api/menu/general/list`
출력:
- `checkedStores`
- `totalStores`
- `matchedStores`
- `matchedStoreSamples`
- `storeCache`
- `foundCount`
- `availableCount`
- `soldOutCount`
- `notListedCount`
- `errorsCount`
- `availableStores`
- `soldOutStores`
### `check_mgc_stock_by_region`
지역 매장 대상 재고 조회 전용 도구입니다.
서울 종로구 전체 조회:
```json
{
"itemCode": "107350",
"regionQuery": "서울 종로구",
"maxStores": 5000,
"concurrency": 8,
"resultLimit": 100
}
```
서울 종로구의 이화동/혜화동 키워드 조회:
```json
{
"itemCode": "107350",
"city": "서울",
"district": "종로구",
"neighborhoods": ["이화동", "혜화동"],
"maxStores": 5000,
"concurrency": 8,
"resultLimit": 100
}
```
주의:
- 앱 매장 주소가 행정동 이름을 항상 포함하지는 않습니다.
- 예를 들어 혜화권 매장이 `혜화동` 대신 `혜화로`, `대학로`, `서울혜화초교점`처럼 저장될 수 있습니다.
- 이 경우 `neighborhoods`에 `혜화로`, `대학로`, `혜화` 같은 실제 주소/매장명 키워드를 같이 넣으면 됩니다.
## 6. 설치 및 실행
### 로컬 설치
```bash
npm install
npm run build
node dist/server.js
```
앱 API 베이스 URL을 실행 인자로 바꾸려면:
```bash
node dist/server.js \
--app-api-base-url https://app.annhouse.co.kr/api/ \
--app-user-agent okhttp/4.12.0
```
검증:
```bash
npm run build
npm test
```
현재 확인 결과:
- TypeScript 빌드 통과
- Vitest 테스트 통과
- `checkNationwideStock({ itemCode: "107350", maxStores: 20 })` 스모크 테스트 통과
### Codex에 등록
로컬 저장소에서 설치한 경우 다음 명령으로 Codex MCP 설정에 바로 등록할 수 있습니다.
```bash
npm run codex:install
```
이 명령은 빌드 후 아래와 같은 Codex 등록을 자동 실행합니다.
```bash
codex mcp add mgc-mcp -- node <현재 패키지>/dist/server.js
```
이미 같은 이름의 MCP 서버가 있으면 `npm run codex:install`은 기존 `mgc-mcp` 등록을 제거한 뒤 다시 추가합니다.
수동으로 등록하려면 다음 명령을 사용합니다.
```bash
codex mcp add mgc-mcp -- node C:/Users/sh953/Documents/code/active/MGC_MCP/dist/server.js
```
등록 확인:
```bash
codex mcp get mgc-mcp
codex mcp list
```
서버 실행 인자를 함께 등록하려면 `--` 뒤에 `mgc-mcp` 인자를 붙입니다.
```bash
node dist/codexInstall.js --force -- \
--app-api-base-url https://app.annhouse.co.kr/api/ \
--app-user-agent okhttp/4.12.0
```
다른 이름으로 등록하려면:
```bash
node dist/codexInstall.js --name mgc-mcp-dev --force
```
GitHub 저장소를 직접 설치해서 Codex에 등록하려면:
```bash
npx -y --package github:maskelog/MGC_MCP mgc-mcp-install-codex --force
```
GitHub 설치 방식에서도 저장소의 `data/mgc-stores.json`이 패키지에 포함됩니다.
따라서 사용자는 별도 캐시 생성 없이 바로 지역 재고 조회를 실행할 수 있습니다.
특정 브랜치나 태그를 고정하려면:
```bash
npx -y --package github:maskelog/MGC_MCP#main mgc-mcp-install-codex --force
```
## 7. MCP 설정 예시
Codex 등록 도우미를 사용하지 않고 MCP 설정 JSON을 직접 작성해야 하는 클라이언트에서는 다음 형태를 사용합니다.
```json
{
"mcpServers": {
"mgc-mcp": {
"command": "node",
"args": ["C:/Users/sh953/Documents/code/active/MGC_MCP/dist/server.js"]
}
}
}
```
커스텀 재고 API를 우선 사용하려면:
```json
{
"mcpServers": {
"mgc-mcp": {
"command": "node",
"args": ["C:/Users/sh953/Documents/code/active/MGC_MCP/dist/server.js"],
"env": {
"MGC_STOCK_API_URL": "https://example.internal/mgc-stock"
}
}
}
}
```
앱 API 베이스 URL을 바꾸려면:
```json
{
"mcpServers": {
"mgc-mcp": {
"command": "node",
"args": ["C:/Users/sh953/Documents/code/active/MGC_MCP/dist/server.js"],
"env": {
"MGC_APP_API_BASE_URL": "https://app.annhouse.co.kr/api/",
"MGC_APP_USER_AGENT": "okhttp/4.12.0"
}
}
}
}
```
실행 인자로 앱 API 베이스 URL을 바꾸려면:
```json
{
"mcpServers": {
"mgc-mcp": {
"command": "node",
"args": [
"C:/Users/sh953/Documents/code/active/MGC_MCP/dist/server.js",
"--app-api-base-url",
"https://app.annhouse.co.kr/api/",
"--app-user-agent",
"okhttp/4.12.0"
]
}
}
}
```
캐시를 사용자 작업 폴더에 따로 저장하고 싶으면:
```json
{
"mcpServers": {
"mgc-mcp": {
"command": "npx",
"args": [
"-y",
"github:maskelog/MGC_MCP"
],
"env": {
"MGC_STORE_CACHE_PATH": "data/mgc-stores.json"
}
}
}
}
```
## 8. 캡처 및 분석 메모
ADB 확인:
- 연결 단말: `R3CY10A8WCN`
- 앱 패키지: `co.kr.waldlust.megacoffee`
- 메인 액티비티: `co.kr.waldlust.megacoffee/.ui.main.MainActivity`
APK 분석에서 확인한 항목:
- `MegaApi.smali`
- `GeneralMenuRequest`
- `StoreInfoRequest`
- `MegaOrderOptionRequest`
- 메뉴 응답 모델의 `item_cd`, `item_nm`, `sold_out`
생성/보관된 작업 파일:
- `apk/base.apk`
- `mgc-current.png`
- `mgc-product-detail.png`
- `mgc-cheesestick-national.json`
## 9. 실패 대응
1. `401/403` 또는 앱 API 실패
- 앱 최신 버전에서 헤더, 베이스 URL, 세션 요구 여부 재확인
- `MGC_APP_USER_AGENT`를 실제 앱 User-Agent로 조정
2. 메뉴가 전역 조회에서는 보이지만 매장별 조회에서 없음
- 해당 매장 메뉴에 상품이 노출되지 않은 상태일 수 있음
- 이 경우 MCP는 `notListed`로 집계
3. 상품명이 오타인 경우
- 가능한 경우 `itemCode`를 우선 사용
- 예: `와앙 핫 치즈스틱 & 딥` -> `107350`
4. 전국 조회가 오래 걸리는 경우
- `maxStores`를 낮춰 부분 검증
- `concurrency`를 4~12 범위에서 조정
- 기본값은 `concurrency: 8`
5. 결과가 너무 큰 경우
- `resultLimit`로 반환 매장 수 제한
- 집계 수치(`checkedStores`, `foundCount`, `soldOutCount`)는 제한 없이 계산됨
TDQS
Scored across 7 tools
Most tools have distinct purposes: stock checking split by scope (public site vs app, regional vs nationwide) and store listing split by search method (lat/lng vs region from cache). However, 'check_mgc_stock' and 'check_mgc_stock_by_region' could be confused if users don't read descriptions carefully, and 'find_mgc_stores' vs 'list_mgc_stores_by_region' have overlapping outputs.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., 'check_mgc_stock', 'find_mgc_stores', 'search_mgc_menu'). The naming is predictable and easy to understand.
With 7 tools, the set is well-scoped for the domain of checking stock and finding stores for a coffee chain. Each tool serves a clear purpose without unnecessary duplication.
The tool set covers core operations: stock checking via multiple methods, store finding, menu search, and cache refresh. Minor gaps exist, such as no tool to retrieve store details (hours, address) or update stock, but these are not essential for a read-only consumer service.