From 3b69776d4a54fd2a9e4860fa4a33f3132fcd264b Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Tue, 27 Oct 2026 13:01:47 +0900 Subject: [PATCH 1/2] =?UTF-8?q?test:=20=EC=95=88=EB=82=B4=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=9D=98=20=EC=8B=A4=EC=A0=9C=20HTML=20?= =?UTF-8?q?=EB=A7=81=ED=81=AC=20=ED=9A=8C=EA=B7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/pages/latestGuide.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/pages/latestGuide.test.ts b/tests/pages/latestGuide.test.ts index f291ffe7..2a42fa76 100644 --- a/tests/pages/latestGuide.test.ts +++ b/tests/pages/latestGuide.test.ts @@ -21,6 +21,20 @@ describe('최신 안내 경로와 원본 이미지', () => { expect(text).toContain('image_query'); expect(text).toContain('이미지 검색'); }); + it('현재 안내는 웹 도구가 실제 링크 ID로 선택할 수 있는 HTML을 제공한다', async () => { + const response = await app.request('/guide/' + version); + const text = await response.text(); + expect(response.headers.get('Content-Type')).toContain('text/html'); + expect(text).toContain('웹 조회 시작'); + expect(text).toContain('최신 안내 확인'); + expect(text).toContain('응답 생성 시각'); + expect(text).toContain(''); + }); + it('llms.txt의 UTF-8 평문 계약은 HTML 안내와 별도로 보존한다', async () => { + const response = await app.request('/llms.txt'); + expect(response.headers.get('Content-Type')).toBe('text/plain; charset=utf-8'); + expect(await response.text()).not.toContain(' { const text=await (await app.request('/prompt')).text(); const urls=text.match(/https?:\/\/[^\s]+\/browse\/[^\s]+/g)!; From 49d71a30205dbf07cf06affcb58185d39ff91d3a Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Tue, 27 Oct 2026 13:03:43 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EB=B2=84=EC=A0=84=20=EC=95=88?= =?UTF-8?q?=EB=82=B4=EB=A5=BC=20=EC=8B=A4=EC=A0=9C=20=EB=A7=81=ED=81=AC?= =?UTF-8?q?=EA=B0=80=20=EC=9E=88=EB=8A=94=20HTML=EB=A1=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- docs/ai-instruction.md | 2 +- docs/service-reference.md | 2 +- .../plans/2026-10-27-guide-html-links.md | 13 +++++++++++++ skills/daiso-cli/SKILL.md | 2 +- src/pages/agentStart.ts | 19 +++++++++++++++++-- tests/pages/latestGuide.test.ts | 2 +- tests/pages/productCards.test.ts | 2 +- tests/scripts/repository-config.test.ts | 2 +- 9 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 docs/superpowers/plans/2026-10-27-guide-html-links.md diff --git a/README.md b/README.md index cd0189ff..a1353a11 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AI 에이전트 사용 안내 > [!IMPORTANT] -> **최신 안내:** [현재 버전](https://mcp.aka.page/guide/2026-10-27.2) · [항상 최신 버전으로 이동](https://mcp.aka.page/guide/latest) +> **최신 안내:** [현재 버전](https://mcp.aka.page/guide/2026-10-27.3) · [항상 최신 버전으로 이동](https://mcp.aka.page/guide/latest) > -> **안내 버전: 2026-10-27.2 · 갱신일: 2026-10-27** +> **안내 버전: 2026-10-27.3 · 갱신일: 2026-10-27** > > **웹 읽기는 실제 링크 ID로 click하세요.** 새 검색 URL을 조립해 open하지 말고 [웹 조회 시작](https://mcp.aka.page/browse/read) 화면의 글자 선택 링크를 사용하세요. 상품의 **매장 지역 선택** 링크에서 지역도 선택할 수 있습니다. 입력 중에는 원본 조회를 실행하지 않습니다. click이 없는 도구의 동일 동작은 보장하지 않습니다. > @@ -130,7 +130,7 @@ 2. 서버 URL을 입력하고, 전송 방식을 묻는 경우 **HTTP / Streamable HTTP**를 선택합니다. 3. 도구를 활성화하고 `다이소 MCP로 수납박스 검색해줘`라고 요청합니다. -[앱별 연결 방법](docs/client-guide.md#원격-mcp-연결) · [WebFetch로 첫 조회](docs/service-reference.md?guide=2026-10-27.2#설치-없이-첫-조회) +[앱별 연결 방법](docs/client-guide.md#원격-mcp-연결) · [WebFetch로 첫 조회](docs/service-reference.md?guide=2026-10-27.3#설치-없이-첫-조회)

스마트폰과 노트북을 클라우드로 연결하는 두 햄스터 @@ -208,7 +208,7 @@ MCP 연결 없이 웹 읽기와 GET 요청을 지원하는 에이전트는 [REST | 문서 | 내용 | | :-------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | | [연결·사용 가이드](docs/client-guide.md) | 앱별 MCP 연결, CLI, Skill, OpenAPI | -| [서비스 레퍼런스](docs/service-reference.md?guide=2026-10-27.2) | 서비스별 도구·REST API·응답 모델·가격 비교 | +| [서비스 레퍼런스](docs/service-reference.md?guide=2026-10-27.3) | 서비스별 도구·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 d77046e6..d0f355e3 100644 --- a/docs/ai-instruction.md +++ b/docs/ai-instruction.md @@ -2,7 +2,7 @@ ## 설치 없이 첫 조회 -최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.2)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. +최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.3)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. 1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. 2. 실제 브라우저 도구가 있으면 /browse/ HTML GET 주소를 열고 실제 상품·매장·재고를 읽습니다. Work의 내장 브라우저도 사용 가능합니다. diff --git a/docs/service-reference.md b/docs/service-reference.md index c1639e3f..a5d581ab 100644 --- a/docs/service-reference.md +++ b/docs/service-reference.md @@ -16,7 +16,7 @@ README 하단에 있던 기능, REST API, 개발, 아키텍처 설명을 분리 모든 후속 웹 GET도 `/browse/`를 사용하세요. 자동 HTML이며 쿼리 문자열이나 format 지정은 필요 없습니다. 상품 검색 결과의 실제 ID로 재고를 조회하고 검색 성공만으로 매장 재고를 단정하지 않습니다. 이미지는 응답 imageUrl과 카드의 원본 Markdown만 사용하고 이미지 검색으로 대체하지 않습니다. -현재 안내는 [버전 안내](https://mcp.aka.page/guide/2026-10-27.2), 다음 버전도 따라가려면 [항상 최신 안내](https://mcp.aka.page/guide/latest)를 여세요. 이 상세 레퍼런스를 끝까지 읽기 전에 첫 조회를 실행하세요. +현재 안내는 [버전 안내](https://mcp.aka.page/guide/2026-10-27.3), 다음 버전도 따라가려면 [항상 최신 안내](https://mcp.aka.page/guide/latest)를 여세요. 이 상세 레퍼런스를 끝까지 읽기 전에 첫 조회를 실행하세요. 이미 연결된 MCP 도구가 있는 환경만 `search_products`에 `service=daiso`, `query=수납박스`를 전달합니다. 서버는 https://mcp.aka.page 이며 Streamable HTTP, 인증 없음입니다. 실제로 실행한 도구·URL·오류만 보고하고 실행하지 않은 요청의 성공·실패를 만들지 않습니다. diff --git a/docs/superpowers/plans/2026-10-27-guide-html-links.md b/docs/superpowers/plans/2026-10-27-guide-html-links.md new file mode 100644 index 00000000..6ef1855f --- /dev/null +++ b/docs/superpowers/plans/2026-10-27-guide-html-links.md @@ -0,0 +1,13 @@ +# 안내 페이지의 실제 링크 제공 + +ChatGPT 임시 대화에서 현재 안내27.2는 읽었지만 평문 `/browse/read`에 링크 ID가 없어 후속 click을 하지 못했다고 보고했다. 현재 서버 구현도 안내와 llms.txt를 같은 text/plain 응답으로 제공한다. + +1. 현재 버전 안내의 Content-Type과 실제 HTML anchor를 기대하는 회귀를 먼저 추가한다. llms.txt 평문 계약은 별도 검사한다. +2. cloud CI에서 기존 text/plain이 기대 HTML과 달라 실패하는지 확인한다. 실패를 통과로 처리하지 않는다. +3. 버전 안내만 HTML로 바꾸고 웹 조회 시작, 최신 안내, 상세 사용법 링크를 실제 anchor로 제공한다. 텍스트 지침은 HTML escape하여 보존한다. llms.txt와 prompt, JSON API, CLI, 공개 MCP10도구는 유지한다. +4. 새 안내27.3을 문서와 기대값에 맞춘다. 전체 cloud CI·Coverage100%·Mac·CodeQL 및 독립 읽기 전용 리뷰를 수행한다. +5. 배포 후 실제 웹 도구와 기존 Chat 임시 대화에서 안내 링크→조회 시작→실제 상품 링크를 검증한다. Chat UI의 자체 보고와 원시 웹 도구 결과를 구분한다. + +브라우저는 소유 탭1개만 사용한다. Chrome 본체 추가 생성, 공용 helper 종료, 자원 보호 우회, 로컬 전체 검사와 브라우저 실험 중첩은 하지 않는다. + +RED: cloud Coverage40447456763에서 신규 HTML 검사만 실패했다. 기존 text/plain이 기대 text/html과 다르다는 실패를 확인한 뒤 구현했다. 4,152개 통과,1개 실패, Mac 전용1개 별도 검사였다. diff --git a/skills/daiso-cli/SKILL.md b/skills/daiso-cli/SKILL.md index 2b58f565..34b110c8 100644 --- a/skills/daiso-cli/SKILL.md +++ b/skills/daiso-cli/SKILL.md @@ -21,7 +21,7 @@ Use this skill to operate the Daiso MCP project through `npx daiso` and the publ ## 설치 없이 첫 조회 -최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.2)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. +최신 서버 안내는 [현재 버전](https://mcp.aka.page/guide/2026-10-27.3)과 [최신 연결](https://mcp.aka.page/guide/latest)에서 제공합니다. 웹 도구는 과거 리디렉션·수집본을 반환할 수 있으므로 표시된 버전과 HTML 생성 시각을 확인하세요. 1. 연결된 MCP 도구가 있으면 `search_products`에 `{"service":"daiso","query":"수납박스","pageSize":3}`를 전달합니다. 2. 실제 브라우저 도구가 있으면 /browse/ HTML GET 주소를 열고 실제 상품·매장·재고를 읽습니다. Work의 내장 브라우저도 사용 가능합니다. diff --git a/src/pages/agentStart.ts b/src/pages/agentStart.ts index 475c3289..714d9d96 100644 --- a/src/pages/agentStart.ts +++ b/src/pages/agentStart.ts @@ -1,5 +1,5 @@ /** 검색·읽기 사본의 안내 세대를 구분하는 고정 버전 */ -export const AGENT_GUIDE_VERSION = '2026-10-27.2'; +export const AGENT_GUIDE_VERSION = '2026-10-27.3'; export const AGENT_GUIDE_UPDATED = '2026-10-27'; export const AGENT_GUIDE_STAMP = `안내 버전: ${AGENT_GUIDE_VERSION} · 갱신일: ${AGENT_GUIDE_UPDATED}`; export const AGENT_GUIDE_PATH = `/guide/${AGENT_GUIDE_VERSION}`; @@ -65,9 +65,24 @@ export function createAgentStartResponse(baseUrl: string): Response { }); } +/** 웹 읽기 도구가 후속 주소를 실제 링크로 선택할 수 있는 안내입니다. */ +function createGuideHtmlResponse(baseUrl: string): Response { + const text = buildAgentStartText(baseUrl) + .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' }, + }); +} + /** 오래된 버전 주소도 현재 안내로 연결하며 영구 리다이렉트 캐시를 만들지 않습니다. */ export function createVersionedGuideResponse(baseUrl: string, version: string): Response { - if (version === AGENT_GUIDE_VERSION) return createAgentStartResponse(baseUrl); + if (version === AGENT_GUIDE_VERSION) return createGuideHtmlResponse(baseUrl); return new Response(null, { status: 307, headers: { Location: AGENT_GUIDE_PATH, 'Cache-Control': 'no-store' }, diff --git a/tests/pages/latestGuide.test.ts b/tests/pages/latestGuide.test.ts index 2a42fa76..6ec3f878 100644 --- a/tests/pages/latestGuide.test.ts +++ b/tests/pages/latestGuide.test.ts @@ -4,7 +4,7 @@ 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.2'; +const version = '2026-10-27.3'; describe('최신 안내 경로와 원본 이미지', () => { it.each(['/guide/latest', '/guide/2026-10-21.2', '/guide/unknown'])('%s는 캐시 없이 현재 버전으로 연결한다', async path => { const r = await app.request(path); diff --git a/tests/pages/productCards.test.ts b/tests/pages/productCards.test.ts index 40c68ac4..378527b6 100644 --- a/tests/pages/productCards.test.ts +++ b/tests/pages/productCards.test.ts @@ -51,7 +51,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.2'); + expect(text).toContain('안내 버전: 2026-10-27.3'); expect(text).toContain('갱신일: 2026-10-27'); } }); diff --git a/tests/scripts/repository-config.test.ts b/tests/scripts/repository-config.test.ts index 26d6247d..e592f6aa 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.2#설치-없이-첫-조회'); + expect(fastStart).toContain('docs/service-reference.md?guide=2026-10-27.3#설치-없이-첫-조회'); const directCall = readText('docs/service-reference.md').split('### MCP 표준 응답 모델')[0]; expect(directCall).toContain('WebFetch'); expect(directCall).toContain('/browse/daiso/products/');