Nuxt MCP Server — AI가 내 앱 문서를 직접 읽게 만들기
AI 어시스턴트에게 "우리 Nuxt 앱에서 인증 어떻게 구현해?"라고 물으면 엉뚱한 답이 나온다. 학습 데이터에 없는 내부 로직이니까. 이걸 해결하는 방법이 RAG와 MCP인데, Nuxt 팀이 자신들의 문서 서버를 MCP로 직접 만들어서 공개했다.
@nuxtjs/mcp-toolkit 하나로 어떻게 구현하는지 살펴본다.
RAG vs MCP — 선택 기준
보통 "AI에게 내 데이터를 먹이는 방법"으로 RAG를 먼저 떠올린다. 둘의 차이를 먼저 짚고 넘어간다.
| 항목 | RAG | MCP |
|---|---|---|
| 방식 | 벡터 검색 후 컨텍스트 삽입 | 표준 프로토콜로 도구/데이터 노출 |
| 데이터 최신성 | 재색인 필요 | 실시간 접근 |
| 구조화 | 텍스트 덩어리 | 타입 검증된 구조화 데이터 |
| 연결성 | 단방향 검색 | 도구 체인 구성 가능 |
| 적합한 경우 | 정적 문서 대량 검색 | 앱과 AI의 양방향 상호작용 |
Nuxt 팀이 MCP를 선택한 이유는 "Structured data in, structured data out" 이다. 파라미터 검증과 타입 반환으로 LLM 환각을 줄이고, 한 도구의 출력을 다른 도구 입력으로 연결할 수 있다.
[💡 잠깐! 이 용어는?] RAG(Retrieval-Augmented Generation): 질의와 유사한 외부 문서를 벡터 검색으로 찾아서 LLM 입력에 붙이는 패턴. 재색인이 필요하고, 검색 결과의 정확도에 품질이 좌우된다.
MCP의 3가지 구성요소
MCP 서버는 세 가지 방식으로 AI와 상호작용한다.
Resource → AI에게 데이터 제공 (읽기 전용)
Tool → AI가 실행하는 함수 (검색, API 호출)
Prompt → 재사용 가능한 프롬프트 템플릿비유하면 Resource는 도서관의 책, Tool은 사서에게 요청하는 검색, Prompt는 자주 쓰는 질문 양식이다.
설치와 기본 설정
npx nuxi module add mcp-toolkitexport default defineNuxtConfig({
modules: ["@nuxtjs/mcp-toolkit"],
mcp: {
name: "my-nuxt-app",
},
})모듈이 server/mcp/ 디렉토리를 자동으로 스캔해서 하위 파일들을 MCP 엔드포인트로 등록한다. 파일을 만들기만 하면 된다.
Resource 구현: 문서 목록 제공
import { defineMcpResource } from "@nuxtjs/mcp-toolkit/server"
import { queryCollection } from "#content"
export default defineMcpResource({
uri: "resource://my-app/documentation-pages",
description: "앱의 모든 문서 페이지 목록",
cache: "1h",
async handler(uri: URL) {
const allDocs = await queryCollection(event, "docs")
const result = allDocs.map((doc) => ({
path: doc._path,
title: doc.title,
description: doc.description,
}))
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(result, null, 2),
},
],
}
},
})cache: '1h'로 캐싱을 설정하면 1시간 동안 같은 요청에 캐시된 결과를 돌려준다. 매번 DB를 조회하지 않아도 된다.
Tool 구현: 콘텐츠 검색
import { defineMcpTool, jsonResult } from "@nuxtjs/mcp-toolkit/server"
import { z } from "zod"
export default defineMcpTool({
description: "앱 문서에서 특정 주제를 검색한다",
inputSchema: {
query: z.string().describe("검색할 키워드 또는 질문"),
limit: z.number().optional().default(5).describe("최대 결과 수"),
},
async handler({ query, limit }) {
const results = await searchDocuments(query, { limit })
return jsonResult(
results.map((r) => ({
path: r._path,
title: r.title,
excerpt: r.body?.slice(0, 200),
score: r._score,
}))
)
},
})Tool은 AI가 파라미터를 추출해서 실행하는 함수다. inputSchema의 Zod 정의를 AI가 읽고 어떤 값을 넣어야 하는지 파악한다. describe() 설명이 정확할수록 AI가 올바른 값을 전달한다.
Prompt 구현: 워크플로우 안내
import { defineMcpPrompt } from "@nuxtjs/mcp-toolkit/server"
import { z } from "zod"
export default defineMcpPrompt({
description: "특정 주제에 대한 최적의 Nuxt 문서를 찾아준다",
inputSchema: {
topic: z.string().describe("알고 싶은 주제 또는 기능"),
},
async handler({ topic }) {
const docs = await searchDocuments(topic, { limit: 3 })
const docsList = docs
.map((d) => `- ${d.title}: ${d._path}`)
.join("\n")
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `"${topic}"에 대한 문서를 찾아줘.\n\n관련 문서:\n${docsList}`,
},
},
],
}
},
})Prompt는 자주 쓰는 질문 흐름을 미리 정의해두는 것이다. AI 어시스턴트 UI에서 슬래시 커맨드처럼 사용자가 직접 호출할 수 있다.
Tool 체이닝: 도구를 연결하기
MCP의 강점은 도구를 체인으로 연결할 수 있다는 점이다.
사용자: "Nuxt에서 소셜 로그인 구현하는 법 알려줘"
1. search-docs Tool 호출 (query: "소셜 로그인")
→ ["auth/social-login", "modules/oauth"] 반환
2. get-page-content Tool 호출 (path: "auth/social-login")
→ 전체 문서 내용 반환
3. AI가 문서 내용을 바탕으로 답변 생성각 Tool의 출력이 다음 Tool의 입력이 된다. 검색 → 내용 조회 → 답변 생성이 하나의 대화로 이어진다. RAG처럼 벡터 DB 설정 없이, 앱 서버에서 직접 데이터를 가져온다.
AI 도구 연동
MCP 호스트 설정 방법이다. Claude Desktop을 예로 든다.
{
"mcpServers": {
"my-nuxt-app": {
"url": "https://my-app.com/mcp",
"transport": "http"
}
}
}Cursor, Windsurf, VS Code도 같은 방식으로 연결할 수 있다. 서버 URL 하나만 있으면 어떤 MCP 호환 도구에도 붙일 수 있다.
| AI 도구 | 지원 여부 |
|---|---|
| Claude Desktop | 원클릭 설치 지원 |
| Cursor | 지원 |
| Windsurf | 지원 |
| VS Code (Copilot) | 지원 |
| ChatGPT | 지원 |
프로덕션 팁
응답 포맷 통일 — jsonResult() 헬퍼를 쓰면 MCP 표준 응답 형식에 맞게 자동 직렬화된다. 직접 포맷을 맞추다가 오류 나는 케이스를 방지한다.
캐싱 전략 — 자주 바뀌지 않는 Resource는 cache: '1h'나 cache: '24h'로 캐싱한다. 검색 Tool은 캐싱하지 않는 편이 좋다 — 동일 쿼리에 동일 결과를 원한다면 예외다.
에러 처리 — Tool handler에서 예외가 발생하면 MCP 클라이언트에 에러 응답이 전달된다. AI가 "이 도구가 실패했다"고 인식하고 다른 방법을 시도하게 된다.
import { defineMcpTool, jsonResult } from "@nuxtjs/mcp-toolkit/server"
import { z } from "zod"
export default defineMcpTool({
description: "앱 문서에서 특정 주제를 검색한다",
inputSchema: {
query: z.string().min(1).describe("검색할 키워드 또는 질문"),
},
async handler({ query }) {
try {
const results = await searchDocuments(query)
if (results.length === 0) {
return jsonResult({ message: "검색 결과가 없다", query })
}
return jsonResult(results)
} catch (error) {
throw new Error(`문서 검색 실패: ${error instanceof Error ? error.message : "알 수 없는 오류"}`)
}
},
})마무리
Nuxt MCP 서버는 세 가지 문제를 해결한다.
- AI가 앱 내부 정보를 모른다 → Resource로 실시간 데이터 제공
- AI가 앱 기능을 실행 못한다 → Tool로 함수를 노출
- 같은 질문 흐름을 매번 입력한다 → Prompt로 워크플로우 템플릿화
server/mcp/ 디렉토리에 파일 하나 만드는 것으로 시작할 수 있다. 기존 Nuxt 앱에 모듈 하나 추가하면 되니까, 새 프로젝트를 만들 필요도 없다.
AI 어시스턴트가 내 앱을 "진짜로 이해하는 것처럼" 동작하길 원한다면, MCP 서버가 현재 가장 표준적인 방법이다.
참고:
- Nuxt 공식 블로그: https://nuxt.com/blog/building-nuxt-mcp
- @nuxtjs/mcp-toolkit: https://nuxt.com/modules/mcp-toolkit
- MCP 공식 문서: https://modelcontextprotocol.io/
관심 있을 만한 포스트
카카오페이 MCP Agent Toolkit — AI 에이전트로 결제 API 연동하기
카카오페이 개발팀이 MCP 표준으로 결제 Open API를 AI 에이전트에 연결한 방법과 실제 코드 구조를 살펴본다.
AI 에이전트 프롬프트 캐싱 — 응답 속도를 높이는 공짜 최적화
AI 에이전트에서 시스템 프롬프트와 도구 정의를 캐싱해 응답 속도를 높이는 프롬프트 캐싱의 동작 원리와 설정 방법을 정리한다.
LLM 내부 동작 원리 — 백엔드 개발자를 위한 6단계 해설
토크나이징부터 반복 디코딩까지, LLM이 텍스트를 처리하는 6단계 과정을 코드와 비유로 풀어본다.
뱅크샐러드의 LLM 코드 안전화 — DSL로 Vibe Coding을 프로덕션에 쓰는 법
LLM이 생성한 코드를 프로덕션에서 안전하게 실행하기 위해 뱅크샐러드가 선택한 DSL 기반 전략을 해부한다.
Context Engineering — 에이전트 품질을 결정하는 진짜 레버
프롬프트 엔지니어링을 넘어선 컨텍스트 엔지니어링의 4가지 구성요소와 실전 패턴을 정리한다.
Google Cloud 멀티 에이전트 — A2A와 MCP로 만드는 5가지 통합 패턴
에이전트 간 통신을 위한 A2A와 외부 도구 연결을 위한 MCP가 Google Cloud에서 어떻게 통합되는지, 5가지 패턴으로 정리한다.
Cloudflare Agents Week 2026 — 에이전트 클라우드가 온다
Cloudflare가 Agents Week에 발표한 컴퓨팅, 보안, 메모리, AI 추론 인프라를 한 번에 정리한다.
Cloudflare AI 코드 리뷰 — 48,000건 MR을 AI로 검토한 실전 아키텍처
Cloudflare가 48,095건의 머지 요청에 AI 코드 리뷰를 적용한 방식과 리스크 티어, 조정자 패턴, 프롬프트 주입 방지 구현을 분석한다.