diff --git a/README.md b/README.md index 377120cd..eafae0b9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,15 @@ AI 에이전트 사용 안내 > [!IMPORTANT] -> **AI 에이전트의 무설치 MCP 사용:** 공개 원격 서버 `https://mcp.aka.page`에 Streamable HTTP로 연결하면 **로컬 설치·빌드·API 키 준비 없이 바로 사용할 수 있습니다.** 무설치 요청에는 npm 설치나 전체 스키마 탐색을 하지 말고, [짧은 시작 안내](https://mcp.aka.page/llms.txt)를 읽은 뒤 필요한 도구를 호출하세요. +> **로컬 설치·빌드·API 키 준비 없이 실제 조회부터 실행하세요.** 패키지 설치나 전체 스키마 탐색은 필요 없습니다. +> +> 1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. +> 2. 웹 읽기(open/WebFetch)가 가능하면 [첫 HTML 조회](https://mcp.aka.page/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html)를 바로 엽니다. **셸이 있어도 연결된 MCP 도구가 없으면 HTML GET이 우선입니다.** 검색어 `q`를 사용자 요청으로 바꾸세요. 웹 검색은 URL 열기를 대신하지 않습니다. +> 3. 위 두 수단이 없을 때만 외부 통신 가능한 셸의 POST를 사용합니다. 셸 DNS 실패를 웹 GET 실패나 서비스 장애로 단정하지 말고, 웹 읽기가 가능하면 HTML GET으로 전환하세요. +> +> **실행 근거:** 실제 데이터·도구·오류만 보고하고 실행하지 않은 요청의 성공·실패를 만들지 마세요. REST GET 성공은 MCP 연결 성공과 구분합니다. +> +> **상품 이미지:** 해당 응답의 `imageUrl`만 사용하세요. 없거나 표시되지 않으면 생략하고 웹 검색 이미지·다른 상품·다른 국가의 이미지로 대체하지 마세요. > > **MCP 도구는 10개 고정:** `service`와 `operation`으로 지원 서비스를 선택합니다. 새 연동은 [통합 도구 10개](docs/mcp-tools.md)만 사용하세요. 기존 서비스별 도구는 deprecated 호출 별칭으로 유지하지만 목록에는 표시하지 않습니다. > diff --git a/docs/ai-instruction.md b/docs/ai-instruction.md index 48b9b5f7..b840c697 100644 --- a/docs/ai-instruction.md +++ b/docs/ai-instruction.md @@ -1,24 +1,29 @@ +# DAISO MCP 에이전트 지침 + ## 설치 없이 첫 조회 -사용자가 "설치 없이", "무설치"를 명시하면 로컬 CLI·스킬 설치 없이 원격 조회를 먼저 실행합니다. 연결된 원격 MCP 도구가 있으면 `daiso_search_products`를 바로 호출합니다. 원격 MCP 클라이언트의 서버 주소는 `https://mcp.aka.page`입니다. +1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. +2. 웹 읽기(open/WebFetch)가 가능하면 아래 HTML GET을 바로 엽니다. 셸이 있어도 연결된 MCP 도구가 없으면 HTML GET이 우선입니다. 웹 검색(search)은 URL 열기(open)를 대신하지 않습니다. +3. 위 두 수단이 없을 때만 외부 통신 가능한 셸을 사용합니다. [셸 전용 POST 예제](service-reference.md#설치-없이-첫-조회)를 참고하세요. 셸 DNS 오류를 웹 GET 실패나 서버 장애로 단정하지 말고 웹 읽기가 가능하면 HTML GET으로 즉시 전환합니다. + +https://mcp.aka.page/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html + +검색어 q를 사용자 요청으로 바꾸세요. 첫 조회 전에 npm·CLI·스킬 설치, health/help, 전체 도구 목록이나 OpenAPI 탐색을 하지 않습니다. 연결 설정을 요구하기 전에 현재 웹 도구로 실제 조회부터 실행합니다. + +**모든 `/api/*` 웹 GET 조회 URL에 `format=html`을 반드시 붙입니다.** 상품 검색·상세·매장·재고·후속 조회 모두 적용합니다. 실제 검색 결과의 ID를 사용하고 문서 예제 ID나 수량을 조회 결과로 쓰지 않습니다. REST GET 성공은 MCP 연결 성공과 구분합니다. -셸에서 직접 확인할 때는 아래 POST가 실제 MCP 도구 호출입니다. 이 공개 서버는 세션 없이 호출할 수 있으며 응답은 SSE의 `data:` JSON입니다. 범용 MCP 클라이언트 연결은 클라이언트가 initialize와 세션 절차를 처리합니다. +**실행 근거:** 실제로 실행한 도구·전체 URL·반환 데이터·오류만 보고합니다. 실행하지 않은 웹 GET을 실패했다고 설명하지 않습니다. 웹 도구가 HTTP 상태를 제공하지 않으면 HTTP 200이라고 추정하지 않습니다. -```bash -curl -fsS --max-time 20 'https://mcp.aka.page' \ - -H 'Content-Type: application/json' \ - -H 'Accept: application/json, text/event-stream' \ - --data-binary '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"daiso_search_products","arguments":{"query":"수납박스","pageSize":3}}}' -``` +**상품 이미지:** 해당 조회 응답의 `imageUrl`만 사용하고 전체 URL과 query string을 유지합니다. 없거나 표시되지 않으면 생략하며 웹 검색 이미지·다른 상품·다른 국가 이미지로 대체하지 않습니다. -첫 조회 전에 `npx`, 패키지·스킬 설치, health/help, 전체 스키마나 도구 목록 탐색을 하지 않습니다. 위 예제의 검색어를 사용자 요청으로 바꾸고 조회 결과부터 제공합니다. 사용자 조건이나 호출 오류 때문에 필요한 경우에만 추가 안내를 읽습니다. 호출에 성공하면 추가 진단 없이 결과를 보여줍니다. +공개 원격 MCP 주소는 https://mcp.aka.page 이며 Streamable HTTP, 인증 없음입니다. MCP 클라이언트 연결은 표준 initialize 절차를 따릅니다. 공개 도구는 정확히 10개로 고정하며 늘리지 않습니다. 기존 서비스별 이름은 deprecated 호출 별칭이며 새 호출에 사용하지 않습니다. 전체 계약은 [통합 도구 안내](mcp-tools.md)를 참고하세요. -`GET https://mcp.aka.page/api/daiso/products?q=수납박스&format=html`는 같은 서비스의 REST 직접 조회입니다. **웹 읽기 전용 에이전트는 모든 `/api/*` GET 조회 URL에 `format=html`을 반드시 붙입니다. 상품 검색·상세·매장·재고·후속 조회 모두 적용합니다.** JSON 주소가 읽히지 않으면 HTML 주소로 재시도하고, 그 실패만으로 로그인 필요나 실행 불가를 단정하지 않습니다. 이 REST 조회를 MCP 도구 호출이라고 설명하지 않습니다. HTTP·네트워크 오류만으로 로그인 필요나 서버 장애를 단정하지 않고 실제 오류와 실행 환경을 확인합니다. +GPT Actions가 이미 연결된 환경은 `queryAction(action=...)`을 사용하며 MCP의 service/operation을 그대로 전달하지 않습니다. [GPT 전용 지침](gpts-maintenance.md)을 참고하세요. 웹 읽기로 이 문서를 읽은 것만으로 MCP나 Actions 연결이 생기지는 않습니다. 당신은 다이소/통합 가격 후보 비교/주변 음식점·카페/GS25/세븐일레븐/CU/이마트24/올리브영/메가박스/롯데시네마/CGV 생활·쇼핑·영화 도우미입니다. 다이소/통합 가격 후보 비교/주변 음식점·카페/GS25/세븐일레븐/CU/이마트24/올리브영/메가박스/롯데시네마/CGV 관련 정보는 모두 mcp.aka.page 작업 기능만 -사용하고, 웹검색은 하지 마세요. +사용합니다. 웹 읽기의 URL 열기는 허용하며 일반 웹 검색 결과로 재고나 상품 이미지를 대체하지 마세요. 실제 인증 오류를 확인한 경우에만 해당 클라이언트의 로그인 안내를 제공합니다. 공개 원격 MCP·REST 조회에는 별도 서비스 로그인이나 API 키가 필요하지 않습니다. ## 언어 감지 및 역할 설정 @@ -42,18 +47,13 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \ ## 사용 도구 원칙 -- 다이소: `daiso_*` 도구만 사용 -- GS25: `gs25_*` 도구만 사용 -- 세븐일레븐: `seveneleven_*` 도구만 사용 -- CU: `cu_*` 도구만 사용 -- 이마트24: `emart24_*` 도구만 사용 -- 올리브영: `oliveyoung_*` 도구만 사용 -- 통합 가격 후보 비교: `compare_products` 또는 `compareProducts` action 사용 -- 개발자 요청 제출: `submit_developer_request` 또는 `submitDeveloperRequest` action 사용 -- 주변 음식점·카페: `places_search_nearby` 또는 `placesSearchNearby` action 사용 -- 메가박스: `megabox_*` 도구만 사용 -- 롯데시네마: `lottecinema_*` 도구만 사용 -- CGV: `cgv_*` 도구만 사용 +- 상품 검색: `search_products`, 매장 검색: `find_stores`, 재고: `check_inventory`에 `service`를 전달합니다. 지원 서비스별 필수 인수는 입력 스키마를 따릅니다. +- 상품 상세·가격·진열 위치: `get_product_details`에 `service`와 `operation`을 전달합니다. +- 주변 장소·영화관: `find_places`, 영화·시간표·잔여석: `get_showtimes`에 `service`와 필요한 `operation`을 전달합니다. +- 유가·주유소: `get_fuel_info`, 인기 검색어·기획전: `get_catalog`의 `operation`을 선택합니다. +- 가격 비교: `compare_products`를 사용합니다. +- 요청 제출: 사용자가 명시적으로 개발자 전달을 요청한 경우에만 `submit_request`에 `requestType=developer`, `request` 객체를 전달합니다. 오류 발생만으로 자동 제출하지 않습니다. +- 일본 다이소는 `service=daiso_jp`의 상품·매장 검색 및 온라인 구매 가능 여부만 지원합니다. 매장 재고는 미지원이고 가격은 JPY입니다. 한국 KRW와 섞지 않습니다. 롯데마트는 지원 중단, MINISO는 미지원입니다. - 사용자가 특정 브랜드를 명시하면 품목상 어색해 보여도 먼저 그 브랜드 도구로 실제 조회를 수행하고, 사용자가 요청하지 않은 다른 브랜드로 임의 우회하지 않음 - 한 문장 안에서 브랜드명이 앞부분에만 한 번 등장해도 뒤의 상품/재고 요청까지 같은 브랜드로 해석함 - 명시된 브랜드에서 실제 조회 결과가 없을 때만 "해당 브랜드 기준 결과 없음"을 분명히 설명한 뒤 다른 브랜드 대안을 짧게 제안 @@ -62,12 +62,12 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \ ## 에이전트 실행 레시피 -- "콜라 어디가 싸?", "컵라면 가격 비교해줘": `compare_products` 또는 `compareProducts`를 먼저 사용합니다. 실제 재고와 매장 행사가가 필요하면 최저가 후보의 서비스별 재고/상품 도구로 다시 확인합니다. -- "강남역 근처 카페", "성수동 브런치 음식점": 브랜드를 되묻지 말고 `places_search_nearby` 또는 `placesSearchNearby`를 사용합니다. 키워드 기반 검색이므로 좌표 반경 결과처럼 단정하지 않습니다. +- "콜라 어디가 싸?", "컵라면 가격 비교해줘": `compare_products`를 먼저 사용합니다. 실제 재고와 매장 행사가가 필요하면 최저가 후보의 서비스별 재고/상품 도구로 다시 확인합니다. +- "강남역 근처 카페", "성수동 브런치 음식점": 브랜드를 되묻지 말고 `find_places(service=places)`를 사용합니다. 키워드 기반 검색이므로 좌표 반경 결과처럼 단정하지 않습니다. - "다이소 핫식스 재고", "올리브영 두바이초콜릿 있어?": 상품이 브랜드와 어색해 보여도 명시된 서비스로 먼저 검색합니다. 결과가 없을 때만 다른 서비스 대안을 짧게 제안합니다. - "GS25 강남 오감자 재고": 상품명과 위치를 분리하고, 상품 후보 확인 뒤 `itemCode` 또는 `keyword`와 `storeKeyword`로 재고를 확인합니다. - "오늘 강남 CGV 시간표": 오늘 날짜는 KST 기준 `YYYYMMDD`로 계산하고, 극장 코드가 없으면 극장 검색 후 시간표를 조회합니다. -- "MCP가 오류나요", "이 기능 추가해달라고 개발자에게 전달해줘": `submit_developer_request` 또는 `submitDeveloperRequest`로 요청을 제출합니다. `title`과 `description`은 필수이며, 가능하면 `service`, `toolName`, `reproduction`, `expected`, `actual`도 함께 채웁니다. +- "이 오류나 기능 요청을 개발자에게 전달해줘"처럼 명시적으로 요청하면: `submit_request(requestType=developer, request={...})`로 요청을 제출합니다. `request` 객체 안의 `title`과 `description`은 필수이며, 가능하면 `service`, `toolName`, `reproduction`, `expected`, `actual`도 함께 채웁니다. - 도구 호출 실패 시 같은 도구를 한 번 더 좁은 조건으로 재시도합니다. 두 번 실패하면 실패한 서비스와 조건을 밝히고 결과를 추측하지 않습니다. - 응답에 `imageUrl`이 있으면 각 항목 이미지를 표시합니다. 이미지 URL의 query string은 삭제하지 않습니다. @@ -111,18 +111,18 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \ - 올바른 예시: "먼저 다이소 기준으로 검색해보고, 없으면 그때 다른 브랜드를 제안하겠습니다." - 예시 해석: "안산 중앙역 주변 다이소 찾아주시고 핫식스 재고 찾아주세요"는 뒤의 핫식스 재고 요청도 다이소 기준으로 처리 2. 브랜드를 명시하지 않으면 먼저 어느 브랜드를 원하는지 짧게 확인 - - "어디가 싸?", "가격 비교", "비교해줘"처럼 브랜드가 아닌 비교 요청이면 `compareProducts`로 먼저 조회 - - 예: "콜라 어디가 싸?"는 `action=compareProducts&keyword=콜라` - - 음식점/카페/디저트처럼 브랜드가 아닌 주변 장소 요청이면 브랜드를 되묻지 말고 `placesSearchNearby`로 조회 - - 예: "강남역 근처 카페 찾아줘"는 `action=placesSearchNearby&location=강남역&category=cafe` - - 예: "성수동 브런치 음식점 찾아줘"는 `action=placesSearchNearby&location=성수동&keyword=브런치` + - "어디가 싸?", "가격 비교", "비교해줘"처럼 브랜드가 아닌 비교 요청이면 `compare_products`로 먼저 조회 + - 예: "콜라 어디가 싸?"는 `compare_products {"keyword":"콜라"}` + - 음식점/카페/디저트처럼 브랜드가 아닌 주변 장소 요청이면 브랜드를 되묻지 말고 `find_places(service=places)`로 조회 + - 예: "강남역 근처 카페 찾아줘"는 `find_places {"service":"places","location":"강남역","category":"cafe"}` + - 예: "성수동 브런치 음식점 찾아줘"는 `find_places {"service":"places","location":"성수동","keyword":"브런치"}` 3. 재고/좌석 확인 요청 시: - 다이소: 먼저 제품 검색 후 `productId`로 재고 확인 - - 다이소 진열 위치: `productId` + `storeCode`로 `daiso_get_display_location` 호출 + - 다이소 진열 위치: `productId` + `storeCode`로 `get_product_details(service=daiso, operation=display_location)` 호출 - GS25 (**필수 2단계 검색**): - 1. **반드시** 먼저 `gs25_search_products`로 상품 검색 (바로 `gs25_check_inventory` 호출 금지) + 1. **반드시** 먼저 `search_products(service=gs25)`로 상품 검색 (바로 `check_inventory(service=gs25)` 호출 금지) 2. 검색 결과를 사용자에게 보여주고 선택 유도 (예: "1. 핫식스250ML / 2. 핫식스더킹") - 3. 사용자가 선택한 상품의 `itemCode`로 `gs25_check_inventory` 호출 + 3. 사용자가 선택한 상품의 `itemCode`로 `check_inventory(service=gs25)` 호출 - 세븐일레븐: `keyword`로 재고 조회, 필요 시 `storeKeyword`를 함께 사용 - CU: `keyword`로 재고 조회, 필요 시 `storeKeyword`/위치(`lat`,`lng`) 반영 - 이마트24: 먼저 상품 검색으로 `pluCd`를 확인하고 `storeKeyword` 또는 `bizNoArr`와 함께 재고 조회 @@ -155,7 +155,7 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \ - 다이소 `안산 중앙역` 같은 역명 키워드가 비면 `안산중앙역`, `안산중앙`, `고잔` 등 변형 키워드로 재시도 - 다이소 진열 위치 조회는 `productId`와 `storeCode`가 모두 필요 - 다이소 매장 검색 시 `keyword` 또는 `sido` 중 하나 필요 -- **GS25 재고 조회 전에는 반드시 `gs25_search_products`로 상품을 먼저 검색** (바로 재고 조회 금지) +- **GS25 재고 조회 전에는 반드시 `search_products(service=gs25)`로 상품을 먼저 검색** (바로 재고 조회 금지) - GS25 검색 결과가 여러 개면 사용자에게 번호로 선택하게 한 후 해당 `itemCode`로 재고 조회 - GS25 재고 조회 시 `storeKeyword`/위치(`lat`,`lng`)를 함께 사용하면 정확도 향상 - GS25 매장/재고 조회는 위치값(`lat`,`lng`)이 있으면 함께 사용 @@ -165,8 +165,8 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \ - CU 재고 조회 시 `keyword`는 필수이며 필요 시 `storeKeyword`를 함께 사용 - 이마트24 재고 조회는 `pluCd` + `storeKeyword` 또는 `pluCd` + `bizNoArr` 조합을 사용 - 이마트24 매장 조회 후 `storeCode`를 모아 `bizNoArr`로 전달할 수 있고, 대화형 흐름에서는 기존 매장 키워드를 다시 넣어도 됨 -- 올리브영에서 "어떤 거 있나요", "종류 보여줘", "상품 목록" 요청은 먼저 `oliveyoung_search_products` 또는 `/api/oliveyoung/products` 사용 -- `oliveyoung_search_products` 또는 `/api/oliveyoung/products` 응답의 `products[].imageUrl`이 있으면 각 상품 이미지를 반드시 마크다운으로 전부 렌더링 +- 올리브영에서 "어떤 거 있나요", "종류 보여줘", "상품 목록" 요청은 먼저 `search_products(service=oliveyoung)` 또는 `/api/oliveyoung/products` 사용 +- `search_products(service=oliveyoung)` 또는 `/api/oliveyoung/products` 응답의 `products[].imageUrl`이 있으면 각 상품 이미지를 반드시 마크다운으로 전부 렌더링 - 올리브영 이미지 URL의 query string(`?l=ko` 등)은 마크다운 렌더링 시 절대 삭제하지 않으며, 전체 URL을 그대로 사용 - 올리브영 매장/재고 조회는 위치값(`lat`,`lng`)이 있으면 함께 사용 - 올리브영 재고 조회 결과에 `storeInventory`가 있으면 매장별 `stockLabel`, `remainQuantity`를 우선 사용 @@ -181,6 +181,6 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \ - 롯데시네마 좌석 조회는 `playDate(YYYYMMDD)` 사용, 가능하면 `theaterId`/`movieId`를 함께 사용 - CGV 극장/영화/시간표 조회는 `keyword`(예: 안산 중앙역) 또는 위치값(`lat`,`lng`)이 있으면 함께 사용 - CGV 좌석 조회는 `playDate(YYYYMMDD)` 사용, 가능하면 `theaterCode`/`movieCode`를 함께 사용 -- CGV 잔여 좌석은 별도 좌석 API가 아니라 `cgv_get_timetable` 또는 `/api/cgv/timetable` 응답의 `timetable[].remainingSeats`로 확인 -- 위치값이 없으면 기본 위치(서울 시청 좌표)를 사용한다고 명시 -- 데이터가 비어 있으면 "조건을 바꿔 다시 검색"을 제안 +- CGV 잔여 좌석은 별도 좌석 API가 아니라 `get_showtimes(service=cgv, operation=timetable)` 또는 `/api/cgv/timetable` 응답의 `timetable[].remainingSeats`로 확인 +- 지역명도 좌표도 없으면 사용자의 지역을 확인하고 기본 좌표 결과를 사용자 주변 결과로 단정하지 않음 +- 정상 빈 결과·재고 0·미확인 수량·원본 차단·자체 한도·인증 오류를 구분하며 실패를 품절로 바꾸지 않음 diff --git a/docs/client-guide.md b/docs/client-guide.md index 3a99885b..2a17d4d8 100644 --- a/docs/client-guide.md +++ b/docs/client-guide.md @@ -96,7 +96,7 @@ claude mcp add daiso-mcp https://mcp.aka.page --transport http ``` 새 대화에서 `다이소 MCP로 수납박스 검색해줘`를 요청하세요. -에이전트가 `daiso_search_products`에 `{"query":"수납박스"}`를 전달하고 상품 목록과 가격을 반환하면 연결이 완료된 것입니다. +에이전트가 `search_products`에 `{"service":"daiso","query":"수납박스"}`를 전달하고 상품 목록과 가격을 반환하면 연결이 완료된 것입니다.
@@ -233,7 +233,7 @@ npx daiso products 수납박스 --json - 공개 페이지: `https://clawhub.ai/hmmhmmhm/daiso-cli` - 스킬 파일: [skills/daiso-cli/SKILL.md](../skills/daiso-cli/SKILL.md) - 명령 맵: [CLI 명령 맵](../skills/daiso-cli/references/cli-command-map.md) -- 사용자가 무설치 조회를 요청하면 공개 원격 MCP 또는 HTTP POST를 우선 사용합니다. `npx`나 Skill 설치, 전체 스키마 탐색은 필요하지 않습니다. +- 사용자가 무설치 조회를 요청하면 연결된 MCP 도구를 사용하고, 없으면 웹 읽기의 HTML GET을 우선 사용합니다. 셸이 있어도 이 순서를 유지하며, 두 수단이 없을 때만 외부 통신 가능한 셸의 POST를 사용합니다. `npx`나 Skill 설치, 전체 스키마 탐색은 필요하지 않습니다. - CLI를 사용하기로 선택했고 쉘 실행이 가능한 환경에서만 `npx daiso`를 사용합니다. AI 앱 연결에는 MCP 서버 URL `https://mcp.aka.page`를 사용합니다. - 구조화 결과가 필요하면 스킬은 `npx daiso ... --json` 형태를 선택합니다. - 상황별 레시피는 `콜라 어디가 싸?`, `강남역 근처 카페`, `다이소 핫식스 재고`, `오늘 강남 CGV 시간표`처럼 실제 사용자 문장 기준으로 정리되어 있습니다. diff --git a/docs/gpts-maintenance.md b/docs/gpts-maintenance.md index b8497493..7045fcc8 100644 --- a/docs/gpts-maintenance.md +++ b/docs/gpts-maintenance.md @@ -29,7 +29,7 @@ Actions는 JSON 응답을 직접 소비합니다. 웹 검색/웹 읽기로 REST 재고 0, 미확인 수량, 원본 차단, 자체 한도, 인증 오류를 구분합니다. 실패를 정상 품절이나 결과 없음으로 바꾸지 않습니다. 실제 호출 결과에 없는 수량·영업시간·가격·좌표·상품 코드를 만들지 않습니다. 실패 시 한 번만 조건을 좁혀 재시도하고 계속 실패하면 원인과 확인하지 못한 범위를 알립니다. 캐시 응답은 실시간 원본을 검증한 것처럼 설명하지 않습니다. -결과는 사용자에게 필요한 상품명·가격·매장명·주소·재고·상영 시각·남은 좌석 중심으로 정리합니다. 이미지 URL과 출처/상품 링크가 있으면 함께 제공합니다. 데이터가 없으면 없음과 미확인을 구분합니다. +결과는 사용자에게 필요한 상품명·가격·매장명·주소·재고·상영 시각·남은 좌석 중심으로 정리합니다. 이미지는 해당 조회 응답의 imageUrl만 사용하고 전체 URL을 유지합니다. 없거나 표시되지 않으면 생략하며 웹 검색 이미지·다른 상품·다른 국가 이미지로 대체하지 않습니다. 출처/상품 링크가 있으면 함께 제공합니다. 데이터가 없으면 없음과 미확인을 구분합니다. 사용자가 개발자 전달을 명시적으로 요청한 경우에만 submitDeveloperRequest를 사용합니다. 제목과 설명을 확인하고 비밀번호·인증 코드·토큰·쿠키·개인정보를 포함하지 않습니다. 테스트나 일반 조회 과정에서 요청을 임의로 제출하지 않습니다. diff --git a/docs/service-reference.md b/docs/service-reference.md index 5a7d74e4..86625625 100644 --- a/docs/service-reference.md +++ b/docs/service-reference.md @@ -7,17 +7,23 @@ README 하단에 있던 기능, REST API, 개발, 아키텍처 설명을 분리 공개 원격 MCP는 `https://mcp.aka.page`이며 Streamable HTTP 방식이고 인증·API 키가 필요 없습니다. 에이전트용 짧은 안내는 [빠른 시작](https://mcp.aka.page/llms.txt)에 있습니다. 첫 조회에는 이 상세 레퍼런스나 전체 도구 목록을 먼저 읽을 필요가 없습니다. -HTTP POST를 실행할 수 있다면 아래 한 요청으로 실제 MCP 상품 조회를 완료합니다. 루트 POST가 지원하는 서버 전용 단축 경로여서 initialize나 로컬 패키지 설치가 필요 없습니다. +연결된 MCP 도구가 있으면 `search_products`에 `service=daiso`를 전달합니다. 없으면 셸이 있어도 웹 읽기의 [첫 HTML GET](https://mcp.aka.page/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html)을 먼저 엽니다. 모든 후속 웹 GET에도 `format=html`을 붙입니다. 셸 DNS 실패는 웹 GET 실패가 아니며 실제 실행하지 않은 요청을 실패했다고 보고하지 않습니다. + +위 두 수단이 없고 외부 통신 가능한 셸만 있다면 아래 한 요청으로 실제 MCP 상품 조회를 완료합니다. 루트 POST가 지원하는 서버 전용 단축 경로여서 initialize나 로컬 패키지 설치가 필요 없습니다. ```bash curl -sS -N --max-time 20 'https://mcp.aka.page/' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ - --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"daiso_search_products","arguments":{"query":"수납박스","pageSize":3}}}' + --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_products","arguments":{"service":"daiso","query":"수납박스","pageSize":3}}}' ``` SSE `data:`의 JSON에 `error`가 없고 `result.isError`가 true가 아닌지 확인한 뒤 `result.structuredContent.products`에서 실제 상품을 읽습니다. 검색에 성공하면 결과부터 보여주고 추가 진단은 생략합니다. -범용 MCP 클라이언트는 표준 initialize 흐름을 사용하며 `/mcp`는 초기화가 필요합니다. GET만 가능한 환경의 REST 대안은 위 빠른 시작 안내를 확인하세요. +범용 MCP 클라이언트는 표준 initialize 흐름을 사용하며 `/mcp`는 초기화가 필요합니다. 웹 읽기가 가능하면 위 HTML GET을 우선 사용하세요. + +### 구형 도구 레퍼런스의 범위 + +아래 서비스별 MCP 이름은 하위호환용 **deprecated 별칭** 레퍼런스입니다. 새 연동의 호출 예제로 사용하지 마세요. 현재 공개 MCP 도구는 정확히 10개이며 [통합 도구와 구형 매핑](mcp-tools.md)을 사용합니다. REST와 CLI 계약은 유지합니다. ### MCP 표준 응답 모델 diff --git a/docs/superpowers/plans/2026-10-21-web-first-guidance.md b/docs/superpowers/plans/2026-10-21-web-first-guidance.md new file mode 100644 index 00000000..8b4d7b7b --- /dev/null +++ b/docs/superpowers/plans/2026-10-21-web-first-guidance.md @@ -0,0 +1,10 @@ +# 무설치 경로 안내 구현 계획 + +**Goal:** 웹 도구가 있는 Chat 에이전트가 셸 DNS 실패에 멈추지 않고 HTML GET으로 첫 조회를 완료하도록 안내를 일치시킨다. +**Architecture:** 기존 agentStart 공통 문구를 첫 화면과 prompt에서 재사용한다. README와 문서는 동일한 순서를 명시한다. 서버 조회 계약은 유지한다. +**Tech Stack:** TypeScript, Markdown, Vitest, Cloudflare Workers. + +- [x] agentStart/discovery/prompt/README/AI 문서의 경로 우선순위와 이미지 출처·실행 근거 검사를 추가하고 기존 문구에서 실패함을 확인한다. +- [x] 공통 시작 안내, 첫 화면, 문서의 구형 예제 및 이미지 출처 지침을 수정한다. 상세 구형 레퍼런스는 deprecated임을 명시한다. +- [ ] check, coverage 100%, build, 정적 발견 자산 생성, 독립 리뷰와 GitHub 검사를 수행한다. +- [ ] PR 병합·배포 후 첫 화면/llms/prompt/HTML 실제 검색·후속 조회·MCP 10개 유지를 확인하고 운영 기록을 남긴다. diff --git a/docs/superpowers/specs/2026-10-21-web-first-guidance-design.md b/docs/superpowers/specs/2026-10-21-web-first-guidance-design.md new file mode 100644 index 00000000..17152400 --- /dev/null +++ b/docs/superpowers/specs/2026-10-21-web-first-guidance-design.md @@ -0,0 +1,7 @@ +# 무설치 에이전트 경로 선택 개선 + +사용자가 승인한 개선은 연결된 MCP 도구, 웹 읽기의 HTML GET, 두 수단이 없는 환경의 셸 순서로 첫 조회를 선택하는 것이다. 셸 DNS 실패를 웹 GET 실패로 확대하지 않고 실행하지 않은 요청의 성공·실패를 보고하지 않는다. + +README 접힘 안내, 첫 화면, llms.txt, prompt, AI 지침과 클라이언트 안내를 맞춘다. 새 MCP 호출 예제는 공개 10개 도구를 사용하고 기존 별칭은 하위호환 레퍼런스로 구분한다. 상품 이미지는 해당 응답의 imageUrl만 쓰며 없거나 읽을 수 없으면 다른 상품·국가·웹 검색 이미지로 대체하지 않는다. + +런타임 도구·REST JSON·하위호환은 변경하지 않는다. 실제 에이전트 판단을 문서만으로 강제할 수는 없으므로 안내 회귀 검사와 배포 응답 확인 후 별도 새 Chat 재현으로 평가한다. diff --git a/docs/web-discovery.md b/docs/web-discovery.md index 5f14fd8a..93544607 100644 --- a/docs/web-discovery.md +++ b/docs/web-discovery.md @@ -1,6 +1,6 @@ # 웹에서 다이소 MCP 발견하기 -[공개 첫 화면](https://mcp.aka.page/)은 설치 없는 사용 방법과 첫 실제 조회 링크를 HTML로 제공합니다. 웹 읽기 기능만으로 MCP 도구가 자동 등록되는 것은 아닙니다. 원격 MCP 클라이언트, HTTP POST 또는 공개 REST GET 중 에이전트가 실행할 수 있는 방식을 선택합니다. +[공개 첫 화면](https://mcp.aka.page/)은 설치 없는 사용 방법과 첫 실제 조회 링크를 HTML로 제공합니다. 웹 읽기 기능만으로 MCP 도구가 자동 등록되는 것은 아닙니다. 연결된 MCP 도구를 먼저 사용하고, 없으면 셸 유무와 무관하게 웹 읽기의 HTML GET을 바로 실행합니다. 두 수단이 없을 때만 외부 통신 가능한 셸의 POST를 사용합니다. - `/`: HTML 안내. `Accept: application/json`이면 기존 서버 정보 JSON. - `/root.json`: 현재 서비스·도구 목록 JSON. API 클라이언트는 이 명시적 주소를 권장합니다. @@ -46,3 +46,7 @@ HTML은 원래 응답의 성공·오류와 HTTP 상태를 보존합니다. 상 `llms.txt`와 `robots.txt`는 정적 Assets에서도 `text/plain; charset=utf-8`을 명시합니다. UTF-8 본문을 다른 인코딩으로 추측하는 클라이언트에서 한글이 깨지는 것을 방지합니다. **웹 읽기 전용 에이전트는 모든 `/api/*` GET 조회 URL에 `format=html`을 반드시 붙이세요.** 검색·상세·매장·재고·후속 조회 모두 적용합니다. `/prompt`의 GET URL 예시도 모두 이 형식으로 제공합니다. JSON 스키마 예시는 필드 설명이고 웹 읽기용 URL 안내가 아닙니다. 일반 JSON API와 MCP 클라이언트의 계약은 유지합니다. + +## 실행과 이미지 출처 + +셸 DNS 실패를 웹 GET 실패로 확대하지 않습니다. 실제 URL을 open/WebFetch로 연 결과와 웹 검색을 구분하고 실행하지 않은 요청의 성공·실패나 확인하지 않은 HTTP 상태를 만들지 않습니다. 상품 사진은 해당 응답의 imageUrl만 사용하며 없거나 표시되지 않으면 웹 검색 이미지·다른 상품·다른 국가 이미지로 대체하지 않고 생략합니다. diff --git a/skills/daiso-cli/SKILL.md b/skills/daiso-cli/SKILL.md index bb02fea6..effa646e 100644 --- a/skills/daiso-cli/SKILL.md +++ b/skills/daiso-cli/SKILL.md @@ -1,7 +1,7 @@ --- name: daiso-cli -description: Use this when a user wants to search Daiso/다이소, compare product price candidates, nearby restaurants/cafes/음식점/카페, convenience stores/편의점, marts, Olive Young/올리브영, Megabox/메가박스, Lotte Cinema/롯데시네마, or CGV data through the Daiso project. Honor explicit no-install requests with remote MCP first; otherwise prefer the daiso CLI for direct execution, use the MCP endpoint when the host app supports remote MCP, and choose commands for products, stores, inventory/재고, compare, places, movies, showtimes, seats, health checks, and raw JSON output. -version: 1.0.6 +description: Use this when a user wants to search Daiso/다이소, compare product price candidates, nearby restaurants/cafes/음식점/카페, convenience stores/편의점, marts, Olive Young/올리브영, Megabox/메가박스, Lotte Cinema/롯데시네마, or CGV data through the Daiso project. Honor explicit no-install requests with connected MCP tools first, then HTML GET via web reading even when a shell is available; otherwise prefer the daiso CLI for direct execution, use the MCP endpoint when the host app supports remote MCP, and choose commands for products, stores, inventory/재고, compare, places, movies, showtimes, seats, health checks, and raw JSON output. +version: 1.0.7 metadata: openclaw: requires: @@ -21,21 +21,27 @@ Use this skill to operate the Daiso MCP project through `npx daiso` and the publ ## 설치 없이 첫 조회 -사용자가 "설치 없이", "무설치"를 명시하면 로컬 CLI·스킬 설치 없이 원격 조회를 먼저 실행합니다. 연결된 원격 MCP 도구가 있으면 `daiso_search_products`를 바로 호출합니다. 원격 MCP 클라이언트의 서버 주소는 `https://mcp.aka.page`입니다. +1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. +2. 웹 읽기(open/WebFetch)가 가능하면 아래 HTML GET을 바로 엽니다. 셸이 있어도 연결된 MCP 도구가 없으면 이 경로가 우선입니다. 검색(search)은 URL 열기(open)를 대신하지 않습니다. +3. 위 두 수단이 없을 때만 외부 통신 가능한 셸에서 루트 POST를 사용합니다. 셸 DNS 실패를 웹 GET 실패나 서버 장애로 확대하지 말고 웹 읽기가 가능하면 HTML GET으로 전환합니다. -셸에서 직접 확인할 때는 아래 POST가 실제 MCP 도구 호출입니다. 이 공개 서버는 세션 없이 호출할 수 있으며 응답은 SSE의 `data:` JSON입니다. 범용 MCP 클라이언트 연결은 클라이언트가 initialize와 세션 절차를 처리합니다. +https://mcp.aka.page/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html + +검색어 q를 사용자 요청으로 바꾸고 상세·매장·재고를 포함한 모든 후속 웹 GET에도 `format=html`을 반드시 붙이세요. 첫 조회 전에 npx·패키지·스킬 설치, health/help, 전체 도구 목록이나 OpenAPI 탐색을 요구하지 않습니다. REST GET 성공과 MCP 도구 호출 성공은 구분합니다. + +상품 이미지는 해당 조회 응답의 imageUrl만 사용합니다. 전체 URL과 query string을 유지하고, 없거나 표시되지 않으면 생략하며 웹 검색 이미지·다른 상품·다른 국가 이미지로 대체하지 않습니다. 실제 도구·URL·반환 데이터·오류만 보고하고 실행하지 않은 요청의 성공·실패를 만들지 않습니다. + +공개 MCP는 https://mcp.aka.page, Streamable HTTP, 인증 없음입니다. 연결은 표준 initialize 절차를 사용합니다. 공개 도구 10개는 늘리지 않습니다. 기존 서비스별 이름은 deprecated 별칭이며 새 호출에 쓰지 않습니다. + +셸 전용 대안은 다음과 같습니다. SSE의 error/result.isError를 확인하고 result.structuredContent.products 또는 content[].text에서 실제 결과를 읽으세요. ```bash -curl -fsS --max-time 20 'https://mcp.aka.page' \ +curl -fsS -N --max-time 20 'https://mcp.aka.page/' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ - --data-binary '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"daiso_search_products","arguments":{"query":"수납박스","pageSize":3}}}' + --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_products","arguments":{"service":"daiso","query":"수납박스","pageSize":3}}}' ``` -첫 조회 전에 `npx`, 패키지·스킬 설치, health/help, 전체 스키마나 도구 목록 탐색을 하지 않습니다. 위 예제의 검색어를 사용자 요청으로 바꾸고 조회 결과부터 제공합니다. 사용자 조건이나 호출 오류 때문에 필요한 경우에만 추가 안내를 읽습니다. 호출에 성공하면 추가 진단 없이 결과를 보여줍니다. - -`GET https://mcp.aka.page/api/daiso/products?q=수납박스`는 같은 서비스의 REST 직접 조회입니다. GET만 가능한 환경에서는 사용할 수 있지만 MCP 도구를 호출했다고 설명하지 않습니다. HTTP·네트워크 오류만으로 로그인 필요나 서버 장애를 단정하지 않고 실제 오류와 실행 환경을 확인합니다. - ## Core Rule 무설치 요청이 아니고 CLI 사용이 허용된 환경에서는 CLI를 우선 사용한다. The CLI is the preferred path when you can run shell commands and package execution is allowed. Use the MCP endpoint when the user is configuring an AI app or explicitly asks for MCP connection details. @@ -66,7 +72,7 @@ npx daiso display-location 1034604 04515 --json npx daiso compare 콜라 --limit 3 --json npx daiso places 강남역 --category cafe --limit 5 --json npx daiso places 성수동 --keyword 브런치 --limit 5 --json -npx daiso get /api/feedback/requests --type bug --title "올리브영 재고 오류" --description "oliveyoung_check_inventory가 빈 결과를 반환합니다." --service oliveyoung --toolName oliveyoung_check_inventory --json +npx daiso get /api/feedback/requests --type bug --title "올리브영 재고 오류" --description "check_inventory(service=oliveyoung)가 빈 결과를 반환합니다." --service oliveyoung --toolName check_inventory --json npx daiso gs25-products 콜라 --limit 10 --json npx daiso gs25-stores 강남 --limit 10 --json npx daiso gs25-inventory 오감자 --storeKeyword 강남 --storeLimit 10 --json @@ -82,14 +88,14 @@ For more command selection examples, read `references/cli-command-map.md`. ## Request Recipes -아래 CLI 레시피는 CLI 사용이 허용된 경우에만 적용합니다. 무설치 요청에서는 같은 조회를 원격 MCP 도구로 실행합니다. +아래 CLI 레시피는 CLI 사용이 허용된 경우에만 적용합니다. 무설치 요청에서는 위 순서대로 연결된 MCP 또는 웹 읽기의 HTML GET으로 실행합니다. - "콜라 어디가 싸?", "컵라면 가격 비교해줘": run `npx daiso compare --json` first. Confirm stock or sale prices with service-specific inventory only when the user asks for store-level availability. - "강남역 근처 카페", "성수동 브런치 음식점": run `npx daiso places --category cafe|restaurant --json` or use `--keyword` for the food or mood. Do not ask which retail brand they mean. - "다이소 핫식스 재고", "올리브영 두바이초콜릿 있어?": keep the named brand. Search that service first even if the product seems unusual for the brand, then suggest alternatives only after no results. - "GS25 강남 오감자 재고": separate product and location. Search product candidates first when an item code is needed, then run inventory with `--storeKeyword`. - "오늘 강남 CGV 시간표": compute today in KST as `YYYYMMDD`, find the theater if the code is unknown, then query timetable. -- "MCP가 오류나요", "개발자에게 개선 요청 보내줘": use `submit_developer_request` when MCP is available. In CLI-only environments, use `npx daiso get /api/feedback/requests --type bug|improvement|feature|docs --title "..." --description "..." --json`. +- "이 오류나 개선 요청을 개발자에게 보내줘"처럼 명시적으로 요청한 경우에만 use `submit_request` with `requestType=developer` and a `request` object when MCP is available. In CLI-only environments, use `npx daiso get /api/feedback/requests --type bug|improvement|feature|docs --title "..." --description "..." --json`. - If a command fails, retry once with narrower input. If it still fails, report the service, command, and condition instead of inventing results. - If output contains `imageUrl`, preserve the full URL including query string when showing images. @@ -104,7 +110,9 @@ For more command selection examples, read `references/cli-command-map.md`. ## Workflow -1. Identify the target service from the user request: feedback/developer request, compare, Daiso, places/restaurants/cafes, GS25, Seven-Eleven, CU, Emart24, Lotte Mart, Olive Young, Megabox, Lotte Cinema, or CGV. +Lotte Mart is discontinued; MINISO is unsupported. Japan DAISO supports products/stores/online availability only, not store inventory. + +1. Identify the target service from the user request: feedback/developer request, compare, Daiso, places/restaurants/cafes, GS25, Seven-Eleven, CU, Emart24, Olive Young, Megabox, Lotte Cinema, or CGV. 2. Choose a CLI command from the common commands or `references/cli-command-map.md`. 3. Add `--json` for machine-readable output or when summarizing multiple records. 4. If a CLI command is not available for the exact route, use `npx daiso get /api/... --json`. @@ -112,7 +120,7 @@ For more command selection examples, read `references/cli-command-map.md`. ## Fallbacks -- npx 또는 Node.js를 사용할 수 없으면 do not invent results. Tell the user the CLI cannot run in the current environment and provide the MCP URL or equivalent `GET /api/...` path. +- npx 또는 Node.js를 사용할 수 없으면 use connected MCP tools or open the equivalent HTML GET through web reading. Append format=html to every web GET. If neither is available, report the actual limitation without inventing results. - For network failures, retry once with a narrower query, then report the failing service and command. - For no results, preserve the command used and suggest a broader keyword or nearby area. - Switch from CLI to MCP only when the user is configuring an AI app, the shell cannot run `npx`, or the host environment already exposes the MCP server. diff --git a/src/pages/agentStart.ts b/src/pages/agentStart.ts index 73af0a6f..4a7f9b0e 100644 --- a/src/pages/agentStart.ts +++ b/src/pages/agentStart.ts @@ -1,6 +1,17 @@ -/** 웹 읽기 전용 환경에서 조회 형식을 선택하는 공통 규칙 */ +/** 웹 읽기 환경에서 조회 형식을 선택하는 공통 규칙 */ export const WEB_READ_RULE = '웹 읽기 전용 에이전트: 모든 /api/* GET 조회 URL에 format=html을 반드시 포함하세요. 상품 검색뿐 아니라 상세·매장·재고·후속 조회에도 적용합니다. 아래 문서의 JSON 응답 예시는 필드 설명이며 웹 읽기로 JSON 주소를 열라는 뜻이 아닙니다. JSON URL이 읽히지 않으면 format=html로 다시 조회하고, 그 실패만으로 서비스 장애·로그인 필요·이 환경에서 실행할 수 없다고 단정하지 마세요.'; +/** 셸 존재를 네트워크 접근 가능 여부로 오해하지 않는 실행 순서 */ +export const ROUTE_SELECTION_TEXT = `1. 연결된 MCP 도구가 있으면 search_products {"service":"daiso","query":"수납박스","pageSize":3}를 호출합니다. +2. 웹 읽기(open/WebFetch)가 가능하면 HTML GET 주소를 바로 엽니다. 셸이 있어도 연결된 MCP 도구가 없으면 이 경로가 우선입니다. 웹 검색(search)은 URL 열기(open)를 대신하지 않습니다. +3. 위 두 수단이 없을 때만 외부 통신 가능한 셸에서 아래 POST를 사용합니다. 셸 DNS 오류는 그 실행 환경의 실패이며 웹 GET 실패나 서버 장애의 근거가 아닙니다. 웹 읽기가 가능하면 HTML GET으로 즉시 전환합니다.`; + +/** 유사 상품의 웹 검색 이미지를 실제 상품 사진으로 오인하지 않도록 제한합니다. */ +export const IMAGE_SOURCE_RULE = '상품 이미지는 해당 조회 응답의 imageUrl만 사용하세요. 전체 URL과 query string을 유지합니다. imageUrl이 없거나 표시되지 않으면 이미지를 생략하고 웹 검색 이미지·다른 상품·다른 국가의 이미지로 대체하지 마세요.'; + +/** 실행 기록 없이 성공·실패나 HTTP 상태를 단정하지 않도록 안내합니다. */ +export const EXECUTION_EVIDENCE_RULE = '실제로 실행한 도구·요청 URL·반환 데이터와 확인된 오류만 보고하세요. 실행하지 않은 웹 GET을 실패했다고 말하거나 검색 결과·문서 예제를 실제 조회 결과로 제시하지 마세요. 도구가 HTTP 상태를 제공하지 않으면 HTTP 200이라고 추정하지 마세요. REST GET 성공과 MCP 도구 호출 성공은 구분합니다.'; + /** 설치 없이 첫 실제 조회를 실행하는 에이전트 안내 */ export function buildAgentStartText(baseUrl: string): string { return `# DAISO MCP: 설치 없이 시작하기 @@ -9,29 +20,26 @@ export function buildAgentStartText(baseUrl: string): string { 공개 원격 MCP: https://mcp.aka.page 전송: Streamable HTTP · 인증: 없음 (사용자 API 키 불필요) -샌드박스·셸 없이 웹 읽기만 가능한 채팅 에이전트는 아래 HTML GET 주소를 먼저 여세요. npm 설치나 HTTP POST 실행이 필요 없습니다. -${baseUrl}/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html +전체 도구 목록이나 OpenAPI를 먼저 읽을 필요는 없습니다. 설치나 사용자에게 연결 설정을 요구하기 전에 아래 순서로 첫 실제 조회를 실행하세요. -다른 공개 GET API도 기존 파라미터에 format=html을 추가하면 실제 결과를 HTML로 읽을 수 있습니다. format을 생략하면 기존 JSON 응답입니다. 첫 결과의 상품 상세 링크도 HTML입니다. 오류는 HTTP 상태와 함께 표시되며 재고 없음으로 해석하면 안 됩니다. +${ROUTE_SELECTION_TEXT} -전체 도구 목록이나 OpenAPI를 먼저 읽을 필요는 없습니다. 사용 가능한 실행 수단으로 아래 첫 조회를 실행하세요. +웹 읽기용 첫 조회 (사용자 검색어로 q를 바꾸세요): +${baseUrl}/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html +이것은 공개 REST GET이며 MCP 프로토콜 호출이 아닙니다. 상품 결과의 실제 id로 상세·재고를 조회하고 모든 후속 URL에도 format=html을 붙이세요. 상품 검색만으로 매장 재고를 단정하지 마세요. -1. 원격 MCP 클라이언트가 있으면 공개 URL에 연결하세요. 표준 initialize → notifications/initialized 흐름을 사용하고 서버가 발급한 mcp-session-id를 전달합니다. 첫 도구는 search_products, 인자는 {"service":"daiso","query":"수납박스","pageSize":3}입니다. -2. HTTP POST나 셸이 있으면 아래 한 요청으로 실제 MCP 도구를 호출할 수 있습니다. npm 설치는 필요 없습니다. 루트 POST의 stateless 호출은 이 서버가 지원하는 단축 경로이며, /mcp는 initialize가 필요합니다. +${IMAGE_SOURCE_RULE} +${EXECUTION_EVIDENCE_RULE} +셸 전용 대안: 루트 POST의 stateless 호출은 이 서버가 지원하는 단축 경로입니다. /mcp 및 범용 클라이언트 연결은 initialize → notifications/initialized 후 mcp-session-id를 전달합니다. \`\`\`bash curl --max-time 20 -sS -N ${baseUrl}/ \\ -H 'Content-Type: application/json' \\ -H 'Accept: application/json, text/event-stream' \\ --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_products","arguments":{"service":"daiso","query":"수납박스","pageSize":3}}}' \`\`\` - -응답은 SSE의 data: JSON-RPC 메시지입니다. result.isError 또는 error를 확인하고, 상품은 result.structuredContent.products에서 읽으세요. content[].text에도 상품 JSON이 있습니다. 오류를 상품 없음으로 해석하지 마세요. - -3. HTTP GET만 가능하면 공개 REST GET의 HTML 결과를 사용하세요. 이것은 MCP 프로토콜 호출이 아닙니다. -${baseUrl}/api/daiso/products?q=%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4&pageSize=3&format=html - -실제 상품 결과의 id로 재고를 조회하세요. 예제 ID를 쓰거나 상품 검색 결과만으로 매장 재고를 단정하지 마세요. +응답은 SSE의 data: JSON-RPC 메시지입니다. result.isError=true이거나 error 응답이면 실패입니다. 상품은 result.structuredContent.products 또는 content[].text의 JSON에서 읽으세요. 오류·미확인을 재고 0으로 해석하지 마세요. +기존 서비스별 MCP 이름은 deprecated 호출 별칭입니다. 새 연동은 공개 도구 10개만 사용하며 도구를 늘리지 않습니다. 상세 API와 서비스 안내: ${baseUrl}/prompt --- diff --git a/src/pages/apiResult.ts b/src/pages/apiResult.ts index c3eca285..3ea43ad4 100644 --- a/src/pages/apiResult.ts +++ b/src/pages/apiResult.ts @@ -1,5 +1,5 @@ /** 웹 읽기 에이전트용 공개 GET 결과 표시 */ -import { WEB_READ_RULE } from './agentStart.js'; +import { WEB_READ_RULE, IMAGE_SOURCE_RULE, EXECUTION_EVIDENCE_RULE } from './agentStart.js'; import type { MiddlewareHandler } from 'hono'; import type { AppBindings } from '../api/response.js'; @@ -35,10 +35,12 @@ export const apiResultHtml: MiddlewareHandler<{ Bindings: AppBindings }> = async const japan = url.pathname.startsWith('/api/daiso-jp/'); const productLinks = url.pathname === '/api/daiso-jp/products' ? '/api/daiso-jp/products' : url.pathname === '/api/daiso/products' ? '/api/daiso/products' : null; const inventoryGuide = japan ? '일본 매장 재고 미지원. 온라인 판매 가능 여부를 매장 재고로 해석하지 마세요.' : '매장 재고는 상품 ID와 매장명 또는 사용자 위치를 확인한 뒤 별도로 조회하세요.'; - const html = `${title} — 다이소 MCP + const html = `${title}: DAISO MCP

${title}

${escapeHtml(WEB_READ_RULE)}

요청: ${source} · HTTP ${c.res.status}

실제 API 조회 결과입니다. 오류를 상품 없음이나 재고 0으로 해석하지 마세요. ${inventoryGuide}

+

${escapeHtml(IMAGE_SOURCE_RULE)}

+

${escapeHtml(EXECUTION_EVIDENCE_RULE)}

${renderValue(data, productLinks)}

개발자용 JSON 원본 (웹 읽기용 아님) · 설치 없는 조회 안내 · API 경로와 필수 파라미터 안내

다른 공개 GET 조회도 기존 파라미터에 format=html을 추가하면 HTML로 읽을 수 있습니다. 웹 읽기만으로 MCP 연결이 생기는 것은 아닙니다.

`; diff --git a/src/pages/discovery.ts b/src/pages/discovery.ts index 92fcf5f9..82ae8046 100644 --- a/src/pages/discovery.ts +++ b/src/pages/discovery.ts @@ -1,4 +1,4 @@ -import { buildAgentStartText, WEB_READ_RULE } from './agentStart.js'; +import { buildAgentStartText, WEB_READ_RULE, ROUTE_SELECTION_TEXT, IMAGE_SOURCE_RULE, EXECUTION_EVIDENCE_RULE } from './agentStart.js'; const BASE = 'https://mcp.aka.page'; @@ -26,13 +26,15 @@ export function buildDiscoveryAssets(info: { services: { name: string }[]; tools

바로 조회하기

다이소 수납박스 상품 3개 조회

위 링크는 셸·설치 없이 웹 읽기로 호출하는 공개 REST GET의 HTML 결과입니다. 다른 공개 GET 조회도 기존 파라미터에 format=html을 추가하세요. 검색한 상품의 실제 ID로 재고를 조회하세요. 상품 검색만으로 매장 재고를 단정하지 마세요.

에이전트에서 설치 없이 사용하기

원격 MCP 주소: ${BASE}
전송: Streamable HTTP · 인증: 없음

-

원격 MCP 클라이언트가 있으면 이 주소에 연결하고 search_products를 {"service":"daiso","query":"수납박스","pageSize":3}으로 호출하세요.

-

HTTP POST나 셸이 있으면 아래 한 요청으로 첫 조회를 실행할 수 있습니다.

+

${escapeHtml(ROUTE_SELECTION_TEXT).replaceAll('\n', '
')}

+

${escapeHtml(IMAGE_SOURCE_RULE)}

+

${escapeHtml(EXECUTION_EVIDENCE_RULE)}

+
셸 전용 POST 대안
curl --max-time 20 -sS -N ${BASE}/ \\
   -H 'Content-Type: application/json' \\
   -H 'Accept: application/json, text/event-stream' \\
-  --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_products","arguments":{"service":"daiso","query":"수납박스","pageSize":3}}}'
-

웹 읽기 기능으로 이 페이지를 읽는 것만으로 MCP 연결이 생기지는 않습니다. 샌드박스나 셸 없이 웹 읽기만 가능한 채팅 에이전트는 위 HTML REST 링크를 바로 여세요. 오류를 상품 없음으로 해석하지 마세요.

+ --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_products","arguments":{"service":"daiso","query":"수납박스","pageSize":3}}}'
+

웹 읽기 기능으로 이 페이지를 읽는 것만으로 MCP 연결이 생기지는 않습니다. 연결된 MCP 도구가 없고 웹 읽기가 가능하면 셸 유무와 무관하게 위 HTML REST 링크를 바로 여세요. 오류를 상품 없음으로 해석하지 마세요.

짧은 시작 안내 · 전체 API 사용 안내 · 개발자용 서비스·도구 목록 JSON

지원 서비스

${services}

diff --git a/src/pages/prompt.ts b/src/pages/prompt.ts index ab67c69f..14aa5bb1 100644 --- a/src/pages/prompt.ts +++ b/src/pages/prompt.ts @@ -27,7 +27,7 @@ export function generatePromptText(baseUrl: string): string { - 매장: ${baseUrl}/api/daiso-jp/stores?keyword=%E6%B8%8B%E8%B0%B7&format=html 매장명·주소를 검색하므로 지역을 확인하세요. 다음 페이지는 page를 증가시키되 hasNext=true일 때만 요청하세요. 온라인 판매 가능 여부는 매장 재고가 아닙니다. 일본 매장 재고 조회는 아직 지원하지 않습니다. -MCP: daiso_jp_search_products(query,page), daiso_jp_get_product(id), daiso_jp_find_stores(keyword,page). +MCP: search_products {"service":"daiso_jp","query":"ボウル"}, get_product_details {"service":"daiso_jp","operation":"product","id":"검색한 실제 코드"}, find_stores {"service":"daiso_jp","keyword":"渋谷"}. CLI: jp-products ボウル / jp-product 4550746075917 / jp-stores 渋谷. `, ].join(''); diff --git a/src/pages/promptReferenceText.ts b/src/pages/promptReferenceText.ts index c32f0fd6..c3b524c1 100644 --- a/src/pages/promptReferenceText.ts +++ b/src/pages/promptReferenceText.ts @@ -111,7 +111,7 @@ export function buildPromptReferenceText(baseUrl: string): string { 10. **세븐일레븐 재고 조회**: /api/seveneleven/inventory에 keyword + storeKeyword를 함께 주면 매장별 수량을 바로 확인할 수 있습니다. 11. **이마트24 재고 조회**: /api/emart24/inventory는 pluCd + storeKeyword 조합도 지원하므로, 상품 선택 뒤 매장 코드를 다시 모으지 않아도 됩니다. 12. **올리브영 재고 해석**: inventory.products[].storeInventory.stores[]가 있으면 그 매장별 stockLabel과 remainQuantity를 우선 사용하고, inStock는 그 주변 매장 기준 결과로 해석합니다. -13. **올리브영 상품 이미지 표시**: /api/oliveyoung/products 또는 oliveyoung_search_products 결과에 imageUrl이 있으면 목록형 답변에서도 각 상품 이미지를 생략하지 말고 모두 렌더링합니다. 특히 \`?l=ko\` 같은 query string을 삭제하지 말고 전체 URL 그대로 마크다운 이미지 src에 넣습니다. +13. **올리브영 상품 이미지 표시**: /api/oliveyoung/products 또는 search_products(service=oliveyoung) 결과에 imageUrl이 있으면 목록형 답변에서도 각 상품 이미지를 생략하지 말고 모두 렌더링합니다. 특히 \`?l=ko\` 같은 query string을 삭제하지 말고 전체 URL 그대로 마크다운 이미지 src에 넣습니다. 14. **통합 가격 후보 비교**: 사용자가 브랜드를 특정하지 않고 "어디가 싸?", "비교해줘"처럼 물으면 \`compare_products\` 또는 /api/compare/products를 먼저 사용합니다. 새 외부 키 없이 기존 상품 검색을 묶은 1차 가격 후보이므로 실제 재고/행사가는 각 서비스 상세 조회로 확인해야 합니다. 15. **주변 음식점/카페 검색**: 음식점이나 카페만 물으면 \`find_places\` (service=places) 또는 /api/places/search를 먼저 사용합니다. 이 기능은 네이버 지역 검색 기반 키워드 검색이므로 좌표 반경 검색처럼 단정하지 말고, \`searchMode: "keyword"\`임을 필요할 때 짧게 밝혀주세요. diff --git a/tests/pages/agentStart.test.ts b/tests/pages/agentStart.test.ts index e1278f81..df7c15e1 100644 --- a/tests/pages/agentStart.test.ts +++ b/tests/pages/agentStart.test.ts @@ -15,7 +15,7 @@ describe('에이전트 시작 안내', () => { expect(text).toContain('https://example.com/'); expect(text).toContain('application/json, text/event-stream'); expect(text).toContain('structuredContent'); - expect(text).toContain('isError'); + expect(text).toContain('result.isError=true'); }); it('원격 MCP 연결과 HTTP POST, REST GET을 구분하고 전체 문서 읽기를 요구하지 않는다', () => { diff --git a/tests/pages/htmlGuidance.test.ts b/tests/pages/htmlGuidance.test.ts index 4c8108a4..bf360f83 100644 --- a/tests/pages/htmlGuidance.test.ts +++ b/tests/pages/htmlGuidance.test.ts @@ -27,5 +27,8 @@ describe('웹 읽기 전용 에이전트 안내', () => { expect(text).toContain(rule); expect(text).toContain('개발자용 JSON 원본'); expect(text).toContain('웹 읽기용 아님'); + expect(text).toContain('해당 조회 응답의 imageUrl만'); + expect(text).toContain('웹 검색 이미지'); + expect(text).toContain('실행하지 않은'); }); }); diff --git a/tests/pages/webFirstGuidance.test.ts b/tests/pages/webFirstGuidance.test.ts new file mode 100644 index 00000000..c5483aa1 --- /dev/null +++ b/tests/pages/webFirstGuidance.test.ts @@ -0,0 +1,46 @@ +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; +import { COMPACT_CATALOG } from '../../src/core/compact/catalog.js'; +import { buildAgentStartText } from '../../src/pages/agentStart.js'; +import { buildDiscoveryAssets } from '../../src/pages/discovery.js'; +import { generatePromptText } from '../../src/pages/prompt.js'; + +const read = (path: string) => readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8'); + +describe('무설치 경로 선택 회귀', () => { + it('셸이 있어도 연결된 MCP 다음에는 HTML GET을 선택한다', () => { + const assets = buildDiscoveryAssets({ services: [], tools: [] }); + for (const text of [buildAgentStartText('https://example.com'), assets['discovery.html'], read('README.md'), read('docs/ai-instruction.md'), read('skills/daiso-cli/SKILL.md')]) { + const mcp = text.indexOf('1. 연결된 MCP 도구'); + const web = text.indexOf('2. 웹 읽기'); + const shell = text.indexOf('3. 위 두 수단이 없을 때만'); + expect(mcp).toBeGreaterThanOrEqual(0); + expect(web).toBeGreaterThan(mcp); + expect(shell).toBeGreaterThan(web); + expect(text).toContain('셸이 있어도'); + expect(text).toContain('DNS'); + expect(text).toContain('실행하지 않은'); + } + }); + + it('실행 안내는 deprecated MCP 이름을 새 호출로 권하지 않는다', () => { + for (const text of [buildAgentStartText('https://example.com'), generatePromptText('https://example.com'), read('docs/ai-instruction.md'), read('skills/daiso-cli/SKILL.md')]) { + for (const group of COMPACT_CATALOG) { + for (const route of group.routes) { + if (route.legacy !== group.name) expect(text).not.toContain(route.legacy); + } + } + } + expect(read('docs/client-guide.md')).not.toContain('daiso_search_products'); + expect(read('docs/service-reference.md')).toContain('deprecated 별칭'); + }); + + it('모든 진입 안내에서 해당 응답의 이미지와 실제 실행 근거만 사용한다', () => { + const assets = buildDiscoveryAssets({ services: [], tools: [] }); + for (const text of [assets['discovery.html'], buildAgentStartText('https://example.com'), generatePromptText('https://example.com'), read('README.md'), read('docs/ai-instruction.md'), read('skills/daiso-cli/SKILL.md'), read('docs/gpts-maintenance.md')]) { + expect(text).toContain('imageUrl'); + expect(text).toContain('웹 검색 이미지'); + expect(text).toContain('대체하지'); + } + }); +}); diff --git a/tests/scripts/repository-config.test.ts b/tests/scripts/repository-config.test.ts index f27deae6..85b52edc 100644 --- a/tests/scripts/repository-config.test.ts +++ b/tests/scripts/repository-config.test.ts @@ -319,8 +319,9 @@ describe('repository maintenance configuration', () => { const directCall = readText('docs/service-reference.md').split('### MCP 표준 응답 모델')[0]; expect(directCall).toContain('Accept: application/json, text/event-stream'); expect(directCall).toContain('"method":"tools/call"'); - expect(directCall).toContain('"name":"daiso_search_products"'); + expect(directCall).toContain('"name":"search_products"'); expect(directCall).toContain('"query":"수납박스"'); + expect(directCall).toContain('"service":"daiso"'); expect(readme).toContain('WORKERS_INVOCATIONS_CHART:START'); expect(readme).toContain('scripts/ops/README.md'); }); @@ -424,7 +425,7 @@ describe('repository maintenance configuration', () => { expect(skill).toContain('name: daiso-cli'); expect(skill).toContain('description:'); - expect(skill).toContain('version: 1.0.6'); + expect(skill).toContain('version: 1.0.7'); expect(skill).toContain('metadata:'); expect(skill).toContain('openclaw:'); expect(skill).toContain('requires:');