SQL-MCP-101
SQL-MCP-101
MCP가 처음이신가요? 대화형 튜토리얼부터 시작하세요. 도구, 리소스, 프롬프트를 클릭하며 살펴보고, 어떤 기능이 어느 것에 해당하는지 결정하는 방법을 배울 수 있습니다.
약 1,100줄의 Python으로 구현된 세 가지 Model Context Protocol 프리미티브(도구, 리소스, 프롬프트)를 모두 보여주는, 주석이 매우 상세한 소규모 MySQL용 MCP 서버이며, 탐색할 수 있는 브라우저 UI도 포함합니다.
이 저장소는 단지 실행되는 것이 아니라 읽히기 위해 존재합니다. MCP에 대해 들어보았고 서버를 구축하는 것이 실제로 무엇을 수반하는지 이해하고 싶다면, 이 저장소는 한 번에 읽을 수 있을 만큼 작은 완전하고 동작하는 예제입니다. 파일마다 하나의 프리미티브, 무엇이 아니라 이유를 설명하는 주석, 그리고 예제가 장난감이 아닌 실제 문제를 찾도록 일부러 결함을 넣어 둔 데모 데이터베이스가 있습니다.
mcp_server/
├── database.py read-only introspection; the only file not about MCP
├── execution.py running queries and writes, plus every safety control
├── tools.py 6 TOOLS inspect structure, cannot read or change a row
├── data_tools.py 6 TOOLS read rows, and insert / update / delete / alter
├── resources.py 4 RESOURCES content the APPLICATION attaches (+2 templates)
├── prompts.py 6 PROMPTS workflows the USER invokes
└── server.py wires them together, about 10 meaningful lines이 서버는 읽기-쓰기가 가능합니다. 실제 쿼리를 실행해 데이터에 대한 질문에 답하고, 데이터와 스키마를 변경할 수도 있습니다. 서버는 단일 임시 데모 데이터베이스에 고정되어 있으며, 안전하게 만드는 제어 장치는 execution.py에 있고 아래에서 설명합니다. 그 설계 자체가 교훈의 일부입니다.
기억해 둘 한 가지 아이디어
대부분의 MCP 튜토리얼은 도구만 다루기 때문에 사람들이 MCP가 도구라고 생각하게 됩니다. 하지만 MCP는 세 가지 프리미티브이며, 이들은 누가 통제하는지에 따라 다릅니다.
프리미티브 | 결정 주체 | 발생 시점 | 비유 |
도구 | 모델 | 대화 중, 자율적으로 | 모델이 호출할 수 있는 함수 |
리소스 | 애플리케이션 | 사전에, 인간이 선택 | 첨부하는 파일 |
프롬프트 | 사용자 | 명시적으로, 메뉴에서 | 저장된 전문가 질문 |
같은 데이터가 둘 이상의 형태로 나타날 수 있습니다. 이 저장소에서 get_table_ddl은 도구이고 동시에 schema://table/{name}/ddl은 리소스입니다. 같은 바이트에 두 가지 다른 방식으로 접근하는 것입니다. "모델이 필요하다고 판단했을 때 가져오는 것"과 "인간이 시작 전에 첨부하는 것"은 정말로 다른 필요이기 때문입니다.
Related MCP server: mysql-mcp-server
빠른 시작
git clone https://github.com/Khushboo-Mishra/SQL-MCP-101.git
cd SQL-MCP-101
bash scripts/setup.shsetup.sh는 사전 요구 사항을 확인하고, virtualenv를 만들고, 두 개의 의존성을 설치하고, 데모 데이터베이스를 생성한 다음, 서버를 끝까지 검증합니다. 첫 번째로 빠진 항목이 있으면 특정 메시지와 함께 중단됩니다.
그런 다음 세 가지 프리미티브를 한 번에 모두 확인하세요:
bash scripts/run_explorer.sh요구 사항
Python 3.10+
로컬에서 실행 중인 MySQL 8.x (
brew services start mysql)Node.js: 선택 사항, MCP Inspector에서만 필요
Ollama: 선택 사항, UI의 Chat 패널에서만 필요
기본값은 비밀번호 없이 127.0.0.1:3306의 root이며, 이는 Homebrew 기본값이므로 대부분의 사람은 아무것도 변경하지 않아도 됩니다. 그 외에는 MYSQL_USER, MYSQL_PASSWORD, MYSQL_HOST, MYSQL_PORT를 내보내세요(export).
무엇이 만들어지나
**6개 테이블로 구성된 데모 데이터베이스 위에 도구 12개, 리소스 4개 + URI 템플릿 2개, 프롬프트 6개가 만들어집니다.
도구: 모델이 호출하는 것
하위 시스템이 아니라 영향 범위(blast radius)별로 두 파일에 나뉘어 있습니다. 이는 따라 할 만한 의도적인 설계 선택입니다. 위험한 표면을 작게 유지하고 서버를 검토하거나 데이터베이스 GRANT 권한을 작성하는 누구에게나 명확하게 보이도록 합니다.
tools.py: 구조를 검사합니다. 행을 읽을 수 없고 아무것도 변경할 수 없습니다.
도구 | 용도 |
| 행 추정치를 포함한 모든 테이블과 뷰 |
| 열, 유형, 키, 인덱스, 외래 키 |
| 정확한 |
| 선언된 모든 외래 키 |
| 이름이 PII 또는 비밀을 암시하는 열 |
| 열이 어떤 테이블에 있는지 잊었을 때 열 찾기 |
data_tools.py: 행을 읽고 데이터를 변경합니다. 이쪽이 결과를 수반하는 반쪽입니다.
도구 | 용도 |
| SELECT를 실행하고 결과 행을 반환합니다. 데이터 질문에 답하는 것이 바로 이것입니다. |
| INSERT / UPDATE / DELETE / CREATE / ALTER / DROP / TRUNCATE |
| 구조화된 삽입, 값은 바인딩 매개변수로 전송됨 |
| 구조화된 업데이트, |
| 구조화된 삭제, |
| 서버가 실행한 모든 문장 |
일반 execute_statement와 구조화된 래퍼를 모두 두는 이유는 무엇일까요? 구조화된 도구는 더 안전합니다. 인자가 타입이 지정되고 값이 바인딩되므로 모델이 SQL 텍스트를 작성하지 않으며 잘못된 형식을 만들어 낼 수 없습니다. 하지만 예상한 대로만 동작합니다. 일반 SQL 통로는 긴 꼬리(long tail)를 처리합니다. 예를 들어 윈도우 함수, 예측하지 못한 ALTER 등입니다. 대부분의 실제 서버는 바로 그 이유로 두 가지를 모두 제공하게 됩니다.
리소스: 애플리케이션이 첨부하는 것
URI | 유형 | 내용 |
| JSON | 테이블 목록 |
| SQL | 전체 스키마의 DDL |
| JSON | 모든 외래 키 |
| Markdown | 사람이 읽을 수 있는 요약 |
| JSON | 하나의 테이블 (템플릿) |
| SQL | 하나의 테이블 DDL (템플릿) |
정적 리소스는 고정된 URI를 가지며 resources/list에 나타나므로 클라이언트가 선택기(picker)에 표시할 수 있습니다. 템플릿 리소스는 {placeholders}를 가지며 대신 resources/templates/list에 나타납니다. 표시할 고정 목록이 없으므로 클라이언트가 빈칸을 채웁니다.
프롬프트: 사용자가 호출하는 것
프롬프트 | 인자 | 하는 일 |
| 없음 | 5단계 상태 점검: 키, 관계, PII, 명명 규칙 |
|
| 하나의 테이블을 쉬운 언어로 설명 |
|
| 쿼리를 작성하고, 실행한 뒤, 쉬운 언어로 답합니다. |
|
| 변경 사항에 대해 미리 보기 → 확인 → 적용 → 검증 |
| 없음 | 참조 문서 생성 |
|
| 역할에 맞게 조정된 안내형 첫인상 |
결정하기: 도구, 리소스, 프롬프트?
사람들이 가장 막히는 질문입니다. 다음 순서로 생각해 보세요.
1. 동작을 수행하거나 모델이 선택하는 무언가를 가져오는가? → 도구. 모델이 스스로 결정하고 수행할 수 있어야 하는 모든 것.
2. 인간이 시작하기 전에 합리적으로 첨부할 문서인가? → 리소스. 참조 자료, 전체 스키마 컨텍스트, 안정적인 모든 것.
**3. 누군가 반복하는 작업이며, 질문하는 방식이 전문성인가?** → 프롬프트. 재발견을 기대하는 대신 좋은 질문을 함께 제공하세요.
남은 대부분의 의문을 해결해 주는 두 가지 휴리스틱:
누가 시작하는가? 모델 → 도구. 애플리케이션 → 리소스. 사용자 → 프롬프트.
이것이 메뉴에 있으면 좋겠는가? 그렇다면 프롬프트입니다. 메뉴는 사람을 위한 것이며, 오직 프롬프트만 사람에게 명령으로 노출됩니다.
이 저장소의 실제 예시
기능 | 선택 | 이유 |
하나의 테이블 구조 가져오기 | 도구 | 모델이 추론 중에 예측할 수 없이 필요로 함 |
전체 스키마 DDL | 둘 다 | 모델에게는 도구; 인간이 사전에 첨부하기에는 리소스 |
스키마 감사 | 프롬프트 | 무엇을 물어볼지 아는 것이 가치인 반복 작업 |
열 검색 | 도구 | 호출 시점에 모델이 선택하는 인자를 받음 |
Markdown 개요 | 리소스 | 수동적인 참조, 결정 불필요 |
사람들이 자주 틀리는 부분
모든 것을 도구로 만드는 것. 동작은 하지만, 모델이 인간이 한 번에 첨부할 수 있었던 컨텍스트를 가져오기 위해 호출을 낭비하고, 사용자는 발견 가능한 진입점을 얻지 못합니다.
모델이 선택하는 인자가 필요한 것을 리소스로 만드는 것. 모델이 매개변수를 결정한다면 그것은 도구입니다.
일을 수행하는 프롬프트. 프롬프트는 텍스트를 반환합니다. 프롬프트 안에서 데이터베이스를 질의하게 된다면, 원래 도구가 필요했던 것입니다.
데모 데이터베이스
mcp_demo는 6개의 테이블로 구성되며, 예제가 실제 문제를 찾도록 일부러 불완전하게 만들어졌습니다:
테이블 | 의도적인 결함 |
|
|
|
|
| (깨끗함, 참조 예제) |
|
|
| 기본 키가 전혀 없음 |
| 다른 모든 것이 |
audit_schema를 실행하면 위의 모든 문제가 드러나야 합니다. 이것이 데모입니다. 도구가 장난감이 아닌 실제 문제를 찾아냅니다.
실행하기
탐색기: 모든 프리미티브를 한 번에
bash scripts/run_explorer.shinitialize 핸드셰이크를 출력한 다음 도구, 리소스(정적 및 템플릿), 프롬프트를 나열하고 실행합니다. 먼저 이 명령을 실행하면 설정이 제대로 작동하는지 확인할 수 있고 전체 프로토콜 표면을 한 화면에 보여줍니다.
웹 UI: 브라우저에서 세 가지 프리미티브 모두
bash scripts/run_ui.sh # http://127.0.0.1:8000
PORT=9000 bash scripts/run_ui.sh보여줄 가치가 있는 것마다 하나씩, 총 네 개의 패널:
패널 | 보여주는 것 |
Chat | 쉬운 영어로 질문할 수 있습니다. 모델이 선택한 모든 도구가 답변 위에 인라인으로 나열됩니다. |
Tools | 전체 12개를 영향 범위별로 그룹화, 각각은 폼에서 호출 가능 |
Resources | 정적 및 템플릿 리소스를 제자리에서 읽을 수 있음 |
Prompts | 하나를 펼치면 텍스트를 보거나 채팅으로 바로 보낼 수 있음 |
하단의 실시간 Activity 스트립은 그 뒤에서 일어나는 실제 JSON-RPC(tools/call, resources/read, prompts/get)를 보여 주므로 프로토콜이 항상 눈에 보입니다.
이 페이지는 그 자체가 MCP 클라이언트입니다. 자체적으로 MySQL에 접근할 수 없습니다. 화면의 모든 것은 Claude Desktop이 사용하는 것과 동일한 프로토콜을 통해 도착했습니다.
Chat은 Ollama를 통한 로컬 LLM이 필요합니다. 무료이고 API 키가 필요 없으며 아무것도 머신 밖으로 나가지 않습니다:
brew install ollama && ollama serve
ollama pull qwen2.5:7b대신 ANTHROPIC_API_KEY를 설정하면 자동으로 Claude API로 전환됩니다. Tools, Resources, Prompts 패널은 LLM 없이도 완전히 작동합니다.
MCP Inspector: Anthropic의 공식 클라이언트
bash scripts/run_inspector.sh인쇄된 http://localhost:6274?... URL을 여세요. 토큰이 필요합니다. 여기에는 별도의 Tools, Resources, Prompts 탭이 있으며, 이 세 가지를 모두 보여주는 가장 설득력 있는 방법입니다. 이 중 어느 것도 우리 코드가 아니므로, Inspector가 서버를 구동한다면 서버는 진정으로 스펙을 준수하는 것입니다.
추천 투어: Tools → ORDERS로 describe_table; Resources → schema://overview; Prompts → audit_schema.
Claude Desktop / Claude Code
bash scripts/add_to_claude_desktop.sh # Claude Desktop, run from Terminal.app
bash scripts/install_claude.sh # Claude Code, safe to run anywhereadd_to_claude_desktop.sh는 설정을 백업하고, 이미 등록된 서버를 보존하며, JSON을 검증하고, 정확한 실행 명령을 스모크 테스트한 다음 앱을 다시 실행합니다. 완료되면 제안된 데모 스크립트를 출력합니다.
그런 다음 *"이 데이터베이스를 감사해줘"*라고 묻거나, 메뉴에서 audit_schema 프롬프트를 사용하세요. 프롬프트가 마침내 표시되는 곳입니다.
--desktop은 Claude Desktop 내부가 아닌 Terminal.app에서 실행해야 합니다. Claude Desktop은 설정을 메모리에 보관하고 해당 복사본에서 파일을 다시 작성하므로, 실행 중에 편집한 내용은 조용히 폐기됩니다. 스크립트는 앱을 종료하고, 편집하고, 다시 실행하므로, 스크립트를 실행한 세션이 종료됩니다.
코드 읽기
대략 1시간 정도 소요됩니다. 이 순서는 앞선 참조 없이 차근차근 구성됩니다:
1. mcp_server/server.py: 여기서 시작하세요. 의미 있는 10줄이며, 전체 아키텍처가 한 화면에 들어갑니다: 서버 생성, 세 가지 프리미티브 등록, 실행. 나머지는 모두 세부 사항입니다.
2. mcp_server/database.py: MCP가 전혀 없는 일반적인 MySQL 코드입니다. MCP 계층이 실제로 얼마나 얇은지 보여주기 때문에 일찍 읽을 가치가 있습니다: 이미 데이터 접근 계층이 있다면, 대부분 완료된 것입니다.
safe_identifier를 자세히 살펴보세요. MySQL은 테이블 이름을 파라미터로 바인딩할 수 없습니다(SHOW CREATE TABLE %s는 유효한 SQL이 아닙니다). 따라서 식별자는 문자열에 보간되어야 합니다. 이는 진정한 인젝션 위험이며, 이 작은 함수 하나가 안전을 보장합니다.
3. mcp_server/tools.py: @mcp.tool() 데코레이터와 프로젝트 전체에서 가장 많은 작업을 수행하는 아이디어: docstring이 프롬프트입니다. 모델이 도구 호출 여부를 결정할 때 읽는 유일한 것이므로, 소스를 읽는 사람이 아닌 모델을 위해 작성되었습니다.
4. mcp_server/resources.py: 정적 URI 대 템플릿 URI, 그리고 get_table_ddl이 도구 이면서 리소스로 존재하는 이유. 그 중복은 의도적이며, 누가 무엇을 제어하는지에 대한 가장 명확한 예시입니다.
5. mcp_server/prompts.py: 프롬프트는 데이터가 아닌 텍스트를 반환합니다. 텍스트는 일반적으로 모델에게 어떤 도구를 사용할지 알려주는 지시사항입니다. 짧은 파일이며, 대부분의 사람이 본 적 없는 파일입니다.
6. mcp_server/execution.py: 쓰기 접근을 어떻게 안전하게 만들 수 있는지 알고 싶을 때 읽으세요. 각각 무엇을 방지하는지 설명하는 주석이 있는 5가지 제어 장치가 있습니다.
7. examples/explore_server.py: 프로토콜의 반대편입니다. 모든 것을 나열하고 호출하는 최소 클라이언트로, 실제로 네트워크를 통해 무엇이 오가는지 확인할 수 있습니다.
더 나아가기
이 서버는 예제를 짧게 유지하기 위해 하나의 데이터베이스로 범위가 제한되어 있습니다. 더 확장하려면:
다중 스키마:
MYSQL_DEMO_SCHEMA를 읽는 대신schema를 도구 인자로 받으세요. 에이전트가 프로덕션에 접근할 수 없도록 허용 목록을 추가하세요.쿼리 실행:
run_query도구. 가능하지만 보안 구조가 완전히 바뀝니다: 서버는 테이블을 읽을 수 있는 자격 증명이 필요하고, 결과가 모델의 컨텍스트에 들어갑니다.SELECT전용을 강제하고,LIMIT을 주입하고, 읽기 전용 데이터베이스 사용자를 사용하세요.원격 전송:
mcp.run(transport="streamable-http"). 동일한 도구, 동일한 코드, 다른 파이프. 노출 전에 인증을 추가하세요.캐싱:
describe_table는 호출할 때마다 데이터베이스에 접근합니다. 모델이 루프에서 호출하기 시작하면 짧은 TTL 캐시가 가치가 있습니다.
보안 참고 사항
이 서버는 데이터를 변경할 수 있습니다. 이는 의도적입니다: "에이전트가 내 데이터베이스에 쓸 수 있는가?"는 모든 팀이 묻는 질문이며, 안전하게 수행하는 방법에 대한 작동 예제는 주제를 회피하는 것보다 더 유용합니다. 그러나 제어 장치가 중요하다는 것을 의미합니다.
5가지 제어 장치, 모두 execution.py에 있음
제어 장치 | 방지하는 것 |
스키마 잠금 | 모든 문은 데모 데이터베이스에 고정된 연결에서 실행됩니다; 다른 데이터베이스에 대한 참조는 거부됩니다 |
호출당 단일 문 | 두 번째 문이 합법적인 문에 편승할 수 없습니다 |
읽기/쓰기 분리 |
|
행 상한 | 광범위한 |
감사 로그 | 모든 문이 기록되고 |
차단 목록은 또한 스키마 잠금을 우회하거나, 파일 시스템에 도달하거나, 서버 전체 상태를 변경하는 문, 권한 변경, 사용자 관리, 파일 가져오기/내보내기, 데이터베이스 수준 작업을 거부합니다.
한 가지 미묘한 점, 반복하기 쉬운 실수이기 때문입니다: 스키마 잠금은 패턴만으로는 작동할 수 없습니다. SQL에서 a.b는 일반적으로 schema.table이 아닌 alias.column(SELECT c.NAME FROM CUSTOMERS c)이므로, 모든 점으로 구분된 이름을 거부하면 일반적인 조인이 깨집니다. 이것이 바로 이 기능의 첫 번째 버전에 있던 버그입니다. 이제 각 한정자를 서버의 실제 데이터베이스 목록과 비교합니다: 실제 데이터베이스 이름은 거부되고, 테이블 별칭은 그대로 통과합니다.
제한된 사용자로 연결하세요
위의 제어 장치는 심층 방어이지, 방어 자체가 아닙니다. 데모를 넘어서는 모든 것에서, 노출하려는 스키마만 포함하는 권한을 가진 MySQL 사용자로 연결하세요. 자격 증명이 프로덕션에 도달할 수 없다면, 프롬프트 인젝션이나 모델 실수도 도달할 수 없습니다.
명확히 언급할 가치가 있는 두 가지 더:
테이블 이름은 바인딩 파라미터가 될 수 없습니다.
SHOW CREATE TABLE %s는 유효한 SQL이 아니므로 식별자는 보간되어야 하며, 이는 진정한 인젝션 지점입니다.database.safe_identifier가 이를 안전하게 만드는 것이며, 프로젝트에서 가장 중요한 단일 함수입니다.연결하는 MySQL 사용자가 실제 경계입니다. 노출하려는 스키마로 범위가 제한된 읽기 전용
GRANT를 부여하세요. 코드의 읽기 전용성은 심층 방어이지, 방어 자체가 아닙니다.
라이선스
MIT, LICENSE 참조.
This server cannot be installed
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
- AlicenseNot gradedqualityDmaintenanceEnables interaction with MySQL databases through MCP, supporting query execution, table operations (insert, update, delete), and schema inspection for natural language database management.121MIT
- AlicenseNot gradedqualityDmaintenanceEnables MySQL database operations through MCP, including executing SQL queries, listing databases and tables, and describing table structures.4545MIT
- AlicenseNot gradedqualityDmaintenanceEnables natural language interaction with MySQL databases through MCP, supporting SQL execution, schema exploration, and database management via tools, resources, and prompts.5MIT
- AlicenseNot gradedqualityCmaintenanceEnables natural language interaction with MySQL databases through MCP tools for querying, executing DDL/DML, listing databases/tables, and describing table schemas, with parameterized queries and read-only mode.454MIT
Related MCP Connectors
GibsonAI MCP server: manage your databases with natural language
Connect to PlanetScale databases, branches, schema, query insights, and execute SQL
MCP server for managing Prisma Postgres.
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/Khushboo-Mishra/SQL-MCP-101'
If you have feedback or need assistance with the MCP directory API, please join our Discord server