From 793a4ebc69e83ffd62fa82e10de55790c81931d3 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Mon, 2 Nov 2026 11:01:52 +0900 Subject: [PATCH 1/4] =?UTF-8?q?test:=20=EC=9D=BD=EA=B8=B0=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=EC=9D=98=20=EC=99=84=EC=84=B1=20URL=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=84=EC=86=A1=20=EC=95=88=EB=82=B4=20=ED=9A=8C=EA=B7=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/pages/browseRead.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/pages/browseRead.test.ts b/tests/pages/browseRead.test.ts index 15c3cf09..a751cd4b 100644 --- a/tests/pages/browseRead.test.ts +++ b/tests/pages/browseRead.test.ts @@ -53,6 +53,10 @@ describe('웹 수집본과 구분할 수 있는 읽기 세션 링크', () => { const response = await app.request(prefix + '/daiso/products/연필/pageSize/3'); expect(response.status).toBe(200); const body = await response.text(); + expect(body).toContain('아래 문장을 그대로 복사해 이 대화에 보내주세요'); + expect(body).toContain(`https://mcp.aka.page${prefix}/daiso/products/`); + expect(body).toContain('웹 URL 열기 도구로 직접 열어'); + expect(body).not.toContain('https://localhost'); expect(hits).toHaveLength(1); expect(Object.fromEntries(hits[0].searchParams)).toEqual({ q: '연필', pageSize: '3', format: 'html' }); expect(body).toContain(`href="${prefix}/daiso/product/58450"`); From bf3201280549fc757eaa4b538a3f188a146972a7 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Mon, 2 Nov 2026 11:04:08 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=EC=9B=B9=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=99=84=EC=84=B1=20URL=20=EC=9E=AC=EC=A0=84=EC=86=A1=20?= =?UTF-8?q?=EC=95=88=EB=82=B4=EC=99=80=20=EB=AC=B8=EC=84=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++-- docs/ai-instruction.md | 3 ++ docs/client-guide.md | 3 ++ docs/daiso-jp-network-analysis.md | 2 +- docs/mcp-tools.md | 2 +- docs/service-reference.md | 5 ++- docs/web-reading-troubleshooting.md | 18 ++++++++- skills/daiso-cli/SKILL.md | 3 ++ src/pages/agentStart.ts | 27 ++++++++++---- src/pages/browseRead.ts | 8 +++- src/pages/promptCoreText.ts | 2 +- tests/pages/browseRead.test.ts | 29 +++++++++++---- tests/pages/latestGuide.test.ts | 57 ++++++++++++++++++++--------- tests/pages/productCards.test.ts | 2 +- 14 files changed, 127 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 1e7b52e1..ed41e04d 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AI 에이전트 사용 안내 > [!IMPORTANT] -> **최신 안내:** [현재 버전](https://mcp.aka.page/guide/2026-10-27.3) · [항상 최신 버전으로 이동](https://mcp.aka.page/guide/latest) +> **최신 안내:** [현재 버전](https://mcp.aka.page/guide/2026-11-02.1) · [항상 최신 버전으로 이동](https://mcp.aka.page/guide/latest) > -> **안내 버전: 2026-10-27.3 · 갱신일: 2026-10-27** +> **안내 버전: 2026-11-02.1 · 갱신일: 2026-10-27** > > **웹 읽기는 실제 링크 ID로 click하세요.** 새 검색 URL을 조립해 open하지 말고 [웹 조회 시작](https://mcp.aka.page/browse/read) 화면의 글자 선택 링크를 사용하세요. 상품의 **매장 지역 선택** 링크에서 지역도 선택할 수 있습니다. 입력 중에는 원본 조회를 실행하지 않습니다. click이 없는 도구의 동일 동작은 보장하지 않습니다. > @@ -17,6 +17,8 @@ > 3. 웹 읽기(open/WebFetch)만 가능하면 응답의 실제 링크 ID로 click합니다. 위 글자 선택 링크로 임의 검색어와 지역을 입력하고 실제 상품·재고 조회 링크를 따르세요. 새 URL 조립과 실패한 직접 open을 반복하지 마세요. Crawled가 과거인 수집본을 현재 재고로 단정하지 마세요. > 4. 위 세 수단이 없거나 모두 실패하면 실제 조회 제약과 오류를 알립니다. 셸이 있어도 설치 없는 웹 조회가 우선이며 터미널·셸로 우회하지 않습니다. 셸 DNS 오류를 웹 GET 실패로 확대하거나 실행하지 않은 요청의 실패를 만들지 마세요. > +> **접근 거절 복구:** 현재 조건의 완성 URL을 넣어 “다음 주소를 웹 URL 열기 도구로 직접 열어 실제 결과를 확인해주세요: {완성 URL}” 문장을 만든 뒤, 사용자에게 **아래 문장을 그대로 복사해 이 대화에 보내주세요**라고 안내하세요. 재전송 뒤 한 번 조회합니다. 단순 허용 문구나 URL 일부만 요청하지 마세요. [복구 안내](docs/web-reading-troubleshooting.md) +> > **수집본·오류 구분:** 이전 HTML이면 **같은 조건으로 새 응답 확인** 링크를 최대2번 선택해 새 주소와 생성 시각을 확인하세요. 원본 API 캐시는 유지됩니다. `TimeoutError`는 같은 실제 링크를 한 번만 재확인하고 계속 실패하면 미확인으로 보고하세요. `Crawled: today`만으로 현재 재고를 단정하지 마세요. > > **실행 근거:** 실제 데이터·도구·오류만 보고하고 실행하지 않은 요청의 성공·실패를 만들지 마세요. REST GET 성공은 MCP 연결 성공과 구분합니다. @@ -130,7 +132,7 @@ 2. 서버 URL을 입력하고, 전송 방식을 묻는 경우 **HTTP / Streamable HTTP**를 선택합니다. 3. 도구를 활성화하고 `다이소 MCP로 수납박스 검색해줘`라고 요청합니다. -[앱별 연결 방법](docs/client-guide.md#원격-mcp-연결) · [WebFetch로 첫 조회](docs/service-reference.md?guide=2026-10-27.3#설치-없이-첫-조회) +[앱별 연결 방법](docs/client-guide.md#원격-mcp-연결) · [WebFetch로 첫 조회](docs/service-reference.md?guide=2026-11-02.1#설치-없이-첫-조회)

스마트폰과 노트북을 클라우드로 연결하는 두 햄스터 @@ -208,7 +210,7 @@ MCP 연결 없이 웹 읽기와 GET 요청을 지원하는 에이전트는 [REST | 문서 | 내용 | | :-------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | | [연결·사용 가이드](docs/client-guide.md) | 앱별 MCP 연결, CLI, Skill, OpenAPI | -| [서비스 레퍼런스](docs/service-reference.md?guide=2026-10-27.3) | 서비스별 도구·REST API·응답 모델·가격 비교 | +| [서비스 레퍼런스](docs/service-reference.md?guide=2026-11-02.1) | 서비스별 도구·REST API·응답 모델·가격 비교 | | [일본 다이소](docs/daiso-jp-network-analysis.md) | 일본 상품·매장 검색과 지원 범위 | | [독립·예술영화관](docs/dtryx.md) | 디트릭스 지원 극장과 조회 방법 | | [AI 조회 가이드](docs/ai-instruction.md) | 도구 선택과 상품·매장·재고 조회 순서 | diff --git a/docs/ai-instruction.md b/docs/ai-instruction.md index c5133ca8..87d54a63 100644 --- a/docs/ai-instruction.md +++ b/docs/ai-instruction.md @@ -1,5 +1,8 @@ # DAISO MCP 에이전트 지침 +웹 읽기 접근 거절이 계속되면 **현재 조건의 완성 URL을 넣은 복사용 문장**을 제시하고 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하세요. 사용자 재전송 뒤 한 번 조회합니다. 단순 허용 문구·URL 일부 제공·실행하지 않은 실패 보고로 대체하지 마세요. [복사 재전송 및 오류 구분](https://github.com/hmmhmmhm/daiso-mcp/blob/main/docs/web-reading-troubleshooting.md)을 따릅니다. + + ## 설치 없이 첫 조회 최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.3)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. diff --git a/docs/client-guide.md b/docs/client-guide.md index 5988285e..ce44bdc5 100644 --- a/docs/client-guide.md +++ b/docs/client-guide.md @@ -1,5 +1,8 @@ # 앱 연결·CLI·Skill 가이드 +웹 읽기 접근 거절이 계속되면 **현재 조건의 완성 URL을 넣은 복사용 문장**을 제시하고 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하세요. 사용자 재전송 뒤 한 번 조회합니다. 단순 허용 문구·URL 일부 제공·실행하지 않은 실패 보고로 대체하지 마세요. [복사 재전송 및 오류 구분](https://github.com/hmmhmmhm/daiso-mcp/blob/main/docs/web-reading-troubleshooting.md)을 따릅니다. + + 실제 브라우저가 있으면 /browse/ HTML을 엽니다. 웹 읽기(open/WebFetch)만 있으면 /browse/read에서 실제 링크 ID로 click합니다. 이전 HTML은 같은 조건의 새 응답 링크를 최대2번 확인하고 TimeoutError 재확인은 한 번만 합니다. 응답 생성 시각과 원본 재고 갱신은 구분하며 새 브라우저를 반복 생성하지 마세요. 웹 도구의 `Crawled: today`만으로 현재 재고라고 단정하지 마세요. 응답의 HTML 생성 시각과 실제 수량을 확인하고, 수량이 null이면 품절이 아닌 미확인으로 보고합니다. diff --git a/docs/daiso-jp-network-analysis.md b/docs/daiso-jp-network-analysis.md index 89a93172..964b6efb 100644 --- a/docs/daiso-jp-network-analysis.md +++ b/docs/daiso-jp-network-analysis.md @@ -20,7 +20,7 @@ {"name":"find_stores","arguments":{"service":"daiso_jp","keyword":"東京都渋谷区","page":1}} ``` -연결된 MCP 도구가 없는 웹 읽기 에이전트는 open/WebFetch로 아래 `/browse/` 링크를 엽니다. 모든 후속 조회도 `/browse/`를 사용하며 자동 HTML이므로 쿼리 문자열이나 format 지정은 필요 없습니다. +아래는 실제 브라우저·일반 HTTP 클라이언트의 조회 경로입니다. 웹 읽기 에이전트는 문서의 실제 링크를 선택하고 새 URL 조합을 반복하지 마세요. 접근 거절 시 [완성 URL 복사 재전송](web-reading-troubleshooting.md)을 안내합니다. 모든 후속 조회도 `/browse/`를 사용하며 자동 HTML이므로 쿼리 문자열이나 format 지정은 필요 없습니다. - [상품 검색](https://mcp.aka.page/browse/daiso-jp/products/%E3%83%9C%E3%82%A6%E3%83%AB) - [상품 상세](https://mcp.aka.page/browse/daiso-jp/product/4550746075917) diff --git a/docs/mcp-tools.md b/docs/mcp-tools.md index 3ad1a71d..c56654d5 100644 --- a/docs/mcp-tools.md +++ b/docs/mcp-tools.md @@ -17,7 +17,7 @@ ## 호출 예시 -아래 예시는 이미 연결된 MCP 도구의 호출 계약입니다. 웹 읽기만 가능한 환경에서는 설치·연결 설정 없이 [첫 HTML 조회](https://mcp.aka.page/browse/daiso/products/%EC%88%98%EB%82%A9%EB%B0%95%EC%8A%A4/pageSize/3)를 open/WebFetch로 엽니다. 모든 후속 조회는 `/browse/` 경로이며 쿼리 문자열이나 format 지정은 필요 없습니다. +아래 예시는 이미 연결된 MCP 도구의 호출 계약입니다. 웹 읽기만 가능한 환경에서는 설치·연결 설정 없이 [웹 조회 시작](https://mcp.aka.page/browse/read)의 실제 링크를 선택합니다. 접근 거절이 계속되면 [완성 URL 복사 재전송](web-reading-troubleshooting.md)을 안내합니다. 모든 후속 조회는 `/browse/` 경로이며 쿼리 문자열이나 format 지정은 필요 없습니다. 상품 검색: `search_products {"service":"daiso","query":"수납박스","pageSize":3}` diff --git a/docs/service-reference.md b/docs/service-reference.md index 24053bdc..2cc0e844 100644 --- a/docs/service-reference.md +++ b/docs/service-reference.md @@ -1,5 +1,8 @@ # DAISO MCP 서비스 레퍼런스 +웹 읽기 접근 거절이 계속되면 **현재 조건의 완성 URL을 넣은 복사용 문장**을 제시하고 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하세요. 사용자 재전송 뒤 한 번 조회합니다. 단순 허용 문구·URL 일부 제공·실행하지 않은 실패 보고로 대체하지 마세요. [복사 재전송 및 오류 구분](https://github.com/hmmhmmhm/daiso-mcp/blob/main/docs/web-reading-troubleshooting.md)을 따릅니다. + + 실제 브라우저 도구가 있으면 /browse/ HTML을 그 도구로 여세요. 웹 읽기(open/WebFetch)는 [웹 조회 시작](https://mcp.aka.page/browse/read) 화면의 글자 선택 링크를 응답의 실제 링크 ID로 click합니다. 새 검색 URL을 조립하지 않고 상품·매장 지역·실제 재고 링크를 선택합니다. 접근 오류 시 사용 가능한 브라우저로 전환할 수 있으나 새 브라우저를 계속 실행하지 마세요. Crawled가 과거인 수집본은 현재 재고 확인이 아닙니다. 응답 생성 시각도 함께 확인하세요. 이전 HTML이면 같은 조건의 새 응답 링크를 최대2번 선택합니다. `TimeoutError`만 같은 실제 링크를 한 번 재확인하고 계속 실패하면 미확인으로 보고하세요. 새 주소도 기존 API 캐시를 사용하며 원본 갱신을 보장하지 않습니다. README 하단에 있던 기능, REST API, 개발, 아키텍처 설명을 분리한 문서입니다. @@ -826,7 +829,7 @@ GET /api/cgv/timetable?playDate={YYYYMMDD}&theaterCode={극장코드}&movieCode= ## 사용 예시 -웹 읽기(open/WebFetch)는 아래 경로로 실행합니다. `{...}`는 앞선 실제 응답 또는 사용자가 알려 준 조건으로 바꾸고 각 값을 한 번 URL 인코딩합니다. 모든 결과는 자동 HTML입니다. +아래 표는 일반 HTTP API 클라이언트용 경로 문법입니다. 웹 읽기(open/WebFetch) 에이전트는 위의 실제 링크 선택 흐름을 사용하세요. 접근 거절 복구용 문장을 만들 때만 사용자 조건과 실제 응답의 ID로 완성 URL을 구성합니다. 표의 `{...}`를 미확인 상품 ID로 채우거나 직접 open을 반복하지 마세요. 모든 결과는 자동 HTML입니다. | 사용자 요청 | 웹 조회 경로 | | ------------------------------ | ---------------------------------------------------------------------- | diff --git a/docs/web-reading-troubleshooting.md b/docs/web-reading-troubleshooting.md index 879c6b3e..8b9c1230 100644 --- a/docs/web-reading-troubleshooting.md +++ b/docs/web-reading-troubleshooting.md @@ -8,11 +8,27 @@ Cloudflare 관측 구간에는 정상 페이지의 OpenAI 요청에서 200과 1. 연결된 MCP 도구가 있으면 직접 호출합니다. 2. 실제 브라우저 도구가 있으면 `/browse/` 주소를 열고 데이터를 읽습니다. 설치나 MCP 등록은 필요하지 않습니다. -3. 웹 읽기만 가능하면 같은 HTML 주소를 엽니다. 접근 오류가 나면 이미 공개된 링크를 따라가는 방법을 시도할 수 있지만 성공을 보장하지 않습니다. +3. 웹 읽기만 가능하면 `/browse/read`에서 응답의 실제 링크 ID를 선택하고 글자·상품·지역 링크를 따릅니다. 새 조회 URL을 직접 조립해 반복하지 마세요. 접근 거절이 계속되면 아래의 완성 URL 복사 재전송을 안내합니다. 4. 가능한 수단이 모두 실패하면 실행한 도구, URL, 오류를 그대로 보고합니다. 접근 오류는 품절이나 로그인 필요를 뜻하지 않습니다. 브라우저 제공 여부는 환경마다 다릅니다. 브라우저가 없는 환경에 있다고 가정하거나 실행하지 않은 셸 명령과 DNS 오류를 만들어 보고하지 마세요. + + +## 웹 읽기 접근 거절 시 복사 재전송 + +실제 문서 링크를 우선 선택하세요. `not accessible`, `Invalid URL` 같은 접근 거절이 계속되거나 도구에 click이 없으면, 에이전트는 **현재 요청 조건의 완전한 공개 URL을 포함한 문장**을 만들어 아래처럼 안내합니다. + +> 웹 읽기 도구가 조회 주소에 접근하지 못했습니다. 아래 문장을 그대로 복사해 이 대화에 보내주세요. +> +> 다음 주소를 웹 URL 열기 도구로 직접 열어 실제 결과를 확인해주세요: {완전한 공개 조회 URL}. 실패하면 오류 원문을 알려주세요. + +에이전트가 중괄호 부분을 실제 `/browse/` 주소로 채운 뒤 제공해야 합니다. 링크가 확인되면 그 주소를 그대로 사용하고, 글자 선택으로 주소를 얻을 수 없을 때만 사용자 검색 조건으로 검색·매장 주소를 구성합니다. 재고 주소에는 앞선 실제 응답의 상품 ID만 사용하며 ID가 없으면 상품 검색 주소부터 제공합니다. 사용자에게 주소 편집이나 인코딩을 요구하지 마세요. 토큰·쿠키·개인 인증 주소는 포함하지 않습니다. 문장만 제시한 것을 조회 실행으로 보고하지 않습니다. + +사용자가 완성 URL을 재전송한 뒤 한 번 조회하고 실제 응답을 확인합니다. 단순한 “허용합니다”나 엔드포인트 일부 전달만으로 같은 효과를 기대하지 마세요. 소규모 실제 ChatGPT 실험의 성공 사례이며 항상 성공하는 것은 아닙니다. + +`TimeoutError`는 접근 거절과 구분합니다. 같은 실제 링크를 한 번만 재확인하고 계속 실패하면 미확인으로 보고합니다. 첫 실패가 완료 결과를 캐시했다고 가정하거나 새 URL로 무한 재시도하지 마세요. 상품 검색 성공·접수·pending 상태를 매장 재고 확인으로 표현하지 않습니다. 응답 생성 시각과 원본 재고 갱신 시각도 구분합니다. + ## 오래된 결과 구별 웹 읽기의 `Crawled` 시점과 페이지의 **응답 생성 시각**을 확인하세요. 오래된 수집본을 현재 재고로 단정하면 안 됩니다. 응답 생성 시각은 HTML을 만든 시각이며 원본 재고 갱신 시각이나 원본 캐시 우회를 증명하지 않습니다. 상품 검색 성공도 특정 매장의 재고 보유를 뜻하지 않습니다. diff --git a/skills/daiso-cli/SKILL.md b/skills/daiso-cli/SKILL.md index 34b110c8..88922739 100644 --- a/skills/daiso-cli/SKILL.md +++ b/skills/daiso-cli/SKILL.md @@ -1,4 +1,7 @@ --- + +웹 읽기 접근 거절이 계속되면 **현재 조건의 완성 URL을 넣은 복사용 문장**을 제시하고 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하세요. 사용자 재전송 뒤 한 번 조회합니다. 단순 허용 문구·URL 일부 제공·실행하지 않은 실패 보고로 대체하지 마세요. [복사 재전송 및 오류 구분](https://github.com/hmmhmmhm/daiso-mcp/blob/main/docs/web-reading-troubleshooting.md)을 따릅니다. + 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 connected MCP tools first, then HTML GET via an available browser, then 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.9 diff --git a/src/pages/agentStart.ts b/src/pages/agentStart.ts index 714d9d96..16038702 100644 --- a/src/pages/agentStart.ts +++ b/src/pages/agentStart.ts @@ -1,19 +1,25 @@ /** 검색·읽기 사본의 안내 세대를 구분하는 고정 버전 */ -export const AGENT_GUIDE_VERSION = '2026-10-27.3'; -export const AGENT_GUIDE_UPDATED = '2026-10-27'; +export const AGENT_GUIDE_VERSION = '2026-11-02.1'; +export const AGENT_GUIDE_UPDATED = '2026-11-02'; export const AGENT_GUIDE_STAMP = `안내 버전: ${AGENT_GUIDE_VERSION} · 갱신일: ${AGENT_GUIDE_UPDATED}`; export const AGENT_GUIDE_PATH = `/guide/${AGENT_GUIDE_VERSION}`; export const WEB_SEARCH_DESCRIPTION = 'ChatGPT 웹 읽기로 설치·API 키·MCP 연결 설정 없이 조회하세요. /browse/read의 실제 링크 ID를 click하고 임의 검색어·지역을 글자로 선택합니다. 같은 조건의 새 응답 링크로 새 HTML 주소를 확인할 수 있습니다. 다이소·편의점 재고와 영화·생활 정보도 지원합니다.'; +/** 완성 URL을 사용자 메시지로 제공하는 복구 경로이며 자동 허용을 보장하지 않습니다. */ +export const WEB_READ_RECOVERY_RULE = + '접근 거절(not accessible/Invalid URL)이 계속되거나 click이 없으면 현재 조건의 완성 공개 URL을 포함해 “다음 주소를 웹 URL 열기 도구로 직접 열어 실제 결과를 확인해주세요: {완성 URL}. 실패하면 오류 원문을 알려주세요.” 문장을 만드세요. 사용자에게 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하고 실제 URL로 채운 문장을 별도 코드 블록에 제공합니다. 실제 링크가 있으면 그대로 사용하고 없을 때만 사용자 검색 조건으로 복구용 주소를 구성하세요. 상품 ID가 없으면 상품 검색부터 요청하며 재고 ID를 추측하지 마세요. 사용자가 재전송한 뒤 한 번 조회합니다. 단순 허용 문구나 주소 일부만 요청하지 마세요. 문장을 제시한 것은 실제 조회가 아닙니다. 토큰·쿠키를 포함하지 마세요. TimeoutError의 같은 링크 재확인은 한 번만 하며 실패 결과가 캐시되어 다음에 성공한다고 가정하지 마세요.'; + /** 웹 읽기 환경에서 쿼리 없는 HTML 경로를 우선합니다. */ export const WEB_READ_RULE = - '웹 조회는 /browse/ 경로를 사용하세요. 실제 브라우저 도구가 있으면 /browse/ HTML을 열고, 웹 읽기(open/WebFetch)만 있으면 /browse/read의 실제 링크 ID로 click하여 시작하세요. 새 URL을 조립하지 말고 글자 선택·상품·매장 지역 선택 링크를 따르세요. 오래된 수집본이면 같은 조건으로 새 응답 확인 링크를 최대2번 선택해 새 주소와 HTML 생성 시각을 확인하세요. 이 경로도 기존 API 캐시·한도·권한을 사용하며 원본 재고 갱신을 보장하지 않습니다. TimeoutError는 같은 실제 링크를 한 번만 재확인하고 계속 실패하면 미확인으로 보고하세요. URL 접근 거절을 같은 주소의 직접 open으로 반복하지 마세요. Crawled today만으로 현재 재고를 단정하지 말고 응답 생성 시각을 보고하세요. 모든 후속 /browse/ 조회는 자동 HTML이며 쿼리 문자열은 필요 없습니다. JSON API·셸로 우회하거나 브라우저를 추가로 계속 실행하지 마세요. 접근 오류를 상품 없음·재고0·로그인 필요로 단정하지 마세요. 해당 오류만으로 이 환경에서 실행할 수 없다고 단정하지 마세요.'; + '웹 조회는 /browse/ 경로를 사용하세요. 실제 브라우저 도구가 있으면 /browse/ HTML을 열고, 웹 읽기(open/WebFetch)만 있으면 /browse/read의 실제 링크 ID로 click하여 시작하세요. 새 URL을 조립하지 말고 글자 선택·상품·매장 지역 선택 링크를 따르세요. 오래된 수집본이면 같은 조건으로 새 응답 확인 링크를 최대2번 선택해 새 주소와 HTML 생성 시각을 확인하세요. 이 경로도 기존 API 캐시·한도·권한을 사용하며 원본 재고 갱신을 보장하지 않습니다. TimeoutError는 같은 실제 링크를 한 번만 재확인하고 계속 실패하면 미확인으로 보고하세요. URL 접근 거절을 같은 주소의 직접 open으로 반복하지 마세요. Crawled today만으로 현재 재고를 단정하지 말고 응답 생성 시각을 보고하세요. 모든 후속 /browse/ 조회는 자동 HTML이며 쿼리 문자열은 필요 없습니다. JSON API·셸로 우회하거나 브라우저를 추가로 계속 실행하지 마세요. 접근 오류를 상품 없음·재고0·로그인 필요로 단정하지 마세요. 해당 오류만으로 이 환경에서 실행할 수 없다고 단정하지 마세요.' + + WEB_READ_RECOVERY_RULE; /** 셸 존재를 네트워크 접근 가능 여부로 오해하지 않는 실행 순서 */ export const ROUTE_SELECTION_TEXT = `1. 연결된 MCP 도구가 있으면 search_products {"service":"daiso","query":"수납박스","pageSize":3}를 호출합니다. 2. 실제 브라우저 도구가 있으면 /browse/ HTML GET 주소를 열고 페이지의 실제 상품·매장·재고를 읽습니다. Work의 내장 브라우저도 이 경로를 사용합니다. 3. 웹 읽기(open/WebFetch)만 가능하면 /browse/read의 실제 링크 ID로 click합니다. 임의 검색어를 글자로 선택하고 상품의 매장 지역 선택으로 재고를 조회합니다. 이전 HTML이면 같은 조건의 새 응답 링크를 최대2번 선택하고 생성 시각을 확인하세요. TimeoutError 재확인은 한 번만 합니다. 도구에 click이 없으면 실제 링크를 열되 같은 동작을 보장하지 않습니다. 수집본이나 미확인 수량을 현재 재고0으로 바꾸지 마세요. +${WEB_READ_RECOVERY_RULE} 4. 위 세 수단이 없거나 모두 실패하면 실제 조회 제약과 오류를 알립니다. 셸이 있어도 설치 없는 웹 조회가 우선입니다. 터미널·셸 호출로 우회하지 않습니다. 셸 DNS 오류를 웹 GET 실패나 서버 장애로 확대하지 말고 실제로 실행하지 않은 요청의 실패를 만들지 마세요.`; /** 유사 상품의 웹 검색 이미지를 실제 상품 사진으로 오인하지 않도록 제한합니다. */ @@ -68,16 +74,21 @@ export function createAgentStartResponse(baseUrl: string): Response { /** 웹 읽기 도구가 후속 주소를 실제 링크로 선택할 수 있는 안내입니다. */ function createGuideHtmlResponse(baseUrl: string): Response { const text = buildAgentStartText(baseUrl) - .replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>'); - return new Response(` + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>'); + return new Response( + ` DAISO MCP 사용 안내 ${AGENT_GUIDE_VERSION}

DAISO MCP: 설치 없이 시작하기

${AGENT_GUIDE_STAMP}

안내 응답 생성 시각: . 원본 재고 갱신 시각이 아닙니다.

-
${text}
`, { - headers: { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' }, - }); +
${text}
`, + { + headers: { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' }, + }, + ); } /** 오래된 버전 주소도 현재 안내로 연결하며 영구 리다이렉트 캐시를 만들지 않습니다. */ diff --git a/src/pages/browseRead.ts b/src/pages/browseRead.ts index 06c7a4fb..a3be7afb 100644 --- a/src/pages/browseRead.ts +++ b/src/pages/browseRead.ts @@ -41,7 +41,13 @@ export function registerBrowseReadRoutes(app: Hono): void { .replaceAll('"', '"') .replaceAll('<', '<') .replaceAll('>', '>'); - const note = `

읽기 세션: ${id} · HTML 응답 생성: ${new Date().toISOString()}

새 주소도 기존 API 캐시·한도·권한을 사용합니다. HTML 응답 생성 시각은 원본 재고 갱신 시각이 아닙니다.

같은 조건으로 새 응답 확인

`; + const copyUrl = `https://mcp.aka.page${prefix}${suffix}` + .replaceAll('&', '&') + .replaceAll('"', '"') + .replaceAll('<', '<') + .replaceAll('>', '>'); + const recovery = `
웹 읽기 접근 거절 시 복사 재전송

아래 문장을 그대로 복사해 이 대화에 보내주세요. 접수나 문장 제시는 재고 조회 완료가 아닙니다.

다음 주소를 웹 URL 열기 도구로 직접 열어 실제 결과를 확인해주세요: ${copyUrl}. 실패하면 오류 원문을 알려주세요.

사용자가 재전송한 뒤 한 번 조회합니다. 단순 허용 문구나 URL 일부로 대체하지 마세요. TimeoutError는 같은 실제 링크를 한 번만 재확인하고 계속 실패하면 미확인으로 보고합니다.

`; + const note = `

읽기 세션: ${id} · HTML 응답 생성: ${new Date().toISOString()}

새 주소도 기존 API 캐시·한도·권한을 사용합니다. HTML 응답 생성 시각은 원본 재고 갱신 시각이 아닙니다.

같은 조건으로 새 응답 확인

${recovery}
`; body = body.includes('') ? body.replace('', note + '') : body + note; headers.delete('Content-Length'); headers.delete('ETag'); diff --git a/src/pages/promptCoreText.ts b/src/pages/promptCoreText.ts index 396b7ba6..fba5d27a 100644 --- a/src/pages/promptCoreText.ts +++ b/src/pages/promptCoreText.ts @@ -6,7 +6,7 @@ export function buildPromptCoreText(baseUrl: string): string { return `# 다이소 MCP API 다이소 제품 검색, 매장 찾기, 재고 확인을 위한 API입니다. -아래 웹 조회는 /browse/ 경로를 open/WebFetch로 여는 GET 방식입니다. 모든 조회가 자동 HTML이며 쿼리 문자열은 필요 없습니다. 응답 예시 JSON은 기본 JSON 응답의 구조를 설명하며 HTML에도 같은 실제 필드가 표시됩니다. 개발자용 기존 /api/ JSON API는 그대로 유지합니다. +아래 경로 문법은 일반 HTTP API 클라이언트용입니다. 웹 읽기(open/WebFetch)는 /browse/read의 실제 링크를 선택하고 새 URL을 직접 조립해 반복하지 않습니다. 접근 거절은 위의 완성 URL 복사 재전송 안내를 따르세요. 모든 조회가 자동 HTML이며 쿼리 문자열은 필요 없습니다. 응답 예시 JSON은 기본 JSON 응답의 구조를 설명하며 HTML에도 같은 실제 필드가 표시됩니다. 개발자용 기존 /api/ JSON API는 그대로 유지합니다. Base URL: ${baseUrl} diff --git a/tests/pages/browseRead.test.ts b/tests/pages/browseRead.test.ts index a751cd4b..b765de64 100644 --- a/tests/pages/browseRead.test.ts +++ b/tests/pages/browseRead.test.ts @@ -23,7 +23,11 @@ function fixture() { ? c.json({ success: false }, 503) : c.html('
실패
', 503), ); - app.get('/browse/existing-read', (c) => c.html('새 세션기존 세션')); + app.get('/browse/existing-read', (c) => + c.html( + '새 세션기존 세션', + ), + ); registerBrowseRoutes(app); return { app, hits }; } @@ -58,7 +62,11 @@ describe('웹 수집본과 구분할 수 있는 읽기 세션 링크', () => { expect(body).toContain('웹 URL 열기 도구로 직접 열어'); expect(body).not.toContain('https://localhost'); expect(hits).toHaveLength(1); - expect(Object.fromEntries(hits[0].searchParams)).toEqual({ q: '연필', pageSize: '3', format: 'html' }); + expect(Object.fromEntries(hits[0].searchParams)).toEqual({ + q: '연필', + pageSize: '3', + format: 'html', + }); expect(body).toContain(`href="${prefix}/daiso/product/58450"`); expect(body).toContain(`href="${prefix}/compose/daiso/inventory/58450/~"`); expect(body).toContain('href="https://cdn.daisomall.co.kr/image.jpg"'); @@ -103,7 +111,9 @@ describe('웹 수집본과 구분할 수 있는 읽기 세션 링크', () => { const detail = await app.request(prefix + '/daiso/product/redirect'); expect(detail.status).toBe(302); expect(detail.headers.get('Location')).toBe(prefix + '/daiso/product/58450'); - expect(await (await app.request(detail.headers.get('Location')!)).text()).toContain('상품 58450'); + expect(await (await app.request(detail.headers.get('Location')!)).text()).toContain( + '상품 58450', + ); }); it('기존 읽기 링크는 이중으로 감싸지 않는다', async () => { const { app } = fixture(); @@ -119,11 +129,14 @@ describe('웹 수집본과 구분할 수 있는 읽기 세션 링크', () => { expect(response.status).toBe(503); expect(await response.json()).toEqual({ success: false }); }); - it.each(['invalid', '00000000-0000-0000-0000-000000000000'])('잘못된 ID를 거절한다: %s', async (id) => { - const { app, hits } = fixture(); - expect((await app.request(`/browse/read/${id}/daiso/products/a`)).status).toBe(400); - expect(hits).toHaveLength(0); - }); + it.each(['invalid', '00000000-0000-0000-0000-000000000000'])( + '잘못된 ID를 거절한다: %s', + async (id) => { + const { app, hits } = fixture(); + expect((await app.request(`/browse/read/${id}/daiso/products/a`)).status).toBe(400); + expect(hits).toHaveLength(0); + }, + ); it('중첩 read와 관리·외부 URL 경로는 전달하지 않는다', async () => { const { app, hits } = fixture(); const { prefix } = await seed(app); diff --git a/tests/pages/latestGuide.test.ts b/tests/pages/latestGuide.test.ts index 6ec3f878..d4479d78 100644 --- a/tests/pages/latestGuide.test.ts +++ b/tests/pages/latestGuide.test.ts @@ -4,19 +4,23 @@ import app from '../../src/index.js'; import { buildDiscoveryAssets } from '../../src/pages/discovery.js'; import { apiResultHtml } from '../../src/pages/apiResult.js'; -const version = '2026-10-27.3'; +const version = '2026-11-02.1'; describe('최신 안내 경로와 원본 이미지', () => { - it.each(['/guide/latest', '/guide/2026-10-21.2', '/guide/unknown'])('%s는 캐시 없이 현재 버전으로 연결한다', async path => { - const r = await app.request(path); - expect(r.status).toBe(307); - expect(r.headers.get('Location')).toBe('/guide/'+version); - expect(r.headers.get('Cache-Control')).toBe('no-store'); - }); + it.each(['/guide/latest', '/guide/2026-10-21.2', '/guide/unknown'])( + '%s는 캐시 없이 현재 버전으로 연결한다', + async (path) => { + const r = await app.request(path); + expect(r.status).toBe(307); + expect(r.headers.get('Location')).toBe('/guide/' + version); + expect(r.headers.get('Cache-Control')).toBe('no-store'); + }, + ); it('현재 버전은 최신 조회 링크와 이미지 검색 금지 안내를 제공한다', async () => { - const r = await app.request('/guide/'+version); const text = await r.text(); + const r = await app.request('/guide/' + version); + const text = await r.text(); expect(r.status).toBe(200); expect(r.headers.get('Cache-Control')).toBe('no-store'); - expect(text).toContain('안내 버전: '+version); + expect(text).toContain('안내 버전: ' + version); expect(text).toContain('/browse/read'); expect(text).toContain('image_query'); expect(text).toContain('이미지 검색'); @@ -36,31 +40,50 @@ describe('최신 안내 경로와 원본 이미지', () => { expect(await response.text()).not.toContain(' { - const text=await (await app.request('/prompt')).text(); - const urls=text.match(/https?:\/\/[^\s]+\/browse\/[^\s]+/g)!; + const text = await (await app.request('/prompt')).text(); + const urls = text.match(/https?:\/\/[^\s]+\/browse\/[^\s]+/g)!; expect(urls.length).toBeGreaterThan(30); - for(const url of urls) { + for (const url of urls) { expect(url).not.toContain('?'); expect(url).not.toContain('guide='); } }); it('발견 HTML/robots/sitemap에서 현재 버전 안내를 발견한다', () => { const a = buildDiscoveryAssets({ services: [], tools: [] }); - for (const key of ['discovery.html','robots.txt','sitemap.xml']) expect(a[key]).toContain('/guide/'+version); + for (const key of ['discovery.html', 'robots.txt', 'sitemap.xml']) + expect(a[key]).toContain('/guide/' + version); expect(a['discovery.html']).toContain('/browse/read'); expect(a['_headers']).toContain('Cache-Control: no-store'); }); it('HTML 후속 링크와 원본 Markdown은 현재 버전을 사용하고 JSON 캐시는 유지한다', async () => { - const a = new Hono(); a.use('/api/*', apiResultHtml); - a.get('/api/daiso/products', c => c.json({ data: { products: [{ id:'p1',name:'상품[1]\\표기\n이름',imageUrl:'https://cdn.example/p.png?l=ko&x=2' }] } },200,{'Cache-Control':'public, max-age=30'})); - const r = await a.request('/api/daiso/products?format=html&guide=old');const text = await r.text(); + const a = new Hono(); + a.use('/api/*', apiResultHtml); + a.get('/api/daiso/products', (c) => + c.json( + { + data: { + products: [ + { + id: 'p1', + name: '상품[1]\\표기\n이름', + imageUrl: 'https://cdn.example/p.png?l=ko&x=2', + }, + ], + }, + }, + 200, + { 'Cache-Control': 'public, max-age=30' }, + ), + ); + const r = await a.request('/api/daiso/products?format=html&guide=old'); + const text = await r.text(); expect(text).toContain('href="/browse/daiso/product/p1"'); expect(text).toContain('복사할 원본 이미지 Markdown'); expect(text).toContain('!['); expect(text).toContain('https://cdn.example/p.png?l=ko&x=2'); expect(text).toContain('상품\\[1\\]\\\\표기 이름'); expect(r.headers.get('Cache-Control')).toBe('no-store'); - const raw=await a.request('/api/daiso/products'); + const raw = await a.request('/api/daiso/products'); expect(raw.headers.get('Cache-Control')).toBe('public, max-age=30'); expect((await raw.json()).data.products[0].imageUrl).toBe('https://cdn.example/p.png?l=ko&x=2'); }); diff --git a/tests/pages/productCards.test.ts b/tests/pages/productCards.test.ts index 3818f035..29d577af 100644 --- a/tests/pages/productCards.test.ts +++ b/tests/pages/productCards.test.ts @@ -99,7 +99,7 @@ describe('실제 상품 이미지 카드', () => { const assets = buildDiscoveryAssets({ services: [], tools: [] }); expect(assets['discovery.html']).toMatch(/name="description" content="ChatGPT.*browse\//); for (const text of [assets['discovery.html'], buildAgentStartText('https://example.com')]) { - expect(text).toContain('안내 버전: 2026-10-27.3'); + expect(text).toContain('안내 버전: 2026-11-02.1'); expect(text).toContain('갱신일: 2026-10-27'); } }); From 64a9ddcdfec6e6cd7861ede26c0c389aab692db5 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Mon, 2 Nov 2026 11:05:53 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EC=8A=A4=ED=82=AC=20=EB=A9=94?= =?UTF-8?q?=ED=83=80=EB=8D=B0=EC=9D=B4=ED=84=B0=EC=99=80=20=EC=95=88?= =?UTF-8?q?=EB=82=B4=20=EA=B0=B1=EC=8B=A0=EC=9D=BC=20=EC=A0=95=ED=95=A9?= =?UTF-8?q?=EC=84=B1=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/ai-instruction.md | 2 +- skills/daiso-cli/SKILL.md | 6 +++--- tests/pages/productCards.test.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ed41e04d..ad2be2bb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ > [!IMPORTANT] > **최신 안내:** [현재 버전](https://mcp.aka.page/guide/2026-11-02.1) · [항상 최신 버전으로 이동](https://mcp.aka.page/guide/latest) > -> **안내 버전: 2026-11-02.1 · 갱신일: 2026-10-27** +> **안내 버전: 2026-11-02.1 · 갱신일: 2026-11-02** > > **웹 읽기는 실제 링크 ID로 click하세요.** 새 검색 URL을 조립해 open하지 말고 [웹 조회 시작](https://mcp.aka.page/browse/read) 화면의 글자 선택 링크를 사용하세요. 상품의 **매장 지역 선택** 링크에서 지역도 선택할 수 있습니다. 입력 중에는 원본 조회를 실행하지 않습니다. click이 없는 도구의 동일 동작은 보장하지 않습니다. > diff --git a/docs/ai-instruction.md b/docs/ai-instruction.md index 87d54a63..d068ae80 100644 --- a/docs/ai-instruction.md +++ b/docs/ai-instruction.md @@ -5,7 +5,7 @@ ## 설치 없이 첫 조회 -최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.3)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. +최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-11-02.1)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. 1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. 2. 실제 브라우저 도구가 있으면 /browse/ HTML GET 주소를 열고 실제 상품·매장·재고를 읽습니다. Work의 내장 브라우저도 사용 가능합니다. diff --git a/skills/daiso-cli/SKILL.md b/skills/daiso-cli/SKILL.md index 88922739..6bf054cb 100644 --- a/skills/daiso-cli/SKILL.md +++ b/skills/daiso-cli/SKILL.md @@ -1,7 +1,5 @@ --- -웹 읽기 접근 거절이 계속되면 **현재 조건의 완성 URL을 넣은 복사용 문장**을 제시하고 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하세요. 사용자 재전송 뒤 한 번 조회합니다. 단순 허용 문구·URL 일부 제공·실행하지 않은 실패 보고로 대체하지 마세요. [복사 재전송 및 오류 구분](https://github.com/hmmhmmhm/daiso-mcp/blob/main/docs/web-reading-troubleshooting.md)을 따릅니다. - 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 connected MCP tools first, then HTML GET via an available browser, then 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.9 @@ -17,6 +15,8 @@ metadata: - daiso homepage: https://github.com/hmmhmmhm/daiso-mcp --- +웹 읽기 접근 거절이 계속되면 **현재 조건의 완성 URL을 넣은 복사용 문장**을 제시하고 “아래 문장을 그대로 복사해 이 대화에 보내주세요”라고 안내하세요. 사용자 재전송 뒤 한 번 조회합니다. 단순 허용 문구·URL 일부 제공·실행하지 않은 실패 보고로 대체하지 마세요. [복사 재전송 및 오류 구분](https://github.com/hmmhmmhm/daiso-mcp/blob/main/docs/web-reading-troubleshooting.md)을 따릅니다. + # Daiso CLI @@ -24,7 +24,7 @@ Use this skill to operate the Daiso MCP project through `npx daiso` and the publ ## 설치 없이 첫 조회 -최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.3)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. +최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-11-02.1)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. 1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. 2. 실제 브라우저 도구가 있으면 /browse/ HTML GET 주소를 열고 실제 상품·매장·재고를 읽습니다. Work의 내장 브라우저도 사용 가능합니다. diff --git a/tests/pages/productCards.test.ts b/tests/pages/productCards.test.ts index 29d577af..bde5f8ed 100644 --- a/tests/pages/productCards.test.ts +++ b/tests/pages/productCards.test.ts @@ -100,7 +100,7 @@ describe('실제 상품 이미지 카드', () => { expect(assets['discovery.html']).toMatch(/name="description" content="ChatGPT.*browse\//); for (const text of [assets['discovery.html'], buildAgentStartText('https://example.com')]) { expect(text).toContain('안내 버전: 2026-11-02.1'); - expect(text).toContain('갱신일: 2026-10-27'); + expect(text).toContain('갱신일: 2026-11-02'); } }); }); From f2504011e9f6c3c2222deddee651e390717a220c Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Mon, 2 Nov 2026 11:08:21 +0900 Subject: [PATCH 4/4] =?UTF-8?q?test:=20README=20=EC=B5=9C=EC=8B=A0=20?= =?UTF-8?q?=EC=95=88=EB=82=B4=20=EB=A7=81=ED=81=AC=20=EA=B8=B0=EB=8C=80?= =?UTF-8?q?=EA=B0=92=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/scripts/repository-config.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/repository-config.test.ts b/tests/scripts/repository-config.test.ts index 3de0d9f9..6e5cad28 100644 --- a/tests/scripts/repository-config.test.ts +++ b/tests/scripts/repository-config.test.ts @@ -315,7 +315,7 @@ describe('repository maintenance configuration', () => { expect(fastStart).toContain('설치·API 키 없이'); expect(fastStart).toMatch(/\| 인증\s*\| 없음\s*\|/); expect(readme).toContain('로컬 설치·빌드·API 키 준비 없이'); - expect(fastStart).toContain('docs/service-reference.md?guide=2026-10-27.3#설치-없이-첫-조회'); + expect(fastStart).toContain('docs/service-reference.md?guide=2026-11-02.1#설치-없이-첫-조회'); const directCall = readText('docs/service-reference.md').split('### MCP 표준 응답 모델')[0]; expect(directCall).toContain('WebFetch'); expect(directCall).toContain('/browse/daiso/products/');