본문 바로가기

MCP

Supabase + Claude Code MCP 완전 가이드 — AI 에이전트가 Postgres를 올바르게 다루게 만드는 법

반응형

AI 에이전트가 Supabase를 알고는 있습니다. 그런데 제대로 쓰는 건 다른 얘기입니다. RLS 없이 테이블 만들고, 없는 CLI 명령 날조하고, security_invoker 빠뜨린 뷰를 만듭니다. MCP + Agent Skills로 이걸 고칩니다.

[핵심 요약]
→ Supabase MCP: AI 에이전트가 자연어로 DB 관리 (20개+ 툴)
→ Postgres Best Practices: AI 에이전트용 30가지 Postgres 룰셋
→ Supabase Agent Skills: MCP + 보안 규칙 + 문서 검색 통합 패키지
→ 지원 클라이언트: Claude Code, Cursor, Codex, GitHub Copilot, Windsurf
→ 핵심 문제: MCP만으론 부족 — 에이전트가 여전히 잘못된 패턴 사용
→ 해결: MCP + Skill 조합 → RLS, security_invoker, 문서 검증 자동화
→ 주의: 프로덕션 DB에 MCP 연결 금지 — 개발/테스트 전용

에이전트가 Supabase에서 자주 망치는 것들

[AI 에이전트의 흔한 실수]

1. RLS 빠뜨리기
→ 에이전트: "users 테이블 만들었습니다"
→ 실제: RLS 없음 → anon 사용자가 전체 데이터 접근 가능

2. 존재하지 않는 CLI 명령 날조
→ 에이전트: "supabase db execute로 실행하세요"
→ 실제: 그런 명령 없음 → 에러

3. security_invoker 없는 뷰
→ 에이전트가 만든 뷰: 뷰 생성자 권한으로 실행
→ 결과: RLS 우회 → 다른 사용자 데이터 노출

4. 오래된 훈련 데이터 기반 코드
→ Supabase는 빠르게 변함
→ 에이전트: 몇 달 전 API로 코드 작성 → 지금 작동 안 함

[Supabase 팀 내부 실험 결과]
MCP만 사용:
→ security_invoker 적용률: 낮음
→ 문서 검색 활용: 거의 없음

MCP + Agent Skill:
→ security_invoker 적용률: 대폭 향상
→ 문서 검색 후 구현: 일관적
→ 모든 테스트 모델(Claude, GPT) 동일하게 개선

실전 1 — Supabase MCP 설치 (Claude Code)

# Claude Code에서 Supabase MCP 추가
# 방법 1: OAuth 자동 인증 (권장)
claude mcp add --transport http supabase https://mcp.supabase.com/mcp

# Claude Code 실행
claude

# 인증 트리거
> Authenticate with Supabase MCP
# → 브라우저 열림 → Supabase 로그인 → 권한 부여

# 연결 확인
> What tables are in my database? Use MCP tools
# → list_tables 툴 자동 호출 → DB 스키마 반환되면 성공
# 특정 프로젝트로 범위 제한 (보안 권장)
claude mcp add --transport http supabase \
  "https://mcp.supabase.com/mcp?project_ref=YOUR_PROJECT_REF"

# project_ref: Supabase 대시보드 → Project Settings → Project ID
// ~/.claude.json에 직접 추가하는 방법
{
  "mcpServers": {
    "supabase": {
      "command": "npx",
      "args": [
        "-y",
        "@supabase/mcp-server-supabase@latest",
        "--access-token",
        "YOUR_SUPABASE_ACCESS_TOKEN",
        "--project-ref",
        "YOUR_PROJECT_REF"
      ]
    }
  }
}

 

[MCP 설정 보안 옵션]

프로젝트 범위 제한 (필수 권장):
→ project_ref 설정 → 해당 프로젝트만 접근
→ 미설정: 조직 내 전체 프로젝트 접근 가능

읽기 전용 모드:
→ 프로덕션 연결 시 반드시 사용
→ 모든 쿼리를 읽기 전용 Postgres 사용자로 실행

기능 그룹 제한:
→ features 옵션으로 툴 그룹 선택 노출
→ 불필요한 툴 제거 → 공격 표면 축소

실전 2 — MCP 20가지 핵심 툴

[Supabase MCP 툴 목록]

데이터베이스 관리:
→ list_tables: 테이블 목록 조회
→ execute_sql: SQL 직접 실행
→ apply_migration: 마이그레이션 적용 (버전 추적)
→ list_migrations: 마이그레이션 히스토리

스키마/타입:
→ generate_typescript_types: DB 스키마 → TypeScript 타입 자동 생성
→ get_schema: 스키마 정보 조회

프로젝트 관리:
→ get_project: 프로젝트 정보 (URL, API 키)
→ list_projects: 프로젝트 목록
→ create_branch: 개발용 브랜치 생성
→ merge_branch: 브랜치 머지

디버깅:
→ get_logs: 서비스별 로그 (api, postgres, auth, storage, realtime)
→ get_advisors: 보안/성능 권고사항

인증/보안:
→ get_auth_config: 인증 설정 조회
→ update_auth_config: 인증 설정 변경
# Claude Code에서 실제 사용 예시

# 1. 테이블 생성 (RLS 포함)
> users 테이블 만들어줘. id, email, created_at 컬럼, RLS 활성화

# 2. TypeScript 타입 자동 생성
> DB 스키마 기반으로 TypeScript 타입 파일 생성해줘

# 3. 마이그레이션 적용
> 이 SQL을 마이그레이션으로 적용해줘:
> ALTER TABLE posts ADD COLUMN published_at timestamptz;

# 4. 로그 확인
> 지난 1시간 auth 서비스 에러 로그 보여줘

# 5. 보안 권고사항 확인
> 이 프로젝트 보안 취약점 체크해줘

# 6. 개발 브랜치 생성
> 오늘 작업용 개발 브랜치 만들어줘

실전 3 — Postgres Best Practices 30 Rules 설치

MCP만으로는 부족합니다. 에이전트가 "어떻게" 툴을 쓸지는 알아도 "언제, 왜" 써야 하는지는 모릅니다. 30 Rules가 그걸 알려줍니다.

# Agent Skills 설치 (Claude Code 플러그인)
# 방법 1: Vercel Skills npm 패키지
npx @vercel/skills install supabase

# 방법 2: Claude Code 직접 설치
claude skills install supabase

# 방법 3: GitHub 수동 설치
# github.com/supabase/agent-skills 에서 SKILL.md 다운로드
# → 프로젝트 루트 또는 ~/.claude/skills/ 에 배치
<!-- SKILL.md 핵심 내용 요약 (직접 확인 권장) -->

## Supabase Agent Skill

### 1순위: 문서 먼저 확인
Supabase 관련 코드 작성 전:
1. MCP search_docs 툴로 최신 문서 검색
2. supabase.com/docs 공식 문서 참조
3. 훈련 데이터에 의존하지 말 것 (버전 차이 있음)

### 보안 필수 사항
- 모든 노출된 테이블에 RLS 활성화
- 뷰 생성 시 security_invoker = true 필수
- anon 역할에 불필요한 권한 부여 금지
- Edge Function에서 service_role 키 사용 금지

### 스키마 관리
- 변경사항은 항상 마이그레이션으로 관리
- apply_migration 툴 사용 (직접 SQL 실행 지양)
- 컬럼명: snake_case
- 기본키: UUID v7 (순차적, 인덱스 친화적)

### 툴 워크플로우
1. list_tables → 현재 스키마 파악
2. get_advisors → 기존 문제 확인
3. 변경 전 create_branch → 안전한 개발 환경
4. apply_migration → 변경 적용
5. generate_typescript_types → 타입 동기화

실전 4 — 30 Rules 핵심 내용

-- Rule 1: 모든 public 테이블에 RLS 필수
CREATE TABLE posts (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id uuid REFERENCES auth.users(id),
  content text
);

-- ❌ RLS 없으면 누구나 전체 접근
-- ✅ RLS 활성화
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- 사용자별 정책 설정
CREATE POLICY "users can see own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);

CREATE POLICY "users can insert own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Rule 2: 뷰에 security_invoker 필수
-- ❌ 잘못된 뷰 (RLS 우회 가능)
CREATE VIEW reports_view AS
  SELECT * FROM reports;

-- ✅ 올바른 뷰 (RLS 적용됨)
CREATE VIEW reports_view
WITH (security_invoker = true) AS
  SELECT * FROM reports;

-- 이유:
-- 기본값 security_definer = 뷰 생성자 권한으로 실행
-- → RLS 정책이 있어도 뷰를 통해 우회 가능
-- security_invoker = 쿼리하는 사용자 권한으로 실행
-- → RLS 정책이 올바르게 적용됨
-- Rule 3: UUID v7 기본키 (v4 대신)
-- ❌ UUID v4 (완전 랜덤 → 인덱스 단편화)
id uuid DEFAULT gen_random_uuid()

-- ✅ UUID v7 (시간 순 정렬 → 인덱스 효율적)
id uuid DEFAULT gen_random_uuid_v7()

-- v7 장점:
-- 시간 순서 정렬 가능 → B-tree 인덱스 효율
-- 전역 고유성 유지
-- 페이지네이션에 유리
-- Rule 4: 외래키 인덱스 반드시 추가
-- ❌ 인덱스 없는 외래키 (JOIN 성능 저하)
ALTER TABLE posts
ADD CONSTRAINT posts_user_id_fkey
FOREIGN KEY (user_id) REFERENCES auth.users(id);

-- ✅ 인덱스 함께 생성
ALTER TABLE posts
ADD CONSTRAINT posts_user_id_fkey
FOREIGN KEY (user_id) REFERENCES auth.users(id);

CREATE INDEX posts_user_id_idx ON posts(user_id);
-- Rule 5: Realtime 구독은 선택적 활성화
-- ❌ 모든 테이블 Realtime 활성화 (불필요한 부하)
-- ✅ 필요한 테이블만 활성화
ALTER PUBLICATION supabase_realtime ADD TABLE messages;
-- messages 테이블만 실시간 구독 가능

-- Rule 6: Edge Function에서 service_role 금지
-- ❌ 위험
const supabase = createClient(url, process.env.SERVICE_ROLE_KEY)

-- ✅ 사용자 JWT로 클라이언트 생성
const supabase = createClient(url, process.env.ANON_KEY, {
  global: { headers: { Authorization: req.headers.get('Authorization') } }
})

실전 5 — Claude Code + Supabase 실전 워크플로우

# 프로젝트 시작 시 전체 워크플로우

# 1. MCP 연결 확인
claude
> /mcp
# → Supabase: connected 확인

# 2. 현재 스키마 파악
> list_tables를 사용해서 현재 DB 구조 보여줘

# 3. 보안 점검
> get_advisors로 보안 및 성능 권고사항 확인해줘

# 4. 개발 브랜치 생성
> 오늘 users 기능 개발용 브랜치 만들어줘

# 5. 스키마 변경 (브랜치에서)
> users 테이블에 avatar_url 컬럼 추가해줘.
> UUID v7 기본키, RLS 활성화, 필요한 인덱스 포함해줘

# 6. 타입 동기화
> DB 스키마 기반으로 TypeScript 타입 regenerate해줘
> src/types/database.ts에 저장해줘

# 7. 로그 확인
> 최근 auth 에러 로그 확인해줘

# 8. 브랜치 머지
> 작업 완료됐으면 브랜치 머지해줘
[Claude Code + Supabase 자동화 시나리오]

시나리오 1: 새 기능 스키마 설계
> "다중 테넌트 SaaS의 organizations, members, invitations
>  테이블 설계해줘. RLS, 인덱스, UUID v7 포함"
→ Claude가 MCP로 현재 스키마 확인 후 최적 설계 제안 + 마이그레이션 적용

시나리오 2: 성능 최적화
> "슬로우 쿼리 분석해줘. 인덱스 필요한 곳 추가해줘"
→ get_advisors + 로그 분석 → 인덱스 추가 마이그레이션

시나리오 3: 보안 감사
> "이 프로젝트 RLS 설정 전체 검토해줘. 취약점 있으면 수정해줘"
→ 모든 테이블 RLS 상태 확인 → 누락된 정책 추가

시나리오 4: 타입 자동 동기화
> "DB 스키마 바뀔 때마다 TypeScript 타입 자동 업데이트해줘"
→ 마이그레이션 적용 직후 generate_typescript_types 자동 실행

실전 6 — 보안 설정 완전 정리

[Supabase MCP 보안 체크리스트]

✅ 반드시 해야 할 것:
□ project_ref로 특정 프로젝트만 접근 (조직 전체 접근 차단)
□ 개발/테스트 DB에만 연결 (프로덕션 절대 금지)
□ 프로덕션 연결 불가피 시 read_only 모드
□ features 옵션으로 필요한 툴 그룹만 노출
□ Personal Access Token → 안전하게 환경변수 관리

❌ 절대 하지 말 것:
□ 프로덕션 DB에 MCP 연결
□ 고객/사용자에게 MCP 서버 제공
□ service_role 키를 MCP에 사용
□ 실제 사용자 데이터가 담긴 DB에 연결
# 읽기 전용 모드로 프로덕션 데이터 조회 (불가피한 경우)
claude mcp add --transport http supabase-readonly \
  "https://mcp.supabase.com/mcp?project_ref=PROD_REF&read_only=true"

# 특정 기능만 활성화 (최소 권한)
"https://mcp.supabase.com/mcp?project_ref=REF&features=database,docs"
# database: DB 관련 툴만
# docs: 문서 검색만
# functions: Edge Functions
# auth: 인증 관련
# storage: 스토리지

마무리

✅ 이 설정으로 얻는 것

기존 방식:
→ Claude Code ↔ Supabase 대시보드 컨텍스트 전환
→ 마이그레이션 SQL 직접 작성 + 대시보드에서 실행
→ TypeScript 타입 스키마 변경마다 수동 업데이트
→ 로그 확인 → 대시보드 → 에러 복붙 → Claude에 질문

MCP + Agent Skill:
→ 터미널에서 전부 해결
→ "인덱스 추가해줘" → MCP로 자동 마이그레이션
→ 스키마 변경 → TypeScript 타입 자동 동기화
→ "에러 로그 분석해줘" → MCP로 직접 조회 + 분석
→ RLS, security_invoker 자동 적용

[필수 기억사항]
→ MCP만으론 부족: Agent Skill 함께 설치
→ 프로덕션 연결 금지: 개발 DB에만
→ project_ref 범위 제한: 조직 전체 접근 차단
→ 스키마 변경 = 마이그레이션: 직접 SQL 실행 지양

 


관련 글:

 

https://cell-devlog.tistory.com/62

 

MCP 서버 직접 만들기 — 내 서비스를 Claude에 연동하는 법

MCP(Model Context Protocol)는 Claude가 외부 서비스랑 직접 대화하게 해주는 표준 프로토콜이에요.기존에는 이랬어요.나: "우리 DB에서 오늘 주문 건수 알려줘"Claude: "저는 DB에 접근할 수 없어요. 직접 확

cell-devlog.tistory.com

https://cell-devlog.tistory.com/71

 

Claude Code용 주요 MCP 서버 15개 — 실전 설치 가이드

MCP 서버가 지금 1만 개 넘게 있어요. 근데 대부분은 주말에 만든 장난감이에요. 실제 프로덕션에서 쓸 수 있는 건 몇 개 안 돼요.이 목록은 실제 개발 워크플로우에서 매일 쓰는 것들만 뽑았어요.

cell-devlog.tistory.com

https://cell-devlog.tistory.com/66

 

MCP 서버 보안 설정 완전 가이드 — 인증, 권한 제한, 위험 차단

MCP 연동하고 나서 이 생각 한 번쯤 해봤을 거예요."Claude가 우리 DB에 직접 접근하는데... 혹시 DROP TABLE 날리면 어떡하지?""Slack 토큰이 .env에 있는데 유출되면?""GitHub 토큰으로 레포 삭제도 되는 거

cell-devlog.tistory.com

 


 

반응형