웹사이트를 에이전트가 완벽하게 읽을 수 있도록 만든 방법: MCP 서버 + NLWeb /ask in Next.js
요약
웹사이트를 AI 에이전트가 완벽하게 이해하고 상호작용할 수 있도록 재구축하는 방법을 다룹니다. 특히 Next.js 환경에서 로케일 라우팅 문제를 해결하기 위해 프록시/미들웨어를 사용하여 순수 API 경로를 유지하는 것이 핵심입니다. 또한, Model Context Protocol(MCP)을 직접 구현하여 에이전트의 도구 발견 및 호출 과정을 구조화하고 안정성을 높였습니다.
핵심 포인트
- AI 에이전트는 인간과 달리 구조화되고 기계가 읽을 수 있는 답변과 액션을 원합니다.
- Next.js i18n 미들웨어 충돌 방지를 위해 API 경로를 rewrite하는 것이 필수적입니다.
- MCP 서버를 직접 구현하여 JSON-RPC 2.0 기반의 안정적인 도구 호출 환경을 구축했습니다.
- llms.txt와 .well-known 디렉토리를 활용해 에이전트가 사이트를 발견하도록 설계해야 합니다.
웹사이트를 에이전트가 완벽하게 읽을 수 있도록 만든 방법: MCP 서버 + NLWeb /ask in Next.js
대부분의 웹사이트는 브라우저를 사용하는 인간을 위해 만들어졌습니다. 그러나 방문자는 점점 AI 에이전트—Claude, 커스텀 어시스턴트, 또는 자율적인 도구—가 되고 있으며, 이들은 당신의 히어로 애니메이션을 원하지 않습니다. 그들이 원하는 것은 구조화되고 기계가 읽을 수 있는 답변과 _수행할 수 있는 액션_입니다.
저는 제 웹사이트 yonyon.ai를 에이전트가 처음부터 끝까지 읽고 사용할 수 있도록 재구축했습니다: 라이브 /ask 엔드포인트 (Microsoft의 NLWeb 형태), /mcp에서 실제 MCP 서버, 인-브라우저 WebMCP 도구, 그리고 llms.txt와 .well-known/ 디스커버리 트리입니다. 이 게시물은 작업 예시이며—실제 코드를 포함하여 무거운 작업을 수행한 세 가지 구성 요소에 대한 내용입니다.
함정: 로케일 라우팅이 에이전트 엔드포인트를 망가뜨린다
제 사이트는 next-intl을 사용하여 국제화(internationalized)되었습니다. 이 미들웨어는 모든 경로를 일치시키고 이를 [locale] 세그먼트로 라우팅합니다. 그래서 제가 에이전트를 위해 순수한 /ask 경로를 추가하자마자, i18n 미들웨어가 먼저 이를 가로채서 /[locale]/ask를 렌더링하려고 시도했고—404가 발생했습니다. 같은 문제가 /mcp에도 영향을 주었을 것입니다.
에이전트는 순수하고 접두사가 없는 경로( /ask, /mcp)를 기대합니다—/en/ask 같은 것이 아닙니다. 해결책은 이 경로들을 i18n 매처가 실행되기 전에 프록시/미들웨어에서 가로채서, 실제 API 경로로 재작성(rewrite)하는 것입니다. redirect()가 아닌 rewrite()를 사용하면 HTTP 메서드와 바디가 유지되므로, POST /ask는 여전히 POST입니다:
// src/proxy.ts (next-intl 미들웨어 진입점)
import createMiddleware from
모델 컨텍스트 프로토콜(Model Context Protocol)은 에이전트가 사용 가능한 도구(tools)를 발견하고 호출하는 방식입니다. 공식 SDK는 훌륭하지만, **zod 3**에 의존하며 제 저장소는 **zod 4**를 사용합니다. 종속성 트리를 맞추기 위해 싸우는 대신, 제가 직접 핸들러를 구현했습니다. MCP의 Streamable-HTTP 전송 방식은 단순히 POST를 통한 **JSON-RPC 2.0**이며, 저는 `initialize`, `tools/list`, `tools/call`, `ping` 등 몇 가지 메서드만 필요했습니다. 종속성 위험이 전혀 없습니다:
// src/app/api/mcp/route.ts
export const dynamic = "force-dynamic";
...
에이전트 사용 편의성을 위해 중요한 두 가지 세부 사항:
* **도구 주석(Tool annotations)** (`readOnlyHint`, `destructiveHint`, `openWorldHint`)을 통해 플래너가 도구를 자율적으로 호출해도 안전한지 여부를 결정할 수 있게 합니다.
* 알려지지 않은 도구는 친근한 텍스트 조각이 아닌 **구조화된 JSON-RPC 오류**(`code` + `message`)를 반환합니다. 따라서 에이전트는 문자열 매칭 대신 프로그램적으로 이를 분기 처리할 수 있습니다.
## 발견(Discovery): llms.txt + .well-known
엔드포인트가 아무도 찾을 수 없다면 쓸모가 없습니다. 두 가지 규칙이 이를 해결합니다:
`/llms.txt` — `robots.txt`를 모델로 하여 LLM을 위해 만들어진 사이트의 사람 및 에이전트 가독성 지도입니다: 누가 당신인지, 에이전트가 여기서 무엇을 할 수 있는지, 그리고 정확한 엔드포인트까지 포함합니다:
yonyon.ai — Yonatan Gross
AI Platform Engineer & Backend Developer. Builds production AI systems
...
`.well-known/` 트리는 기계가 읽을 수 있는 사양을 담고 있습니다:
public/.well-known/
├── mcp.json # 에이전트를 /mcp로 안내
├── mcp/server-card.json # MCP 서버 신분증
...
이 파일들은 `public/`에 위치하기 때문에 일반 정적 파일로 제공되어 로케일 라우터를 완전히 우회하며, 따라서 dotpath/404 문제가 발생하지 않습니다. 또한 RFC 8288의 `Link` 헤더(`rel=
이 단발성(single-shot), 인증 불필요(no-auth)의 에이전트 전용 엔드포인트는 사이트 채팅에 사용되는 것과 동일한 RAG 기반 모델로부터 근거가 마련된 답변을 반환합니다. 에이전트는 이후 MCP `book_intro_call` 도구를 호출하고 행동할 수 있습니다.
에이전트가 사용할 준비가 된 인터페이스(agent-ready surfaces)를 구축하는 것은 코퍼스 AI 모델 훈련에도 좋은 관행입니다. 귀하의 존재가 구조화되고 인용 가능할수록, 모델이 귀하의 작업을 기억할 확률이 높아집니다. 저는 이러한 패턴들(그리고 훨씬 더 많은 것들)을 **[OrchestKit](https://github.com/yonatangross/orchestkit)**이라는 오픈 소스 Claude Code 에이전트 프레임워크인 **[OrchestKit]**으로 패키징했습니다 — 99개의 스킬, 35개의 에이전트, 106개의 후크를 포함합니다.
만약 에이전트가 읽을 수 있는 무언가를 만들고 있고 두 번째 검토자의 시선(second pair of eyes)을 원한다면, **[yonyon.ai](https://yonyon.ai)**의 프런트 도어 자체가 데모입니다 — 질문을 하거나 무료 15분 소개 통화를 예약하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기