SQL MCP Server
SQL MCP 서버
AI 기반 Model Context Protocol (MCP) 서버로, 자연어를 사용하여 전자상거래 SQLite 데이터베이스를 쿼리하고 분석할 수 있습니다.
다음과 같은 질문을 해 보세요:
"총 지출 기준 상위 5명의 고객은 누구인가요?"
"재고가 50개 미만인 Electronics 카테고리의 모든 제품을 보여주세요"
"2026년 완료된 주문의 총 매출은 얼마였나요?"
네 가지 도구 중 세 가지는 API 키가 전혀 필요 없습니다. 두 가지 독립적인 수준에서 읽기 전용이며, 페이지 매김 결과, SQLite 자체 오류 텍스트를 호출자에게 전달하고, 74개의 자동화된 테스트가 있습니다.
목차 — 빠른 시작 · AI 공급자 구성 · 도구 · 페이지 매김 · 오류 · 테스트 · Docker · MCP 클라이언트 · 구성 · 안전 · 데이터 송신 · 프로젝트 구조
🚀 빠른 시작
1. 사전 요구 사항
Node.js:
v22.5.0이상(내장node:sqlite모듈용);v24권장npm:
v11.0.0이상
2. 설치
이 저장소를 클론하고 의존성을 설치합니다:
npm install
cp .env.example .env
npm run build이 정도면 서버를 클라이언트에 연결하고 list_tables, describe_table, execute_sql을 사용할 수 있습니다. 자연어 도구에만 공급자가 필요합니다 — 아래를 참조하세요.
Related MCP server: Shop SQLite MCP
🔑 AI 공급자 구성
.env 파일을 열고 선호하는 AI 모델을 설정하세요. 서버는 설정한 변수를 기반으로 공급자를 자동으로 감지합니다:
옵션 A: Anthropic Claude (권장)
ANTHROPIC_API_KEY=sk-ant-api03-...
ANTHROPIC_MODEL=claude-opus-5옵션 B: 로컬 Ollama (무료 및 오프라인)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2참고: Ollama가 실행 중인지(
ollama serve) 모델을 가져왔는지(ollama pull llama3.2) 확인하세요.
옵션 C: OpenAI
OPENAI_API_KEY=sk-proj-...
OPENAI_MODEL=gpt-4o-mini옵션 D: 사용자 지정 / 타사 (Groq, DeepSeek, OpenRouter)
OPENAI_API_KEY=your_api_key
OPENAI_BASE_URL=https://api.groq.com/openai/v1
OPENAI_MODEL=llama-3.3-70b-versatile🛠 사용 가능한 도구
네 가지 중 세 가지는 SQLite에 직접 연결됩니다 — API 키 없음, 비용 없음, 즉시:
도구 | 기능 | 공급자 필요 |
| 모든 테이블과 그 내용에 대한 평이한 설명, 행 수와 열, 테이블 간 관계, 이 데이터베이스가 사용하는 매출 규칙. | 아니요 |
| 한 테이블 전체 — 열(유형, 키, 설명 포함), 외래 키, | 아니요 |
| 모든 읽기 전용 | 아니요 |
| 평이한 질문을 받아 적절한 SQL을 생성 및 실행하고, 통찰력이 포함된 서면 답변을 반환합니다. | 예 |
각 도구의 설명은 호출 에이전트에게 도구가 무엇을 하는지뿐만 아니라 언제 사용하지 말아야 하는지도 알려줍니다 — query_database는 값이 아닌 산문을 반환하고, 비용이 들며, 두 번의 LLM 호출을 수행한다고 명시하고, 에이전트가 계산하려는 모든 것에 대해 execute_sql을 가리킵니다. 두 도구 모두 행 상한과 매출 규칙을 인라인으로 명시하므로 에이전트가 시행착오로 발견할 필요가 없습니다.
예: describe_table
// describe_table { "table_name": "orders" } — abridged
{
"table": "orders",
"purpose": "Order headers — one row per order placed by a customer, carrying its date, lifecycle status and total.",
"rowCount": 750,
"columns": [
{ "name": "status", "type": "TEXT", "primaryKey": false, "notNull": true, "default": null,
"description": "Lifecycle stage, one of: new, processing, shipped, completed, cancelled. Determines whether the order counts as revenue." }
],
"foreignKeys": [
{ "column": "customer_id", "referencesTable": "customers", "referencesColumn": "id", "onDelete": "CASCADE" }
],
"notes": ["Revenue convention: count every order whose status is not 'cancelled' …"],
"dataCoverage": { "order_date": { "min": "2026-02-17 18:53:30", "max": "2026-08-22 17:06:30" } },
"createStatement": "CREATE TABLE orders ( … )"
}dataCoverage는 에이전트가 빈 결과와 범위를 벗어난 질문을 구분할 수 있도록 하기 위한 것입니다. 2025년에 대해 묻는 경우 버그처럼 보이는 단순한 0 대신 "데이터는 …부터 …까지"를 반환합니다.
📄 대용량 결과 페이지 매김
모든 결과는 DATABASE_MAX_ROWS(기본값 100) 또는 전달한 더 작은 limit으로 제한됩니다. 더 큰 limit은 거부되지 않고 잘리므로 호출자는 항상 행을 받습니다.
execute_sql은 limit과 offset을 받고 더 많은 데이터가 있는지 알려줍니다:
// execute_sql { "sql": "SELECT id, name FROM products ORDER BY id", "limit": 2, "offset": 2 }
{
"columns": ["id", "name"],
"rows": [
{ "id": 3, "name": "Ноутбук UltraBook 15" },
{ "id": 4, "name": "Умные часы FitWatch" }
],
"rowCount": 2,
"offset": 2,
"hasMore": true,
"nextOffset": 4,
"note": "More rows matched than were returned. Call again with offset=4 for the next page.",
"executionTimeMs": 0.09
}hasMore가 false가 될 때까지 offset: nextOffset으로 계속 호출하세요. 결과가 한 페이지에 맞으면 hasMore는 false이고 totalAvailableRows는 실제 총계를 보고합니다.
상한은 문을 실행하는 동안 적용되며 완료된 결과를 잘라내는 것이 아닙니다. 서버는 상한보다 한 행 더 멈추고 나머지를 구체화하지 않습니다. SQL은 모델 생성이므로 우발적인 교차 조인은 버려지기 전에 수백만 행을 메모리로 가져올 수 있습니다. 페이지 매김도 SQL에 LIMIT/OFFSET을 추가하는 대신 반복 중에 수행되며, 생성된 문이 이미 끝나는 방식에 관계없이 작동해야 합니다.
query_database는 행 상한을 공유하지만 페이지 매김은 하지 않습니다 — 산문으로 요약하며, 페이지 번호가 붙을 대상이 없습니다. 한 페이지보다 큰 것은 execute_sql을 사용하세요.
🚦 오류 형태
실패는 전송 수준 오류가 아닌 일반 MCP 도구 결과로 isError: true와 호출 에이전트가 조치할 수 있는 메시지로 반환됩니다.
보내는 내용 | 받는 내용 |
|
|
|
|
|
|
|
|
데이터 삭제를 요청하는 자연어 요청 |
|
이 텍스트를 지배하는 두 가지 규칙:
SQLite 자체 메시지가 보존됩니다. "no such column: nope"는 에이전트에게 가장 유용한 정보로, 쿼리를 다시 작성하고 재시도하기에 충분합니다. "query failed"로 평탄화되지 않습니다.
호스트 세부 정보는 절대 유출되지 않습니다. 인식할 수 없는 오류(스택 추적을 포함할 수 있음)는 일반적인 한 줄로 축소되고, 나가는 모든 것은 데이터베이스 경로, 프로젝트 루트, 홈 디렉터리에서 삭제됩니다. 전체 세부 정보는 서버 로그에 남습니다. 이는 자체 테스트 파일로 다룹니다.
🧪 자동화 테스트
npm test # 74 tests across 4 files, runs in well under a second
npm run test:watch
npm run typecheck일반 node --test와 tsx — 테스트 프레임워크 의존성 없음. 스위트는 실제 db/shop.db에 대해 실행되며 목이 아닙니다. 따라서 스키마와 문서가 어긋나면 실패합니다.
파일 | 내용 |
| 쓰기가 읽기 전용 가드를 우회할 수 있는 모든 방법: 선행 주석, |
| 행 상한, |
| 호출자가 볼 수 있는 것: 실행 가능한 메시지는 통과하고, 알 수 없는 오류는 축소되며, 데이터베이스 경로 / 프로젝트 루트 / 홈 디렉터리가 둘 다에서 삭제됩니다. |
| 라이브 데이터베이스의 모든 테이블과 열에 서면 설명이 있고, 더 이상 존재하지 않는 테이블을 참조하는 설명이 없으며, 매출 규칙이 명시되어 있는지. |
가드 스위트가 가장 중요합니다. "읽기 전용"을 의도가 아닌 사실로 만드는 경계이며, 그 사례 중 하나는 개발 중에 발견한 실제 오탐입니다.
🐳 Docker
docker build -t sql-mcp .이미지에는 데이터베이스가 포함되어 있으므로 볼륨 마운트가 필요 없습니다. stdio 서버이므로 -i와 TTY 없이 실행해야 합니다 — 컨테이너의 stdin과 stdout이 JSON-RPC 스트림을 전달합니다:
docker run -i --rm -e ANTHROPIC_API_KEY sql-mcpexamples/claude_desktop_config.docker.json으로 클라이언트에 연결하세요. 자격 증명 없이 실행하려면 -e ANTHROPIC_API_KEY를 제거하세요 — list_tables, describe_table, execute_sql은 공급자 없이 작동합니다.
빌드는 다단계입니다. TypeScript는 node:24-alpine 빌더에서 컴파일되고, dist/, db/ 및 프로덕션 의존성만 런타임 이미지에 복사됩니다. 권한 없는 node 사용자로 실행되며, .env는 절대 복사되지 않고(자격 증명은 -e에서 옴), SQLite가 Node 자체에 포함되어 있으므로 컴파일할 네이티브 애드온이 없습니다.
🔌 MCP 클라이언트 연결
바로 사용할 수 있는 구성 파일은 examples/에 있습니다 — 클라이언트에 맞는 파일을 복사하고 경로를 바꾸세요. examples/claude_desktop_config.no-api-key.json은 자격 증명 없이 서버를 실행하며, list_tables, describe_table, execute_sql에 충분합니다.
Claude Desktop 구성
이 서버를 Claude Desktop 구성 파일(claude_desktop_config.json)에 추가하세요:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
(연결 전에 npm run build를 한 번 실행하세요)
예 1: Anthropic Claude (기본)
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-api03-your-key-here",
"ANTHROPIC_MODEL": "claude-opus-5"
}
}
}
}예 2: 로컬 Ollama (무료 및 오프라인)
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"OLLAMA_BASE_URL": "http://localhost:11434",
"OLLAMA_MODEL": "llama3.2"
}
}
}
}예 3: OpenAI
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"OPENAI_API_KEY": "sk-proj-your-key-here",
"OPENAI_MODEL": "gpt-4o-mini"
}
}
}
}예 4: 사용자 지정 / Groq / OpenRouter / DeepSeek
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"OPENAI_API_KEY": "gsk_your_groq_api_key",
"OPENAI_BASE_URL": "https://api.groq.com/openai/v1",
"OPENAI_MODEL": "llama-3.3-70b-versatile"
}
}
}
}서버는 db/shop.db를 자체 위치 기준으로 해석하므로 DATABASE_PATH는 이 중 어느 것에도 필요하지 않습니다 — MCP 클라이언트는 서버를 자체 선택한 작업 디렉터리에서 시작하며, 서버는 이에 의존하지 않습니다.
🔎 로컬에서 시도하기
즉시 터미널 테스트
터미널에서 자연어 질문을 직접 테스트할 수 있습니다:
npm run query -- "Show top 3 products by price"시각적 웹 검사기
공식 MCP Inspector를 사용하여 브라우저에서 도구를 대화형으로 테스트하세요:
npm run inspect:dev브라우저에서 검사기 URL을 엽니다(예:
http://localhost:5173).Connect를 클릭합니다.
Tools 아래에서
query_database를 선택하고 질문을 입력한 후 Run Tool을 클릭합니다.
모든 npm 스크립트
스크립트 | 기능 |
|
|
| 빌드된 서버를 stdio로 실행 |
| 소스에서 실행 (리로드 포함, |
| 자동화된 테스트 |
|
|
| 터미널에서 질문하기 |
|
|
🔧 구성 참조
모든 변수는 선택 사항입니다. 기본값은 아무것도 설정하지 않았을 때 실행되는 값입니다.
변수 | 기본값 | 용도 |
|
| 데이터베이스 위치. 절대 경로 또는 프로젝트 루트 기준 상대 경로 — 작업 디렉터리 기준은 안 됩니다. |
|
| 호출당 반환되는 행 수와 LLM으로 전송되는 행 수의 상한. |
|
| LLM 호출당 요청 상한. 질문 하나는 순차 호출 두 번을 하므로, 이 값이 없으면 응답이 없는 공급자가 도구 호출을 멈추게 합니다. |
| 자동 감지 |
|
| — / | Anthropic 공급자. |
| — / | OpenAI 및 OpenAI 호환 엔드포인트. |
|
| 로컬 Ollama. |
| 설정 안 됨 |
|
잘못된 값은 stderr에 보고되고 기본값으로 대체되며, 조용히 수용되지 않습니다 — 클라이언트의 env 블록에 있는 오타는 변수가 설정되지 않은 것처럼 동작하는 대신 시작 시 표시됩니다. DEBUG 로그에는 묻는 모든 질문과 생성된 모든 문장이 기록되며, MCP 클라이언트에서는 클라이언트의 영구 로그 파일에 저장되므로, 명시적으로 선택하지 않는 한 꺼져 있습니다.
🔒 안전
데이터베이스는 드라이버 수준에서 읽기 전용으로 열리며, 모든 문장은 실행 전에 검증됩니다: 단일 SELECT/WITH/VALUES 문이어야 하며, 데이터를 쓰거나, 스키마를 변경하거나, 연결 상태를 바꾸는 키워드가 없어야 합니다. 두 검사 모두 구성으로 끌 수 없습니다. "삭제된 모든 주문 삭제" 같은 요청은 실행되지 않고 거부됩니다.
검증기는 원시 텍스트가 아닌 문장의 토큰화된 뷰에서 작동하므로, 주석, 문자열 리터럴, 따옴표로 묶인 식별자로 키워드를 숨길 수 없습니다 — /* c */ DELETE FROM orders와 WITH x AS (SELECT 1) DELETE FROM orders는 모두 거부되지만, SELECT replace(name, 'a', 'b')는 거부되지 않습니다.
이 서버가 작성하지 않은 텍스트 — 사용자의 질문과 데이터베이스에서 읽은 값 — 는 프롬프트에서 위조할 수 없는 요청별 마커로 구분되므로, Widget (SYSTEM: ignore prior instructions…) 같은 제품 이름이 명령 컨텍스트로 빠져나갈 수 없습니다. 이는 이 프로세스 너머에서도 중요합니다: 답변은 도구 출력으로 호출 에이전트에게 돌아가며, 한 홉 더 이동합니다.
🔐 무엇이 어디로 전송되는가
이 서버는 LLM을 호출하여 질문에 답하므로, query_database 호출마다 데이터베이스 콘텐츠가 사용자의 머신을 떠납니다. 구체적으로 각 호출은 다음을 전송합니다:
데이터베이스 스키마 — 테이블 이름, 열 이름과 유형, 행 수 — SQL을 생성하기 위해.
쿼리가 반환한 행 (
DATABASE_MAX_ROWS까지, 기본 100) — 이를 서면 답변으로 바꾸기 위해.
번들로 제공되는 shop 데이터베이스의 경우 해당 행에는 고객 이름, 이메일 주소, 전화번호가 포함됩니다. 이들은 구성한 공급자, OPENAI_BASE_URL이 가리키는 엔드포인트로 전송됩니다 — Groq, OpenRouter 또는 DeepSeek의 경우 자체 약관이 적용되는 제3자입니다.
데이터에 대해 이것이 허용되지 않는 경우:
다른 세 가지 도구를 사용하세요.
list_tables,describe_table,execute_sql은 네트워크 호출을 전혀 하지 않습니다 — 아무것도 머신을 떠나지 않습니다.Ollama를 사용하세요. 로컬에서 실행되므로 아무것도 머신을 떠나지 않습니다.
쿼리를 제한하세요. 집계 질문("카테고리별 매출")은 고객 레코드 대신 요약 행을 반환합니다.
DATABASE_MAX_ROWS를 낮추세요. 쿼리당 전송되는 행 데이터의 양을 제한합니다.
서버는 데이터베이스 파일을 절대 전송하지 않으며, 읽기만 가능합니다 — 안전 참조.
📁 프로젝트 구조
src/
index.ts MCP server entry point (stdio transport)
cli.ts Terminal harness: npm run query -- "…"
config/ Env parsing, provider detection, path resolution
tools/ The four MCP tools and their descriptions
services/
database.service.ts SQLite access, row capping, paging, introspection
sql-guard.ts Read-only enforcement (tokenizing validator)
errors.ts Caller-safe messages, path redaction
schema-metadata.ts Human-written meaning the schema cannot record
query-engine.service.ts NL → SQL → execute → prose pipeline
llm/ Anthropic / OpenAI / Ollama behind one interface
prompts/ SQL generation, humanization, untrusted-input framing
tests/ node --test suites (see Automated Tests)
db/ shop.db and its schema documentation
docs/ Architecture and sequence diagrams
examples/ Ready-to-paste client configurations📚 기술 문서
기술 사양 및 아키텍처 다이어그램: 시스템 설계, 시퀀스 다이어그램, LLM 전략 패턴, 안전 메커니즘.
데이터베이스 스키마 문서: 전체 테이블 스키마 정의, ER 다이어그램, SQLite 데이터 사전.
클라이언트 구성 예시: 복사할 구성 파일과 API 키 없이 실행하는 방법.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables natural-language sales queries against a SQLite database, generating and executing read-only SQL through a secure MCP server with table listing, schema description, and query execution.
- FlicenseNot gradedqualityCmaintenanceEnables safe, read-only analysis of an online store's SQLite database, providing schema introspection, restricted SELECT queries, and specialized analytics tools through MCP.
- FlicenseAqualityCmaintenanceEnables AI agents to read-only query an online store's SQLite database, listing tables, inspecting schemas, and running SELECT queries over customers, products, orders, and order items.3
Related MCP Connectors
Connect e-commerce and marketing data to AI assistants via MCP.
Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.
GibsonAI MCP server: manage your databases with natural language
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/harutlc/sql-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server