Supabase MCP 서버 구현 계획
이 문서에서는 GitHub Copilot과 같은 AI 어시스턴트가 Supabase 데이터베이스와 상호 작용할 수 있도록 Supabase에 연결되는 MCP(Model Context Protocol) 서버를 만드는 계획을 설명합니다.
목차
Related MCP server: Metabase Server MCP
개요
Supabase MCP 서버는 AI 어시스턴트(예: GitHub Copilot)와 Supabase 데이터베이스를 연결하는 다리 역할을 합니다. 이를 통해 AI는 다음과 같은 작업을 수행할 수 있습니다.
데이터베이스 스키마를 이해하세요
테이블과 관계에 대해 알아보세요
쿼리 작성 지원
데이터 모델과 관련된 컨텍스트 인식 제안을 제공합니다.
필수 조건
구현 단계
1. 서버 패키지 생성
지엑스피1
2. 종속성 설치
npm install @supabase/supabase-js @modelcontextprotocol/server dotenv
3. 기본 서버 구조
다음 파일을 생성하세요.
src/index.js - 주요 진입점
src/supabase-client.js - Supabase 연결 처리
src/schema-provider.js - 데이터베이스 스키마 추출
src/query-handler.js - 안전한 쿼리 실행
.env.example - 환경 변수 템플릿
config.js - 구성 관리
4. 서버 구현 세부 사항
src/index.js
이 파일은 MCP 서버를 초기화하고 구성 요소를 연결합니다.
const { MCPServer } = require('@modelcontextprotocol/server');
const { getSupabaseClient } = require('./supabase-client');
const { SchemaProvider } = require('./schema-provider');
const { QueryHandler } = require('./query-handler');
const config = require('./config');
async function main() {
try {
// Initialize Supabase client
const supabaseClient = getSupabaseClient(config.supabase.url, config.supabase.key);
// Create providers
const schemaProvider = new SchemaProvider(supabaseClient);
const queryHandler = new QueryHandler(supabaseClient, config.security.allowedQueries);
// Initialize MCP server
const server = new MCPServer({
name: 'mcp-server-supabase',
version: '1.0.0',
});
// Register handlers
server.registerHandler('getSchema', async () => {
return await schemaProvider.getFullSchema();
});
server.registerHandler('getTableInfo', async (params) => {
return await schemaProvider.getTableInfo(params.tableName);
});
server.registerHandler('executeQuery', async (params) => {
return await queryHandler.execute(params.query, params.params);
});
// Start the server
await server.start();
console.log('MCP Supabase server is running');
} catch (error) {
console.error('Failed to start MCP server:', error);
process.exit(1);
}
}
main();
src/supabase-client.js
const { createClient } = require('@supabase/supabase-js');
function getSupabaseClient(url, apiKey) {
if (!url || !apiKey) {
throw new Error('Supabase URL and API key must be provided');
}
return createClient(url, apiKey, {
auth: { persistSession: false },
});
}
module.exports = { getSupabaseClient };
src/schema-provider.js
class SchemaProvider {
constructor(supabaseClient) {
this.supabase = supabaseClient;
}
async getFullSchema() {
// Query Supabase for full database schema
const { data, error } = await this.supabase
.rpc('get_schema_information', {});
if (error) throw new Error(`Failed to get schema: ${error.message}`);
return data;
}
async getTableInfo(tableName) {
// Get detailed information about a specific table
const { data, error } = await this.supabase
.rpc('get_table_information', { table_name: tableName });
if (error) throw new Error(`Failed to get table info: ${error.message}`);
return data;
}
}
module.exports = { SchemaProvider };
src/query-handler.js
class QueryHandler {
constructor(supabaseClient, allowedQueryTypes = ['SELECT']) {
this.supabase = supabaseClient;
this.allowedQueryTypes = allowedQueryTypes;
}
validateQuery(queryString) {
// Basic SQL injection prevention and query type validation
const normalizedQuery = queryString.trim().toUpperCase();
// Check if the query starts with allowed query types
const isAllowed = this.allowedQueryTypes.some(
type => normalizedQuery.startsWith(type)
);
if (!isAllowed) {
throw new Error(`Query type not allowed. Allowed types: ${this.allowedQueryTypes.join(', ')}`);
}
return true;
}
async execute(queryString, params = {}) {
// Validate query before execution
this.validateQuery(queryString);
// Execute the query through Supabase
const { data, error } = await this.supabase
.rpc('execute_query', { query_string: queryString, query_params: params });
if (error) throw new Error(`Query execution failed: ${error.message}`);
return data;
}
}
module.exports = { QueryHandler };
config.js
require('dotenv').config();
module.exports = {
supabase: {
url: process.env.SUPABASE_URL,
key: process.env.SUPABASE_SERVICE_KEY,
},
server: {
port: process.env.PORT || 3000,
},
security: {
allowedQueries: process.env.ALLOWED_QUERY_TYPES
? process.env.ALLOWED_QUERY_TYPES.split(',')
: ['SELECT'],
}
};
.env.예제
SUPABASE_URL=https://your-project-ref.supabase.co
SUPABASE_SERVICE_KEY=your-service-key
PORT=3000
ALLOWED_QUERY_TYPES=SELECT
5. Supabase 데이터베이스 함수
Supabase에서 다음과 같은 저장 프로시저를 만들어야 합니다.
get_schema_information() - 데이터베이스 스키마를 반환합니다.
get_table_information(table_name TEXT) - 특정 테이블에 대한 정보를 반환합니다.
execute_query(query_string TEXT, query_params JSONB) - 쿼리를 안전하게 실행합니다.
서버 아키텍처
┌─────────────────────┐ ┌───────────────────┐
│ │ │ │
│ VS Code + Copilot │◄────►│ MCP Protocol │
│ │ │ │
└─────────────────────┘ └─────────┬─────────┘
│
▼
┌─────────────────────┐
│ │
│ Supabase MCP Server │
│ │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ │
│ Supabase Database │
│ │
└─────────────────────┘
구성
VS Code settings.json 에 Supabase MCP 서버를 추가합니다.
"mcp": {
"inputs": [],
"servers": {
// ...existing servers...
"mcp-server-supabase": {
"command": "node",
"args": [
"/path/to/mcp-server-supabase/src/index.js"
],
"env": {
"SUPABASE_URL": "https://your-project-ref.supabase.co",
"SUPABASE_SERVICE_KEY": "your-service-key",
"ALLOWED_QUERY_TYPES": "SELECT"
}
}
}
}
보안 고려 사항
API 키 관리 :
쿼리 제한 사항 :
안전을 위해 SELECT 전용으로 기본 설정
쿼리 허용 목록 접근 방식 구현을 고려하세요
남용을 방지하기 위해 속도 제한을 추가하세요
데이터 보호 :
설치 가이드
지역 개발
저장소를 복제합니다
git clone https://github.com/yourusername/mcp-server-supabase.git
cd mcp-server-supabase
종속성 설치
예제에서 .env 파일을 만듭니다.
Supabase 자격 증명으로 .env 편집하세요.
서버를 시작합니다
VS 코드 통합
서버 구성으로 VS Code settings.json 업데이트하세요.
VS 코드 재시작
VS Code MCP 패널에서 서버가 실행 중인지 확인하세요.
사용 예
통합이 완료되면 Supabase MCP 서버를 다양한 방법으로 사용할 수 있습니다.
스키마 탐색:
What tables do I have in my Supabase database?
테이블 정보:
What columns are in the users table?
질의 지원:
Help me write a query to get all users who signed up in the last 7 days
문제 해결
서버가 시작되지 않습니다
스키마가 로드되지 않습니다
VS Code에 연결할 수 없습니다