대상: 사내 DBA / DB 담당자 — 4개 DB 종류 별 사용자 권한 / 연결 정보 / 트러블슈팅 선행 조건: 커넥터 설치 + 툴킷 사용 가이드 숙지 (Toolkit 사용 가이드) 본 문서는 DB 측 작업 중심 — Studio 폼 입력은 툴킷 가이드 §5 참고
공통 보안 원칙
- 읽기 전용 사용자 별도 생성 — 기존 운영 계정 재사용 X
- DB 레벨에서 SELECT 만 권한 부여 — DDL / DML 자체 차단 (코드 단의 안전망 외 한 겹 더)
- 노출 범위 제한 — 모든 스키마 X. 비즈니스 분석 필요한 view / 테이블만 권한
- 비밀번호는 secrets 파일 에만 — Studio / Hub 에 절대 평문 X
- 네트워크: 커넥터 호스트에서만 접근 가능하도록 DB 측 ACL 조정 권장
Studio 폼 입력 — placeholder 사용 정책
| 필드 | 평문 입력 | placeholder 사용 |
|---|---|---|
| 비밀번호 | ✗ (금지) | ✅ 반드시 ${DB_PASSWORD} 등 |
| Host / Port / Database / User | ✅ 가능 | ✅ 가능 — ${DB_HOST}, ${DB_NAME}, ${DB_USER} 등 |
- 본 가이드의 각 dialect 연결 정보 표는 평문 예시 로 적었지만, 어떤 필드든
${VAR}placeholder 로 치환 가능합니다. 그 경우 secrets 파일 (/etc/mcp-connector/secrets/*.env) 에 같은 이름의 변수도 함께 추가하세요. - 사내 보안팀이 토폴로지 (호스트/DB 이름/계정명) 평문 저장도 금지 한다면 모두 placeholder 로, 그렇지 않으면 비밀번호만 placeholder — 두 방식 다 정상 동작.
- 자세한 정책은 Toolkit 사용 가이드 §3 참고.
1. PostgreSQL
1-1. 읽기 전용 사용자 생성
-- 슈퍼유저로 접속
CREATE USER mcp_reader WITH PASSWORD 'Pa55word!2024';
GRANT CONNECT ON DATABASE erp TO mcp_reader;
\c erp
GRANT USAGE ON SCHEMA public TO mcp_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO mcp_reader;
-- 미래 생성될 테이블도 자동 SELECT 권한
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO mcp_reader;
1-2. 노출 범위 좁히기 (선택)
특정 테이블만 노출:
REVOKE SELECT ON ALL TABLES IN SCHEMA public FROM mcp_reader;
GRANT SELECT ON public.orders, public.customers TO mcp_reader;
비즈니스 view 만 노출 (가장 안전):
CREATE VIEW analytics.v_orders_summary AS
SELECT id, customer_id, total, created_at FROM orders;
GRANT USAGE ON SCHEMA analytics TO mcp_reader;
GRANT SELECT ON analytics.v_orders_summary TO mcp_reader;
1-3. 연결 정보 (Studio 폼 입력값)
| 필드 | 값 |
|---|---|
| Host | pg-erp.internal |
| Port | 5432 |
| Database | erp |
| User | mcp_reader |
| 비밀번호 | ${DB_PASSWORD} |
| SSL | 사용 (CA 검증 없음) — 사내 자체서명일 때<br>사용 (시스템 CA) — Let's Encrypt 등 공인 CA |
1-4. secrets 파일
/etc/mcp-connector/secrets/pg.env:
DB_PASSWORD=Pa55word!2024
1-5. 사전 연결 테스트 (커넥터 호스트에서)
psql "postgres://mcp_reader:Pa55word!2024@pg-erp.internal:5432/erp" -c "SELECT 1"
# 출력: ?column? \n ---------- \n 1
1-6. 트러블슈팅
| 증상 | 원인 / 해결 |
|---|---|
password authentication failed | 사용자/비밀번호 재확인 — \password 로 재설정 가능 |
connection refused | PG 의 pg_hba.conf 에 커넥터 호스트 IP 허용 라인 추가 필요 |
permission denied for table X | GRANT SELECT 누락 — 위 1-1 절 다시 |
SSL connection failed | pg_hba.conf 의 method 가 hostssl 이면 SSL 필수. Studio 의 SSL 옵션 require 이상으로 |
2. MySQL / MariaDB
2-1. 읽기 전용 사용자 생성
CREATE USER 'mcp_reader'@'%' IDENTIFIED BY 'Pa55word!2024';
GRANT SELECT ON appdb.* TO 'mcp_reader'@'%';
FLUSH PRIVILEGES;
2-2. 노출 범위 좁히기
-- 특정 테이블만
GRANT SELECT ON appdb.orders, appdb.customers TO 'mcp_reader'@'%';
-- view 만 (권장)
CREATE VIEW appdb.v_orders_summary AS
SELECT id, customer_id, total, created_at FROM orders;
GRANT SELECT ON appdb.v_orders_summary TO 'mcp_reader'@'%';
2-3. 연결 정보
| 필드 | 값 |
|---|---|
| Host | mysql-app.internal |
| Port | 3306 |
| Database | appdb |
| User | mcp_reader |
| 비밀번호 | ${DB_PASSWORD} |
| SSL | 사용 (CA 검증 없음) 권장 |
2-4. secrets 파일
/etc/mcp-connector/secrets/mysql.env:
DB_PASSWORD=Pa55word!2024
2-5. 사전 연결 테스트
mysql -h mysql-app.internal -P 3306 -u mcp_reader -p'Pa55word!2024' appdb -e "SELECT 1"
2-6. 트러블슈팅
| 증상 | 원인 / 해결 |
|---|---|
Access denied for user 'mcp_reader'@'커넥터호스트' | 'mcp_reader'@'%' 가 아닌 특정 호스트만 허용된 사용자. % 또는 커넥터 호스트 IP 명시 |
Unknown database 'appdb' | DB 이름 오타 — 대소문자 구분 (SHOW DATABASES; 확인) |
MySQL 5.7 + caching_sha2_password 인증 오류 | 커넥터의 mysql2 드라이버 호환. 비밀번호를 mysql_native_password 로 재설정 또는 MySQL 8 권장 |
| TLS handshake error | SSL 옵션 mismatch — MySQL 의 require_secure_transport=ON 이면 SSL require 필수 |
3. MS SQL Server
3-1. 읽기 전용 로그인 + 사용자 생성
USE master;
CREATE LOGIN mcp_reader WITH PASSWORD = 'Pa55word!2024';
USE ERPProd;
CREATE USER mcp_reader FOR LOGIN mcp_reader;
-- 데이터베이스 전체 읽기
EXEC sp_addrolemember 'db_datareader', 'mcp_reader';
3-2. 노출 범위 좁히기
특정 스키마만:
USE ERPProd;
REVOKE SELECT FROM mcp_reader; -- db_datareader 제거
GRANT SELECT ON SCHEMA::dbo TO mcp_reader;
특정 테이블 / view 만:
GRANT SELECT ON dbo.orders TO mcp_reader;
GRANT SELECT ON dbo.v_summary TO mcp_reader;
3-3. 연결 정보
| 필드 | 값 |
|---|---|
| Host | mssql-erp.internal |
| Port | 1433 |
| Database | ERPProd |
| User | mcp_reader |
| 비밀번호 | ${MSSQL_PASS} |
| SSL | 사용 (CA 검증 없음) 또는 사용 안함 (사내 네트워크) |
3-4. secrets 파일
/etc/mcp-connector/secrets/mssql.env:
MSSQL_PASS=Pa55word!2024
비밀번호에
@가 들어가면 SQL Server 연결 문자열에서 따옴표 escape 가 까다로움. 가능하면@제외한 강력한 비밀번호 사용.
3-5. 사전 연결 테스트
# sqlcmd (microsoft/mssql-tools 이미지) 또는 사내 환경의 SQL 도구
docker run --rm -it mcr.microsoft.com/mssql-tools \
/opt/mssql-tools/bin/sqlcmd \
-S mssql-erp.internal,1433 -U mcp_reader -P 'Pa55word!2024' \
-d ERPProd -Q "SELECT 1"
3-6. 트러블슈팅
| 증상 | 원인 / 해결 |
|---|---|
Login failed for user 'mcp_reader' | SQL Server 인증 모드 (Windows / Mixed) 확인 — Mixed Mode 필수 |
Cannot open database "ERPProd" | 사용자가 그 DB 의 사용자로 추가 안 됨 — USE ERPProd; CREATE USER 다시 |
| TLS handshake (encrypted connection) | SQL Server 2019+ 는 default 암호화. Studio SSL 옵션 require 권장 |
SELECT ... TOP 100 외 결과 잘림 | 정상 동작 — execute_query 가 100 행 제한 (안전 측면) |
4. Oracle DB
4-1. 읽기 전용 사용자 생성
-- DBA 로 접속
CREATE USER mcp_reader IDENTIFIED BY "Pa55word!2024"
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
QUOTA 0 ON users;
GRANT CREATE SESSION TO mcp_reader;
-- 특정 스키마 / 테이블 SELECT 권한
GRANT SELECT ON erp_owner.orders TO mcp_reader;
GRANT SELECT ON erp_owner.customers TO mcp_reader;
GRANT SELECT ON erp_owner.v_summary TO mcp_reader;
4-2. SERVICE_NAME 확인 (중요)
Oracle 은 SID 가 아닌 SERVICE_NAME 사용:
SELECT value FROM v$parameter WHERE name = 'service_names';
-- 또는
SHOW PARAMETER service_names;
출력 예: ERPSVC, XEPDB1, FREEPDB1 등
4-3. 연결 정보
| 필드 | 값 |
|---|---|
| Host | oracle-erp.internal |
| Port | 1521 |
| Database | SERVICE_NAME (위에서 확인한 값) |
| User | mcp_reader |
| 비밀번호 | ${ORACLE_PASS} |
| SSL | 사용 안함 (사내 네트워크) 또는 사용 (CA 검증 없음) (TCPS) |
미리보기에 표시되는 baseUrl:
oracle://mcp_reader:${ORACLE_PASS}@oracle-erp.internal:1521/ERPSVC
4-4. secrets 파일
/etc/mcp-connector/secrets/oracle.env:
ORACLE_PASS=Pa55word!2024
4-5. 사전 연결 테스트
# sqlplus 가 있을 때
sqlplus 'mcp_reader/"Pa55word!2024"@//oracle-erp.internal:1521/ERPSVC'
# 비밀번호의 특수문자는 따옴표로 감싸기
# 또는 docker 로
docker run --rm -it gvenzl/oracle-free:23-slim sqlplus \
'mcp_reader/Pa55word!2024@//oracle-erp.internal:1521/ERPSVC'
4-6. Oracle 버전 호환
| Oracle 버전 | 우리 커넥터 호환 |
|---|---|
| 12c (12.1+) / 18c / 19c / 21c / 23ai | ✅ 호환 (Thin 모드 자동) |
| 11g 이하 (2013 이전 release) | ❌ 별도 Thick 모드 이미지 필요 — 별도 문의 |
우리 커넥터는
oracledbv6 Thin 모드 사용 — Instant Client 설치 불필요. 단 Oracle 11g 이하는 미지원 (보안 패치 EOL 이라 사실상 거의 없음).
4-7. 트러블슈팅
| 증상 | 원인 / 해결 |
|---|---|
ORA-12154: TNS could not resolve | 4-3 의 baseUrl 형식 오류. //host:port/SERVICE_NAME 형식 확인 |
ORA-12541: TNS:no listener | 1521 포트 차단 — 사내 방화벽 / DB 호스트 listener 상태 확인 |
ORA-01017: invalid username/password | 비밀번호 특수문자. secrets 파일에 따옴표 없이 그대로 (escape X) |
ORA-00942: table or view does not exist | GRANT SELECT 누락. erp_owner schema 의 객체는 fully qualified (erp_owner.orders) 로 권한 부여 |
| LOB / CLOB 컬럼이 깨짐 | 안전상 large object 는 string 변환 — 너무 크면 truncate. SELECT ... DBMS_LOB.SUBSTR(...) 로 좁히기 |
5. DB 4종 공통 점검 체크리스트
새 DB 툴킷 만들기 전:
- 읽기 전용 사용자 생성 (DDL/DML 권한 없음)
- 노출할 스키마 / 테이블만 GRANT
- 비밀번호 강도 충분 (특수문자 포함,
@가급적 회피) - 커넥터 호스트에서 DB 호스트로 telnet / 사내 SQL 도구로 직접 연결 가능
- SSL 정책 결정 (사내 사설 인증서 → CA 검증 없음 / 공인 → 검증 사용)
- secrets 파일 권한 600, 폴더 700
- Studio 폼의 비밀번호 필드 =
${VAR}placeholder (평문 금지). Host / Database / User 는 정책에 따라 평문 또는 placeholder - 사용자 운영 모니터링 — DB 측 audit log 도 같이 기록 권장
6. AI 뷰 추천 (가상 뷰)
DB 툴킷은 기본으로 두 가지 도구 (describe_schema · execute_query) 를 제공합니다 — AI 가 스키마를 직접 보고 SQL 을 짜는 자유 질의 방식입니다. 여기에 더해, 자주 쓰는 조회를 이름 붙은 가상 뷰 도구로 만들 수 있습니다. 두 방식은 함께 쓸 수 있고, 뷰를 추가해도 자유 질의 도구는 그대로 남습니다.
가상 뷰의 장점
- 반복 업무에서 매번 SQL 을 새로 짜지 않아 안정적입니다
- "일별 매출 집계" 처럼 업무 언어로 대화할 수 있습니다
- 뷰에 적힌 컬럼만 AI 에 보여주므로 개인정보 노출이 줄어듭니다 (데이터베이스에는 아무것도 만들지 않습니다 — 뷰는 커넥터에 저장된 이름 붙은 SQL 입니다)
사용 방법 (Studio → DB 툴킷 상세 → 도구 탭)
- AI 뷰 추천 받기 — 업무 설명 한 줄 (선택) 을 넣으면 AI 가 스키마를 분석해 뷰 후보를 제안합니다. 개인정보로 보이는 컬럼 (이메일 · 전화번호 등) 은 기본으로 제외되고, 제외된 컬럼과 사유가 카드에 표시됩니다.
- 검증 실행 — 후보의 SQL 을 1행만 실제로 실행해 문법 · 컬럼 오류를 미리 확인합니다.
- 도구로 등록 — 클릭하면 이 뷰가 툴킷의 도구 목록에 추가됩니다.
- 뷰 정의 복사 → 붙여넣기 — 카드의 [뷰 정의 복사] 버튼은
"이름": { ... }형태의 조각(바깥 중괄호 없음)을 복사합니다. 이미/etc/mcp-connector/secrets/db-views.json파일이 있다면 파일의{ }안에 그대로 붙여넣으세요 (항목 사이에는 쉼표가 필요합니다). 파일을 처음 만드는 경우엔 후보 목록 아래 [파일 전체 복사] 버튼으로 지금 보이는 모든 후보를 완전한 JSON 파일 형태로 한 번에 복사해 저장하세요 (단, 이미 직접 추가한 항목이 있는 파일이면 통째로 덮어쓰지 말고 필요한 항목만 옮기세요). 파일 저장 즉시 반영되며 재시작이 필요 없습니다.
{
"daily_sales_summary": {
"description": "지정한 기간의 일별 주문 건수와 총 매출액 집계",
"sql": "SELECT date_trunc('day', ordered_at) AS order_date, count(*) AS order_count, sum(amount) AS total_amount FROM orders WHERE ordered_at BETWEEN $1 AND $2 GROUP BY 1 ORDER BY 1",
"params": [
{ "name": "start_date", "type": "string", "description": "집계 시작일 (ISO 8601)" },
{ "name": "end_date", "type": "string", "description": "집계 종료일 (ISO 8601)" }
]
}
}
권한 안내 — AI 는 계정에 SELECT 권한이 있는 테이블만 볼 수 있습니다. 읽기 전용 계정 + 업무 스키마 SELECT 권한을 권장하며, 민감 테이블 (급여 · 인사 등) 은 계정 권한에서 제외하면 원천 차단됩니다 (위 1-1 · 1-2 절 참고).
7. 문의
- DB 권한 / 사내 정책 협의: 사내 DBA / 보안 담당자
- 도구 설명 정확도 / 호출 빈도 튜닝: WRKS 담당자
같이 보세요:
- 툴킷 사용 → Toolkit 사용 가이드
- 커넥터 설치 → Connector 설치 가이드