JAMYPG NL2SQL MCP
Go-based MCP server for metadata-grounded NL2SQL over PostgreSQL, MySQL, and
MariaDB. Current source version: v0.58.0 (converted from the Oracle-based
jasql project).
The server loads JSON metadata from a dataset directory (e.g. data/metadb,
data/sakila), compiles it into an in-memory catalog, search index, join
graph, prompt registry, and static SQL guardrails, then exposes them through
MCP tools, resources, and prompts. Generated SQL can be executed read-only
against any of the three target engines through pure-Go drivers — no CGO, no
client libraries, no build tags.
Built with Codex and GPT-5.6
JAMYPG was developed through a human-directed AI engineering workflow using OpenAI Codex and GPT-5.6.
How Codex Was Used
Codex served as the primary implementation agent throughout the project. It was used to:
- Explore and understand the existing Go codebase
- Implement MCP tools, resources, prompts, and transport behavior
- Develop metadata catalog, search, and join-graph features
- Add PostgreSQL, MySQL, and MariaDB connectivity
- Implement SQL validation and read-only execution guardrails
- Create REST APIs, administration features, and integration tests
- Refactor duplicated code and improve error handling
- Update technical documentation alongside source-code changes
Development was performed iteratively. Each task was defined with explicit goals and constraints, and Codex generated or modified the relevant code. The resulting changes were then reviewed, tested, and refined before being accepted.
How GPT-5.6 Was Used
GPT-5.6 was used as the architecture, reasoning, and review layer of the development process. It helped with:
- Designing the metadata-grounded NL2SQL architecture
- Defining safe and explainable SQL-generation workflows
- Identifying schema-hallucination and incorrect-join risks
- Designing clarification, validation, and query-execution stages
- Reviewing MCP client compatibility and session behavior
- Developing multi-database abstraction strategies
- Creating test scenarios and evaluation criteria
- Reviewing security, maintainability, and enterprise-readiness
- Improving project documentation and presentation materials
GPT-5.6 was particularly useful for reasoning across multiple system concerns at once, including metadata quality, SQL dialect differences, MCP protocol behavior, database security, and LLM reliability.
Human Oversight
AI-generated changes were not accepted automatically. The project owner remained responsible for:
- Defining product goals and technical requirements
- Reviewing generated code and architectural decisions
- Running unit and integration tests
- Verifying SQL safety rules
- Evaluating generated queries against expected results
- Approving the final implementation
This combination allowed Codex to accelerate implementation while GPT-5.6 supported architectural reasoning and systematic review, with human judgment controlling the final result.
📚 상세 문서: docs/README.md — 아키텍처, MCP 도구 레퍼런스(85종), SQL 생성 워크플로, 검증 룰 카탈로그(33종), 데이터셋 가이드(18종), REST API, DB 커넥터, 운영/평가/보안/개발자 가이드.
Quick Start
| 목적 | 명령 |
|---|---|
| 로컬 HTTP MCP + 관리자 UI | go run ./cmd/jamypg-mcp -transport http -data ./data/metadb -addr 127.0.0.1:9797 |
| 로컬 stdio MCP | go run ./cmd/jamypg-mcp -transport stdio -data ./data/metadb |
| 컨테이너 (모든 DB 실행 가능) | docker build -t jamypg-mcp:v0.58.0 . |
| 통합 테스트 DB 3종 기동 | docker compose -f deploy/test/docker-compose.yml up -d |
| 통합 테스트 (pg+mysql+mariadb) | go test -tags integration ./test/integration -v |
HTTP 모드 기본 진입점:
- MCP endpoint:
http://127.0.0.1:9797/mcp - Web admin:
http://127.0.0.1:9797/admin - Swagger UI:
http://127.0.0.1:9797/docs - Health check:
http://127.0.0.1:9797/healthz
Supported Target Databases
| DB | 프로파일 type |
드라이버 | read-only 세션 강제 |
|---|---|---|---|
| PostgreSQL | postgres (기본) |
pgx/v5 (pure Go) |
default_transaction_read_only=on |
| MySQL 8.x | mysql |
go-sql-driver/mysql (pure Go) |
transaction_read_only=1 |
| MariaDB 10.x/11.x | mariadb |
go-sql-driver/mysql (pure Go) |
tx_read_only=1 |
connect_string은 host:port/dbname 축약형, postgres:///mysql:// URL,
go-sql-driver DSN을 모두 허용합니다. 생성 SQL의 방언은 데이터셋의
databases.json(dbms) 또는 overrides.json(dialect)이 결정하며 기본은
postgres입니다. 상세: docs/db-connector.md.
NL2SQL Recommended Flow
대부분의 질문은 개별 도구를 여러 번 오케스트레이션하지 말고
prepare_sql_context부터 호출하세요.
prepare_sql_context(question)호출- 응답이
status: "needs_clarification"이면 SQL을 만들지 말고clarifications의 질문을 사용자에게 되묻습니다. - 답을 받은 뒤
prepare_sql_context(question, clarifications={...})로 다시 호출합니다. status: "ready"이면skeleton.skeleton_sql의/* SLOT */만 채워 SQL을 완성합니다.validate_sql→explain_sql→ 필요 시run_sql_safely순서로 진행합니다.
이 흐름은 테이블/컬럼/지표/시간조건/조인 경로/검증 힌트를 한 번에 묶어 LLM이 스키마를 추측하거나 필수 검증 단계를 건너뛰는 일을 줄입니다.
Transports
stdio: newline-delimited JSON-RPC over standard input/output. Use this for desktop MCP clients that launch a local subprocess.http: Streamable HTTP at a single MCP endpoint. Use this for local HTTP clients, gateways, or remote service wrapping.
Build
순수 Go 빌드 하나로 세 DB 모두 지원합니다 (CGO 불필요, 클라이언트 라이브러리 불필요):
Windows PowerShell:
.\scripts\build.ps1
Linux/macOS shell:
sh ./scripts/build.sh
Artifacts:
dist/jamypg-mcp-windows-amd64.exe
dist/jamypg-mcp-linux-amd64
dist/jamypg-mcp-linux-arm64
Single-platform builds:
go build -o .\bin\jamypg-mcp.exe .\cmd\jamypg-mcp
go build -o ./bin/jamypg-mcp ./cmd/jamypg-mcp
Docker Image
단일 Dockerfile이 실행 가능한 완전한 이미지를 만듭니다 (과거의
Dockerfile.oracle/Instant Client 절차는 제거되었습니다):
docker build -t jamypg-mcp:v0.58.0 .
docker run --rm -p 9797:9797 \
-e JAMYPG_ADMIN_TOKEN=change-me \
-e PG_PROD_PW=... \
jamypg-mcp:v0.58.0
DB 프로파일은 /admin/db 또는 DB profile REST/MCP API로 구성한 뒤
run_sql_safely로 read-only 실행합니다. See
docs/db-connector.md.
Integration Test Environment (pg + mysql + mariadb)
jamypg의 메타 DB 스키마 자체를 text2sql 대상으로 세 엔진에 적재한 테스트 환경이 포함되어 있습니다:
docker compose -f deploy/test/docker-compose.yml up -d
# postgres:16 → 127.0.0.1:55432 (db jamypg_meta; 메타 DB 겸 대상 DB)
# mysql:8.4 → 127.0.0.1:53306 (database `public`)
# mariadb:11.4 → 127.0.0.1:53307 (database `public`)
go test -tags integration ./test/integration -v # ping/guard/limit/explain/
# 오류코드/text2sql 골든셋 8종 × 3개 DB
# 서버를 이 데이터셋으로 직접 띄워보기
go run ./cmd/jamypg-mcp -data data/metadb -addr 127.0.0.1:9797
# (선택) 메타 DB 모드: -meta-db 'postgres://postgres:[email protected]:55432/jamypg_meta'
카탈로그 데이터셋은 data/metadb/(물리/논리 모델, 관계, 용어집, 지표/코드
사전, 컬럼 통계, 예제 SQL, 골든셋, 프로파일 3종)이며
python3 deploy/test/gen_testenv.py로 재생성합니다.
유명 오픈소스 스키마 데이터셋 (sakila / northwind / wordpress)
같은 컨테이너에 유명 오픈소스 서비스 스키마 3종이 시드되어 있고, 각각 독립
데이터셋으로 text2sql을 검증합니다 (python3 deploy/test/gen_oss_testenv.py로
재생성):
| 데이터셋 | 스키마 | 유래 | 골든셋 |
|---|---|---|---|
data/sakila |
sakila (9 tables: film/actor/customer/rental/payment...) | MySQL 공식 샘플 DB (DVD 렌탈) | 6 (정답 검증 포함) |
data/northwind |
northwind (8 tables: products/orders/customers...) | 고전 주문관리 샘플 | 6 (정답 검증 포함) |
data/wordpress |
wordpress (8 tables: wp_posts/wp_comments/wp_terms...) | WordPress CMS 핵심 테이블 | 5 (정답 검증 포함) |
세 스키마 모두 PostgreSQL(스키마)·MySQL/MariaDB(동명 데이터베이스)에 동일하게
적재되어 sakila.film 같은 스키마 한정 SQL이 세 엔진에서 그대로 실행되고,
골든셋의 기대 정답(예: 카테고리별 영화 수 1위)이 세 엔진에서 일치하는지까지
통합 테스트가 검증합니다:
go run ./cmd/jamypg-mcp -data data/sakila -addr 127.0.0.1:9797 # 프로파일: pg-sakila / mysql-sakila / mariadb-sakila
Run With stdio
Windows:
.\dist\jamypg-mcp-windows-amd64.exe -transport stdio -data .\data\metadb
Linux:
chmod +x ./dist/jamypg-mcp-linux-amd64
./dist/jamypg-mcp-linux-amd64 -transport stdio -data ./data/metadb
Example MCP client config for Windows:
{
"mcpServers": {
"jamypg": {
"command": "C:\\Users\\USER\\projects\\jamypg\\dist\\jamypg-mcp-windows-amd64.exe",
"args": ["-transport", "stdio", "-data", "C:\\Users\\USER\\projects\\jamypg\\data\\metadb"]
}
}
}
Example MCP client config for Linux:
{
"mcpServers": {
"jamypg": {
"command": "/opt/jamypg/dist/jamypg-mcp-linux-amd64",
"args": ["-transport", "stdio", "-data", "/opt/jamypg/data/metadb"]
}
}
}
stdio smoke test:
$msg = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0.0.1"}}}'
$msg | .\dist\jamypg-mcp-windows-amd64.exe -transport stdio -data .\data\metadb
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0.0.1"}}}' \
| ./dist/jamypg-mcp-linux-amd64 -transport stdio -data ./data/metadb
Run With Streamable HTTP
go run ./cmd/jamypg-mcp -transport http -data .\data\metadb -addr 127.0.0.1:9797
MCP endpoint:
http://127.0.0.1:9797/mcp
Health check:
Invoke-RestMethod http://127.0.0.1:9797/healthz
MCP Transport
This implements the MCP Streamable HTTP transport:
POST /mcpaccepts one JSON-RPC MCP message.GET /mcpopens a Server-Sent Events stream for server-to-client messages.DELETE /mcpcloses a stateful session.Mcp-Session-Idis issued afterinitializebut never required: clients that do not echo the header (qwen-code, opencode, ...) are served normally (lenient session policy).MCP-Protocol-Version: 2025-06-18is accepted on subsequent requests.- Origin validation allows empty origins,
localhost,127.0.0.1, and::1.
For stateless local testing:
go run ./cmd/jamypg-mcp -transport http -data .\data\metadb -stateless
To return POST responses as SSE:
go run ./cmd/jamypg-mcp -transport http -data .\data\metadb -sse-post
Curl Smoke Test
Initialize:
$init = @{
jsonrpc = "2.0"
id = 1
method = "initialize"
params = @{
protocolVersion = "2025-06-18"
capabilities = @{}
clientInfo = @{ name = "curl"; version = "0.0.1" }
}
} | ConvertTo-Json -Depth 10
$res = Invoke-WebRequest `
-Uri http://127.0.0.1:9797/mcp `
-Method POST `
-ContentType "application/json" `
-Headers @{ Accept = "application/json, text/event-stream" } `
-Body $init
$sid = $res.Headers["Mcp-Session-Id"]
$res.Content
List tools:
$body = @{
jsonrpc = "2.0"
id = 2
method = "tools/list"
} | ConvertTo-Json -Depth 5
Invoke-RestMethod `
-Uri http://127.0.0.1:9797/mcp `
-Method POST `
-ContentType "application/json" `
-Headers @{
Accept = "application/json, text/event-stream"
"Mcp-Session-Id" = $sid
"MCP-Protocol-Version" = "2025-06-18"
} `
-Body $body
Search schema:
$body = @{
jsonrpc = "2.0"
id = 3
method = "tools/call"
params = @{
name = "search_schema"
arguments = @{
question = "최근 6개월간 신용카드 이용 내역이 있는 고객 수"
top_k = 5
include_columns = $true
}
}
} | ConvertTo-Json -Depth 10
Invoke-RestMethod `
-Uri http://127.0.0.1:9797/mcp `
-Method POST `
-ContentType "application/json" `
-Headers @{
Accept = "application/json, text/event-stream"
"Mcp-Session-Id" = $sid
"MCP-Protocol-Version" = "2025-06-18"
} `
-Body $body
Tools
prepare_sql_context— 질문 분석→검색→지표→스키마→조인→SQL 골격을 한 번에 생성하는 권장 진입점analyze_question— 질문 분해: intent, 지표(사전 매칭), 차원, 필터, 시간범위, 정렬/limit, 모호성, 적용 기본값retrieve_context— 검색 후보와 조인 그래프 확장을 결합하고 선정 근거·조인 경로·값 증거를 반환search_schema— 다중 신호 스코어링(물리/논리명, 설명, 동의어, 도메인, 지표사전, 샘플값, 과거 성공 SQL, 조인 연결성) + 매칭 사유 + 제외 후보/사유get_schema_context— 압축 컨텍스트: 선택 테이블/컬럼 Top-K, 필수 조인 조건, 지표 계산식, 시간 조건, PII 표시, 제외 컬럼 로그get_join_paths— 조인 그래프 기반 경로(모든 쌍), confidence/preferred/caution, 저신뢰·경로없음 가이던스, 금지 조인 차단get_metric_definition— 지표 사전(metrics.json) 우선 조회; exact/business name/alias와 glossary·토큰 근접도를 결합하고 confidence/evidence를 반환, 없으면 추정 후보를 명확히 분리get_column_stats— 메타 + 프로파일 통계(null 비율, distinct, min/max, top values, 포맷 패턴)find_filter_columns— 질문 속 리터럴 값(서울, 정상, 개인사업자...)을 코드사전/top values로 필터 컬럼에 매핑resolve_time— 시간 표현(오늘/지난달/최근 3개월/2025년 6월/상반기/전월 대비...)을 semantic_type별 SQL 조건으로 변환search_examples— golden SQL 예제 검색 (질문의 intent 시그니처와 예제target_intent의 구조 유사도로 랭킹 — 같은 SQL 형태의 예제 우선)build_sql_skeleton— 복잡/다중 테이블 질문용: 검증된 부품(카탈로그 조인 조건+alias, 지표사전 expression, semantic_type별 시간 조건, 정책 필터)을 조립한 SQL 골격 반환. LLM은/* SLOT */주석만 채움rank_candidates— 후보 SQL 여러 개를 서버측 객관 신호(검증 오류/경고, 리스크, 결과 스키마 커버리지, 지표 일치)로 정렬해 최선안 반환 — self-consistency를 LLM 자기평가 대신 객관 점수로 구현suggest_joins— 단일 컬럼 PK 마스터를 참조하는 미연결 테이블을 발굴해 조인 엣지 후보 제안(FK/인덱스/타입/동시출현 근거 + overrides.json 스니펫). 운영자 검토용 — 자동 적용되지 않음suggest_join_relations— 골든셋에서 조인 경로가 끊긴 테이블 쌍을 찾고 공통 키 기반 relation 보강 후보를 제안validate_sql— 정적 검증: 미존재 테이블/컬럼, 조인 그래프, 카티션, GROUP BY, 방언(postgres/mysql/mariadb — Oracle 전용 문법 차단, 교차 방언 함수 경고), 날짜 타입, PII, 지표식 일치, 코드사전 값 검증(존재하지 않는 코드 리터럴 차단), 결과 스키마 검증(expected_outputs로 요구 차원/지표 누락 감지), CTE/인라인뷰 스코프 인식, 구조화된fix_hints(최대 2회 자동수정 루프용)explain_sql— 리스크 추정: 정적 분석 +profile지정 시 실측 EXPLAIN(postgresEXPLAIN (FORMAT JSON), mysql/mariadbEXPLAIN FORMAT=JSON) — full scan/카티션/대량 정렬/고비용 탐지, 개선 제안list_db_profiles— 호출자가 사용할 수 있는 DB 연결 프로파일 id와 마스킹된 접속·정책 정보를 반환route_db_profile— 프로파일이 많을 때 SQL이 참조하는 테이블을 방언 파서로 추출해 각 프로파일의 실측 인벤토리(information_schema)·선언 스키마·방언·헬스·우선순위로 점수화하여 실행 대상 프로파일을 판정. 명확한 승자가 있으면decisive=true로selected_profile을, 애매하면 후보 목록을 반환.run_sql_safely(profile="auto")가 내부적으로 사용run_sql_safely— 검증 후 실제 DB 실행 (profile지정 시; postgres/mysql/mariadb, read-only 세션, 타임아웃·행 제한·truncated·감사 로그).profile="auto"면 router가 대상 프로파일을 판정(애매하면profile_choice_required로 재질문). 프로파일 미지정 시 dry-run 가드. 검증 실패 SQL은 실행하지 않음execute_with_repair— 자기수정 실행: 검증→실행→진단을 한 번에 수행하고 실패 시repair키트(실패 단계, 분류된 error_code+힌트, 카탈로그 fix_hints, 참조 테이블 스키마)를 반환해 한 턴에 SQL 교정 가능. 0행이면executed_empty+zero_row_hints. run_sql_safely와 동일 가드, 반복이 예상되면 이 도구 우선list_metadata_sources— 자동 메타데이터 수집 원천으로 쓸 수 있는 DB 프로파일(source_id/name/type/마스킹 접속대상) 목록. 물리 메타데이터는 자동 수집하되 업무 의미는 승인 기반으로 관리discover_metadata— 원천 DB의 비시스템 스키마 목록 조회(information_schema만 읽는 read-only). 수집 범위 지정용db_health_report— DBA 헬스 점검: 연결된 프로파일 DB의 시스템 카탈로그를 읽어 PK 없는 테이블(high)·인덱스 없는 FK 컬럼(medium)·미사용 인덱스(low)·통계 오래됨/없음(medium)·대형 테이블(코멘트 여부, info)을 진단. PostgreSQL 전체, MySQL/MariaDB는 이식 가능 항목만. 읽기 전용(수정·실행 없음, 개선은 DBA 검토 후)suggest_indexes— 인덱스 어드바이저: 쿼리 감사 로그(query-*.jsonl)에서 느린 성공 쿼리를 분석해 인덱스가 없는 WHERE/JOIN/ORDER BY 컬럼을 집계하고, 영향도(발생 횟수 × 평균 지연) 순으로 후보 인덱스를 제안. 각 후보에 검토용CREATE INDEXDDL과 대표 쿼리 포함. 읽기 전용·권고용(자동 생성하지 않으며 DBA가 카디널리티·쓰기부하 검토 후 수행).profile(선택)·min_elapsed_ms(기본 200)·days(기본 7)lint_sql— SQL 안티패턴 린트: 단일 문장을 정적 분석해 고전적 성능·정합성 스멜을 진단 —SELECT *, 선두 와일드카드LIKE '%…',NOT IN (서브쿼리), 인덱스 컬럼을 함수로 감싼 비-sargable 조건, 인덱스 컬럼 부등호, 콤마 크로스 조인,WHERE의OR,LIMIT없는ORDER BY,WHERE없는 DML. 각 항목에 심각도와 개선 제안 포함. 카탈로그 인덱스 커버리지 인식·권고용(자동 수정 안 함).sql·profile(선택)explain_sql_in_words— SQL 자연어 설명: SQL이 어떤 테이블(카탈로그 논리명)에서 무엇을 필터·조인·그룹·정렬하고 어떤 집계를 계산하는지 한국어로 요약. 정적 구조 분석(실행 안 함).sql·profile(선택)workload_report— 워크로드 리포트: 감사 로그를 기간별로 집계해 총/성공/오류 건수·오류율, 지연 분포(avg/p50/p95/p99/max), 느린 쿼리 수, 가장 많이 접근한 테이블, 상위 오류 코드, 툴·프로파일별 사용량, 가장 느린 문장, 피크 시간대를 리포트. 읽기 전용.profile(선택)·days(기본 7)·slow_ms(기본 200)get_dba_digest— DBA 다이제스트: 워크로드 리포트와 인덱스 어드바이저를 압축한 능동형 운영 스냅샷 — 쿼리량·오류율·p95/최대 지연·느린 쿼리 수·핫 테이블·상위 인덱스 후보와 한 줄 헤드라인. 읽기 전용. 스케줄러(-sync-interval+-digest-webhook+-dba-digest)가 틱마다 웹훅으로 push하는 것과 동일한 데이터.profile(선택)·days(기본 7)·slow_ms(기본 200)
DBA 관리 도구 (privileged, dba/admin 역할 전용)
프로파일에 DBA 자격증명(db_profiles의 dba.enabled+dba.username+dba.password_ref)을 설정한 경우에만 사용할 수 있습니다. 읽기 전용 쿼리 계정과 분리된 쓰기 가능 커넥션으로 실행되며, 모든 변경은 감사 로그(dba:*)에 기록됩니다. 관리 화면: /admin/dba-console.
dba_overview— 콘솔 개요: 방언·DBA 활성 여부·서버 버전·역할/DB 수 (읽기 전용)dba_list_users— 사용자/역할 목록과 속성(superuser·createdb·createrole·login·연결제한)dba_list_databases— 데이터베이스 목록(소유자·인코딩·콜레이션·크기)dba_list_settings— 서버 설정 파라미터(pg_settings/global_variables), 이름 부분검색dba_list_sessions— 활성 세션/백엔드(pid·사용자·상태·지속시간·현재 쿼리)dba_create_user— 사용자/역할 생성(postgres LOGIN/SUPERUSER/CREATEDB/CREATEROLE, mysqlCREATE USER). 비밀번호는 감사 로그에서 마스킹dba_alter_user— 비밀번호·속성 변경dba_drop_user— 사용자/역할 삭제(confirm=true필수)dba_grant— 권한 부여/회수(revoke=true),WITH GRANT OPTION지원dba_create_database— 데이터베이스 생성(OWNER/ENCODING 또는 CHARACTER SET)dba_drop_database— 데이터베이스 삭제(confirm=true필수)dba_set_parameter— 설정 변경(postgresALTER SYSTEM+pg_reload_conf(), mysqlSET GLOBAL/SESSION)dba_terminate_session— 세션 종료/쿼리 취소(pg_terminate_backend/pg_cancel_backend, mysqlKILL)dba_run_maintenance— 유지보수(postgres VACUUM/ANALYZE/REINDEX, mysql ANALYZE/OPTIMIZE)dba_execute— 임의 권한 SQL 실행(에스케이프 해치,confirm=true필수, 감사 로그에 원문 기록)describe_db_schema— 연결된 프로파일 DB의 라이브 스키마(information_schema)를 조회해 카탈로그에 없는 테이블도 SQL 생성 근거로 제공. 카탈로그 우선: 등록된 테이블/컬럼엔 논리명·설명을 함께 붙이고in_catalog플래그로 구분. 읽기 전용·비저장. 라이브 전용 테이블을 검증까지 통과시키려면apply_metadata_sync로 반영run_metadata_sync— 원천 DB의 물리 모델(스키마·테이블·뷰·컬럼·PK/FK/Unique/Check·인덱스·코멘트·행수추정)을 버전 스냅숏으로 수집하고 이전 스냅숏 대비 변경분을 반환. 기본 증분(스키마 해시 동일 시 스킵). 삭제는 즉시 반영하지 않고 폐기 후보로 표시. 물리 정보만 수집하며 업무 의미(논리명·지표)는 운영 카탈로그에 쓰지 않음apply_metadata_sync— (관리자) 원천의 최신 스냅숏을 카탈로그에 자동 반영: 물리 모델(컬럼·타입·NULL·PK/FK·FK 관계)을 meta_physical_models.json/topology_relations.json에 병합(백업)하고 핫리로드. 물리 사실은 자동 반영하되 기존 설명(업무 의미)은 보존, 삭제분은prune=true가 아니면 폐기 후보로만 표시. 스케줄러-sync-apply로 매 싱크 시 자동 실행 가능list_profile_catalogs— 등록된 DB 프로파일별 카탈로그 워크스페이스(<data>/profiles/<profile>/) 유무·테이블/관계 수·구축 시각 목록. 프로파일마다 독립 메타데이터 JSON을 조회·관리get_profile_catalog— 특정 프로파일 워크스페이스의 카탈로그 요약·데이터셋 인벤토리·헬스 조회build_profile_catalog— (관리자) 프로파일의 라이브 스키마로 워크스페이스 구축/갱신(물리 모델을 프로파일 디렉터리에 기록, 기존 설명 보존·삭제는 폐기 후보)get_profile_dataset/put_profile_dataset— 프로파일 워크스페이스의 개별 메타데이터 JSON(overrides·glossary·physical_models 등) 조회 / (관리자) 검증·백업·롤백과 함께 관리build_all_profile_catalogs— (관리자) 등록된 모든(또는 선택) 프로파일의 워크스페이스를 라이브 DB에서 일괄 구축/갱신. 프로파일별 권한 확인·실패는 개별 보고(배치 중단 없음). 다수 DB 온보딩용import_openmetadata_to_profile— (관리자) OpenMetadata의 큐레이션 메타데이터(논리명·설명·PII·용어집)를 특정 프로파일 워크스페이스로 import(전역 카탈로그 아님). 각 DB의 업무 메타데이터를 그 DB 워크스페이스에 수급, 빈 필드만·기존값 보존,apply=false미리보기get_active_catalog/set_active_catalog— 현재 NL2SQL이 쓰는 카탈로그(기본-datavs 핫스왑된 프로파일 워크스페이스) 조회 / (관리자) 무재기동 전환. DB 프로파일·감사·워크스페이스는 운영 디렉터리에 고정(전환 영향 없음), 단독 모드 전용·재기동 시-data로 복귀get_sync_status— 원천별 저장된 스냅숏 목록(최신순, 수집시각·스키마해시·객체수)diff_metadata_snapshots— 두 스냅숏 간 변경분(테이블/컬럼 추가·삭제, 타입/Null/키/코멘트/인덱스/뷰SQL 변경, 각각 심각도·처리방침) 계산profile_metadata_assets— 컬럼 통계(행수·Null비율·distinct·min/max·상위값·포맷패턴)를 비용 제어(모드별 샘플: fast 2k / standard 100k / deep 전체)·개인정보 보호형(민감 컬럼은 원본값·min/max·상위값 미저장, 길이·패턴·건수만)으로 계산. 결과는 검토 후보이며 운영 카탈로그(column_stats)에 자동 반영하지 않음record_feedback— 질문/분석/후보/SQL/검증오류/채택여부/실행시간을 서버가 부여한 actor/session/dataset 범위와 함께pending/untrusted검토 큐에 저장; 승인 전에는 검색·프롬프트·학습에 사용하지 않음review_feedback— 관리자 전용 피드백 검토 큐 조회 및 approve/reject; 승인된 레코드만 trusted 상태로 few-shot·검색 부스트·학습 룰에 사용list_datasets/get_dataset— 서버가 참조하는 모든 JSON 데이터셋의 라이브 레지스트리: 용도, 스키마, 사용 도구, 필수/편집가능 여부, 현재 상태(존재·크기·로드 건수·로드 이슈)와 내용 샘플put_dataset— 데이터셋 교체: JSON 형태 검증 → 기존 파일 백업(backups/) → 쓰기 → 카탈로그 재컴파일 → 핫스왑(재기동 불필요). 컴파일 실패나 신규 오류 발생 시 자동 롤백(force로 강제 적용 가능)remove_dataset— 선택 데이터셋 제거(백업 후) + 핫스왑. 필수(physical_models,logical_models)·시스템 관리(feedback,audit) 대상은 거부reload_catalog— 디스크 파일을 직접 수정한 경우(볼륨 마운트 등) 재컴파일 + 핫스왑get_catalog_health— 메타 컴파일 검증 결과(오류/경고), 커버리지 갭, PII 목록get_metadata_quality— 테이블별 메타데이터 품질 점수(완전성·일관성·관계성·프로파일링·지표연결·사용성·보안성) 0–100 + 등급 A–E, 스키마/도메인 집계, 개선 대상.gate=true면 릴리스 차단 조건(로드 오류·지표/인증조인 손상·PII 미분류·품질 하한 미달) 평가로 전환suggest_semantic_metadata— 논리명·의미타입·설명이 없는 컬럼에 대해 규칙 기반(용어집·동일컬럼 재사용·약어 확장·이름/타입 패턴, 오프라인)으로 검토 후보를 근거·신뢰도와 함께 생성. 고신뢰 항목은 overrides.json columns[] 스니펫으로 반환. 운영 카탈로그에 자동 반영하지 않으며 LLM/담당자가 다듬어 승인suggest_model_candidates— 규칙 기반 모델 후보 생성: 코드사전(저카디널리티 코드 컬럼의 프로파일 top-value로 스켈레톤), 지표(AMOUNT/COUNT/RATIO/SCORE 컬럼→SUM/AVG 집계 지표), 관계(식별자 이름+PK명/테이블명 매칭+타입 호환으로 FK 추론). 근거·신뢰도 동반, 운영 카탈로그 자동 미반영analyze_impact— 테이블/컬럼 변경·폐기 전 계보/영향도 추적: 해당 자산에 의존하는 지표·관계·선호/금지 조인·골든셋·오버라이드·용어집·1홉 하위 테이블을 역추적하고 impact_level(지표/선호조인 의존 시 high) 산출. 카탈로그 읽기 전용 분석review_candidates— 의미보강·모델 후보를 저장된 승인/반려 결정과 조인해 검토 큐로 조회(상태 pending/approved/rejected 필터). 각 항목에 안정적 id 부여. 사람 개입 게이트decide_candidates— 후보를 id로 승인/반려. 검토자·시각·메모와 함께 영속 저장(<data>/reviews/decisions.json). 카탈로그 자동 미반영get_metadata_digest— 카탈로그 운영 상태 요약 스냅숏: 품질 점수·릴리스 게이트, 검토 큐 백로그(대기/승인/반려), 골든 승격 후보 수, 카탈로그 규모·로드 경고 + 한 줄 헤드라인. 일일 점검·알림용openmetadata_status— 설정된 OpenMetadata 서버 연결·인증·버전 확인import_openmetadata— OpenMetadata의 큐레이션 메타데이터(테이블/컬럼 displayName→논리명, 설명, PII 태그→pii/semantic_type, 용어집)를 jamypg 빈 필드에만 후보로 가져오기.apply=false미리보기(기본),apply=trueoverrides.json/glossary.json 병합+리로드(관리자, 백업·수기값 보호)export_to_openmetadata— jamypg 컬럼 설명(명시적 또는 논리명 조합)을 OpenMetadata의 빈 설명 컬럼에만 JSON-Patch로 push.dry_run=true계획만(기본),dry_run=false실제 반영(관리자)openmetadata_drift— jamypg ↔ OpenMetadata 대조(reconciliation) 리포트: 논리명·설명·PII를jamypg_gap(import 후보)·conflict(값 불일치, 사람 결정)·ext_gap(export 후보)으로 분류. 읽기 전용 거버넌스 도구export_lineage_to_openmetadata— jamypg 관계 그래프를 OpenMetadata 테이블 lineage 엣지로 push(from=참조/부모, to=기준/자식). FK 관계형 lineage 매핑(ETL 흐름 아님).dry_run=true계획(기본)/false반영(관리자), OM에 없는 테이블 엣지는 skip 보고get_approved_overrides— 승인된 후보를 목적 파일별(overrides.json columns[], metrics.json, relations.json, 코드사전) 적용 스니펫으로 컴파일apply_approved_candidates— 원클릭 반영: 승인-미반영 후보를 데이터셋 파일 4종에 파일별 백업 후 병합하고 카탈로그 핫리로드. 멱등(applied_at 스탬프+내용 중복 제거), 운영자 수기 값은 덮어쓰지 않음. 관리자 전용run_evaluation— golden query set 평가(테이블/컬럼/지표/조인/SQL 유효성 정확도, 평균 응답시간)learn_from_feedback— 반복 실패 패턴을 learned rule로 승격: 동일 검증오류 반복(예방 경고), 테이블 오선택 교정(검색 패널티), 컬럼 교정(validate_sql 경고).learned_rules.json에 영속화되어 운영자가 검토/수정 가능suggest_golden_from_feedback— 승인·성공·실행된 피드백을 골든셋 후보로 제시(질문/기대 SQL·테이블·컬럼, 질문/SQL 정규화로 기존 골든셋 중복 제외). trust 경계 승인분만 대상(fail-closed)promote_golden_queries— 선택 후보(feedback_id)를golden_queries.json에 백업 후 추가하고 카탈로그 리로드. 운영 트래픽으로 평가셋을 성장시키는 명시적 관리자 행위. 관리자 전용
run_sql_safely validates SQL and, when a DB profile is supplied, executes it
read-only against the target database (postgres/mysql/mariadb) with query
timeout, row limit, and audit logging — drivers are always compiled in.
Without a profile it stays a dry-run guard returning bounded SQL. See
docs/db-connector.md. Start most questions with prepare_sql_context,
which runs the whole analyze→skeleton pipeline in one call.
Web Admin Console & REST API
HTTP 모드로 기동하면 브라우저 기반 관리 화면과 Swagger 문서가 함께 제공됩니다.
| 경로 | 내용 |
|---|---|
/admin |
데이터셋 관리 콘솔 — 18개 데이터셋의 용도·스키마·상태 확인, 내용 편집·적용(백업+검증+핫스왑), 제거, 백업/복원, 카탈로그 리로드. 단계별 사용 가이드가 화면에 내장 |
/admin/editor |
테이블 편집기 — 데이터셋을 표(그리드)로 렌더링해 JSON 없이 편집: 셀 클릭 인라인 수정(타입 자동 보존), 행 추가/복제/삭제, 컬럼 추가/이름변경/삭제, 검색·페이지네이션. 저장 시 동일한 백업·검증·핫스왑·롤백 적용 |
/admin/db |
DB 연결 관리·쿼리 실행 — postgres/mysql/mariadb 프로파일 추가/수정/삭제/접속 테스트, Read-Only 쿼리 콘솔(검증→미리보기→실행→취소), 실행 이력·메트릭 (docs/db-connector.md) |
/admin/dba |
DBA 코파일럿 — 읽기 전용 DBA 진단 대시보드: 헬스 점검, 인덱스 어드바이저(CREATE INDEX 후보), 워크로드 리포트, SQL 안티패턴 린트, SQL 자연어 설명을 탭 UI로 제공(자동 실행·변경 없음, 권고용) |
/admin/dba-console |
DBA 관리 콘솔 (dba/admin 역할 전용) — 권한 있는 쓰기 세션으로 사용자·역할, 데이터베이스, 권한(GRANT/REVOKE), 서버 설정, 세션(취소/종료), 유지보수(VACUUM/ANALYZE/REINDEX), 임의 권한 SQL을 탭 UI로 관리. 프로파일의 dba 자격증명 필요, 모든 변경 감사 로그 기록 |
/auth/login · /admin/users · /admin/keys |
인증·사용자·MCP 키 (메타 DB 활성 시) — 로컬/Keycloak SSO 로그인, 사용자·역할 관리(admin), MCP 키 발급·회전·폐기, 프로파일별 권한(grant). 상세: docs/auth.md |
/docs |
Swagger UI — REST API 문서 + Try it out (오프라인 동작, 자산 임베드) |
/openapi.json |
OpenAPI 3.0 스펙 |
/api/* |
REST API: GET /api/datasets, GET/PUT/DELETE /api/datasets/{name}, GET .../content, GET .../backups, POST .../restore, POST /api/reload, GET /api/health |
변경 API 보호: -admin-token <값> 플래그(또는 JAMYPG_ADMIN_TOKEN 환경변수)를
설정하면 PUT/DELETE/POST에 X-Admin-Token 헤더가 필요합니다. 미설정 시 인증
없이 호출 가능하므로 내부망 외 노출 시 반드시 설정하세요. 모든 변경은
audit/*.jsonl에 기록되고, REST와 MCP 도구(put_dataset 등)는 동일한
검증·백업·롤백 코드를 공유합니다.
단독 HTTP 모드는 기본적으로 loopback 주소만 허용합니다. 0.0.0.0, ::,
인터페이스 IP 또는 hostname에 바인딩하려면 전면 인증을 제공하는 -meta-db를
구성하거나 -public-mcp로 공개 노출을 명시적으로 승인하고 -admin-token도
설정해야 합니다.
-admin-token은 변경·DB 실행 도구를 보호하지만 모든 읽기 전용 MCP 도구의
로그인을 강제하지 않으므로, 인터넷 노출에는 -meta-db 인증을 사용하세요.
피드백을 workspace별로 격리하려면 -feedback-tenant 또는
JAMYPG_FEEDBACK_TENANT를 서버가 관리하는 고정 값으로 설정하세요.
Authentication (optional, Postgres meta DB)
-meta-db <postgres DSN>(또는 JAMYPG_META_DB)를 지정하면 전면 인증이
활성화됩니다. 미지정 시 기존 단독 모드 그대로 동작합니다(하위 호환).
jamypg-mcp -transport http -addr 0.0.0.0:9797 \
-meta-db 'postgres://jamypg:pw@pg:5432/jamypg?sslmode=require' \
-bootstrap-admin 'admin:첫관리자비밀번호'
-
로그인: 로컬 계정(bcrypt) + 세션 쿠키, 또는 Keycloak SSO(OIDC) (
-oidc-issuer/-oidc-client-id/-oidc-client-secret/-oidc-redirect-url) -
역할:
admin(전권) /user. 관리자는 사용자·데이터셋·전체 프로파일· 전체 키 관리 -
MCP 키:
/mcp접근용jsk_...키를 발급·회전·폐기(/admin/keys). 클라이언트는Authorization: Bearer jsk_...또는X-MCP-Key로 접속 -
DB 프로파일 권한: 사용자별 소유 +
use/managegrant +shared공개. Postgres에 저장되어 사용자마다 접근 범위가 다름 -
첫 기동 시 부트스트랩 관리자를 생성(비밀번호 미지정 시 로그에 1회 출력)
-
서버 설정 관리: 마스터 토큰·허용 Origin·Keycloak SSO를
/admin/settings에서 메타 DB에 저장하고 재기동 없이 즉시 적용(플래그/env는 기본값) -
데이터셋도 메타 DB에서 관리: 편집 가능한 카탈로그 JSON 14종의 진실 원본이 Postgres(
jamypg_datasets)가 되어/admin·MCP 도구 편집이 DB에 영속화됨(로드 시 파일로 materialize해 기존 로더 재사용) -
MCP
list_db_profiles: LLM이 사용 가능한 DB 프로파일 id를 발견
메타 DB 드라이버는 순수 Go(pgx)라 CGO/외부 클라이언트가 필요 없습니다. 상세: docs/auth.md.
Operator-Managed Data Files (dataset dir)
| 파일 | 용도 |
|---|---|
glossary.json |
업무 용어/동의어 사전 (검색·질문분해·SQL생성·검증 공용) |
metrics.json |
지표 사전: expression, 집계, grain, 필수 필터, 예시 SQL |
overrides.json |
운영자 보정: 설명/도메인/grain, 컬럼 동의어·샘플값, PII 지정, 금지/권장 조인, 구조 검증 기본 필터(`enforcement: warn |
databases.json |
대상 DB 정보 — dbms(POSTGRES/MYSQL/MARIADB)가 생성 SQL 방언 결정 |
db_profiles.json |
실행용 DB 접속 프로파일 (type/connect_string/password_ref/pool/policy) |
column_stats.json |
컬럼 프로파일 통계 (선택; row count, null 비율, top values, 최신성) |
patterns.json |
다단계 SQL 패턴 사전 (2단 집계, 그룹별 top-N, 전월/전년 대비, 비율, 분포) — 미존재 시 내장 기본값 사용 (방언에 맞게 자동 치환) |
golden_queries.json |
평가용 golden query set — 수작업 케이스 + jamypg-goldgen 자동 선별 (CI에서 go test ./...로 자동 실행) |
learned_rules.json |
learn_from_feedback가 승격한 학습 룰 (운영자 검토/수정/삭제 가능) |
feedback/*.jsonl |
record_feedback 검토 큐 (관리자가 승인한 trusted 레코드만 성공 SQL 학습·룰 승격에 재사용) |
audit/*.jsonl |
모든 tool call 감사 로그 (자동 기록, git 제외) |
Evaluation
go test ./... # golden set 포함 전체 테스트 (CI)
go run ./cmd/jamypg-eval -verbose # 평가만 실행, 케이스별 미스 출력
go run ./cmd/jamypg-eval -data data/metadb -profile pg-meta
# 실행 기반 평가 (실제 DB에 COUNT 검증)
go run ./cmd/jamypg-goldgen -n 80 # sql_datasets에서 golden set 재생성
# (도메인 x 난이도 층화, 카탈로그 검증 통과 케이스만,
# 기존 파일 상단 수작업 케이스는 -keep 개수만큼 보존)
측정 항목: table_selection_acc, column_recall_avg, metric_lookup_acc,
join_path_acc, expected_sql_valid, avg_response_ms (+ -profile 시
execution_success_rate, row_sanity_rate).
data/metadb 8케이스(3개 DB 실측): table 1.0 / join 1.0 / sql 1.0 / 실행 성공률 1.0.
OSS 데이터셋(sakila/northwind/wordpress) 17케이스: 3개 엔진에서 동일 정답 검증 통과.
Feedback Learning Loop
- 클라이언트가
record_feedback으로 질문/SQL/검증오류/교정본/채택여부를 검토 큐에 저장 - 관리자가
review_feedback으로 내용과 범위를 확인해 approve/reject - 승인된 trusted 성공·교정 SQL만 즉시 few-shot 예제와 검색 부스트에 반영
learn_from_feedback호출(또는 주기 실행) 시 승인된 피드백의 반복 패턴을 룰로 승격:recurring_error— 같은 검증 오류가 N회 이상 → 해당 테이블/컬럼 사용 시 예방 경고table_correction— 교정에서 반복적으로 교체된 테이블 → 검색 점수 패널티 + 경고column_correction— 반복 교체된 컬럼 → validate_sql이 대체 컬럼 힌트 제시slow_query/recurring_exec_error— 실행 감사 로그에서 반복 지연·오류(PG-/MY-/TIMEOUT) 승격
- 룰은
learned_rules.json으로 영속화; 서버 재기동 시 자동 적용, 운영자가 직접 편집 가능
SQL Generation Flow
analyze_question→ 모호성 확인 (기본값 적용 시 가정 표시), 패턴·intent 시그니처 확보search_schema(+find_filter_columns,resolve_time)get_metric_definition— 업무 지표는 사전 expression만 사용get_schema_context— 압축 컨텍스트만 LLM에 전달get_join_paths— ON 조건은 반드시 여기서 취득; 경로 없음/저신뢰 시 되묻기- 복잡/다중 테이블 질문이면
build_sql_skeleton으로 골격 확보 후 SLOT만 채움; 단순 질문은 직접 생성 (컨텍스트 내 식별자만, PII 금지, row bound(LIMIT) 필수) validate_sql(expected_outputs,metrics전달) — fix_hints 반영 최대 2회 재시도; 실패 SQL 실행 금지. 난이도 높은 질문은 후보 2~3개를 만들어rank_candidates로 최선안 선택explain_sql— risk=high면 기간/limit 조건 추가 후 재생성 (profile지정 시 실측 EXPLAIN)- 구조화 JSON 응답 (sql, 사용 테이블/컬럼, 지표, 조인, 필터, 가정, 주의, 검증결과, 실행가능여부)
record_feedback
No comments yet
Be the first to share your take.