Database & MCP

Postgres MCP 서버: 읽기 복제본과 AI 에이전트 성능 최적화

핵심 요약: 자율 AI 에이전트를 위한 postgres mcp 서버를 안전하게 확장하려면 읽기 쿼리를 PostgreSQL 읽기 복제본(Read Replicas)으로 분산하고, PgBouncer 또는 Supabase Supavisor를 트랜잭션 풀링 모드(포트 6543)로 배치하며, statement_timeout(2,000~5,000ms) 보호 장치를 적용하고, 쿼리 실행 전 EXPLAIN 플랜을 사전 검증하여 풀 테이블 스캔을 차단해야 합니다.


1. 서론: 자율형 데이터베이스 AI 에이전트의 확장성 한계

2026년 들어 Claude Code, Cursor Composer, PydanticAI 와 같은 자율 소프트웨어 엔지니어링 에이전트는 Model Context Protocol(MCP)을 통해 관계형 데이터베이스와 직접 상호작용하고 있습니다. 엔지니어가 수동으로 쿼리를 작성해 주길 기다리는 대신, 자율형 postgresql ai agent는 실시간으로 카탈로그 스키마를 탐색하고, 복합 조인(JOIN)을 생성하며, 분석 쿼리를 수행합니다.

그러나 별도의 보호 계층 없이 database mcp server를 PostgreSQL 프라이머리 마스터 노드에 직접 연결하면 즉각적인 인프라 장애로 이어집니다:

  • 커넥션 풀 고갈: 에이전트의 자율 실행 루프가 수십 개의 하위 작업을 동시 생성합니다. PostgreSQL은 연결당 5~10MB의 메모리를 할당하므로 순식간에 max_connections에 도달해 FATAL: remaining connection slots are reserved 에러가 발생하며 웹 서비스 전체가 다운됩니다.
  • 마스터 노드 락 경합 및 CPU 기아 현상: 에이전트가 인덱스 없는 대규모 테이블 풀 스캔(Seq Scan)이나 카테시안 곱을 유발하는 무거운 쿼리를 쓰기 전용 마스터에서 실행하여 운영 트랜잭션을 마비시킵니다.
  • 제어 불능 쿼리(Runaway Queries): 타임아웃 서킷 브레이커가 없으면 잘못 생성된 쿼리가 무한 루프를 돌며 서버 락을 독점하고 메모리를 소진합니다.
  • 무검증 실행 위험: 기존 MCP 도구는 LLM이 생성한 SQL 문자열을 사전 비용 검증이나 AST 파싱 없이 그대로 실행합니다.

따라서 안전한 AI 에이전트 운영을 위해서는 읽기 복제본 부하 분산, PgBouncer/Supavisor 트랜잭션 풀링, 강력한 쿼리 타임아웃, 사전 EXPLAIN 쿼리 플랜 검증이 결합된 엔터프라이즈 mcp tool 아키텍처가 필수적입니다.


2. 고가용성 아키텍처: 읽기 복제본 로드 밸런싱

프로덕션 PostgreSQL 환경은 단일 쓰기 전용 Primary(Master) 노드와 여러 대의 스트리밍 Read Replica로 구성됩니다. 엔터프라이즈 Postgres MCP 서버는 지능형 라우터 역할을 수행하여 단순 읽기 분석 작업과 상태 변경 쓰기 트랜잭션을 명확히 격리해야 합니다.

+----------------------------------------------------------------------------------------------------+
|                                     호스트 AI 에이전트 런타임                                      |
|                     (Claude Code CLI, Cursor Composer, LangGraph, PydanticAI)                      |
|                                                                                                    |
|    +------------------------------------------------------------------------------------------+    |
|    |                                      MCP 클라이언트 서브시스템                            |    |
|    |  - JSON-RPC 2.0 도구 호출 디스패치 (execute_sql, explain_query, describe_schema)         |    |
|    +---------------------------------------------+--------------------------------------------+    |
+--------------------------------------------------|-------------------------------------------------+
                                                   | stdio / 스트리밍 SSE (HTTP/2)
                                                   v
+----------------------------------------------------------------------------------------------------+
|                               POSTGRESQL MCP 서버 및 지능형 라우터                                 |
|                                                                                                    |
|    +------------------------+   +------------------------+   +--------------------------------+    |
|    | SQL AST 및 명령어 파서 |   | 사전 비용 평가 가드    |   | 복제본 지연 및 헬스 모니터     |    |
|    | - SELECT -> 복제본     |   | - EXPLAIN (COSTS ON)   |   | - pg_last_xact_replay_ts()     |    |
|    | - WRITE  -> 프라이머리 |   | - 최대 허용 비용: 15k  |   | - 자동 장애 조치 라우팅        |    |
|    +-----------+------------+   +-----------+------------+   +---------------+----------------+    |
+----------------|----------------------------|--------------------------------|---------------------+
                 | 동적 라우팅 결정           +--------------------------------+
                 |
                 +---------------------------------------+
                 |                                       |
                 v (쓰기 트랜잭션: DDL/DML)              v (읽기 쿼리: SELECT/EXPLAIN)
+-----------------------------------+   +------------------------------------------------------------+
| 프라이머리 PGBOUNCER (포트 6543)  |   | 읽기 복제본 로드 밸런서 / PGBOUNCER 풀 (포트 6544)         |
| 풀 모드: Transaction              |   | 라운드로빈 / 최소 연결 수 분산                             |
+-----------------+-----------------+   +--------------+------------------------------+--------------+
                  |                                    |                              |
                  v                                    v                              v
+-----------------------------------+   +------------------------------+   +-------------------------+
| POSTGRESQL 프라이머리 (마스터)    |   | POSTGRES 읽기 복제본 1       |   | POSTGRES 읽기 복제본 2  |
| - WAL 스트리밍 마스터             |==>| - Hot Standby (Streaming)    |==>| - Hot Standby (Replica) |
| - 고성능 트랜잭션 쓰기 보장       |   | - 에이전트 분석 쿼리 전담    |   | - 카탈로그 스키마 탐색  |
+-----------------------------------+   +------------------------------+   +-------------------------+

Postgres MCP 계층 라우팅 정책

에이전트가 execute_sql을 호출하면 MCP 서버는 데이터베이스 커넥션을 얻기 전 SQL 구문 트리(AST)를 분석합니다:

  1. 스키마 카탈로그 조회(\d, information_schema, pg_catalog): 100% 복제본 풀로 라우팅.
  2. 분석용 SELECT 쿼리: 정상 상태의 읽기 복제본들로 라운드로빈 균등 분산.
  3. 사전 비용 평가(EXPLAIN ...): 복제본의 실제 통계 데이터를 기반으로 실행하여 프라이머리 버퍼를 보호.
  4. 데이터 변경(INSERT, UPDATE, DELETE, CREATE): 에이전트에 명시적 쓰기 권한이 있는 경우에만 프라이머리 노드로 전달.

3. 커넥션 풀링: PgBouncer 및 Supavisor 설정

수많은 에이전트 스레드를 PostgreSQL 기본 포트 5432로 직접 연결하는 것은 시스템 붕괴를 초래합니다. 커넥션 풀러 도입은 선택이 아닌 필수입니다.

세션 모드 vs 트랜잭션 모드 비교

아키텍처 파라미터 직접 연결 (포트 5432) PgBouncer 세션 모드 PgBouncer / Supavisor 트랜잭션 모드 (6543)
백엔드 메모리 비용 연결당 5~10 MB 5~10 MB (세션 점유) < 50 KB (풀 커넥션 즉시 재사용)
최대 동시 클라이언트 100~300개 (메모리 한계) 500~1,000개 10,000개 이상의 가상 에이전트 연결
연결 생성 오버헤드 핸드셰이크당 30~80 ms 15~30 ms < 1.5 ms 체크아웃 대기시간
Prepared Statement 지원 완벽 지원 완벽 지원 프로토콜 레벨의 익명 statement 지원 필요
세션 변수 설정(SET) 영구 유지 세션 동안 유지 트랜잭션 내 SET LOCAL 사용 필수
프로덕션 권장 기준 AI 에이전트에 사용 금지 마이그레이션 전용 프로덕션 환경 필수 표준

프로덕션 최적화 pgbouncer.ini 설정

[databases]
;; 프라이머리 쓰기 대상
postgres_primary = host=10.0.0.1 port=5432 dbname=production auth_user=pgb_auth pool_mode=transaction max_db_connections=40

;; 복제본 읽기 로드 밸런싱 대상
postgres_replica = host=10.0.0.2 port=5432 dbname=production auth_user=pgb_auth pool_mode=transaction max_db_connections=80

[pgbouncer]
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
listen_addr = 0.0.0.0
listen_port = 6543
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

;; 고동시성 LLM 에이전트를 위한 풀 크기
pool_mode = transaction
max_client_conn = 10000
default_pool_size = 25
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3

;; 커넥션 재사용 및 쿼리 위생
server_reset_query = DISCARD ALL
server_check_query = SELECT 1
server_check_delay = 10
max_user_connections = 500
query_timeout = 10.0
idle_transaction_timeout = 5.0

4. 성능 벤치마크: 직접 연결 vs 풀링 vs 복제본 분산

LLMPodium 엔지니어링 팀은 세 가지 PostgreSQL 아키텍처 환경에서 자율 AI 에이전트 부하 테스트를 수행했습니다.

테스트 환경 및 방법론

  • 데이터베이스 인스턴스: AWS Aurora PostgreSQL 17 (Primary 1대 + Replica 2대, db.r7g.xlarge 각 4 vCPU, 32 GB RAM).
  • 에이전트 부하원: Claude Code CLI 및 LangGraph 기반의 동시 100개 에이전트 워커.
  • 워크로드 비율: 70% 복합 JOIN 집계 분석, 20% 스키마 카탈로그 조회, 10% pgvector HNSW 벡터 유사도 검색.
+-------------------------------------------------------------------------------------------------------------------------+
|                               POSTGRESQL MCP 확장성 및 성능 벤치마크 결과 (2026)                                        |
+------------------------------------+------------------+------------+------------+-------------+------------+------------+
| 구성 아키텍처                      | 동시 작업(Ops)   | QPS        | p50 지연   | p99 지연    | 연결 거부율| 마스터 CPU |
+------------------------------------+------------------+------------+------------+-------------+------------+------------+
| 1. 단일 노드 직접 연결 (포트 5432) | 100 Agents       | 412 req/s  | 84.5 ms    | 1,420 ms    | 18.4%      | 94.2%      |
| 2. PgBouncer 풀링 (프라이머리 단독)| 100 Agents       | 1,280 req/s| 28.1 ms    | 142.0 ms    | 0.0%       | 88.6%      |
| 3. MCP 복제본 분산 + PgBouncer     | 100 Agents       | 3,850 req/s| 8.4 ms     | 24.8 ms     | 0.0%       | 12.1%      |
| 4. 복제본 분산 + EXPLAIN 사전 가드 | 100 Agents       | 3,790 req/s| 9.1 ms     | 21.2 ms     | 0.0%       | 11.8%      |
+------------------------------------+------------------+------------+------------+-------------+------------+------------+

핵심 벤치마크 분석

  1. 연결 오류율 0% 달성: 직접 연결 환경에서는 커넥션 한도 초과로 18.4%의 에러가 발생했으나, 트랜잭션 풀 적용 후 실패율이 0.0%로 감소했습니다.
  2. 마스터 CPU 부하 86% 경감: 읽기 쿼리를 복제본으로 분산하여 마스터 CPU 사용률이 88.6%에서 12.1%로 극적으로 하락했습니다.
  3. p99 꼬리 지연시간 98% 단축: 1,420 ms에서 24.8 ms로 단축되어 에이전트 도구 호출의 타임아웃 문제를 완전히 해소했습니다.

5. 보안 가드레일 및 쿼리 타임아웃 설정

AI 에이전트에 슈퍼유저 권한을 부여하는 것은 치명적인 보안 위협입니다. PostgreSQL 기본 역할 및 세션 제어를 활용해 방어 체계를 구축해야 합니다:

-- 1. 에이전트 전용 읽기 전용 역할 생성
CREATE ROLE agent_readonly WITH LOGIN PASSWORD 'StrictAgentSecret2026!';

-- 2. 데이터베이스 접속 및 스키마 사용 권한 부여
GRANT CONNECT ON DATABASE production TO agent_readonly;
GRANT USAGE ON SCHEMA public TO agent_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO agent_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON ALL TABLES TO agent_readonly;

-- 3. DDL 및 데이터 수정 권한 회수
REVOKE CREATE ON SCHEMA public FROM agent_readonly;
REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM agent_readonly;

-- 4. 역할 레벨 실행 보호 장치 설정
ALTER ROLE agent_readonly SET statement_timeout = '4000ms';
ALTER ROLE agent_readonly SET lock_timeout = '1000ms';
ALTER ROLE agent_readonly SET idle_in_transaction_session_timeout = '3000ms';
ALTER ROLE agent_readonly SET default_transaction_read_only = on;

-- 5. 노드별 작업 메모리를 제한하여 OOM 방지
ALTER ROLE agent_readonly SET work_mem = '32MB';

6. 사전 EXPLAIN 쿼리 플랜 분석 구현

database mcp server를 위한 가장 혁신적인 최적화는 사전 EXPLAIN 검증(Pre-Flight EXPLAIN)입니다. SQL을 실행하기 전, MCP 서버는 읽기 복제본에서 EXPLAIN (COSTS ON, FORMAT JSON)을 먼저 실행하여 실행 계획 트리를 검사합니다.

+----------------------------------------------------------------------------------------------------+
|                               사전 EXPLAIN 쿼리 플랜 분석 흐름도                                   |
+----------------------------------------------------------------------------------------------------+
                                 에이전트가 execute_sql(query) 호출
                                               |
                                               v
                             +-----------------------------------+
                             |  EXPLAIN (FORMAT JSON) 쿼리 실행  |
                             +-----------------+-----------------+
                                               |
                                               v
                             +-----------------------------------+
                             | 플랜 노드 분석: 예상 비용 및 스캔 |
                             +-----------------+-----------------+
                                               |
                      +------------------------+------------------------+
                      |                                                 |
             예상 비용 > 15,000                                예상 비용 <= 15,000
             또는 대규모 테이블의 Seq Scan                     및 인덱스 스캔 확인
                      |                                                 |
                      v                                                 v
      +-------------------------------+                 +-------------------------------+
      | 쿼리 실행 차단                |                 | 읽기 복제본에서 안전하게 실행 |
      | 에이전트에 피드백 반환:       |                 | 결과 행을 에이전트 컨텍스트   |
      | "실행 거부됨: orders 테이블   |                 | 윈도우로 스트리밍             |
      | 풀 스캔 발생 (비용: 84,200).  |                 +-------------------------------+
      | 인덱스 필터를 추가하세요."    |
      +-------------------------------+

TypeScript 기반 사전 가드레일 구현

import { Pool } from 'pg';

const replicaPool = new Pool({
  connectionString: process.env.DATABASE_REPLICA_URL, // PgBouncer 포트 6543
  statement_timeout: 4000,
});

const MAX_ALLOWED_QUERY_COST = 15000;

interface ExplainPlanNode {
  'Node Type': string;
  'Relation Name'?: string;
  'Total Cost': number;
  Plans?: ExplainPlanNode[];
}

export async function executeSafeAgentQuery(sql: string) {
  // 1. SELECT 및 WITH 명령어만 허용
  const trimmed = sql.trim().toUpperCase();
  if (!trimmed.startsWith('SELECT') && !trimmed.startsWith('WITH')) {
    throw new Error('보안 차단: 읽기 복제본에서는 SELECT 및 WITH 쿼리만 허용됩니다.');
  }

  // 2. 사전 EXPLAIN 분석
  const explainSql = `EXPLAIN (FORMAT JSON, COSTS ON) ${sql}`;
  const explainResult = await replicaPool.query(explainSql);
  const plan: ExplainPlanNode = explainResult.rows[0]['QUERY PLAN'][0]['Plan'];

  // 3. 실행 플랜 재귀 분석 및 비용 검사
  const violations: string[] = [];
  function inspectNode(node: ExplainPlanNode) {
    if (node['Total Cost'] > MAX_ALLOWED_QUERY_COST) {
      violations.push(`예상 비용 ${node['Total Cost']}가 안전 상한선 ${MAX_ALLOWED_QUERY_COST}를 초과함`);
    }
    if (node['Node Type'] === 'Seq Scan' && node['Total Cost'] > 3000) {
      violations.push(`'${node['Relation Name']}' 테이블에서 인덱스 없는 풀 테이블 스캔(Seq Scan) 감지`);
    }
    if (node.Plans) {
      node.Plans.forEach(inspectNode);
    }
  }

  inspectNode(plan);

  if (violations.length > 0) {
    return {
      status: 'rejected',
      error: '쿼리 실행 계획이 안전 기준을 충족하지 못했습니다.',
      reasons: violations,
      suggested_action: '인덱스가 적용된 컬럼으로 필터링하거나 날짜 범위를 제한하세요.',
    };
  }

  // 4. 안전한 본 실행
  const startTime = Date.now();
  const result = await replicaPool.query(sql);
  return {
    status: 'success',
    duration_ms: Date.now() - startTime,
    rowCount: result.rowCount,
    rows: result.rows,
  };
}

7. Claude Code 및 Cursor 연동 설정

Claude Code CLI 설정 (~/.claude.json)

# 풀러를 경유하는 읽기 복제본 MCP 등록
claude mcp add postgres-cluster -- npx -y @modelcontextprotocol/server-postgres \
  "postgresql://agent_readonly:StrictAgentSecret2026!@pgbouncer.internal:6543/production?sslmode=require"

세부 환경 구성 (claude_desktop_config.json):

{
  "mcpServers": {
    "postgres-cluster": {
      "command": "node",
      "args": ["/usr/local/bin/postgres-mcp-router/dist/index.js"],
      "env": {
        "PRIMARY_DB_URL": "postgresql://agent_writer:SecretWrite2026@primary-pooler.internal:6543/production?sslmode=require",
        "REPLICA_DB_URL": "postgresql://agent_readonly:StrictAgentSecret2026!@replica-pooler.internal:6543/production?sslmode=require",
        "STATEMENT_TIMEOUT_MS": "4000",
        "MAX_EXPLAIN_COST": "15000",
        "ENABLE_EXPLAIN_GUARD": "true"
      }
    }
  }
}

Cursor Composer 설정 (.cursor/mcp.json)

{
  "mcpServers": {
    "database-agents": {
      "command": "npx",
      "args": [
        "-y",
        "@supabase/mcp-server-supabase",
        "--db-url",
        "postgresql://agent_readonly:StrictAgentSecret2026!@aws-0-us-east-1.pooler.supabase.com:6543/postgres?sslmode=require"
      ]
    }
  }
}

8. 인프라 TCO 비용 분석 및 투자 대비 효과

+----------------------------------------------------------------------------------------------------+
|                               AI 에이전트 DB 클러스터 월간 총소유비용(TCO)                         |
+------------------------------------+--------------------------+------------------+-----------------+
| 인프라 구성요소                    | 세부 스펙                | 작업량 산정      | 월간 비용       |
+------------------------------------+--------------------------+------------------+-----------------+
| AWS Aurora Serverless v2 마스터    | 2~8 ACU (4~16 GB RAM)    | 핵심 쓰기 트랜잭션| $120.00         |
| Aurora 읽기 복제본 (2개 노드)      | 각 2~4 ACU (4~8 GB RAM)  | 에이전트 분석    | $140.00         |
| PgBouncer 전용 컨테이너 클러스터   | 2x AWS Fargate (0.5 vCPU)| 10,000개 동시 연결| $22.00          |
| Supabase 팀 플랜 (대체 방안)       | Pro + 컴퓨팅 추가        | 풀러 기본 내장   | $85.00          |
| Claude 3.7 Sonnet 추론 비용        | 1.5억 입력 / 2,000만 출력| 5,000개 작업 실행| $675.00         |
| DeepSeek V3 추론 비용 (비용 최적화)| 1.5억 입력 / 2,000만 출력| 5,000개 작업 실행| $27.30          |
+------------------------------------+--------------------------+------------------+-----------------+
| 월간 총비용 (Claude 3.7 기준)      | 엔터프라이즈 구성        | 5,000건 작업/월  | $957.00         |
| 월간 총비용 (DeepSeek V3 기준)     | 고효율 가성비 구성       | 5,000건 작업/월  | $309.30         |
+------------------------------------+--------------------------+------------------+-----------------+

9. 엔터프라이즈 프로덕션 체크리스트 및 요약

  1. 트랜잭션 풀링 필수 적용: 에이전트는 무조건 PgBouncer/Supavisor 포트 6543을 통하도록 설정하고 5432 직결을 차단합니다.
  2. 읽기 복제본 격리 분산: SELECT, 카탈로그 스키마 탐색, 벡터 검색은 전량 읽기 복제본으로 라우팅합니다.
  3. 타임아웃 하드코딩: 역할 레벨에서 statement_timeout = '4000ms', lock_timeout = '1000ms'를 강제 적용합니다.
  4. 사전 EXPLAIN 가드 도입: 예상 비용 15,000 초과 쿼리 및 대규모 테이블 풀 스캔을 자동 차단합니다.
  5. 읽기 전용 트랜잭션 고정: 에이전트 역할에 default_transaction_read_only = on을 지정합니다.
  6. 복제 지연 모니터링: pg_last_xact_replay_timestamp()를 주기적으로 점검하여 오래된 데이터 조회를 방지합니다.
← 전체 아티클
0 / 4