8000 fix: 웹 안내에 선택 가능한 HTML 링크 제공 by hmmhmmhm · Pull Request #339 · hmmhmmhm/daiso-mcp · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<summary>AI 에이전트 사용 안내</summary>

> [!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이 없는 도구의 동일 동작은 보장하지 않습니다.
>
Expand Down Expand Up @@ -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#설치-없이-첫-조회)

<p align="center">
<img src="./assets/readme-banners/connect.webp" alt="스마트폰과 노트북을 클라우드로 연결하는 두 햄스터" width="100%">
Expand Down Expand Up @@ -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) | 도구 선택과 상품·매장·재고 조회 순서 |
Expand Down
2 changes: 1 addition & 1 deletion docs/ai-instruction.md
Original file line number Diff line number Diff line change
Expand Up @@ -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의 내장 브라우저도 사용 가능합니다.
Expand Down
2 changes: 1 addition & 1 deletion docs/service-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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·오류만 보고하고 실행하지 않은 요청의 성공·실패를 만들지 않습니다.

Expand Down
13 changes: 13 additions & 0 deletions docs/superpowers/plans/2026-10-27-guide-html-links.md
Original file line number Diff line number Diff line change
@@ -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개 별도 검사였다.
2 changes: 1 addition & 1 deletion skills/daiso-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. 8000 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의 내장 브라우저도 사용 가능합니다.
Expand Down
19 changes: 17 additions & 2 deletions src/pages/agentStart.ts
Original file line number Diff line number Diff line change
@@ -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}`;
Expand Down Expand Up @@ -65,9 +65,24 @@ export function createAgentStartResponse(baseUrl: string): Response {
});
}

/** 웹 읽기 도구가 후속 주소를 실제 링크로 선택할 수 있는 안내입니다. */
function createGuideHtmlResponse(baseUrl: string): Response {
const text = buildAgentStartText(baseUrl)
.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
return new Response(`<!doctype html><html lang="ko"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DAISO MCP 사용 안내 ${AGENT_GUIDE_VERSION}</title></head><body><main>
<h1>DAISO MCP: 설치 없이 시작하기</h1><p>${AGENT_GUIDE_STAMP}</p>
<nav><a href="/browse/read">웹 조회 시작</a> · <a href="/guide/latest">최신 안내 확인</a> · <a href="/prompt">상세 사용법</a></nav>
<p>안내 응답 생성 시각: <time>${new Date().toISOString()}</time>. 원본 재고 갱신 시각이 아닙니다.</p>
<pre style="white-space:pre-wrap">${text}</pre></main></body></html>`, {
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' },
Expand Down
16 changes: 15 additions & 1 deletion tests/pages/latestGuide.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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('<a href="/browse/read">웹 조회 시작</a>');
expect(text).toContain('<a href="/guide/latest">최신 안내 확인</a>');
expect(text).toContain('응답 생성 시각');
expect(text).toContain('<html lang="ko">');
});
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('<a href=');
});
it('프롬프트의 전체 웹 조회 예제는 쿼리 없는 browse 경로다', async () => {
const text=await (await app.request('/prompt')).text();
const urls=text.match(/https?:\/\/[^\s]+\/browse\/[^\s]+/g)!;
Expand Down
2 changes: 1 addition & 1 deletion tests/pages/productCards.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
});
Expand Down
2 changes: 1 addition & 1 deletion tests/scripts/repository-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/');
Expand Down
Loading
0