8000 fix: 웹 읽기 에이전트의 HTML 조회 필수 안내 통일 by hmmhmmhm · Pull Request #243 · 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
에이전트는 [짧은 시작 안내](https://mcp.aka.page/llms.txt)를 참고하세요. 무설치 요청에는 npm 설치나 전체 스키마 탐색이 필요하지 않습니다.
웹에서는 [공개 첫 화면](https://mcp.aka.page/)에서 시작할 수 있습니다. [검색·크롤러 안내와 배포 구조](docs/web-discovery.md)는 별도 문서에 정리했습니다.

웹 읽기만 가능한 채팅 에이전트는 공개 GET API에 `&format=html`을 추가해 결과를 읽을 수 있습니다. [첫 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) · [사용 방법](docs/web-discovery.md).
**웹 읽기 전용 에이전트는 모든 `/api/*` GET 조회 URL에 `format=html`을 반드시 붙이세요.** 상품 검색·상세·매장·재고·후속 조회 모두 적용합니다. [첫 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) · [사용 방법](docs/web-discovery.md).

## 원격 MCP로 바로 시작하기

Expand Down
2 changes: 1 addition & 1 deletion docs/ai-instruction.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ curl -fsS --max-time 20 'https://mcp.aka.page' \

첫 조회 전에 `npx`, 패키지·스킬 설치, health/help, 전체 스키마나 도구 목록 탐색을 하지 않습니다. 위 예제의 검색어를 사용자 요청으로 바꾸고 조회 결과부터 제공합니다. 사용자 조건이나 호출 오류 때문에 필요한 경우에만 추가 안내를 읽습니다. 호출에 성공하면 추가 진단 없이 결과를 보여줍니다.

`GET https://mcp.aka.page/api/daiso/products?q=수납박스`는 같은 서비스의 REST 직접 조회입니다. GET만 가능한 환경에서는 사용할 수 있지만 MCP 도구를 호출했다고 설명하지 않습니다. HTTP·네트워크 오류만으로 로그인 필요나 서버 장애를 단정하지 않고 실제 오류와 실행 환경을 확인합니다.
`GET https://mcp.aka.page/api/daiso/products?q=수납박스&format=html`는 같은 서비스의 REST 직접 조회입니다. **웹 읽기 전용 에이전트는 모든 `/api/*` GET 조회 URL에 `format=html`을 반드시 붙입니다. 상품 검색·상세·매장·재고·후속 조회 모두 적용합니다.** JSON 주소가 읽히지 않으면 HTML 주소로 재시도하고, 그 실패만으로 로그인 필요나 실행 불가를 단정하지 않습니다. 이 REST 조회를 MCP 도구 호출이라고 설명하지 않습니다. HTTP·네트워크 오류만으로 로그인 필요나 서버 장애를 단정하지 않고 실제 오류와 실행 환경을 확인합니다.

당신은 다이소/통합 가격 후보 비교/주변 음식점·카페/GS25/세븐일레븐/CU/이마트24/올리브영/메가박스/롯데시네마/CGV 생활·쇼핑·영화 도우미입니다.

Expand Down
2 changes: 2 additions & 0 deletions docs/web-discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ OpenAI 검색·사용자 요청·학습 봇의 역할과 공개 IP는 [공식
HTML은 원래 응답의 성공·오류와 HTTP 상태를 보존합니다. 상품 검색 결과를 매장 재고로 단정하거나 오류를 재고 0으로 해석하면 안 됩니다. POST와 MCP 응답 형식은 변경하지 않습니다. 웹 읽기 도구가 HTML 접근도 거부하는 경우에는 이 옵션만으로 도구 내부 문제를 해결하지 못합니다.

`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 클라이언트의 계약은 유지합니다.
5 changes: 5 additions & 0 deletions src/pages/agentStart.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/** 웹 읽기 전용 환경에서 조회 형식을 선택하는 공통 규칙 */
export const WEB_READ_RULE = '웹 읽기 전용 에이전트: 모든 /api/* GET 조회 URL에 format=html을 반드시 포함하세요. 상품 검색뿐 아니라 상세·매장·재고·후속 조회에도 적용합니다. 아래 문서의 JSON 응답 예시는 필드 설명이며 웹 읽기로 JSON 주소를 열라는 뜻이 아닙니다. JSON URL이 읽히지 않으면 format=html로 다시 조회하고, 그 실패만으로 서비스 장애·로그인 필요·이 환경에서 실행할 수 없다고 단정하지 마세요.';

/** 설치 없이 첫 실제 조회를 실행하는 에이전트 안내 */
export function buildAgentStartText(baseUrl: string): string {
return `# Daiso MCP: 설치 없이 시작하기

**${WEB_READ_RULE}**

공개 원격 MCP: https://mcp.aka.page
전송: Streamable HTTP · 인증: 없음 (사용자 API 키 불필요)
샌드박스·셸 없이 웹 읽기만 가능한 채팅 에이전트는 아래 HTML GET 주소를 먼저 여세요. npm 설치나 HTTP POST 실행이 필요 없습니다.
Expand Down
4 changes: 3 additions & 1 deletion src/pages/apiResult.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/** 웹 읽기 에이전트용 공개 GET 결과 표시 */
import { WEB_READ_RULE } from './agentStart.js';
import type { MiddlewareHandler } from 'hono';
import type { AppBindings } from '../api/response.js';

Expand Down Expand Up @@ -33,9 +34,10 @@ export const apiResultHtml: MiddlewareHandler<{ Bindings: AppBindings }> = async
const title = failed ? '조회 실패' : '조회 성공';
const html = `<!doctype html><html lang="ko"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,follow"><title>${title} — 다이소 MCP</title>
<style>body{font-family:system-ui,sans-serif;max-width:900px;margin:32px auto;padding:0 20px;line-height:1.6;overflow-wrap:anywhere}dt{font-weight:600}dd{margin-bottom:12px}li{border-bottom:1px solid #ddd;padding:12px 0}a{color:#075bb5}</style></head><body><main><h1>${title}</h1>
<p><strong>${escapeHtml(WEB_READ_RULE)}</strong></p>
<p>요청: <code>${source}</code> · HTTP ${c.res.status}</p><p>실제 API 조회 결과입니다. 오류를 상품 없음이나 재고 0으로 해석하지 마세요. 매장 재고는 상품 ID와 매장명 또는 사용자 위치를 확인한 뒤 별도로 조회하세요.</p>
${renderValue(data, url.pathname === '/api/daiso/products')}
<p><a href="${source}">동일 조회의 JSON 원본</a> · <a href="/">설치 없는 조회 안내</a> · <a href="/prompt">API 경로와 필수 파라미터 안내</a></p>
<p><a href="${source}">개발자용 JSON 원본 (웹 읽기용 아님)</a> · <a href="/">설치 없는 조회 안내</a> · <a href="/prompt">API 경로와 필수 파라미터 안내</a></p>
<p>다른 공개 GET 조회도 기존 파라미터에 <code>format=html</code>을 추가하면 HTML로 읽을 수 있습니다. 웹 읽기만으로 MCP 연결이 생기는 것은 아닙니다.</p></main></body></html>`;
const headers = new Headers(c.res.headers);
headers.set('Content-Type', 'text/html; charset=utf-8');
Expand Down
5 changes: 3 additions & 2 deletions src/pages/discovery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { buildAgentStartText } from './agentStart.js';
import { buildAgentStartText, WEB_READ_RULE } from './agentStart.js';

const BASE = 'https://mcp.aka.page';

Expand All @@ -22,6 +22,7 @@ export function buildDiscoveryAssets(info: { services: { name: string }[]; tools
<style>body{font-family:system-ui,sans-serif;max-width:760px;margin:48px auto;padding:0 24px;line-height:1.7;color:#18222c;background:#fafafa}h1{line-height:1.3}a{color:#075bb5}pre{white-space:pre-wrap; 8000 overflow-wrap:anywhere;background:#edf1f5;padding:16px;border-radius:8px}code{font-size:.9em}section{margin:32px 0}footer{border-top:1px solid #d8dee5;padding-top:20px}</style>
</head><body><main>
<h1>다이소 MCP</h1><p>설치 없이 상품·매장·재고와 영화관 정보를 조회하세요. 사용자 API 키나 로그인 없이 쓸 수 있는 공개 서비스입니다.</p>
<p><strong>${escapeHtml(WEB_READ_RULE)}</strong></p>
<section><h2>바로 조회하기</h2><p><a href="${escapeHtml(firstQuery)}">다이소 수납박스 상품 3개 조회</a></p>
<p>위 링크는 셸·설치 없이 웹 읽기로 호출하는 공개 REST GET의 HTML 결과입니다. 다른 공개 GET 조회도 기존 파라미터에 <code>format=html</code>을 추가하세요. 검색한 상품의 실제 ID로 재고를 조회하세요. 상품 검색만으로 매장 재고를 단정하지 마세요.</p></section>
<section><h2>에이전트에서 설치 없이 사용하기</h2><p>원격 MCP 주소: <code>${BASE}</code><br>전송: Streamable HTTP · 인증: 없음</p>
Expand All @@ -32,7 +33,7 @@ export function buildDiscoveryAssets(info: { services: { name: string }[]; tools
-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}}}'</code></pre>
<p>웹 읽기 기능으로 이 페이지를 읽는 것만으로 MCP 연결이 생기지는 않습니다. 샌드박스나 셸 없이 웹 읽기만 가능한 채팅 에이전트는 위 HTML REST 링크를 바로 여세요. 오류를 상품 없음으로 해석하지 마세요.</p>
<p><a href="/llms.txt">짧은 시작 안내</a> · <a href="/prompt">전체 API 사용 안내</a> · <a href="/root.json">현재 서비스·도구 목록 JSON</a></p></section>
<p><a href="/llms.txt">짧은 시작 안내</a> · <a href="/prompt">전체 API 사용 안내</a> · <a href="/root.json">개발자용 서비스·도구 목록 JSON</a></p></section>
<section><h2>지원 서비스</h2><p>${services}</p></section>
<footer><a href="https://github.com/hmmhmmhm/daiso-mcp">GitHub 문서와 소스</a> · <a href="/privacy">개인정보 처리방침</a></footer>
</main></body></html>\n`,
Expand Down
50 changes: 25 additions & 25 deletions src/pages/promptCoreText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function buildPromptCoreText(baseUrl: string): string {
return `# 다이소 MCP API 8BD0

다이소 제품 검색, 매장 찾기, 재고 확인을 위한 API입니다.
아래 상세 REST API 요청은 GET 방식이며, 결과는 JSON으로 반환됩니다.
아래 상세 REST API 요청은 GET 방식입니다. 웹 읽기용 URL 예시는 format=html을 포함합니다. 응답 예시 JSON은 기본 JSON 응답의 구조를 설명하며 HTML에도 같은 실제 필드가 표시됩니다. JSON API 클라이언트는 format을 생략하세요.

Base URL: ${baseUrl}

Expand All @@ -18,7 +18,7 @@ Base URL: ${baseUrl}

**설명**: 키워드로 다이소 제품을 검색합니다.

**URL**: ${baseUrl}/api/daiso/products?q={검색어}
**URL**: ${baseUrl}/api/daiso/products?q={검색어}&format=html

**필수 파라미터**:
- q: 검색 키워드 (예: 수납박스, 펜, 정리함)
Expand All @@ -28,8 +28,8 @@ Base URL: ${baseUrl}
- pageSize: 페이지당 결과 수 (기본값: 30, 최대: 100)

**예시**:
- ${baseUrl}/api/daiso/products?q=수납박스
- ${baseUrl}/api/daiso/products?q=펜&page=2&pageSize=10
- ${baseUrl}/api/daiso/products?q=수납박스&format=html
- ${baseUrl}/api/daiso/products?q=펜&page=2&pageSize=10&format=html

**응답 예시**:
\`\`\`json
Expand Down Expand Up @@ -58,10 +58,10 @@ Base URL: ${baseUrl}

**설명**: 제품 ID로 상세 정보를 조회합니다.

**URL**: ${baseUrl}/api/daiso/products/{제품ID}
**URL**: ${baseUrl}/api/daiso/products/{제품ID}?format=html

**예시**:
- ${baseUrl}/api/daiso/products/1234567890
- ${baseUrl}/api/daiso/products/1234567890?format=html

**응답 예시**:
\`\`\`json
Expand All @@ -86,7 +86,7 @@ Base URL: ${baseUrl}

**설명**: 키워드 또는 지역으로 다이소 매장을 검색합니다.

**URL**: ${baseUrl}/api/daiso/stores?keyword={키워드}
**URL**: ${baseUrl}/api/daiso/stores?keyword={키워드}&format=html

**필수 파라미터** (둘 중 하나 필수):
- keyword: 매장명 또는 주소 키워드 (예: 강남, 홍대, 안산)
Expand All @@ -98,9 +98,9 @@ Base URL: ${baseUrl}
- limit: 최대 결과 수 (기본값: 50)

**예시**:
- ${baseUrl}/api/daiso/stores?keyword=강남
- ${baseUrl}/api/daiso/stores?sido=서울&gugun=마포구
- ${baseUrl}/api/daiso/stores?keyword=홍대&limit=10
- ${baseUrl}/api/daiso/stores?keyword=강남&format=html
- ${baseUrl}/api/daiso/stores?sido=서울&gugun=마포구&format=html
- ${baseUrl}/api/daiso/stores?keyword=홍대&limit=10&format=html

**응답 예시**:
\`\`\`json
Expand Down Expand Up @@ -134,7 +134,7 @@ Base URL: ${baseUrl}

**설명**: 특정 제품의 매장별 재고와 온라인 재고를 확인합니다.

**URL**: ${baseUrl}/api/daiso/inventory?productId={제품ID}
**URL**: ${baseUrl}/api/daiso/inventory?productId={제품ID}&format=html

**필수 파라미터**:
- productId: 제품 ID (제품 검색 API에서 조회한 id 값)
Expand All @@ -152,9 +152,9 @@ Base URL: ${baseUrl}
- 안산 중앙역 같은 역명 키워드가 비면 안산중앙역, 안산중앙, 고잔처럼 붙여쓴 변형으로 재시도하세요.

**예시**:
- ${baseUrl}/api/daiso/inventory?productId=1234567890
- ${baseUrl}/api/daiso/inventory?productId=1234567890&lat=37.3219&lng=126.8309
- ${baseUrl}/api/daiso/inventory?productId=1234567890&keyword=안산
- ${baseUrl}/api/daiso/inventory?productId=1234567890&format=html
- ${baseUrl}/api/daiso/inventory?productId=1234567890&lat=37.3219&lng=126.8309&format=html
- ${baseUrl}/api/daiso/inventory?productId=1234567890&keyword=안산&format=html

**응답 예시**:
\`\`\`json
Expand Down Expand Up @@ -197,22 +197,22 @@ Base URL: ${baseUrl}

**설명**: 특정 상품이 특정 매장 내 어디에 진열되어 있는지(구역/층) 조회합니다.

**URL**: ${baseUrl}/api/daiso/display-location?productId={제품ID}&storeCode={매장코드}
**URL**: ${baseUrl}/api/daiso/display-location?productId={제품ID}&storeCode={매장코드}&format=html

**필수 파라미터**:
- productId: 제품 ID (제품 검색 API에서 조회한 id 값)
- storeCode: 매장 코드 (재고 확인 API 결과의 storeCode 값)

**예시**:
- ${baseUrl}/api/daiso/display-location?productId=1234567890&storeCode=04515
- ${baseUrl}/api/daiso/display-location?productId=1234567890&storeCode=04515&format=html

---

### 5. 올리브영 매장 찾기

**설명**: 위치 기반으로 주변 올리브영 매장을 검색합니다.

**URL**: ${baseUrl}/api/oliveyoung/stores?keyword={키워드}
**URL**: ${baseUrl}/api/oliveyoung/stores?keyword={키워드}&format=html

**선택 파라미터**:
- keyword: 매장명/지역 키워드 (예: 명동, 강남)
Expand All @@ -222,8 +222,8 @@ Base URL: ${baseUrl}
- limit: 최대 결과 수 (기본값: 20)

**예시**:
- ${baseUrl}/api/oliveyoung/stores?keyword=명동
- ${baseUrl}/api/oliveyoung/stores?lat=37.498&lng=127.027&limit=5
- ${baseUrl}/api/oliveyoung/stores?keyword=명동&format=html
- ${baseUrl}/api/oliveyoung/stores?lat=37.498&lng=127.027&limit=5&format=html

---

Expand All @@ -235,7 +235,7 @@ Base URL: ${baseUrl}
- 응답의 \`products[].imageUrl\`이 있으면 각 상품 이미지를 반드시 마크다운 이미지로 함께 렌더링합니다.
- 여러 상품이 나오면 첫 상품만 대표로 보여주지 말고, 이미지가 있는 상품은 전부 표시합니다.

**URL**: ${baseUrl}/api/oliveyoung/products?keyword={검색어}
**URL**: ${baseUrl}/api/oliveyoung/products?keyword={검색어}&format=html

**필수 파라미터**:
- keyword: 상품 검색어 (예: 마스크팩, 선크림, 립밤)
Expand All @@ -247,16 +247,16 @@ Base URL: ${baseUrl}
- includeSoldOut: 품절 포함 여부 (기본값: false)

**예시**:
- ${baseUrl}/api/oliveyoung/products?keyword=마스크팩
- ${baseUrl}/api/oliveyoung/products?keyword=립밤&size=10
- ${baseUrl}/api/oliveyoung/products?keyword=마스크팩&format=html
- ${baseUrl}/api/oliveyoung/products?keyword=립밤&size=10&format=html

---

### 7. 올리브영 재고 확인

**설명**: 상품 키워드 기준 올리브영 재고를 조회하고 주변 매장 목록을 함께 반환합니다. 상위 상품에는 storeInventory가 포함되며 매장별 재고 3개, 재고 9개 이상, 품절, 미판매 같은 상태를 제공합니다.

**URL**: ${baseUrl}/api/oliveyoung/inventory?keyword={검색어}
**URL**: ${baseUrl}/api/oliveyoung/inventory?keyword={검색어}&format=html

**필수 파라미터**:
- keyword: 상품 검색어 (예: 선크림, 립밤)
Expand All @@ -270,8 +270,8 @@ Base URL: ${baseUrl}
- includeSoldOut: 품절 포함 여부 (기본값: false)

**예시**:
- ${baseUrl}/api/oliveyoung/inventory?keyword=선크림
- ${baseUrl}/api/oliveyoung/inventory?keyword=립밤&storeKeyword=명동
- ${baseUrl}/api/oliveyoung/inventory?keyword=선크림&format=html
- ${baseUrl}/api/oliveyoung/inventory?keyword=립밤&storeKeyword=명동&format=html

---

Expand Down
4 changes: 3 additions & 1 deletion src/pages/promptReferenceText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
export function buildPromptReferenceText(baseUrl: string): string {
return `## 응답 형식

아래 JSON은 기본 JSON 응답의 구조입니다. 웹 읽기 전용 에이전트는 같은 API에 format=html을 반드시 포함해 HTML 결과를 읽으세요.

### 성공 응답
\`\`\`json
{
Expand Down Expand Up @@ -93,7 +95,7 @@ export function buildPromptReferenceText(baseUrl: string): string {
5. **재고 확인 워크플로우**:
- 먼저 /api/daiso/products로 제품 검색
- 결과에서 원하는 제품의 id 확인
- /api/daiso/inventory에 해당 id로 재고 조회
- /api/daiso/inventory에 해당 id와 확인한 매장 조건, format=html로 재고 조회
- 진열 위치가 필요하면 재고 응답의 storeCode를 확인한 뒤 /api/daiso/display-location에 productId + storeCode로 조회
- 다이소 재고 조회는 storeCode가 필요하지 않습니다.
6. **최소 정보 요청 처리**:
Expand Down
Loading
Loading
0