재우니 개발자 블로그

 

안녕하세요! 오늘은 최근 AI 씬에서 가장 주목받는 기술인 MCP(Model Context Protocol)를 활용해, 내 로컬 데이터베이스와 AI 에이전트(Claude Desktop, Cursor)를 연결하는 방법을 아주 상세하게 알아보겠습니다.

 

AI가 그저 코드를 짜주거나 텍스트를 생성하는 것을 넘어, 내 데이터베이스에 직접 데이터를 저장하고 검색하며 수정하는 '진짜 비서'로 거듭나는 마법 같은 경험을 할 수 있습니다. 이렇게 AI가 활동할 수 있는 환경과 도구를 직접 구성하는 것을 하네스 엔지니어링(Harness Engineering)이라고 부르는데요, 그 훌륭한 첫걸음이 될 것입니다.

 

백엔드 인프라가 익숙하지 않은 주니어 개발자분들도 막힘없이 따라오실 수 있도록, 윈도우(Windows) 환경을 기준으로 처음부터 끝까지 차근차근 설명해 드릴게요!


🌟 0. 시작하기 전에: 준비물과 목표

 

 

이 가이드를 마치면 여러분의 클로드 데스크탑이나 커서에서 이렇게 명령할 수 있게 됩니다.

*"오늘 회의 내용 요약해서 PocketBase에 '240702_회의록'이라는 제목으로 저장해 줘. 태그는 work로 달아주고!"*

 

 

[준비물]

  • 파이썬 3.10 이상 (설치 시 Add Python to PATH 체크 필수)
  • 윈도우 터미널 (PowerShell 권장)
  • Claude Desktop 또는 Cursor IDE

 


🛠️ 1. PocketBase 세팅 (우리의 작고 가벼운 DB)

PocketBase는 복잡한 설치 과정 없이 파일 하나만 실행하면 끝나는 아주 직관적이고 강력한 백엔드 플랫폼입니다.

 

1-1. 다운로드 및 실행

  1. PocketBase 공식 홈페이지에서 윈도우용(Windows amd64) 파일을 다운로드합니다.
  2. 압축을 풀고 해당 폴더 안에서 터미널을 열어 아래 명령어를 실행합니다.
    ./pocketbase serve
    

 


3. 브라우저를 열고 `http://127.0.0.1:8090/_/` 에 접속하여 첫 관리자(Admin) 계정을 생성합니다.

**1-2. 컬렉션(테이블) 만들기**

1. 왼쪽 메뉴에서 **Collections** → **New collection** 클릭
2. 이름은 `mcp_notes`, 타입은 `Base`로 설정합니다.
3. **New field**를 눌러 아래 세 가지 필드를 추가합니다:
* `title` (Type: Text, Required 체크)
* `content` (Type: Editor)
* `tags` (Type: Select, Multiple values 체크, Options에 `work`, `personal`, `idea` 입력)


4. **API Rules 탭 (보안 핵심! 🔒)**
* List/View/Create/Update/Delete 5개 항목 모두 자물쇠 아이콘을 클릭하고 아래 코드를 넣습니다.
* `@request.auth.id != ""` (로그인한 사용자만 접근하게 만드는 보안 규칙입니다)
* 우측 상단의 **Save** 클릭!



**1-3. MCP 전용 서비스 계정 만들기**

* 관리자(Admin) 계정을 AI에게 통째로 넘겨주는 것은 보안상 위험합니다. `mcp_notes`에만 접근할 수 있는 일반 유저 계정을 만듭니다.
* 왼쪽 메뉴 **users** 컬렉션 선택 → 우측 상단 **New record** 클릭
* **email**: `mcp-service@local.dev`
* **password**: (원하는 강력한 비밀번호 입력)
* 저장 후 이 이메일과 비밀번호는 꼭 메모해 두세요! 나중에 서버 설정에 사용됩니다.

---

### 🐍 2. 파이썬 MCP 서버 환경 준비

이제 AI와 PocketBase 사이에서 요청을 전달해 줄 파이썬 프록시 서버를 만들 차례입니다.

**2-1. 가상 환경 세팅 및 패키지 설치**
원하는 곳에 작업 폴더(예: `mcp-pocketbase-demo`)를 만들고, 터미널(PowerShell)을 열어 아래 명령어를 순서대로 입력하세요.

```powershell
# 1. 독립적인 파이썬 가상환경(venv) 생성
python -m venv venv

# 2. 가상환경 활성화 (이 명령어를 치면 프롬프트 맨 앞에 (venv)가 생깁니다)
.\venv\Scripts\activate

 

 

 

그 다음, 폴더에 requirements.txt 파일을 만들고 아래 내용을 적어주세요.

 

 

mcp[cli]>=1.2.0
httpx>=0.27.0

 

 

💡 패키지 설명:
mcp[cli]는 AI 에이전트와 통신하기 위한 프로토콜 엔진이며, [cli] 옵션이 있어야 웹 기반 테스트 화면(Inspector)을 띄울 수 있습니다. httpx는 비동기 통신을 지원하여 서버가 멈추지 않고 빠르게 외부 DB와 데이터를 주고받게 해줍니다.

 

 

파일을 저장했으면 아래 명령어로 설치합니다.

pip install -r requirements.txt

 

 

 

2-2. 서버 코드 작성 (server.py)

 

프로젝트 폴더 최상단에 server.py 파일을 만들고 아래 코드를 그대로 복사해서 붙여넣습니다. 이 코드는 토큰 만료 시 자동으로 재로그인하는 실무적인 재시도 로직까지 포함된 견고한 뼈대입니다.

 

import os
import httpx
from mcp.server.fastmcp import FastMCP

# ── 환경변수 (Claude Desktop / Cursor 설정 파일의 env 항목에서 주입됩니다) ──
POCKETBASE_URL = os.environ.get("POCKETBASE_URL", "http://127.0.0.1:8090")
PB_SERVICE_EMAIL = os.environ.get("PB_SERVICE_EMAIL")
PB_SERVICE_PASSWORD = os.environ.get("PB_SERVICE_PASSWORD")
COLLECTION = "mcp_notes"

mcp = FastMCP("pocketbase-notes")

_token_cache: dict[str, str | None] = {"token": None}

async def _get_token(client: httpx.AsyncClient) -> str:
    """PocketBase 서비스 계정으로 로그인해서 auth 토큰을 받아옵니다."""
    if _token_cache["token"]:
        return _token_cache["token"]

    if not PB_SERVICE_EMAIL or not PB_SERVICE_PASSWORD:
        raise RuntimeError("PB_SERVICE_EMAIL / PB_SERVICE_PASSWORD 환경변수가 설정되지 않았습니다.")

    resp = await client.post(
        f"{POCKETBASE_URL}/api/collections/users/auth-with-password",
        json={"identity": PB_SERVICE_EMAIL, "password": PB_SERVICE_PASSWORD},
    )
    resp.raise_for_status()
    token = resp.json()["token"]
    _token_cache["token"] = token
    return token

async def _authed_request(method: str, path: str, **kwargs) -> httpx.Response:
    """토큰 만료(401)를 만나면 한 번 재로그인 후 재시도하는 공통 요청 헬퍼."""
    async with httpx.AsyncClient(timeout=10) as client:
        token = await _get_token(client)
        headers = kwargs.pop("headers", {})
        headers["Authorization"] = token
        resp = await client.request(method, f"{POCKETBASE_URL}{path}", headers=headers, **kwargs)

        if resp.status_code == 401:
            _token_cache["token"] = None
            token = await _get_token(client)
            headers["Authorization"] = token
            resp = await client.request(method, f"{POCKETBASE_URL}{path}", headers=headers, **kwargs)

        resp.raise_for_status()
        return resp

@mcp.tool()
async def create_note(title: str, content: str, tags: list[str] | None = None) -> dict:
    """새 메모를 PocketBase에 생성합니다."""
    resp = await _authed_request(
        "POST", f"/api/collections/{COLLECTION}/records",
        json={"title": title, "content": content, "tags": tags or []},
    )
    return resp.json()

@mcp.tool()
async def list_notes(search: str = "", limit: int = 20) -> list[dict]:
    """메모 목록을 조회합니다. search를 주면 제목에서 부분일치 검색합니다."""
    params = {"perPage": limit, "sort": "-created"}
    if search:
        params["filter"] = f'title ~ "{search}"'
    resp = await _authed_request("GET", f"/api/collections/{COLLECTION}/records", params=params)
    return resp.json().get("items", [])

@mcp.tool()
async def update_note(note_id: str, title: str | None = None, content: str | None = None) -> dict:
    """기존 메모를 수정합니다."""
    data = {}
    if title is not None: data["title"] = title
    if content is not None: data["content"] = content
    resp = await _authed_request("PATCH", f"/api/collections/{COLLECTION}/records/{note_id}", json=data)
    return resp.json()

@mcp.tool()
async def delete_note(note_id: str) -> str:
    """메모를 삭제합니다."""
    await _authed_request("DELETE", f"/api/collections/{COLLECTION}/records/{note_id}")
    return f"메모 {note_id} 삭제 완료"

if __name__ == "__main__":
    mcp.run(transport="stdio")

 

 


🕵️‍♂️ 3. 웹 인스펙터로 로컬 테스트하기 (에러 단골 구간!)

AI에 연결하기 전에, 이 파이썬 코드가 DB와 잘 통신하는지 MCP Inspector로 먼저 테스트해야 합니다.

🔥 윈도우 환경 극악의 주의사항!
윈도우 터미널을 쓰실 때, CMD와 PowerShell의 환경변수 주입 명령어가 다릅니다. 이 부분을 틀리면 서버가 아이디/비밀번호를 인식하지 못해 에러가 발생합니다.

 

 

PowerShell을 사용하는 경우 (추천)

$env:POCKETBASE_URL="http://127.0.0.1:8090"
$env:PB_SERVICE_EMAIL="mcp-service@local.dev"
$env:PB_SERVICE_PASSWORD="아까_만든_비밀번호"
mcp dev server.py

 

 

명령어를 치면 터미널에 http://localhost:... 형태의 URL이 출력됩니다. 브라우저로 접속하면 MCP Inspector 화면이 뜹니다.
화면의 Tools 탭에서 Notes를 찾아 직접 파라미터를 입력하고 Run Tool을 눌러보세요. PocketBase Admin UI에 실제로 데이터가 들어간다면 성공입니다! 확인 후 터미널에서 Ctrl + C를 눌러 서버를 꺼주세요.


🤖 4. AI(Claude Desktop / Cursor)에 내 서버 등록하기

 

이제 대망의 마지막 단계입니다. AI에게 "이 파이썬 스크립트를 실행하면 내가 만든 도구들을 쓸 수 있어!"라고 알려주는 설정 파일을 작성합니다.

 

 

  • Claude Desktop: Win + R%APPDATA%\Claude 입력 → claude_desktop_config.json 편집
  • Cursor: 프로젝트 루트 폴더에 .cursor/mcp.json 파일 생성

 

 

설정 파일 내용:

{
  "mcpServers": {
    "pocketbase-notes": {
      "command": "C:\\절대경로\\mcp-pocketbase-demo\\venv\\Scripts\\python.exe",
      "args": ["C:\\절대경로\\mcp-pocketbase-demo\\server.py"],
      "env": {
        "POCKETBASE_URL": "http://127.0.0.1:8090",
        "PB_SERVICE_EMAIL": "mcp-service@local.dev",
        "PB_SERVICE_PASSWORD": "아까_만든_비밀번호"
      }
    }
  }
}

 

 

📌 핵심 체크 포인트

  1. command에는 반드시 venv 폴더 안의 python.exe 절대 경로를 적어야 합니다. 시스템에 기본 설치된 python을 호출하면 패키지를 찾지 못합니다.

윈도우 파일 경로는 역슬래시(\)를 쓰는데, JSON 파일 안에서는 반드시 두 번(\\) 써서 이스케이프 처리해야 합니다.


🎉 5. 실사용 테스트! AI 비서 소환하기

 

설정 파일을 저장했다면 클로드 데스크탑이나 커서를 완전히 종료(Quit)했다가 다시 실행합니다.

새 대화창을 열었을 때 입력창 주변에 🔨(망치 모양의 도구 아이콘)이 보이고, 클릭했을 때 pocketbase-notes 도구 목록이 뜬

다면 성공적으로 연동된 것입니다.

 

이제 자연스럽게 프롬프트를 입력해 보세요.

 

 

*"PocketBase에 'MCP 서버 연동 성공!'이라는 제목으로 메모 하나 만들어줘. 내용은 'AI가 내 DB에 직접 접근해서 데이터를 쓰고 있어'라고 적고, 태그는 idea로 달아줘."*

 

 

AI가 코드를 짜주는 대신, 조용히 Notes 도구를 호출하여 내 로컬 DB에 데이터를 집어넣는 놀라운 광경을 목격하실 수 있습니다.

 

수고하셨습니다! 이제 여러분은 단순한 프롬프트 엔지니어링을 넘어, AI의 행동 반경을 직접 설계하고 통제하는 강력한 무기를 얻게 되셨습니다.