Skip to main content
Glama
TaeheeLim

DBMS-MCP

by TaeheeLim

범용 JDBC MCP 서버

Claude -> 이 MCP 서버 -> 임의의 JDBC DB 구조의 데이터베이스 도구. 조회(SELECT/WITH)와 변경(INSERT/UPDATE/DELETE/MERGE)을 모두 지원한다(DDL·다중 문장은 차단). JDBC 드라이버 jar 와 접속 URL 만 있으면 Tibero / Oracle / PostgreSQL / MySQL 등 어떤 DB든 동일한 코드로 사용할 수 있다.

구조

.mcp.json         ← 한 번만 설정 (이후 안 건드림). connections.json 위치만 알려줌
   │
connections.json  ← DB 목록을 여기서 관리 (추가/변경 시 이 파일만 수정)
   │
jdbc_mcp.py       ← 호출할 때마다 connections.json 을 다시 읽음 → Claude 재시작 불필요
   │
jars/             ← JDBC 드라이버 jar 모음 (connections.json 의 jars 가 가리킴)

connections.json 에는 IP·계정·비밀번호가 들어가므로 git 에 커밋하지 않는다(.gitignore 포함). 형식은 아래 예시와 connections copy.json(플레이스홀더 템플릿) 을 참고하라.

Related MCP server: mcp-db-server

레지스트리 백엔드 — 파일 / PostgreSQL

연결정보를 어디서 읽을지 REGISTRY_BACKEND 환경변수로 고른다.

백엔드

저장소

비밀번호

PostgreSQL (기본)

postgres

jdbc_group / jdbc_connection 테이블

Fernet 암호문으로 저장, 키는 서버 env(REGISTRY_ENC_KEY)에만

파일

file

connections.json

평문 (파일 권한/.gitignore 로 보호)

두 백엔드 모두 _resolve_profile 이 만드는 프로파일 형태가 같아 도구 동작은 동일하다. default 개념은 없다 — 호출 시 항상 그룹/연결 을 지정하거나, 자연어로 지칭하면 Claude 가 list_connections 로 골라 쓴다.

PostgreSQL 백엔드 설정

# 1) 레지스트리 DB에 스키마 적용
psql "postgresql://user:pw@HOST:5432/mcp_registry" -f schema.sql

# 2) Fernet 키 생성 (출력값을 REGISTRY_ENC_KEY 로 보관)
python migrate_json_to_pg.py --gen-key

# 3) 기존 connections.json 을 PG로 적재 (비밀번호는 자동 암호화)
$env:REGISTRY_PG_DSN  = "postgresql://user:pw@HOST:5432/mcp_registry"
$env:REGISTRY_ENC_KEY = "<위에서 생성한 키>"
python migrate_json_to_pg.py --dry-run    # 먼저 무엇이 들어갈지 확인
python migrate_json_to_pg.py              # 실제 적재 (멱등, 재실행 안전)

관련 env: REGISTRY_PG_DSN(접속), REGISTRY_ENC_KEY(복호화 키), REGISTRY_CACHE_TTL(캐시 초, 기본 30).

  • 연결정보를 SQL 로 수정한 뒤 캐시 TTL 을 기다리지 않으려면 refresh_connections 도구를 호출한다.

  • MCP 서버는 SELECT 권한만 가진 읽기 전용 계정으로 접속하게 하면 레지스트리 변조를 막을 수 있다.

  • REGISTRY_ENC_KEY 는 마이그레이션 스크립트와 MCP 서버가 반드시 동일한 값이어야 복호화된다. 분실 시 비밀번호를 복구할 수 없다.

jars 는 DB에 경로 문자열만 저장되고 실제 jar 파일은 여전히 MCP 서버 호스트의 jars/ 에 있어야 한다. 새 드라이버 jar 를 추가하면 JVM classpath 재초기화를 위해 서버 재시작이 필요하다(백엔드와 무관).

제공 도구

도구

설명

list_connections()

등록된 DB 연결 목록 (name/desc/driver/url/user, 비밀번호 제외)

run_query(sql, connection?)

SQL 실행 — 조회(SELECT/WITH, 행 수 제한) + 변경(INSERT/UPDATE/DELETE/MERGE, 자동 커밋)

list_tables(connection?, schema?)

테이블/뷰 목록 (JDBC 표준 메타데이터)

describe_table(table_name, connection?, schema?)

컬럼 정보 (JDBC 표준 메타데이터)

refresh_connections()

레지스트리 캐시 비우기 (postgres 백엔드에서 수정 즉시 반영용)

  • connection그룹/연결 형식으로 지정한다 (예: tibero7/lcard). 생략 시 사용 가능한 연결 목록을 안내한다.

  • 사용자가 "개발 티베로", "운영 오라클" 같은 자연어로 DB를 지칭하면 Claude 는 먼저 list_connections 로 각 연결의 desc(설명)를 보고 알맞은 그룹/연결 이름을 고른다. 그래서 각 연결에 desc 를 적어두는 것이 중요하다.

사전 준비

  1. JDK/JRE 설치 (jaydebeapi가 JVM을 사용)

    java -version   # 확인
  2. 해당 DB의 JDBC jar 준비 — 이 저장소는 jars/ 폴더에 Tibero6/7, Oracle 드라이버를 포함한다. 다른 DB는 해당 jar 를 jars/ 에 추가한다.

설치

cd <프로젝트_경로>
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt

DB 등록 — connections.json

DB 추가/변경은 이 파일만 수정하면 된다. IP·포트·계정·비밀번호가 바뀌면 이 파일의 값만 고치면 즉시 반영된다(호출 때마다 다시 읽음 → Claude/서버 재시작 불필요). 단, 새 JDBC 드라이버 jar 가 필요한 경우에는 예외다 → 아래 새 DBMS 추가 참고.

구조 — DB그룹 / 연결 (2단계)

connections 아래 DB 종류별 그룹을 두고, 그 안에 여러 연결을 둔다. 각 그룹의 _defaults 는 그 그룹 공통값(driver/jars)이고, 나머지 키는 개별 연결이다. 연결은 _defaults 를 상속하고 겹치는 값(url/user/password)만 덮어쓴다.

연결은 그룹/연결 형식으로 가리킨다 (예: tibero7/dev1).

{
  "default": "tibero7/dev1",          // 그룹/연결 형식. 이름 생략 시 이 연결 사용
  "connections": {
    "tibero7": {
      "_defaults": {                  // tibero7 그룹 공통값
        "driver": "com.tmax.tibero.jdbc.TbDriver",
        "jars":   "jars/tibero7-jdbc.jar"
      },
      "dev1": {
        "desc":     "A 시스템 개발 티베로",   // list_connections 가 보여주는 설명 (자연어 매칭에 사용)
        "url":      "jdbc:tibero:thin:@<DB호스트>:8724:tibero7",
        "user":     "DEV_USER1",
        "password": "..."
      },
      "dev2": {
        "desc":     "B 시스템 개발 티베로",
        "url":      "jdbc:tibero:thin:@<DB호스트>:8724:tibero7",
        "user":     "DEV_USER2",
        "password": "..."
      }
    },
    "oracle": {
      "_defaults": { "driver": "oracle.jdbc.driver.OracleDriver", "jars": "jars/ojdbc-8.jar" },
      "dev1": {
        "desc":     "C 시스템 개발 오라클",
        "url":      "jdbc:oracle:thin:@<DB호스트>:1521:orcl",
        "user":     "DEV_USER3",
        "password": "..."
      }
    }
  }
}
  • 각 연결에 desc 를 적어두면 list_connections 결과에 노출되어 자연어로 DB를 고를 때 쓰인다.

  • 같은 DB의 다른 환경(개발/테스트/운영)이나 다른 계정은 같은 그룹 안에 연결을 더 추가하면 된다.

  • _defaults 는 예약 키다 — 연결 이름으로 쓸 수 없다.

  • 특정 연결만 driver/jars 가 다르면 그 연결에 직접 적으면 _defaults 를 덮어쓴다.

DB별 driver / url 예시

DB

driver

url

Tibero

com.tmax.tibero.jdbc.TbDriver

jdbc:tibero:thin:@host:8629:tibero

Oracle

oracle.jdbc.driver.OracleDriver

jdbc:oracle:thin:@host:1521:ORCL

PostgreSQL

org.postgresql.Driver

jdbc:postgresql://host:5432/db

MySQL

com.mysql.cj.jdbc.Driver

jdbc:mysql://host:3306/db

MariaDB

org.mariadb.jdbc.Driver

jdbc:mariadb://host:3306/db

  • jars 경로는 상대경로면 connections.json 이 있는 폴더 기준으로 해석된다(예: jars/ojdbc-8.jar). 절대경로도 가능하다.

  • jar 가 여러 개면 ; 또는 , 로 구분하거나 배열로 적어도 된다.

  • 서버는 등록된 모든 jar 를 한 classpath 에 올리므로, 어떤 연결을 먼저 호출하든 모든 드라이버를 쓸 수 있다.

새 연결 / 새 DBMS 추가 시

상황

필요한 작업

재시작

기존 그룹과 같은 드라이버(jar) 를 쓰는 연결 추가 (예: 티베로 계정 하나 더)

connections.json 에 연결 항목 추가

불필요 (다음 호출에 즉시 반영)

새 드라이버 jar 가 필요한 DBMS 추가 (예: 처음으로 MySQL 추가)

jar 를 jars/ 에 넣고 connections.json 에 그룹/연결 추가

필요

새 jar 가 재시작을 요구하는 이유: JVM 의 classpath 는 첫 DB 연결 때 한 번만 고정된다. 이미 서버가 떠서 한 번이라도 연결을 맺은 뒤 새 jar 를 추가하면 그 jar 는 classpath 에 올라가지 않는다. 따라서 새 드라이버를 추가했으면 서버 프로세스(또는 컨테이너)를 재기동해야 한다.

  • 로컬 stdio: Claude Code 를 재시작(MCP 서버 재기동).

  • Docker: docker compose restart jdbc-mcp.

  • systemd: sudo systemctl restart jdbc-mcp.

연결 먼저 검증

python test_connection.py                 # default 연결
python test_connection.py tibero7/dev1     # 특정 연결 (그룹/연결 형식)

연결 목록 → 접속 → 테이블 조회 → 읽기 전용 검증의 4단계 점검이 모두 통과하면 붙일 준비 끝.

Claude Code에 등록 (로컬 단독 / stdio)

.mcp.json 은 한 번만 설정한다(이미 생성됨, git 에는 올리지 않음):

{
  "mcpServers": {
    "jdbc": {
      "command": "python",
      "args": ["<프로젝트_경로>\\jdbc_mcp.py"],
      "env": {
        "JDBC_CONNECTIONS": "<프로젝트_경로>\\connections.json",
        "DB_MAX_ROWS": "200"
      }
    }
  }
}

이 폴더에서 Claude Code 실행 시 jdbc 서버가 자동 인식된다. /mcp 로 상태 확인.

두 가지 사용 모드

모드

전송

용도

방법

로컬 단독

stdio

내 PC에서 혼자 사용/개발

.mcp.json (기본값)

팀 공용

HTTP

서버에 배포해 팀원이 함께 사용

아래 팀 공용 배포 (Docker) — 자세히는 DEPLOY.md

팀 공용 배포 — HTTP

서버를 한 번 띄워두고 팀원은 각자 Claude Code 에서 URL 만 등록해 함께 쓴다. 서버는 MCP_TRANSPORT=http 로 실행되어 http://<서버IP>:8000/mcp 로 노출된다.

팀원 PC들의 Claude Code ──HTTP──► [서버: jdbc_mcp.py + JDK + jars] ──JDBC──► DB

Docker 로 배포 (권장)

이 저장소의 Dockerfile / docker-compose.yml 를 그대로 쓴다. 코드(jdbc_mcp.py)만 이미지에 굽고, connections.jsonjars/ 는 read-only 볼륨으로 마운트한다 — 비밀번호가 이미지에 박히지 않고, 접속 정보를 고쳐도 재빌드가 필요 없다.

  1. 서버에 Docker / Docker Compose 설치, 저장소 파일 배치.

  2. connections.json 준비 — jar 는 상대경로 jars/... 로 적는다(컨테이너 안 /app/jars 로 마운트됨). 서버에서 각 DB 로 네트워크 접속이 되는지 먼저 확인.

  3. 빌드 & 기동:

    docker compose up -d --build
    docker compose logs -f jdbc-mcp     # 로그 확인
  4. http://<서버IP>:8000/mcp 로 노출된다. 방화벽에서 사내망에만 8000 포트를 연다.

운영 중 변경 시:

변경 내용

명령

connections.json 값 수정(기존 드라이버)

없음 — 다음 호출에 즉시 반영

jars/새 드라이버 jar 추가

docker compose restart jdbc-mcp (JVM classpath 재초기화)

코드(jdbc_mcp.py) 수정

docker compose up -d --build (이미지 재빌드)

환경변수(MCP_PORT, DB_MAX_ROWS 등)는 docker-compose.yml 에서 조정한다.

팀원 등록

각 팀원 PC 에서(설치할 것 없음, URL 만 등록):

claude mcp add --transport http jdbc http://<서버IP>:8000/mcp

등록 후 /mcp 로 연결 확인.

사용 예 (자연어)

  • "등록된 DB 연결 뭐뭐 있어?" → list_connections

  • "USER 테이블에 데이터 몇 건이야?" → default 연결로 run_query

안전장치

  • 허용 문장: 조회(SELECT/WITH) + 변경(INSERT/UPDATE/DELETE/MERGE). DDL(CREATE/DROP/ALTER/TRUNCATE)은 차단.

  • 다중 문장 차단: ; 로 이어붙인 쿼리 거부

  • 조회 행 수 제한: DB_MAX_ROWS (기본 200)

  • 변경 문장은 자동 커밋되어 되돌릴 수 없다. UPDATE/DELETE 는 WHERE 절 누락 시 전체 행이 바뀌므로 주의.

  • 권장: DB 계정 권한을 실제 필요한 범위로 제한하라. 조회만 필요한 연결은 읽기 전용 계정을 쓰면 코드 차단과 DB 권한으로 이중 방어가 된다.

보안 주의

  • connections.json 에는 비밀번호가 들어 있으므로 git 등에 커밋하지 말 것 (.gitignore 에 포함됨).

  • HTTP(팀 공용) 모드는 사내망에서만 접근 가능하도록 방화벽으로 제한한다(외부 인터넷 차단).

  • 더 엄격히 하려면 nginx 리버스 프록시 뒤에 두고 토큰/IP 화이트리스트를 둔다.

Related MCP Connectors

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables interaction with 20+ databases (PostgreSQL, MongoDB, Neo4j, Elasticsearch, Redis, and more) through a single unified interface, allowing cross-database queries and operations via natural language.
    1
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables querying PostgreSQL and MySQL databases using natural language, with RESTful endpoints for listing tables, describing schemas, and executing read-only queries.
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables secure, read-only PostgreSQL database interaction through natural language, with automatic database discovery and connection management.
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language querying of SQL databases using AI, supporting multiple database types and automatic schema discovery.
    1
    MIT