AI

Nuxt MCP Server — AI가 내 앱 문서를 직접 읽게 만들기

Nuxt가 공개한 MCP 서버 구축 방법과 @nuxtjs/mcp-toolkit으로 Resource, Tool, Prompt를 정의하는 실전 패턴을 정리한다.

9 min read
MCPNuxtAIVueLLM
Nuxt MCP Server — AI가 내 앱 문서를 직접 읽게 만들기

AI 어시스턴트에게 "우리 Nuxt 앱에서 인증 어떻게 구현해?"라고 물으면 엉뚱한 답이 나온다. 학습 데이터에 없는 내부 로직이니까. 이걸 해결하는 방법이 RAG와 MCP인데, Nuxt 팀이 자신들의 문서 서버를 MCP로 직접 만들어서 공개했다.

@nuxtjs/mcp-toolkit 하나로 어떻게 구현하는지 살펴본다.

RAG vs MCP — 선택 기준

보통 "AI에게 내 데이터를 먹이는 방법"으로 RAG를 먼저 떠올린다. 둘의 차이를 먼저 짚고 넘어간다.

항목RAGMCP
방식벡터 검색 후 컨텍스트 삽입표준 프로토콜로 도구/데이터 노출
데이터 최신성재색인 필요실시간 접근
구조화텍스트 덩어리타입 검증된 구조화 데이터
연결성단방향 검색도구 체인 구성 가능
적합한 경우정적 문서 대량 검색앱과 AI의 양방향 상호작용

Nuxt 팀이 MCP를 선택한 이유는 "Structured data in, structured data out" 이다. 파라미터 검증과 타입 반환으로 LLM 환각을 줄이고, 한 도구의 출력을 다른 도구 입력으로 연결할 수 있다.

[💡 잠깐! 이 용어는?] RAG(Retrieval-Augmented Generation): 질의와 유사한 외부 문서를 벡터 검색으로 찾아서 LLM 입력에 붙이는 패턴. 재색인이 필요하고, 검색 결과의 정확도에 품질이 좌우된다.

MCP의 3가지 구성요소

MCP 서버는 세 가지 방식으로 AI와 상호작용한다.

MCP 구성요소
Resource  → AI에게 데이터 제공 (읽기 전용)
Tool      → AI가 실행하는 함수 (검색, API 호출)
Prompt    → 재사용 가능한 프롬프트 템플릿

비유하면 Resource는 도서관의 책, Tool은 사서에게 요청하는 검색, Prompt는 자주 쓰는 질문 양식이다.

설치와 기본 설정

터미널
npx nuxi module add mcp-toolkit
nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@nuxtjs/mcp-toolkit"],
  mcp: {
    name: "my-nuxt-app",
  },
})

모듈이 server/mcp/ 디렉토리를 자동으로 스캔해서 하위 파일들을 MCP 엔드포인트로 등록한다. 파일을 만들기만 하면 된다.

Resource 구현: 문서 목록 제공

server/mcp/resources/docs.ts
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 구현: 콘텐츠 검색

server/mcp/tools/search-docs.ts
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 구현: 워크플로우 안내

server/mcp/prompts/find-topic.ts
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의 강점은 도구를 체인으로 연결할 수 있다는 점이다.

Tool 체이닝 예시
사용자: "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을 예로 든다.

claude_desktop_config.json
{
  "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가 "이 도구가 실패했다"고 인식하고 다른 방법을 시도하게 된다.

server/mcp/tools/search-docs.ts (에러 처리 포함)
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 서버가 현재 가장 표준적인 방법이다.


참고: