Skip to main content
Glama
znehraks

MCP Notepad Server

by znehraks
guide.md36.1 kB
# MCP 메모장 서버 개발 가이드 MCP(Model Context Protocol)의 핵심 개념과 구현 방법을 설명하는 상세 가이드입니다. ## 목차 1. [MCP 용어 정의](#1-mcp-용어-정의) 2. [전체 아키텍처](#2-전체-아키텍처) (JSON-RPC 포함) 3. [파일별 상세 설명](#3-파일별-상세-설명) 4. [데이터 흐름](#4-데이터-흐름-상세) 5. [MCP 3대 기능 비교](#5-mcp-3대-기능-비교) 6. [파일 영속화](#6-파일-영속화) 7. [개발 팁](#7-개발-팁) 8. [참고 자료](#8-참고-자료) --- ## 1. MCP 용어 정의 ### 핵심 구성요소 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Host │ │ (Claude Desktop, Claude Code, Cursor, Cline, Windsurf 등) │ │ │ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ │ │ LLM │ │ MCP Client │ │ User UI │ │ │ │ (Claude 등) │◄──►│ (프로토콜 │◄──►│ (채팅창 등) │ │ │ │ │ │ 처리 담당) │ │ │ │ │ └────────────────┘ └───────┬────────┘ └────────────────┘ │ │ │ │ └────────────────────────────────┼─────────────────────────────────────┘ │ JSON-RPC (stdin/stdout, SSE, WebSocket) ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ MCP Server │ │ (mcp-notes-server 등) │ │ │ │ 외부 기능 제공: Tools, Resources, Prompts │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 용어 설명 | 용어 | 설명 | 예시 | |------|------|------| | **Host** | MCP Client를 포함하는 AI 애플리케이션. 사용자와 LLM 사이의 인터페이스 제공 | Claude Desktop, Claude Code, Cursor, Cline, Windsurf, Zed | | **MCP Client** | Host 내에서 MCP 프로토콜을 처리하는 컴포넌트. Server와 JSON-RPC 통신 담당 | Host에 내장됨 | | **MCP Server** | 외부 기능(Tools, Resources, Prompts)을 제공하는 서버 프로그램 | mcp-notes-server, filesystem, github 등 | | **LLM** | 대규모 언어 모델. 사용자 요청을 이해하고 적절한 Tool/Resource/Prompt 선택 | Claude, GPT 등 | ### Host 애플리케이션 예시 | Host | 설명 | 용도 | |------|------|------| | **Claude Desktop** | Anthropic 공식 데스크톱 앱 | 일반 사용자용 AI 어시스턴트 | | **Claude Code** | Anthropic CLI 기반 코딩 에이전트 | 터미널에서 코딩 작업 | | **Cursor** | AI 기반 코드 에디터 | IDE에서 AI 코딩 지원 | | **Cline** | VS Code 확장 AI 에이전트 | VS Code 내 AI 코딩 | | **Windsurf** | AI 기반 IDE | 전체 IDE 환경에서 AI 지원 | | **Zed** | 고성능 코드 에디터 | 빠른 AI 코드 편집 | ### MCP Server 예시 | Server | 제공 기능 | |--------|----------| | **mcp-notes-server** (본 프로젝트) | 메모 CRUD, 검색, 프롬프트 | | **@modelcontextprotocol/server-filesystem** | 파일 시스템 읽기/쓰기 | | **@modelcontextprotocol/server-github** | GitHub 저장소 조작 | | **@modelcontextprotocol/server-postgres** | PostgreSQL 쿼리 실행 | | **@modelcontextprotocol/server-slack** | Slack 메시지 전송/읽기 | --- ## 2. 전체 아키텍처 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Host (Claude Code, Cursor, Claude Desktop 등) │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ MCP Client │ │ │ │ - 사용자 요청 해석 │ │ │ │ - LLM과 협력하여 적절한 Tool/Resource/Prompt 선택 │ │ │ │ - MCP Server와 JSON-RPC 통신 │ │ │ └───────────────────────────┬───────────────────────────────────┘ │ └──────────────────────────────┼──────────────────────────────────────┘ │ stdin/stdout (JSON-RPC 2.0) ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ MCP Server (mcp-notes-server) │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ index.ts (진입점) │ │ │ │ - Server 인스턴스 생성 │ │ │ │ - StdioServerTransport (stdin/stdout 통신) │ │ │ │ - capabilities: { tools, resources, prompts } │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌────────────────────┼────────────────────┐ │ │ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ noteTools │ │noteResources│ │ notePrompts │ │ │ │ (도구 실행) │ │(데이터 읽기) │ │(프롬프트생성)│ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ └───────────────────┼───────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ noteStore.ts │ │ │ │ - Map<string, Note> (인메모리 저장소) │ │ │ │ - data/notes.json (파일 영속화) │ │ │ └───────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 통신 방식 | 항목 | 설명 | |------|------| | **프로토콜** | JSON-RPC 2.0 | | **전송 방식** | stdin/stdout (StdioServerTransport) | | **대안** | SSE (Server-Sent Events), WebSocket | ### 전송 방식 비교 | 방식 | 장점 | 단점 | 사용 사례 | |------|------|------|----------| | **stdio** | 간단, 로컬 프로세스 간 통신 | 네트워크 불가 | 로컬 MCP 서버 | | **SSE** | HTTP 기반, 방화벽 친화적 | 단방향 (서버→클라이언트) | 웹 기반 클라이언트 | | **WebSocket** | 양방향, 실시간 | 복잡한 연결 관리 | 실시간 협업 | ### JSON-RPC 2.0이란? **JSON-RPC**는 JSON 형식을 사용하는 원격 프로시저 호출(RPC) 프로토콜입니다. MCP는 이 프로토콜을 사용하여 Client와 Server 간에 통신합니다. #### 핵심 개념 | 개념 | 설명 | |------|------| | **Request** | Client → Server로 보내는 요청 (메서드 호출) | | **Response** | Server → Client로 보내는 응답 (결과 또는 에러) | | **Notification** | 응답을 기대하지 않는 단방향 메시지 (`id` 없음) | #### Request 구조 ```json { "jsonrpc": "2.0", // 프로토콜 버전 (필수, 항상 "2.0") "method": "tools/call", // 호출할 메서드 이름 (필수) "params": { // 메서드 파라미터 (선택) "name": "create_note", "arguments": { "title": "제목", "content": "내용" } }, "id": 1 // 요청 식별자 (필수, 응답과 매칭용) } ``` #### Response 구조 (성공) ```json { "jsonrpc": "2.0", // 프로토콜 버전 "result": { // 성공 시 결과 데이터 "content": [{ "type": "text", "text": "{ \"success\": true }" }] }, "id": 1 // 요청의 id와 동일 } ``` #### Response 구조 (에러) ```json { "jsonrpc": "2.0", "error": { "code": -32600, // 에러 코드 (정수) "message": "Invalid Request", // 에러 메시지 "data": { ... } // 추가 정보 (선택) }, "id": 1 } ``` #### 표준 에러 코드 | 코드 | 이름 | 설명 | |------|------|------| | `-32700` | Parse error | JSON 파싱 실패 | | `-32600` | Invalid Request | 유효하지 않은 요청 | | `-32601` | Method not found | 메서드를 찾을 수 없음 | | `-32602` | Invalid params | 잘못된 파라미터 | | `-32603` | Internal error | 내부 서버 에러 | #### MCP에서 사용하는 메서드들 | 메서드 | 방향 | 설명 | |--------|------|------| | `initialize` | Client → Server | 연결 초기화 및 기능 협상 | | `tools/list` | Client → Server | 사용 가능한 도구 목록 요청 | | `tools/call` | Client → Server | 도구 실행 요청 | | `resources/list` | Client → Server | 리소스 목록 요청 | | `resources/read` | Client → Server | 리소스 읽기 요청 | | `prompts/list` | Client → Server | 프롬프트 목록 요청 | | `prompts/get` | Client → Server | 프롬프트 가져오기 요청 | #### 왜 JSON-RPC인가? | 특징 | 설명 | |------|------| | **간단함** | JSON 기반으로 구현이 쉬움 | | **언어 독립적** | 어떤 언어로든 구현 가능 | | **전송 독립적** | stdin/stdout, HTTP, WebSocket 등 다양한 전송 방식 사용 가능 | | **상태 비저장** | 각 요청이 독립적, 서버가 상태를 유지할 필요 없음 | #### 실제 통신 예시 (stdio) ``` ┌─────────────────────────────────────────────────────────────────┐ │ Host (Claude Code) │ │ │ │ 1. 사용자: "메모 만들어줘" │ │ 2. LLM: create_note Tool 선택 │ │ 3. MCP Client가 JSON-RPC Request 생성 │ └────────────────────────┬────────────────────────────────────────┘ │ stdin으로 전송 │ {"jsonrpc":"2.0","method":"tools/call",...} ▼ ┌─────────────────────────────────────────────────────────────────┐ │ MCP Server (mcp-notes-server) │ │ │ │ 4. stdin에서 JSON 읽기 │ │ 5. method 확인: "tools/call" │ │ 6. handleToolCall() 실행 │ │ 7. JSON-RPC Response 생성 │ └────────────────────────┬────────────────────────────────────────┘ │ stdout으로 전송 │ {"jsonrpc":"2.0","result":{...},"id":1} ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Host (Claude Code) │ │ │ │ 8. MCP Client가 Response 수신 │ │ 9. id로 Request와 매칭 │ │ 10. LLM이 결과 해석 → 사용자에게 응답 │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 3. 파일별 상세 설명 ### 3.1 `src/index.ts` - 진입점 MCP Server 인스턴스를 생성하고 Tools, Resources, Prompts를 등록합니다. ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const server = new McpServer({ name: "mcp-notes-server", version: "1.0.0", }); // 각 모듈에서 등록 함수 호출 registerNoteTools(server); registerNoteResources(server); registerNotePrompts(server); // 서버 시작 const transport = new StdioServerTransport(); await server.connect(transport); ``` #### 기존 API와 비교 | 기존 (Deprecated) | 최신 API (v1.12+) | |-------------------|-------------------| | `Server` 클래스 | `McpServer` 클래스 | | `setRequestHandler(Schema, handler)` | `tool()`, `registerResource()`, `registerPrompt()` | | JSON Schema 수동 정의 | Zod 스키마 (자동 변환) | #### 주의사항 ```typescript // stdout은 MCP 통신 전용이므로 디버깅은 stderr 사용 console.error("[Debug] 메시지"); // ✅ 올바름 console.log("[Debug] 메시지"); // ❌ MCP 통신 방해 ``` --- ### 3.2 `src/tools/noteTools.ts` - 도구 정의 **Tool이란?** - LLM이 **실행**할 수 있는 액션 - CRUD 작업처럼 **부작용(side effect)**이 있는 작업 - LLM이 사용자 요청을 분석하여 적절한 Tool 선택 #### 정의된 도구 | 도구명 | 설명 | 필수 파라미터 | 선택 파라미터 | |--------|------|---------------|---------------| | `create_note` | 메모 생성 | `title`, `content` | `tags` | | `update_note` | 메모 수정 | `id` | `title`, `content`, `tags` | | `delete_note` | 메모 삭제 | `id` | - | | `search_notes` | 메모 검색 | `keyword` | - | #### Tool 등록 방식 (최신 API) ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; export function registerNoteTools(server: McpServer): void { server.tool( "create_note", // Tool 이름 "새로운 메모를 생성합니다...", // 설명 (LLM이 이걸 보고 Tool 선택) { // Zod 스키마 (자동으로 JSON Schema로 변환) title: z.string().describe("메모 제목"), content: z.string().describe("메모 내용"), tags: z.array(z.string()).optional().describe("태그 목록"), }, async ({ title, content, tags }) => { // 핸들러 (타입 자동 추론) const note = createNote(title, content, tags || []); return { content: [{ type: "text", text: JSON.stringify({ success: true, note }) }] }; } ); } ``` #### 핸들러 응답 형식 ```typescript // 성공 시 return { content: [{ type: "text", text: JSON.stringify(result) }] }; // 에러 시 return { content: [{ type: "text", text: "에러 메시지" }], isError: true }; ``` --- ### 3.3 `src/resources/noteResources.ts` - 리소스 정의 **Resource란?** - LLM이 **읽을** 수 있는 데이터 - **읽기 전용**, 부작용 없음 - URI로 식별 #### 정의된 리소스 | URI 패턴 | 설명 | 반환 데이터 | |----------|------|-------------| | `notes://list` | 전체 메모 목록 | 모든 메모 요약 정보 | | `notes://note/{id}` | 개별 메모 상세 | 특정 메모 전체 내용 | #### Resource 등록 방식 (최신 API) ```typescript import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; export function registerNoteResources(server: McpServer): void { // 정적 리소스 server.registerResource( "notes-list", // 내부 식별자 "notes://list", // URI { title: "메모 목록", description: "저장된 모든 메모의 목록", mimeType: "application/json", }, async (uri) => ({ contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(data) }] }) ); // 동적 리소스 (URI 템플릿) server.registerResource( "note-by-id", new ResourceTemplate("notes://note/{noteId}", { list: listNoteResources }), { title: "개별 메모", description: "특정 ID의 메모", mimeType: "application/json" }, async (uri, variables) => { const noteId = variables.noteId as string; const note = getNote(noteId); return { contents: [{ uri: uri.href, text: JSON.stringify(note) }] }; } ); } ``` #### 응답 형식 ```typescript return { contents: [ { uri: "notes://list", mimeType: "application/json", text: JSON.stringify(data) } ] }; ``` --- ### 3.4 `src/prompts/notePrompts.ts` - 프롬프트 정의 **Prompt란?** - 재사용 가능한 **프롬프트 템플릿** - LLM에게 특정 작업을 요청하는 미리 정의된 지시문 - 인자를 받아 동적으로 프롬프트 생성 - Tool/Resource와 달리 **사용자가 명시적으로 선택** #### 정의된 프롬프트 | 이름 | 설명 | 필수 인자 | 선택 인자 | |------|------|-----------|-----------| | `summarize_note` | 메모 요약 | `noteId` | `style` (brief/detailed/bullet) | | `extract_tags` | 태그 추출 제안 | `noteId` | `maxTags` (기본: 5) | | `organize_notes` | 전체 메모 정리 제안 | - | - | #### Prompt 등록 방식 (최신 API) ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; export function registerNotePrompts(server: McpServer): void { server.registerPrompt( "summarize_note", { title: "메모 요약", description: "선택한 메모의 내용을 요약합니다.", argsSchema: { noteId: z.string().describe("요약할 메모의 ID"), style: z.enum(["brief", "detailed", "bullet"]).optional(), }, }, async ({ noteId, style = "brief" }) => { const note = getNote(noteId); return { description: `"${note.title}" 메모 요약`, messages: [{ role: "user", content: { type: "text", text: `요약해주세요: ${note.content}` }}] }; } ); } ``` #### 응답 형식 ```typescript return { description: "메모 요약", messages: [ { role: "user", content: { type: "text", text: "다음 메모의 내용을 요약해주세요..." } } ] }; ``` --- ### 3.5 `src/store/noteStore.ts` - 데이터 저장소 #### 이중 저장 구조 ``` ┌─────────────────────┐ ┌─────────────────────┐ │ Map<string, Note> │ ←→ │ data/notes.json │ │ (인메모리) │ │ (파일 영속화) │ └─────────────────────┘ └─────────────────────┘ ``` #### Note 타입 ```typescript interface Note { id: string; // "note_1_1766475873568" title: string; content: string; tags: string[]; createdAt: Date; updatedAt: Date; } ``` #### 제공 함수 | 함수 | 역할 | 파일 저장 | |------|------|-----------| | `createNote(title, content, tags?)` | 메모 생성 | ✅ | | `getNote(id)` | 단일 조회 | ❌ | | `getAllNotes()` | 전체 조회 (최신순 정렬) | ❌ | | `updateNote(id, updates)` | 메모 수정 | ✅ | | `deleteNote(id)` | 메모 삭제 | ✅ | | `searchNotes(keyword)` | 키워드 검색 | ❌ | --- ## 4. 데이터 흐름 상세 ### 4.1 메모 생성 요청 (`create_note`) ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 1. 사용자 입력 (Host: Claude Code, Cursor 등) │ │ └─ "새 메모 만들어줘. 제목은 '회의록'이고 내용은..." │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 2. LLM (Claude) 분석 │ │ └─ "create_note Tool을 사용해야겠다" │ │ └─ 파라미터 추출: title="회의록", content="..." │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 3. MCP Client → Server (stdin, JSON-RPC) │ │ { │ │ "jsonrpc": "2.0", │ │ "method": "tools/call", │ │ "params": { │ │ "name": "create_note", │ │ "arguments": { "title": "회의록", "content": "..." } │ │ }, │ │ "id": 1 │ │ } │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 4. index.ts - CallToolRequestSchema 핸들러 │ │ └─ handleToolCall("create_note", args) │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 5. noteTools.ts - handleToolCall() │ │ └─ case "create_note": createNote(title, content, tags) │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 6. noteStore.ts - createNote() │ │ ├─ generateId() → "note_1_1766475873568" │ │ ├─ notes.set(id, note) // Map에 저장 │ │ └─ saveToFile() // data/notes.json에 저장 │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 7. Server → Client (stdout, JSON-RPC) │ │ { │ │ "jsonrpc": "2.0", │ │ "result": { │ │ "content": [{ │ │ "type": "text", │ │ "text": "{ \"success\": true, \"note\": {...} }" │ │ }] │ │ }, │ │ "id": 1 │ │ } │ └───────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 8. LLM이 결과 해석 → 사용자에게 응답 │ │ └─ "메모가 생성되었습니다. ID: note_1_..." │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 4.2 리소스 읽기 요청 (`notes://list`) ``` 1. 사용자 (Host: Cursor 등) └─ "저장된 메모 목록 보여줘" 2. LLM 분석 └─ "notes://list Resource를 읽어야겠다" 3. MCP Client → Server { "method": "resources/read", "params": { "uri": "notes://list" } } 4. index.ts └─ ReadResourceRequestSchema 핸들러 └─ readResource("notes://list") 5. noteResources.ts └─ readResource() └─ url.host === "list" └─ getAllNotes() 6. noteStore.ts └─ getAllNotes() └─ Map에서 모든 메모 반환 (파일 읽기 없음) 7. Server → Client { "result": { "contents": [{ "uri": "notes://list", "mimeType": "application/json", "text": "{ \"totalCount\": 2, \"notes\": [...] }" }] } } 8. LLM이 결과 해석 → 사용자에게 목록 표시 ``` ### 4.3 프롬프트 요청 (`summarize_note`) ``` 1. 사용자 (Host: Claude Desktop 등) └─ summarize_note 프롬프트 선택 (UI에서) └─ noteId: "note_1_..." 입력 2. MCP Client → Server { "method": "prompts/get", "params": { "name": "summarize_note", "arguments": { "noteId": "note_1_...", "style": "brief" } } } 3. notePrompts.ts - getPrompt() ├─ getNote(noteId)로 메모 조회 └─ 프롬프트 메시지 생성 4. Server → Client { "result": { "description": "메모 요약", "messages": [{ "role": "user", "content": { "type": "text", "text": "다음 메모의 내용을 2-3문장으로 요약해주세요..." } }] } } 5. LLM이 프롬프트를 받아 요약 수행 └─ 사용자에게 요약 결과 표시 ``` --- ## 5. MCP 3대 기능 비교 | 구분 | Tool | Resource | Prompt | |------|------|----------|--------| | **목적** | 액션 실행 | 데이터 읽기 | 프롬프트 생성 | | **부작용** | 있음 (CUD) | 없음 (R) | 없음 | | **식별** | `name` | `uri` | `name` | | **선택 주체** | LLM이 자동 선택 | LLM이 자동 선택 | 사용자가 명시적 선택 | | **예시** | `create_note` | `notes://list` | `summarize_note` | | **용도** | DB 수정, API 호출 | 파일/DB 조회 | AI 작업 지시 | | **메서드** | `tools/call` | `resources/read` | `prompts/get` | ### Tool vs Resource vs Prompt 선택 기준 ``` 사용자: "메모 만들어줘" └─ LLM 판단: 데이터 변경 필요 → Tool (create_note) 사용자: "메모 목록 보여줘" └─ LLM 판단: 데이터 읽기만 필요 → Resource (notes://list) 사용자: (UI에서 summarize_note 선택) └─ 사용자가 명시적으로 프롬프트 선택 → Prompt (summarize_note) ``` ### 언제 무엇을 사용하나? | 사용자 요청 | 선택 | 이유 | |------------|------|------| | "메모 만들어줘" | Tool (`create_note`) | 데이터 생성 (부작용 있음) | | "메모 목록 보여줘" | Resource (`notes://list`) | 데이터 읽기만 (부작용 없음) | | "이 메모 요약해줘" | Prompt (`summarize_note`) | 미리 정의된 프롬프트 템플릿 사용 | | "메모 삭제해줘" | Tool (`delete_note`) | 데이터 삭제 (부작용 있음) | | "메모 내용 알려줘" | Resource (`notes://note/{id}`) | 데이터 읽기만 | | "태그 추천해줘" | Prompt (`extract_tags`) | AI 분석 작업 | --- ## 6. 파일 영속화 ### 동작 방식 ``` 서버 시작 시: ┌─────────────────────────────────────┐ │ loadFromFile() │ │ └─ data/notes.json 존재? │ │ ├─ Yes → JSON 파싱 → Map에 로드 │ │ └─ No → 빈 Map으로 시작 │ └─────────────────────────────────────┘ 데이터 변경 시 (Create/Update/Delete): ┌─────────────────────────────────────┐ │ saveToFile() │ │ └─ Map → JSON 직렬화 │ │ └─ data/notes.json에 쓰기 │ └─────────────────────────────────────┘ ``` ### JSON 파일 구조 ```json { "idCounter": 2, "notes": [ { "id": "note_1_1766475873568", "title": "메모 제목", "content": "메모 내용", "tags": ["태그1", "태그2"], "createdAt": "2025-12-23T07:44:33.568Z", "updatedAt": "2025-12-23T07:44:33.568Z" } ] } ``` ### 파일 경로 ```typescript const DATA_DIR = join(__dirname, "../../data"); const DATA_FILE = join(DATA_DIR, "notes.json"); // 결과: mcp-notes-server/data/notes.json ``` --- ## 7. 개발 팁 ### 디버깅 ```typescript // stdout은 MCP 통신용이므로 stderr 사용 console.error("[Debug] 변수값:", variable); ``` ### 새 Tool 추가하기 ```typescript // noteTools.ts의 registerNoteTools() 함수 내에 추가 server.tool( "new_tool_name", "도구 설명", { param: z.string().describe("파라미터 설명") }, async ({ param }) => { // 로직 구현 return { content: [{ type: "text", text: "결과" }] }; } ); ``` ### 새 Resource 추가하기 ```typescript // noteResources.ts의 registerNoteResources() 함수 내에 추가 server.registerResource( "resource-name", "custom://uri", { title: "리소스 제목", description: "설명" }, async (uri) => ({ contents: [{ uri: uri.href, text: "데이터" }] }) ); ``` ### 새 Prompt 추가하기 ```typescript // notePrompts.ts의 registerNotePrompts() 함수 내에 추가 server.registerPrompt( "new_prompt", { title: "프롬프트 제목", description: "프롬프트 설명", argsSchema: { arg: z.string().describe("인자 설명") }, }, async ({ arg }) => ({ messages: [{ role: "user", content: { type: "text", text: `프롬프트: ${arg}` }}] }) ); ``` ### Host 설정 (Claude Desktop 예시) `~/Library/Application Support/Claude/claude_desktop_config.json`: ```json { "mcpServers": { "mcp-notes": { "command": "node", "args": ["/절대경로/mcp-notes-server/dist/index.js"] } } } ``` --- ## 8. 참고 자료 - [MCP 공식 문서](https://modelcontextprotocol.io) - [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) - [JSON-RPC 2.0 명세](https://www.jsonrpc.org/specification) - [MCP 서버 예제들](https://github.com/modelcontextprotocol/servers)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/znehraks/mcp-poc'

If you have feedback or need assistance with the MCP directory API, please join our Discord server