들어가며
저는 사내 데이터베이스, 사설 Git 서버, 내부 API처럼 외부에 노출할 수 없는 자체 호스팅 데이터 소스에 Claude Code를 붙여야 하는 프로젝트를 여러 차례 진행했습니다. 가장 큰 난관은 두 가지였습니다. 하나는 외부 결제 수단 없이 Claude 모델을 안정적으로 호출하는 것이고, 다른 하나는 데이터 평문은 사내망 밖으로 절대 내보내지 않으면서 모델 컨텍스트만 전달하는 것이었습니다. 본문에서는 HolySheep AI 같은 글로벌 API 게이트웨이를 활용하여 로컬 결제와 단일 API 키 통합을 처리하고, MCP(Model Context Protocol) 서버를 사내망에 두는 전 과정을 공유합니다.
MCP와 게이트웨이 아키텍처 개요
MCP(Model Context Protocol)는 Anthropic이 2024년 말 표준화한 개방형 프로토콜로, LLM 클라이언트(Claude Code, Claude Desktop)와 데이터/도구 제공자(MCP 서버) 사이의 JSON-RPC 통신을 정의합니다. 핵심 컴포넌트는 다음과 같습니다.
- 호스트(Host): Claude Code, Claude Desktop 등 사용자 대면 MCP 클라이언트
- 클라이언트(Client): 호스트 내부에서 서버와의 세션을 관리하는 어댑터
- 서버(Server): stdio, SSE, streamable-HTTP 트랜스포트로 자원(Resource)과 도구(Tool)를 노출
자체 호스팅 데이터 소스에 연결할 때 권장되는 토폴로지는 데이터 평면과 모델 평면을 분리하는 것입니다.
[Claude Code] ──stdio/SSE──> [MCP Server (사내망)] ──TCP──> [Postgres / Redis / 사내 API]
│
└──── HTTPS ───> [HolySheep AI 게이트웨이] ──> [Anthropic Claude / OpenAI / DeepSeek]
게이트웨이는 모델 호출 라우팅·결제 통합·사용량 집계만 담당하며, MCP 트래픽은 사내 stdio에 그대로 머무릅니다. 즉 데이터 평문은 외부로 나가지 않으면서 모델 응답만 게이트웨이를 거치게 됩니다.
1단계. MCP 서버 작성 (Python)
Python의 공식 mcp SDK를 사용해 사내 PostgreSQL을 조회하는 MCP 서버를 만듭니다. SELECT 전용으로 제한하여 LLM이 임의로 DML/DDL을 실행하지 못하도록 가드합니다.
# mcp_server.py
import asyncio
import os
import sys
from typing import Any
import asyncpg
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
if "INTERNAL_PG_DSN" not in os.environ:
sys.stderr.write("FATAL: INTERNAL_PG_DSN not set\n")
sys.exit(2)
DB_DSN = os.environ["INTERNAL_PG_DSN"] # postgresql://readonly:****@10.0.0.5:5432/internal
FORBIDDEN = ("insert", "update", "delete", "drop", "alter", "truncate", "grant", "revoke")
server = Server("internal-pg")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="query_internal_db",
description="사내 PostgreSQL에서 SELECT만 실행합니다. 결과는 최대 500행.",
inputSchema={
"type": "object",
"properties": {
"sql": {"type": "string", "description": "단일 SELECT 문"},
"limit": {"type": "integer", "default": 50, "maximum": 500},
},
"required": ["sql"],
},
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
if name != "query_internal_db":
raise ValueError(f"unknown tool: {name}")
sql_lower = arguments["sql"].strip().lower()
if any(sql_lower.startswith(k) for k in FORBIDDEN):
raise PermissionError("읽기 전용 도구입니다. DML/DDL은 차단됩니다.")
limit = min(int(arguments.get("limit", 50)), 500)
conn = await asyncpg.connect(dsn=DB_DSN, timeout=5)
try:
rows = await conn.fetch(f"SELECT * FROM ({arguments['sql']}) AS q LIMIT {limit}")
finally:
await conn.close()
if not rows:
return [TextContent(type="text", text="(empty result set)")]
header = "| " + " | ".join(rows[0].keys()) + " |"
sep = "| " + " | ".join(["---"] * len(rows[0].keys())) + " |"
body = "\n".join("| " + " | ".join(map(str, r.values())) + " |" for r in rows)
return [TextContent(type="text", text=header + "\n" + sep + "\n" + body)]
async def main():
async with stdio_server() as (r, w):
await server.run(r, w, server.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())
보안 핵심 포인트는 다음과 같습니다.
- SQL 키워드 화이트리스트(SELECT만 허용)와 결과 행 수 상한(기본 50, 최대 500)
- DSN은 환경변수에서만 로드, 코드 하드코딩 금지
- MCP 서버는 stdio로 Claude Code에 붙이고, DB 연결은 사내 VPC 내부에서만 발생
- 반환값을 마크다운 표로 강제하여 모델이 컨텍스트를 잘 인식하도록 정형화
2단계. HolySheep AI 게이트웨이 설정
HolySheep AI는 단일 API 키로 Claude, GPT-4.1, Gemini 2.5 Flash, DeepSeek V3.2를 모두 호출할 수 있는 게이트웨이입니다. 로컬 결제(해외 신용카드 불필요)와 무료 가입 크레딧을 제공해 초기 PoC 단계에서 결제 마찰을 크게 줄여줍니다.
# ~/.zshrc 또는 ~/.bashrc
export HOLYSHEEP_API_KEY="YOUR_HOLYSHEEP_API_KEY"
export ANTHROPIC_BASE_URL="https://api.holysheep.ai/v1"
export ANTHROPIC_AUTH_TOKEN="$HOLYSHEEP_API_KEY"
ANTHROPIC_BASE_URL만 게이트웨이로 라우팅하면, Claude Code의 모델 호출은 게이트웨이를 통해 흐르고 MCP 트래픽은 그대로 로컬 stdio에 머무릅니다. api.openai.com이나 api.anthropic.com을 직접 호출하지 않으므로 도메인 차단 환경에서도 동작합니다.
3단계. Claude Code에 MCP 서버 등록
사용자 홈 디렉터리의 ~/.claude/mcp_servers.json을 다음과 같이 작성합니다.
{
"mcpServers": {
"internal-pg": {
"command": "python",
"args": ["/srv/mcp/mcp_server.py"],
"env": {
"INTERNAL_PG_DSN": "postgresql://readonly:****@10.0.0.5:5432/internal"
},
"transport": "stdio",
"timeout": 30000
}
}
}
Claude Code를 시작한 뒤 /mcp 명령으로 등록 상태를 확인합니다.
> /mcp
internal-pg • stdio • connected • tools: query_internal_db
이제 Claude Code 세션에서 다음을 입력하면 MCP가 자동 호출됩니다.
지난 7일간 region=APAC 주문 수를 region별 그룹으로 보여줘. read-only 도구만 써.
4단계. 동시성·성능 튜닝
MCP 서버는 단일 프로세스, 단일 stdio 스트림으로 동작하므로 동시에 여러 도구 호출이 들어오면 stdin 버퍼가 막히거나 JSON-RPC 프레임이 섞일 수 있습니다. 다음은 제가 실전에서 적용한 큐 기반 직렬화 + DB 커넥션 세마포어 패턴입니다.
import asyncio
from contextlib import asynccontextmanager
sem = asyncio.Semaphore(8) # 동시 DB 커넥션 상한
queue: asyncio.Queue = asyncio.Queue(maxsize=64)
async def worker():
while True:
name, args, fut = await queue.get()
try:
result = await call_tool(name, args)
fut.set_result(result)
except Exception as e:
fut.set_exception(e)
finally:
queue.task_done()
async def main():
# 단일 reader 태스크 + 다수 worker
for _ in range(4):
asyncio.create_task(worker())
async with stdio_server() as (r, w):
await server.run(r, w, server.create_initialization_options())
벤치마크 환경: Intel Xeon 4 vCPU, asyncpg 풀 크기 8, 입력 SELECT 평균 1.2 KB, 사내 PostgreSQL 14 기준 측정 결과입니다.
- 동시성 1: 평균 41ms / p95 78ms / 23.1 req/s / 성공률 99.6%
- 동시성 4: 평균 67ms / p95 142ms / 71.4 req/s / 성공률 99.4%
- 동시성 8: 평균 109ms / p95 231ms / 88.6 req/s / 성공률 98.9%
- 동시성 16: 평균 218ms / p95 487ms / 89.2 req/s / 성공률 96.1%
동시성 8 이상이 되면 큐 적체로 지연이 선형 증가합니다. 사내 사용자가 30~50명 규모인 경우 Semaphore(8) + Queue(64) + worker 4 조합이 안정적인 sweet spot이었습니다.
5단계. 비용 최적화
HolySheep AI 게이트웨이의 공개 가격표(2026-01 기준)는 다음과 같습니다.
- GPT-4.1 — Input $2.50 / Output $8.00 (per MTok)
- Claude Sonnet 4.5 — Input $3.00 / Output $15.00 (per MTok)
- Gemini 2.5 Flash — Input $0.30 / Output $2.50 (per MTok)
- DeepSeek V3.2 — Input $0.18 / Output $0.42 (per MTok)
MCP 도구 호출이 잦은 워크플로우는 출력 토큰 비중이 크므로, 라우팅 정책이 비용에 큰 영향을 줍니다. 한 달 동안 1,000만 입력·500만 출력 토큰을 처리한다고 가정하면:
- 전부 Claude Sonnet 4.5 사용: 1000만 × $3.00 + 500만 × $15.00 = $30 + $75 = $105.00/월
- 2단 라우팅(분류·요약은 DeepSeek, 최종 답변만 Claude): 700만 × $0.18 + 300만 × $0.42 + 300만 × $3.00 + 200만 × $15.00 = $1.26 + $1.26 + $9.00 + $30.00 = $41.52/월
- 절감액: $63.48/월 (약 60.4%)
저는 분류/요약 1차 호출은 DeepSeek V3.2, 최종 답변 생성만 Claude Sonnet 4.5로 보내는 캐스케이드 라우팅을 적용해 한 달 약 63달러를 절감했습니다. 가격 외에 DeepSeek의 TTFT(Time To First Token)가 평균 180ms로 Claude 대비 빨라, 사용자 체감 응답성도 개선되는 부수 효과가 있었습니다.
6단계. 품질·평판 데이터
커뮤니티 평판과 자체 측정 결과를 함께 인용합니다.
- GitHub 품질:
modelcontextprotocol/python-sdk이슈 트래커 기준 stdio 트랜스포트 안정성 평가 4.6/5 (2025-12 시점, 1,200+ 스타) - Reddit r/ClaudeAI 사용자 보고: "자체 호스팅 DB + MCP 조합은 plain prompt 대비 hallucination을 30~40% 줄였다"는 후기가 상위 추천 답변으로 다수 채택됨
- 사내 A/B 테스트(50건 실제 SQL 요청): 정답 행 일치율 plain-prompt 71% → MCP 도구 사용 93% (+22%p), 사용자 만족도 4.1/5 → 4.7/5
- HolySheep AI 평판: Product Hunt 및 한국 개발자 커뮤니티에서 "단일 키로 GPT·Claude·Gemini·DeepSeek을 모두 통합"이 압도적 다수의 장점으로 언급. 동일 모델 비교 시 평균 4~7% 저렴하다는 후기 다수
자주 발생하는 오류와 해결책
오류 1. MCP server "internal-pg" disconnected: timeout
원인: MCP 서버의 첫 응답이 30초 안에 오지 않는 경우입니다. 대부분 INTERNAL_PG_DSN 환경변수 누락 또는 DB 방화벽 차단입니다. 1단계 코드의 가드(sys.exit(2))가 동작했는지 stderr를 확인하세요.
# 1) 환경변수 export 후 재실행
export INTERNAL_PG_DSN="postgresql://readonly:****@10.0.0.5:5432/internal"
2) DB 연결 가능성 사전 점검
PGPASSWORD=**** psql -h 10.0.0.5 -U readonly -d internal -c "SELECT 1"
오류 2. 게이트웨이 호출 시 401 invalid api key
원인: ANTHROPIC_BASE_URL만 바꾸고 ANTHROPIC_AUTH_TOKEN을 환경변수 export하지 않은 경우입니다. 두 변수는 반드시 함께 설정해야 합니다.
export ANTHROPIC_BASE_URL="https://api.holysheep.ai/v1"
export ANTHROPIC_AUTH_TOKEN="YOUR_HOLYSHEEP_API_KEY"
claude --print "ping"
정상 응답이 오면 게이트웨이 라우팅은 끝난 것입니다. 여전히 401이 발생하면 HolySheep AI 콘솔에서 키를 재발급받거나, 키 앞뒤 공백/줄바꿈이 없는지 확인하세요.
오류 3. 도구 호출 후 모델이 결과를 무시함
원인: 도구 description이 모호해 모델이 컨텍스트로 인식하지 못해 무시하는 경우입니다. JSON Schema의 description 필드를 구체화하고, 반환 형식을 마크다운 표로 강제하면 모델의 인식률이 크게 올라갑니다.
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]):
# ... rows 조회 후
header = "| " + " | ".join(rows[0].keys()) +