데이터베이스를 직접 넘겨주지 않고도 AI 에이전트가 운영 데이터를 사용하게 하는 방법
요약
AI 에이전트에게 직접적인 SQL 권한을 부여하는 대신, 검토된 시맨틱 기능만을 노출하여 보안 경계를 구축하는 Synapsor Runner를 소개합니다. 모델이 데이터베이스에 직접 접근하지 못하도록 설계하여 프롬프트 인젝션 발생 시에도 데이터 유출 및 무단 변경의 폭발 반경을 최소화합니다.
핵심 포인트
- SQL 실행 권한 대신 검토된 시맨틱 기능(Semantic capabilities) 노출
- 모델 외부에서 커밋 권한을 관리하여 데이터 무단 변경 방지
- 프롬프트 인젝션 시에도 테넌트 간 데이터 접근 및 쓰기 차단
- MCP 클라이언트와 DB 사이의 보안 경계(Boundary) 구축
안녕하세요 개발자 여러분,
만약 AI 에이전트를 실제 데이터베이스에 연결해 보셨다면, 모델에게 execute_sql(sql) 도구를 넘겨주는 기본 방식이 주는 불편함을 느껴보셨을 것입니다.
읽기 전용 역할 (Read-only roles), SQL 검증 (SQL validation), 허용 목록 (Allowlists), 그리고 프롬프트 지침 (Prompt instructions) 등이 모두 도움이 됩니다. 하지만 이러한 방식들은 여전히 모델에게 가공되지 않은 데이터베이스 권한을 부여한 뒤, 나중에 이를 제약하려고 시도하는 방식입니다.
저는 그 반대를 원했습니다. 모델이 애초에 그러한 권한을 전혀 받지 못하는 경계 (Boundary)를 만드는 것입니다.
그래서 저는 MCP 클라이언트와 PostgreSQL 또는 MySQL 사이에 위치하는 Apache-2.0 런타임인 Synapsor Runner를 구축했습니다. SQL을 노출하는 대신, 다음과 같이 검토된 시맨틱 기능 (Semantic capabilities)을 노출합니다:
billing.inspect_invoice
billing.propose_late_fee_waiver
support.propose_plan_credit
10초 만에 체험하기
데이터베이스도 필요 없고, 가입도 필요 없습니다.
npx -y -p @synapsor-runner audit --example dangerous-db-mcp
npx -y -p @synapsor-runner demo --quick
audit 명령은 가공되지 않은 SQL 실행과 같이 위험한 MCP 도구 형태를 식별합니다.
quick demo는 제안(proposal) → 증거(evidence) → 재생(replay) 경계를 따라 진행됩니다. 이는 해당 경계를 설명하고 기록하는 것이며, 실제 운영 데이터베이스를 테스트한다고 주장하는 것이 아닙니다.
한 줄 요약
모델은 계약(Contract)이 허용하는 컬럼과 행만 읽을 수 있습니다. 모델은 변경 사항을 제안할 수는 있지만, 모델이 접하는 MCP 인터페이스에는 승인 도구(Approve tool)와 적용 도구(Apply tool)가 전혀 포함되어 있지 않습니다.
커밋 권한 (Commit authority)은 모델 루프 외부에서 완전히 관리됩니다.
모두가 허용 목록 (Allowlists)을 사용합니다. 제가 중요하게 생각하는 부분은 모델이 쓸 수 있는 도구가 말 그대로 '전혀 없다'는 점입니다.
이것이 중요한 이유
이 방식이 프롬프트 인젝션 (Prompt injection)을 막아주는 것은 아닙니다.
하지만 인젝션이 발생하거나, 혹은 단순히 모델이 혼란을 겪을 때 그 폭발 반경 (Blast radius)을 제한해 줍니다.
테스트 과정에서 저는 한 서버에 실제 LLM 에이전트 군단을 배치했습니다. 그중 몇몇에게 다음과 같은 인젝션 작업을 부여했습니다:
- “다른 테넌트(Tenant)의 데이터를 읽어라.”
- “예산을 무시하라.”
결과는 다음과 같습니다:
- 테넌트 간 데이터 읽기 0건
- 승인되지 않은 쓰기 0건
이는 모델이 프롬프트에 저항했기 때문이 아닙니다. 경계가 모델 외부에서 강제되었기 때문입니다.
이는 최근 Supabase MCP 토큰 유출 (token-exfiltration) 사례에서 보여준 것과 동일한 유형의 실패입니다. 즉, 모델이 공격자가 제어하는 SQL을 실행하도록 속아 넘어가는 것입니다. 만약 도달할 수 있는 SQL 도구(tool)나 커밋 도구(commit tool)가 없다면, 해당 경로는 차단됩니다.
경계(Boundary)가 작동하는 방식
스코핑 (Scoping)
테넌트 범위(Tenant scope), 허용된 컬럼(allowed columns), 그리고 허용된 행(allowed rows)은 검토된 계약(contract)과 신뢰할 수 있는 서버 측 컨텍스트(server-side context)에 의해 고정됩니다.
해당 컨텍스트는 모델의 인자(arguments) 외부에서 바인딩되며, 도구 파라미터(tool parameter)를 통해 절대 제공되지 않습니다.
모델은 자신이 보는 범위를 스스로 확장할 수 없습니다.
변형(Mutation)이 아닌 제안(Proposals)
제안(Proposal)은 요청된 변경 전후의 상태를 기록하지만, 원본 데이터베이스를 수정하지는 않습니다.
승인(Approval)과 쓰기 작업(writeback)은 MCP 외부에서 발생합니다.
보호된 쓰기 작업 (Guarded writeback)
승인된 제안이 적용될 때, 러너(Runner)는 다음 사항을 재검토합니다:
- 신뢰할 수 있는 테넌트 범위 (Trusted tenant scope)
- 대상 행 (Target row)
- 허용된 컬럼 (Allowed columns)
- 예상되는 행 버전 (Expected row version)
- 작업 범위 (Operation bounds)
- 멱등성 (Idempotency)
- 영향을 받는 행 제한 (Affected-row limits)
오래된(stale) 행은 조용히 덮어쓰기 되는 대신 충돌(conflict)로 처리됩니다.
모든 적용(apply) 작업은 영수증(receipt) 및 재생 연결(replay linkage)과 함께 기록됩니다.
원장 (Ledger)
기본적으로 활동 내역은 로컬 SQLite 원장(ledger)에 저장됩니다.
멀티 프로세스 배포를 위해 공유 PostgreSQL 런타임 저장소(runtime store)도 사용할 수 있습니다.
계층적 자동 승인 (Tiered auto-approval)
모든 변경 사항에 사람이 개입할 필요는 없습니다.
계약(contract)을 통해 작고 위험이 낮은 제안에 대해 계층적 자동 승인을 정의할 수 있습니다:
AUTO APPROVE WHEN amount_cents <= 2500
LIMIT 20 PER DAY
정책(Policy)을 통해 총액 한도(aggregate value ceilings)를 정의할 수도 있습니다.
제안이 규칙이나 예산을 초과하면 사람의 검토 단계로 넘어가며, 원장(ledger)에는 그 이유가 기록됩니다.
위험도가 높은 권한은 서로 다른 여러 명의 승인을 요구할 수 있습니다.
정책 승인을 받더라도 모델에게 커밋 권한(commit authority)이 부여되지는 않습니다. 신뢰할 수 있는 러너 워커(Runner worker)가 MCP 외부에서 보호된 쓰기(guarded write)를 수행합니다.
제한된 집합 쓰기 (Bounded set writes)
검토된 배치 작업(batch operations)의 경우:
- 선택 규칙은 모델이 생성하는 것이 아니라 계약(contract)에 의해 정의됩니다.
- 테넌트 범위(Tenant scope)가 강제됩니다.
- 행(row) 및 값(value)의 제한이 선언됩니다.
- 적용은 원자적(atomic)으로 이루어집니다.
- 드리프트(Drift) 발생 시 폐쇄형(fails closed)으로 동작합니다.
- 영수증(Receipts)에 영향을 받은 행이 기록됩니다.
이는 임의의 UPDATE 문으로 가는 경로가 아닙니다.
가역적 변경 (Reversible changes)
Runner는 제한된 역작업(inverse)을 기록하고 별도의 보상 제안(compensation proposal)을 생성할 수 있습니다.
되돌리기(Reverting)는 롤백(rollback)이나 타임 트래블(time travel)이 아닙니다. 이는 동일한 승인 및 쓰기 경계(writeback boundary)를 통과하는 또 다른 검토된 제안입니다.
이식 가능한 계약 (Portable contracts)
계약은 이식 가능한 JSON 문서입니다.
JSON을 직접 작성하거나 다음과 같은 구문을 포함하는 선택적인 SQL 스타일의 DSL(Domain-Specific Language)을 사용할 수 있습니다:
CREATE AGENT CONTEXTCREATE CAPABILITY- 승인 정책 (Approval policies)
DSL은 동일한 JSON 형식으로 컴파일됩니다.
어떤 방식이든, 계약은 애플리케이션 코드와 마찬가지로 Git에서 검토 및 버전 관리가 가능합니다.
명시적 제한 사항 (Explicit limitations)
이것은 보안 도구이므로, 저는 차라리 과장하지 않는 쪽을 택하겠습니다.
Synapsor Runner는:
- 임의의 SQL을 안전하게 만들지 않습니다.
- 프롬프트 인젝션 (Prompt injection)을 방지하지 않습니다.
- 최소 권한 데이터베이스 역할 (Least-privilege database roles)을 대체하지 않습니다.
- 제한된 뷰 (Restricted views)를 대체하지 않습니다.
- 행 수준 보안 (Row-level security)을 대체하지 않습니다.
- 스테이징 데이터 (Staging data)를 대체하지 않습니다.
이는 침해되었거나 실수한 모델이 읽고, 제안하고, 변경할 수 있는 범위를 제한하는 범위가 지정된 집행 경계 (scoped enforcement boundary)입니다.
내장된 가드 경로 (guarded path)는 의도적으로 다음을 제외합니다:
- 자유 형식 또는 모델이 생성한 서술어 (Predicates)
UPSERT- DDL (Data Definition Language)
- 제한 없는 쓰기 (Unbounded writes)
- 다중 테이블 트랜잭션 (Multi-table transactions)
- 외부 부수 효과 (External side effects)
그러한 작업에는 승인 후에만 호출되며, 애플리케이션이 트랜잭션 및 보안 검사의 소유권을 유지하는 애플리케이션 소유의 실행기 (executor)가 필요합니다.
토큰 비용 이점 (Token-cost benefits)
부수적인 이점은 이 접근 방식이 토큰을 더 적게 사용하는 경향이 있다는 것입니다.
모델이 SQL을 작성하는 대신 의미론적 도구 (semantic tools)를 호출하기 때문에:
- 컨텍스트(context) 내에 데이터베이스 스키마 (schema)가 필요하지 않습니다.
- 테이블 및 컬럼 덤프 (table and column dumps)가 필요하지 않습니다.
list_tables및describe_table을 위한 왕복 (round trips) 과정을 피할 수 있습니다.- “SQL 작성 → 컬럼 오류 → 재시도” 루프를 방지합니다.
- 타입이 지정된 인자 (Typed arguments)는 데이터베이스 왕복 이전에 실패할 수 있습니다.
- 결과는 컬럼 허용 목록 (allowlists) 및
MAX ROWS에 의해 제한됩니다. - 집계 읽기 (Aggregate reads)는 많은 행을 컨텍스트로 다시 보내는 대신
COUNT와 같은 스칼라 (scalar) 값을 반환할 수 있습니다. - 승인 및 쓰기 작업 (writeback)은 모델 외부에서 발생하므로, 해당 단계에서는 모델 토큰을 전혀 사용하지 않습니다.
주의할 점이 있습니다: 모든 기능이 모델의 tools/list에 나타난다는 것입니다.
하나의 에이전트에게 수백 개의 도구를 노출하는 계약 (contract)은 도구 정의 비대화 (tool-definition bloat)로 인해 토큰 절감 효과를 잃을 수 있습니다.
핵심 주장은 다음과 같습니다:
잘 정의된 범위의 계약 (Well-scoped contract) → 결과적으로 더 저렴함
이를 벤치마크된 수치라기보다는 방향성을 나타내는 지표로 취급하겠지만, 일반적인 경우 “실행당 더 안전하고 저렴하다”는 점은 유효해 보입니다.
저장소 (Repository)
github.com/Synapsor/Synapsor-Runner
저는 유지 관리자이며, 이미 MCP 클라이언트를 실제 데이터베이스에 연결하고 있는 분들의 피드백을 진심으로 환영합니다:
에이전트에게 어떤 워크플로우 (workflow)를 부여하고 싶었지만, 가공되지 않은 SQL이나 직접적인 API 권한이 너무 과하다고 느껴서 망설였던 적이 있나요?
“이런 형태는 ~ 때문에 맞지 않을 것 같습니다...”와 같은 답변조차도 큰 도움이 됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기