
【AI 개발 지침서: 제2회】 Claude · Cursor와 자사 DB를 연결하는 실전 MCP 서버 구축
요약
Claude, Cursor 등 AI 에이전트가 사내 데이터베이스에 안전하게 접근할 수 있도록 MCP(Model Context Protocol) 서버를 구축하는 실전 가이드를 제공합니다. LLM이 직접 SQL을 실행하는 위험한 방식 대신, 파라미터화된 툴을 통해 보안과 타입 안전성을 확보하는 설계 패턴을 다룹니다.
핵심 포인트
- MCP를 활용한 안전한 DB 연동 및 보안 강화 방법론 제시
- Cursor 및 Claude Desktop 환경에서의 실전 통합 설정 절차 해설
- Raw SQL 실행의 위험성을 방지하는 파라미터화된 툴 설계
- Python 기반 MCP SDK를 이용한 실무형 서버 구축 기술
【
신연재: MCP · 고도화된 RAG · 자율 에이전트의 현장 설계론】 ※ 본 연재는 MCP (Model Context Protocol), Context Engineering, GraphRAG, Self-Healing Agent, 로컬 SLM 등의 최첨단 기술 스택을 사용하여, 실무 프로덕션에서 진정으로 견딜 수 있는 차세대 AI 시스템을 구축하는 중후한 핸즈온(Hands-on) 연재입니다.
지난 회차에서는 MCP (Model Context Protocol)의 내부 사양인 JSON-RPC 2.0 통신 메커니즘과, FastMCP 프레임워크를 사용한 기본적인 Tools / Resources / Prompts 구현 방법을 해부했습니다.
하지만 실제 시스템 개발이나 일상적인 개발 업무에서 진정한 가치를 발휘하는 것은, "평소 사용하는 에이전트(Cursor, Windsurf, Claude Desktop)로부터 사내 데이터베이스나 고유의 REST API에 안전하고 타입 안전(Type-safe)하게 액세스하도록 하는" 실전적인 통합입니다.
예를 들어, AI 에이전트에게 "최근 매출 저하의 원인이 되고 있는 고객 ID와 주문 로그를 조사해줘"라고 지시했을 때, 에이전트가 자율적으로 사내 DB를 안전하게 검색하고 결과를 정리하여 코드 보완이나 리포트 작성을 수행해 준다면 개발 생산성은 비약적으로 향상됩니다.
제2회인 이번 회차에서는 LLM에게 직접적인 위험한 SQL을 실행하게 하지 않고, 파라미터화된 타입 안전한 함수(Tools)를 통해 사내 데이터베이스(SQLite / PostgreSQL 가정)와 보안을 유지하며 주고받는 실용적인 MCP 서버를 구축합니다. 나아가, Cursor (.cursor/mcp.json) 및 Claude Desktop에 대한 실제 통합·운용 설정 절차까지 완전 해설하는 것을 목표로 합니다.
Python 버전: Python 3.10 이상 -
동작 확인 완료 주요 라이브러리:-
mcp>=1.2.0 (Anthropic 공식 MCP SDK) -
sqlite3 (Python 표준 라이브러리)
대상 클라이언트 환경:-
Cursor Editor (v0.45 이상, MCP 지원 버전) -
Claude Desktop (macOS / Windows)
LLM을 데이터베이스(DB)에 연결하는 접근 방식에는 크게 두 가지 설계 패턴이 존재합니다.
LLM에 DB 스키마를 전달하고, 동적으로 생성된 가공되지 않은(Raw) SQL 문자열 (SELECT * FROM ..., DELETE FROM ...)을 그대로 DB에 발행하게 하는 방식입니다.
【위험한 접근 방식】
[사용자 지시] ---> [LLM] ---> 가공되지 않은 SQL 문 `DROP TABLE users;` ---> [운영 DB (파괴)]
리스크 1: SQL 인젝션(SQL Injection)과 파괴적 조작: 프롬프트 인젝션(Prompt Injection) 등으로 인해 데이터 삭제나 구조 파괴 명령이 실행될 위험이 있습니다. -
리스크 2: 정보 유출: 권한 외의 테이블(비밀번호 해시, 개인정보 등)을 자유롭게 검색할 우려가 있습니다.
MCP를 통한 설계에서는 가공되지 않은 SQL 실행을 일절 허용하지 않고, **파라미터화된 정형 쿼리 함수(Tools)**만을 MCP 서버를 통해 노출시킵니다.
【보안이 강화된 MCP 접근 방식】
[사용자 지시] ---> [LLM] ---> JSON 파라미터 `{"user_id": "usr_101"}`
↓ (JSON-RPC)
...
| 비교 항목 | 가공되지 않은 Text-to-SQL 직접 실행 | MCP를 통한 툴 캡슐화 (본 수법) |
|---|---|---|
| 보안성 | 극히 위험 (SQL 인젝션, 데이터 삭제 리스크) | 극히 안전 (파라미터화된 쿼리로 SQL 고정화) |
| 타입 안전성 | 없음 (LLM의 출력 문자열에 의존) | 있음 (Pydantic/Python 타입 힌트로 완전 검증) |
| 응답 제어 | DB 전체의 스키마 이해가 필요하여 토큰 낭비 | 필요한 데이터만을 최소한의 JSON/Text로 반환 가능 |
| 액세스 권한 | DB 접속 계정의 권한에 의존 | 노출되는 Tool 함수 단위로 읽기/쓰기 권한을 엄격히 제어 가능 |
Cursor나 Claude Desktop이 로컬의 Python MCP 서버를 통해 데이터베이스와 대화하는 내부 통신 플로우는 다음과 같습니다.
그럼 실제로 고객 정보 테이블과 주문 이력 테이블을 가진 SQLite 데이터베이스를 자동 구축하고, Cursor나 Claude에서 안전하게 호출할 수 있는 MCP 서버 mcp_db_server.py를 작성해 보겠습니다.
새 파일 mcp_db_server.py를 생성하고, 아래의 전체 코드를 작성합니다.
# 동작 확인 완료된 라이브러리 버전: mcp>=1.2.0
import os
import sys
...
구현한 mcp_db_server.py의 기술적인 고안점과 포인트를 해설합니다.
conn.row_factory = sqlite3.Row를 지정함으로써, 쿼리 결과를 r['customer_id']와 같이 컬럼명으로 안전하게 참조할 수 있도록 했습니다.
-
모든 SQL 실행(
cursor.execute)에 있어, 플레이스홀더(Placeholder)?를 사용한 **파라미터화된 쿼리 (Parameterized Query)**를 철저히 적용했습니다. 이를 통해 LLM이 만에 하나 악의적인 문자열을 생성하더라도, 단순한 값 데이터로 이스케이프(Escape)되어 SQL 인젝션 (SQL Injection)이 물리적으로 불가능합니다. -
쓰기 작업(
create_new_order)에서는 반드시conn.commit()을 호출하여 변경 사항을 저장하고, 각 함수 내에서 확실하게conn.close()를 호출하여 데이터베이스 락 (Lock)을 해제하고 있습니다. -
입력값(
amount <= 0또는 고객 미존재)을 Python 로직 측에서 검증하고 명확한 에러 텍스트를 반환함으로써, LLM이 자율적으로 이유를 이해하고 수정 발언을 할 수 있도록 설계했습니다.
작성한 mcp_db_server.py를 Cursor 및 Claude Desktop에 등록하여 실제로 에이전트(Agent)로부터 호출하는 설정 절차를 해설합니다.
Cursor에서는 설정 화면의 UI를 통해 등록하거나, 프로젝트 직하의 .cursor/mcp.json 파일을 생성하여 설정합니다.
프로젝트의 루트 디렉토리에 .cursor 폴더를 생성하고, 아래의 mcp.json을 배치합니다.
{
"mcpServers": {
"company_db": {
...
- Cursor의 **「Cursor Settings」 -> 「MCP」**를 엽니다.
company_db가 표시되고, 녹색 램프(Active)가 점등되어 있는지 확인합니다.- Cursor Chat(
Ctrl + L또는Cmd + L)을 열고, "고객 usr_101의 주문 이력을 조사해줘"라고 지시하면, Cursor가 자동으로list_orders_for_customer도구를 호출하여 결과를 반환합니다.
【Cursor Chat 대화 예시】
사용자: 고객 usr_101의 최근 주문 내용과 합계 금액을 알려줘.
Cursor: 도구 `company_db:list_orders_for_customer`를 호출합니다...
...
claude_desktop_config.json (Windows: %APPDATA%\Claude\claude_desktop_config.json / Mac: ~/Library/Application Support/Claude/claude_desktop_config.json)을 열고, 아래 내용을 추가합니다.
{
"mcpServers": {
"company_db": {
...
- 읽기 전용 (Read-only) 모드의 분리: 본 운영 환경에서는 참조용 도구(
search등)만 탑재한 MCP 서버와 쓰기용 도구(create등)를 가진 MCP 서버를 나누고, 환경 변수READ_ONLY=true로 쓰기 기능을 스위치화하는 설계를 권장합니다. - 절대 경로의 이용:
mcp.json내의command나args에 기술하는 Python 경로 및 스크립트 경로는 상대 경로로 인한 오작동을 방지하기 위해 반드시 절대 경로로 지정해 주세요.
이번에는 에이전트(Cursor / Claude Desktop)로부터 사내 데이터베이스에 타입 안전(Type-safe)하고 보안성 있게 액세스하기 위한 실용적인 MCP 서버를 구축하고, 실제 개발 환경에 통합하여 동작시키는 절차를 해설했습니다.
생 SQL을 전달하지 않고, 파라미터화된 정형 도구(Parameterized Tool)로 캡슐화함으로써 보안 리스크를 제로(Zero)로 만들면서 에이전트의 작업 능력을 몇 배로 끌어올릴 수 있다는 것을 체감하셨을 것입니다.
하지만 에이전트가 복잡한 태스크를 수행하게 되면, 이번에는 "LLM에 전달하는 프롬프트나 문맥(Context)의 비대화"라는 다음 장벽에 부딪히게 됩니다. 토큰 비용(Token Cost)이 폭발적으로 증가하고, 긴 문장 속에 정보가 묻혀 정확도가 저하되는 "Lost in the Middle" 현상입니다.
다음, 제3회.
프롬프트 엔지니어링(Prompt Engineering)의 틀을 넘어, 장문 LLM 시대의 컨텍스트 관리 결정판, **『프롬프트에서 컨텍스트로: 장문 LLM 시대의 Context Engineering의 극의』**로 나아갑니다.
토큰 비용을 최소화하면서 에이전트의 기억과 문맥을 최적으로 제어하는 최첨단 컨텍스트 엔지니어링(Context Engineering)으로 함께 나아가 봅시다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기