db-query-mcp
# db-query-mcp
Claude Code(또는 다른 AI)에서 사용하는 자체 제작 DB 쿼리 실행 MCP 서버 (MySQL / MariaDB).
## 설계 원칙 (보안)
1. **접속 정보는 AI에게 절대 노출되지 않는다.**
- `db-connection-env`(host/user/password)는 MCP 서버 프로세스 내부에서만 읽는다.
- AI가 볼 수 있는 것은 `db-connection-list`의 **번호 + 별칭**뿐이다.
2. **설정 파일 생성에 AI가 개입하지 않는다.**
- `npm run setup`을 사용자가 터미널에서 직접 실행해 생성한다. MCP 도구로 노출되지 않는다.
3. **DML/DDL은 사용자 승인 후에만 실행된다.**
- 읽기 쿼리(`run_select_query`)와 변경 쿼리(`run_write_query`)를 별도 도구로 분리.
- Claude Code 권한 설정에서 `run_write_query`를 `ask`로 두면 실행 직전 화면에서 직접 승인.
4. 다중 문장 실행 차단(`SELECT 1; DROP ...` 불가), 결과 최대 50행, SELECT 타임아웃 90/120/150초(최대 3회 재시도)·WRITE 150초(단일 시도).
5. `SELECT ... INTO OUTFILE/DUMPFILE`은 첫 키워드가 SELECT여도 DB 서버에 파일을 쓰므로 읽기 쿼리에서 차단한다. `readonly` 차단은 도구가 아니라 실행 계층에서 강제되어 어떤 경로로도 우회되지 않는다.
## 설정 파일 (~/.db-query-mcp/)
```
# db-connection-list (번호=별칭)
1=로컬 개발 DB
2=운영 DB
# db-connection-env (번호.key=value)
1.host=localhost
1.port=3306
1.user=devuser
1.password=****
1.database=mg_service
# 선택 옵션
2.host=10.0.0.5
2.user=readonly_user
2.password=****
2.ssl=true # true=인증서 검증, skip-verify=자체서명 허용, 생략=TLS 미사용
2.readonly=true # true면 변경 쿼리(run_write_query)를 서버가 강제 차단
```
> `ssl`·`readonly`은 `npm run setup` 실행 시 질문으로 입력받아 자동 기록된다.
## 설치 (Windows / macOS 공통)
### GitHub에서 설치 (가장 간단)
이 저장소가 곧 Claude Code 플러그인 마켓플레이스입니다. 실행에 필요한 번들(`dist/*.mjs`)이 저장소에 포함되어 있어 **clone·npm install·빌드 없이** 바로 설치됩니다.
*1단계 — 마켓플레이스를 등록합니다.* Claude Code 세션에서:
```
/plugin marketplace add mark3lim/db_query_mcp
```
*2단계 — 플러그인을 설치합니다.*
```
/plugin install db-query@db-query-marketplace
```
설치 범위(user / project / local)를 물어보면 선택합니다. 범위별 차이는 아래 [방법 B의 표](#방법-b--plugin-install-로컬-마켓플레이스-등록)와 같습니다.
*3단계 — 세션을 새로 시작합니다.* stdio MCP 서버의 도구는 세션 시작 시 인식됩니다.
*4단계 — 확인합니다.*
```
/mcp # db-query 가 connected 인지, 도구가 보이는지 확인
```
*5단계 — DB 접속 정보를 등록합니다.* 플러그인 설치는 MCP 도구 등록까지만 합니다. 접속 정보(ID/PW)는 보안상 AI가 만들지 않으므로 **터미널에서 직접** 한 번 실행해야 합니다.
```bash
# 저장소를 받아 setup 실행 (npm install 불필요 — 번들이 포함되어 있음)
git clone https://github.com/mark3lim/db_query_mcp.git
node db_query_mcp/dist/setup.mjs
```
접속 정보는 `~/.db-query-mcp/`(홈)에 저장되므로, **setup을 실행한 폴더 위치는 상관없습니다.** 등록만 끝나면 clone한 폴더는 지워도 플러그인은 정상 동작합니다. 별칭만 바꾸려면 같은 방식으로 `node db_query_mcp/dist/rename.mjs` 를 실행하세요.
*업데이트 / 제거*
```
/plugin update db-query@db-query-marketplace
/plugin uninstall db-query@db-query-marketplace
```
### `/plugin`으로 설치 — 로컬 파일만 사용 (클라우드/깃 불필요)
이 폴더 자체가 Claude Code 플러그인입니다. 의존성을 단일 파일(`dist/bundle.mjs`)로 번들해 두어 **`npm install`/빌드 없이** 바로 동작합니다. 아래 두 방법 모두 **로컬 폴더만** 쓰며, 외부에 올릴 필요가 없습니다.
#### 방법 A — skills 폴더에 넣기 (설치 명령조차 없음, 가장 간단)
압축 푼 폴더를 통째로 아래 위치에 두기만 하면 됩니다. 마켓플레이스 등록도, 설치 명령도 필요 없고, **그 자리에서 그대로 로드**됩니다(캐시 복사 안 함).
```
~/.claude/skills/db-query/
```
이 폴더 안에 `.claude-plugin/plugin.json` 과 `.mcp.json` 이 있으면 됩니다(압축에 포함되어 있음). 폴더를 넣은 뒤:
1. Claude Code를 재시작(또는 새 세션 시작)합니다.
2. `/mcp` 로 `db-query` 서버가 connected 인지, 도구(`list_connections` 등)가 보이는지 확인합니다.
3. DB 접속 정보를 한 번 등록합니다(아래 "접속 정보 등록" 참고).
> 이 방식은 항상 `~/.claude/skills/` 에 둔 그 폴더를 직접 실행합니다. 폴더를 옮기거나 지우면 동작이 멈춥니다.
#### 방법 B — `/plugin install` (로컬 마켓플레이스 등록)
`/plugin install`을 쓰고 싶다면, 깃 없이 **로컬 폴더 경로**로 마켓플레이스를 등록하면 됩니다.
*1단계 — 폴더를 고정 위치에 둡니다.* 예: `~/tools/db-query`. (마켓플레이스 등록·업데이트의 출처가 되므로 옮기거나 지우지 마세요.)
*2단계 — 로컬 경로로 마켓플레이스를 등록합니다.* git URL이 아니라 **폴더 절대경로**를 줍니다.
```
/plugin marketplace add /절대경로/db-query
```
> 대화형으로 하려면 `/plugin` → `Marketplaces` 탭 → `+ Add Marketplace` 에서 로컬 폴더 경로를 입력해도 됩니다.
*3단계 — 플러그인을 설치합니다.* (마켓플레이스 이름 `db-query-marketplace`, 플러그인 이름 `db-query`)
```
/plugin install db-query@db-query-marketplace
```
*4단계 — 설치 범위를 선택합니다.* 설치 시 Claude Code가 범위를 물어봅니다.
| 범위 | 적용 대상 | 저장 위치 |
|---|---|---|
| user | 내 모든 프로젝트 | `~/.claude/settings.json` |
| project | 이 프로젝트(레포로 공유) | `.claude/settings.json` |
| local | 이 프로젝트의 나만(gitignore) | `.claude/settings.local.json` |
*5단계 — 세션을 새로 시작합니다.* stdio MCP 서버의 도구는 세션 시작 시 인식됩니다. 세션 도중 설치했다면 재시작(또는 `/reload-plugins`)하세요.
*6단계 — 확인합니다.*
```
/plugin # Installed 탭에서 db-query 가 enabled 인지 확인
/mcp # db-query 서버가 connected 인지, 도구가 보이는지 확인
```
도구가 0개로 나오면 5단계(세션 재시작)를 다시 하세요.
> 참고: `/plugin install`로 설치하면 플러그인이 `~/.claude/plugins/cache/` 로 **복사**되어 실행됩니다. 번들이 폴더 안에 self-contained 라 복사돼도 정상 동작합니다. 다만 업데이트(`/plugin update`)를 위해 원본 폴더는 그대로 두는 게 좋습니다. 복사가 싫고 "그 자리 실행"을 원하면 방법 A를 쓰세요.
*관리 명령(참고)*
```
/plugin list # 설치된 플러그인 목록
/plugin update db-query@db-query-marketplace # 업데이트
/plugin uninstall db-query@db-query-marketplace # 제거
/plugin marketplace remove db-query-marketplace # 마켓플레이스 제거
```
#### 접속 정보 등록 (두 방법 공통, 한 번만)
플러그인 설치는 MCP 도구 등록까지만 합니다. DB 접속 정보(ID/PW)는 보안상 AI가 만들지 않으므로, **터미널에서 한 번 직접** 등록하세요. `setup.js`는 외부 라이브러리 없이 Node 기본 기능만 쓰므로 `npm install` 없이 바로 실행됩니다. 접속 정보는 `~/.db-query-mcp/` (홈)에 저장되어 폴더 위치와 무관합니다.
```
# 방법 A(skills 폴더)
node ~/.claude/skills/db-query/dist/setup.mjs
# 방법 B(고정 위치)
node /절대경로/db-query/dist/setup.mjs
```
별칭만 바꾸려면 같은 폴더에서 `node dist/rename.mjs` 를 실행하세요.
> `setup.js`는 외부 라이브러리 없이 Node 기본 기능만 쓰므로 `npm install` 없이 바로 실행됩니다. 연결 별칭만 바꾸려면 같은 폴더에서 `node dist/rename.js` 를 실행하세요.
압축을 푼 폴더에서 아래를 실행하면 라이브러리 설치 + 빌드가 자동으로 끝나고, 다음 단계 명령이 화면에 안내됩니다.
```bash
# macOS / Linux
bash install.sh
# Windows: 탐색기에서 install.bat 더블클릭, 또는
install.bat
```
실행하면 **등록 범위(user / project / local)를 물어보고**, 선택한 범위로 `claude mcp add`까지 자동 실행합니다(claude CLI가 PATH에 있을 때). project/local은 실행한 폴더 기준으로 등록되니, 본인 프로젝트 폴더에서 실행하세요.
### 수동 설치 (단계별)
```bash
# 1. 의존성 설치 및 빌드
cd db-query-mcp
npm install
npm run build
# 2. DB 연결 등록 (대화형 — 반드시 사용자가 직접 실행)
npm run setup
# 3. Claude Code에 등록 (절대 경로 사용, --scope로 범위 선택)
# --scope user : 모든 프로젝트 (기본)
# --scope project : 이 프로젝트만 (.mcp.json, 팀 공유)
# --scope local : 이 프로젝트 개인용 (gitignore)
# macOS/Linux
claude mcp add --scope user --transport stdio db-query -- node /절대경로/db-query-mcp/dist/index.js
# Windows (PowerShell)
claude mcp add --scope user --transport stdio db-query -- node C:\절대경로\db-query-mcp\dist\index.js
# 4. 등록 확인
claude mcp list
```
## 권한 설정 (DML/DDL 사용자 확인)
`~/.claude/settings.json` 또는 프로젝트의 `.claude/settings.json`:
```json
{
"permissions": {
"allow": [
"mcp__db-query__list_connections",
"mcp__db-query__run_select_query"
],
"ask": [
"mcp__db-query__run_write_query"
]
}
}
```
- SELECT 계열은 자동 실행 → 생산성 확보
- INSERT/UPDATE/DELETE/DDL은 매번 화면에서 사용자가 직접 승인 → 안전성 확보
## 제공 도구
| 도구 | 설명 |
|---|---|
| `list_connections` | 번호+별칭 목록 조회 (접속 정보 비노출) |
| `run_select_query(connection_no, query)` | 읽기 쿼리(SELECT/SHOW/DESC/EXPLAIN, `WITH...SELECT`, 괄호로 시작하는 `(SELECT...)` 포함) 실행. 결과는 최대 50행(스트리밍 적재), 90/120/150초 3회 재시도 |
| `run_write_query(connection_no, query)` | DML/DDL 실행. read-only 연결은 서버가 차단, 그 외에도 권한 설정(ask)으로 화면 승인 권장 |
| `test_connection(connection_no)` | 접속 가능 여부만 확인(SELECT 1). 데이터·접속정보 비노출 |
| `get_recent_queries()` | 최근 실행 쿼리(select/write) 최대 10개를 최신순으로 반환 |
| `get_management_commands(task?)` | AI가 직접 못 하는 관리 작업(연결 추가/수정/삭제·별칭 변경)의 실행 명령어를 정확한 경로와 함께 안내 |
> `get_management_commands`는 사용자가 "DB 추가해줘", "별칭 바꿔줘"처럼 AI가 보안상 수행할 수 없는
> 작업을 요청할 때, AI가 호출해서 **실제 프로젝트 경로가 들어간 명령어**를 사용자에게 안내하는 용도입니다.
> 직접 작업을 수행하지는 않습니다.
## 보안·안정성 처리
- **에러 마스킹**: DB 에러 메시지의 host/port/user는 `***`로 가려 응답에 노출되지 않는다.
- **read-only 연결**: `N.readonly=true`인 연결은 권한 설정과 무관하게 서버가 변경 쿼리를 차단한다.
- **대용량 SELECT**: 스트리밍으로 최대 50행만 메모리에 적재해 OOM을 방지한다.
- **SELECT 타임아웃·재시도**: 90초 → 120초 → 150초로 최대 3번 시도한다. 시간 초과일 때만 더 긴 타임아웃으로 재시도하며(SQL 에러는 즉시 반환), 3번 모두 초과하면 사용자에게 알린다.
- **WRITE 타임아웃**: 단일 시도(150초). 타임아웃 후 자동 재시도는 중복 적용(이중 INSERT/UPDATE) 위험이 있어 하지 않는다.
- **타입 직렬화**: BIGINT는 문자열로, BLOB/바이너리는 `<BLOB n bytes>`로 안전하게 표기한다.
- **TLS**: `N.ssl=true`(검증) / `skip-verify`(자체서명 허용)로 원격 DB 암호화 연결을 지원한다.
- **쿼리 로그**: 최근 10개(시각·연결번호·종류·성공여부·쿼리문)를 `~/.db-query-mcp/query-log.json`(권한 600)에 보관한다. 쿼리 결과와 접속 정보는 저장하지 않는다.
```
사용자: notification 테이블 최근 10건 조회해줘
AI: list_connections 호출 → "1. 로컬 개발 DB / 2. 운영 DB 중 어디에 연결할까요?"
사용자: 1번
AI: run_select_query("1", "SELECT * FROM notification ORDER BY id DESC LIMIT 10")
→ 결과 표시
```
## 연결 추가/수정
- **연결 추가 / 접속 정보 변경**: `npm run setup`을 다시 실행. 같은 번호를 입력하면 기존 정보를 덮어쓴다.
- **별칭만 수정**: `npm run rename` 실행. 등록된 목록에서 번호를 고르고 새 별칭을 입력하면 된다.
접속 정보(`db-connection-env`)는 건드리지 않고 `db-connection-list`의 별칭만 바꾼다.
- **삭제**: 두 파일에서 해당 번호 줄을 직접 지우면 된다.
> `setup`, `rename` 모두 터미널에서 사용자가 직접 실행하며 MCP 도구로 노출되지 않는다.
> 따라서 별칭 수정 과정에도 AI/서버 통신이 개입하지 않는다.
TDQS
Scored across 6 tools
Each tool has a distinctly different purpose: listing connections, testing connections, running read-only queries, running write queries, fetching management commands, and retrieving recent queries. There is no meaningful overlap that would confuse an agent's tool selection.
All tool names follow a consistent snake_case verb_noun pattern (list_connections, run_select_query, test_connection, run_write_query, get_management_commands, get_recent_queries). The naming clearly signals the action and target of each tool.
Six tools is well-scoped for a DB query MCP server. Each tool covers a necessary part of the workflow—connection discovery, connectivity checks, read/write query execution, management guidance, and query history—without unnecessary bloat.
The tool surface covers the core DB interaction lifecycle: list connections, test availability, run read queries, run write queries, and review recent queries. Connection management is intentionally delegated to terminal commands, and the provided tool properly guides users through that process, so there are no obvious dead ends.