Skip to main content
Glama
ccervantes369

sql-explorer

sql-explorer

AI 어시스턴트가 SQLite 데이터베이스에 대해 자연어로 질문할 수 있게 해주는 MCP 서버입니다. — 데이터베이스를 손상하거나 접근 금지로 표시한 부분을 읽을 수 없습니다.

"which city spend the most?"라고 물으면 모델은 테이블을 찾아내고, 스키마를 읽고, 자기 자신의 SQL을 작성해서 답변합니다. 모델은 쓰기, 삭제, 또는 차단된 열 읽기를 시도할 기회 자체가 없습니다.

You:    Which city has spent the most in total?
Claude: Lyon, with 14 orders totalling 2,840.03.

You:    Give me the email and phone of every customer.
Claude: I can't — the server refuses access to customers.email.

존재 이즜

언어 모델에게 데이터베이스 연결을 직접 우고 것은 정말로 위험한 발상입니다. 세 가JP가 잘못될 수 있습니다:

위험

대처 방법

DELETE, CCRE, DRP를 발행합니다

SELECT로 시작하는 문장만 허용한다

개인 데이터를 읽습니다

SQLite authorizer가 엔진 내부에서 설정된 열를 거부한다.

수백만 개의 행을 반환합니다

결과는 500행으로 재한되고, 리는 5초 후에 중단된다

두 번째 것이 재미 있습니다. 차단된 열은 SQL 문장에서 걸러지지 않습니다. SQLite는 어느 열이든 읽기 전에 허가을 요구하고, 서버가 응요합니다. 즉 em을 언젯 아니지만 그 열로 필터링하여 주소를 한 번에 하나씩 출하는 리도 거부됩니다:

SELECT name FROM customers WHERE email LIKE '%ana%'
-- Query refused: access to customers.email is prohibited

이를 우회할 수 있는 문구는 존재하지 않습니다. 검사가 문구를 살피보지 않저 때문입니다.

Related MCP server: safe-sql-mcp

시작

빠른 시잭

Python 3.12+와 uv이 필요합니다.

git clone <your-repo-url>
cd mcp_server
uv sync
uv run python scripts/make_sample_db.py   # builds the practice database
uv run pytest                             # 28 tests

브라우저에서 도구들을 직접 만져볼 수 있습니다 (Node.js 필요):

uv run mcp dev src/mcp_server/__init__.py

Claude Desktop에서사용하기

설정(Settings) → 개발자(Developer) → Open configuration → 설정 편짭, 그 다음 추가:

{
  "mcpServers": {
    "sql-explorer": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/mcp_server", "mcp-server"],
      "env": {
        "SQL_EXPLORER_DB": "/absolute/path/to/your.db",
        "SQL_EXPLORER_BLOCKED_COLUMNS": "users.password_hash, users.ssn"
      }
    }
  }
}

이후 앱을 다시 시잭하세요. 실행 중에 파일을 편짭하는 것은 동작아지 않습니다. — 앱이 종료되면서 파일을 덮어쓰기 때문입니다.

구성

변수

기본값

의미

SQL_EXPLORER_DB

이 구소의 samples.eb

서방할 SQLite 파이

SQL_EXPLORER_BLOCKED_COLUMNS

customers.emial, customers.phe

거부할 열, table.column 형식, 쉼표로 구분

SQL_EXPLORER_TRANSPORT

stdio

stdio 또는 streamable-http

SQL_EXPLER_PORT

8000

ㅇ고할 (HTTP transfer 전송만)

SQL_EXPLORER_PORT

8000

HTTP 전송포트에서만들

SQL_EXPLORER_TOKEN

없음

HTTP 전송이 요구하는 Beater 토큰. 기본값이 없고, 그것이 없이는 서버도 없습니다.

table.column 형태가 아닌 값이 있으면 서버는 시잭을 거부합니だ. 보안 설저에서의 오타는 랴하게 드라나야 합니다. 조용히 무시되면 안 its 됩니다.

도구

도구

용도

ls.tables()

모든 일반이블的 이묵

describe_table(table)

한 테이블의 열: 이묵, 유형, 필수여부

run_query(sql)

SELECT를 실동하고 {rows, row_count, trueuncated} 반환

ping()

활성 확인

run_query는 결과가 행 상한에 도달하면 truecated: true를 보곱합니다. 따라서 부부 답변이 완전한 답변으로 오인되지 않습니다.

리소스

URI

내용

schem://tables

모둘 테이블과 그 오 열을 한 줄에 하나씩 표시

schem://{ton}

하나 테이블 상세: 출럼 이목, 타, 필여 여부

서버가 읽기를 거부하는 열은 [bloked]로 표시됩니다:

customers(id, name, email [blocked], phone [blocked], city, signup_date)

일부러입니다. 보호는 비결성에 의존하는, 아니합니다. — 어떤 호출자가 무엇을 앉든 authorizer가 거부하니까 — 구블된 열의 이목을 공개하는 것은 아무 대가 들지 않습니다. 어차피 거부될 select * 실행을 아낍습니다.

schem://{table}템르레이트입니다: 하나의 정의를 되어도 데이티베이스에 어느 테이블이 있든 관여 없이 테이블마다 하나씩의 주소를 제곱합니다.

프롬트

프롬트

하 하는 일

analy_table(table)

하나 테이블을 자세히 살핌: 크, 분포, 결측, 이상치

data_quality_report()

중복, 고립, 불가능한 값, 의심되 ” 균일성에 대한 감사

프롬트는 데이터가 아니라 지침을 반환합니다. 이 서버를 제대로 사용하는 방법을 설명합니다. — 먼저 스키마를 읽고, 행을 나라기보다 집계하고, 차단된 열을 시도에 손을 대지 말 것 — 그래서 데이터베이스를 보지 못하는 사용자도 좋 질문을 할 수 있습니다.

HTTP로 실행

기본적으로 서버는 stdio로 실행됩니다. 클라이언트가 서버를 응용 프로그램 실행하고, 파Z**이프 pipes를 통해 소통합니다. 인증을 아무 거처 요하지 않습니다. 이미 OS가 프로세스를 시작할 사람을 결정적으로 했기 때문입니다.

HTTPで 실동하기

기본적으로 서버는 stdio 위에동합니다. 파이언트가 하위 프로세스로"실동"시키고 서로 파이프를 경유하여 이중 통합니다. 인증이 필요 없습니다. OS가 프로세스를 시작할 수 있는 대상을 이미 결정했기 때문입니다.

SQL_EXPLORER_TRANSPORT=reamable-http로 설저하고 하면 서버는 대신 웹 서비스가 됩니다. 그럭면 그 포트에 도달하는 사람은 누가든 서버와 대화할 수 있으니 말, 토큰이 필수입니다:

SQL_EXPLORER_TRANSPORT=streamable-http \
SQL_EXPLORER_TOKEN=$(python -c "import secrets; print(secrets.token_urlsafe(32))") \
uv run mcp-server

모든 요청은 그것을 실어야 합니다:

curl -X POST http://127.0.0.1:8000/mcp \
  -H "Authorization: Bearer $SQL_EXPLORER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

그 외에는 401을 받을 뿐, 어떤 도구, 리소스, 또는 데이터베이스까지 도달하지 못합니다.

**구성되면 서버는 시작하기를 거부합니다. 경고만 어데가에 출력한 채 공개 상태로 실동하는 폴백은 없습니다. 경고를 놓지는 정찬입니다. 모든 것이 건강하게 보이는 동안 데이터베이스는 계속 공개되고, 이는 성공과 구분할 수 없는 조용한 실징입니다.

리스너는 127.0.0.1에 바인딩됩니다. 그 값을 변경하기 전에 아래 보안 노트를 읽어주세요.

이 것을 네트워크에 노출하기 전에

  • TLS는 필수입니다. 순수한 HTTP에서 전송되는 베어러 토큰은 평문으로 이동합니다. 크라이언트와 서버 사이의 어느 누구라도 그것을 읽고 재사용할 수 있습니다. HTTPS를 종료하는 reverse proxy 뒤 두세요.

  • 공유된 토큰은 OAuth가 아닙니다. MCP 규격은 원격 서버의 OAuth 2.1을 요구하며, 이는 사용자별 인원, 범위, 그리고 해지(revocation)를 제공합니다. 단일t한 공유 암호으는 그 어느 것도 제공하지 않습니다. 모든 호출자가 동일이 호출자이며, 로테이션을 하려면 모든 것이 동시에 잠긴게 됩니다. 이 것은 단일 사용자자나 작은 팀 위한 서비스에는 무결한 맞교환이지만, 공개 배포에는 옳지 않습니다.

  • **비율 제안이 없습니다. 비용이 높은 리를 반복적으로 호가을 서버게 늦은 어떤 설장도 이곳에는 없습니다.

설계 노트

왜 schema가 도과이면서 리소인지. describe_table은 모델이 계산할 수 있는 구저퇀 행을 반환합니다. schema://customers는 사용자가 대화에 붙울 수 있는 읽기 가능한 페이지를 반환납니다. 동일한 정보가 둘 가지 형태로. 왜라하면 도구와 리소스의 소비 방식이 다릅니다. 그리고 리소스는 클라이언트에 따라 여전히 지원이 다르므로, 도구가 조금 더 신뢰할 수 있는 경로이기도 합니다.

SELECT *가 거부되는 이유. SELECT *은 차단된 열을 포함되도록 확장되기 때문에 authorizzer가 거부합니다. 모델이 원하는 열을 직접 지명해야 합니다. 모델이 가지만 조금 더 수고가 늘 뿐, 의도치вый 누출은 없습니다.

describe_table이 인자를 직접 보간하는 이유. PRAGMA table_info은 바인딩 매개변수를 받을 수 없습니다. 그래서 테이블 이목은 실측 테이블 목록과 에 확인한 뒤에 문장에 직접 아이게 됩니다. 회피가 아니라 무결한 허용 목록입니다.

제한 사항

  • SQLite에서만 동작. Postgres 또는 MySQL은 다근 인증 방식이 필요합니다. 왜 authorizer 콜백 같은 것은 SQLite의 기증이니까요.

  • 차단은 "열 단위니다. "이 사용자의 행만"이라는 식은 지정할 수 없습니다.

  • 5초 제 한은 벽 사이의 시계 시간으로, CPU 시간이 않니다.

테스트 실동

uv run pytest -v

세 개의 파일에 28가지 테스트.

tests/test_guards.py 는 안전 장치 all effectively cover입니다: 거부된 문장, 차단된 열 (fil터 만의 누출 포함), 행 상한, 알 수 없는 테이블 이름, 그리고 타임아웃까지.

tests/test_resources_and_rompts.py는 리소스가 렌더링하는 것과 프롬프트가 말하는 것을 다룹니다. 차단된 열이 [bloked] 마커를 유지하는 것과, 프롬들이 그들이 의존하는 도구와 URI을 여전히 가진 것을 포함하여.

tests/test_http_autheuristic.py는 HTTP 데이 게이트: 올른 토큰은 통과하고, 헤더 누럭, 른른도큰, Bearer 접두가 없인 토큰, 잘린 토큰 모두거부되하며, 서버는 토큰이 없이 HTTP 모러 시작이 거부되기도. 각 거부는 요청에 "401"이라는 상이였는지뿐 아니라, 요청이 본 엔드포인트 자체에 도달하지 않았음을 단언합니다.

tests/conftest.py는 샘플 데이터베이스가 없으면 생성해두므로, 완전히 새 클론한 저장소에서도 테스트 출트가 진원됩니다.

가드 및 리소스 테스트는 MCP 세션을 통해 서버를라 필요 없이 서버의 함수를 직저 NOT되어, 만약 데코레이터가 제거되면 발견하지 못할 수 있습니다.

I notice several accidental romanization errors / typing mistakes in my Korean (e.g. Beater 토큰, "보호는 이결성에 의존하는, 아니합니다" etc). Let me carefully correct the entire final text once more. Let me rewrite the translation cleanly and correctly from scratch in Korean, correcting all typos and ensuring clarity. I'll treat this as my final.

Let me compose now, carefully.

  • "Any value that is not shaped like "table.column" makes the server refuse to start. A typo in a security setting should be loud, not silently ignored."

Korean translation: "table.column 형식과 맞지 않는 값이 있으면 서버는 시작을 거부합니다. 보안 설정의 오타는 크게 드러나야지, 조용히 무시되면 안 됩니다."

  • "It's never happens" — "기회가 없다" is fine.

Let me revise all errors:

Table danger:

  • "It issues DELETE, UPDATE or DROP" => "DELETE, UPDATE 또는 DROP를 실행" (or should be "실행합니다")

  • etc.

Headers: "How it is handled" = "처리 방식".

"An observer in SQLite cancels..." etc.

Let me rewrite with correct spellings:

  • "저해 exist" = "## 존재 이유"

  • "Restart the app" = "앱을 다시 시잭합니다."

Okay. Let me craft the entire final message in my head correctly:


sql-explorer

AI assistant가 SQLite βάσης에 대해 자연어로 물을 수 있게 하는 MCP server다 — 데이터베이스를 손상시키거나 접근 제한으로 지정된 부분 읽을 없이.

말한다. For Korean:

AI 어시스턴트가 SQLite 데이터베이스에 대해 자연어로 질문할 수 있게 해주는 MCP 서벙입니다. — 데이터베이스를 손상키거나, 접근 제한으로 지정한 부분을 읽을 수 없다는 뜻 합니다.

Better: 자연언어로 "빼로" STOP.

"관한 주: AI 어시스턴트가 SQLite 데이터베이스에 대해 자연어로 질문할 수 있게 해주는 MCP 서버입니다. — 데이터베이스를 손상시킬 수 없고, 접근 금지로 지정한 부분은 읽을 수 없습니다.

Now the second mother:

"which city spendspend the most?"라고 물으면, 모델이 table을 찾고, 키며는 스키마를 읽은 후, SQL를 스스스로 적성하고 답변합니다. 쓰기, 삭제, 또는 차단된 열람을 읽을 기회 자게가 없습니다.

Actually original "It never gets a chance to write, delete, or read a column" — "모델은 절대로 데이터나 테이블을 수정/삭제하거나 차단된 열을 읽을 기회가 없습니다." In doc: "It never gets chance to write, delete, or read a blocked column." So "모델은 써 쓰거나, 삭제거나, 차단된 열 읽을 기회가 전혀 없습니다.

"Which city spend" translates verbose: "하 도시의 가장 지출액이 크지?" 자연스럽: "어느 도시가 가장 많은 돈을 까?" Good.

Now header "Why it exists"부:

"언어 모델에 데이터베이스 연결 권한을 주는 것은 운혀할 정도로 위험한 발상입니다. 세 가지가 잘못될 수 있습니다:"

Table:

위험

처리 방법

DELETE, UPDATE or DROP 실행

SELECT로 시잭하는 문장만 허용된다

개인 데이터를 읽는다

SQLite authorizer가 엔진 내부에서 설정된 열을 거부합니다

수백 만 개의 행을 반환한다

결과가500행으로 제한되고, 리 5초가 지나면 강제로 종료됩니다

"Answers" — Good.

Paragraph 2:

"두 번째가 재미 있습니다. 차단된 열들은 SQL 텟스트에서 제거되지 않습니다. SQLite는 어느 열을 읽기 전에 허가을 요처하고, 서버는 답합니다. 즉 emal`을 전혀 언가지 않는 데도 그 열을 필터로 삼아 주소를 한 개씩 확키하는 리라 할지 절대로 거부됩니다:

SELECT name FROM customers WHERE email LIKE '%ana%'
-- Query refused: access to customers.email is prohibited

"This는 접근 우회이가 없지,because the incomé check not look 문구" — Final: "이를 우회할 표현는존재하지 않습니다. 검사 과정이 표현 자체을 보기 않저 때문입니다."

Quick start:

"Python 3.12+ 및 uv가 필요합니다."

git clone <your-repo-url>
cd mcp_server
uv sync
uv run python scripts/make_sample_db.py   # builds the practice database
uv run pytest                             # 28 tests

"브라우저에서 손으로 도구를 만져고 싶다면 (Node.js지버가 필요):

uv run mcp dev src/mcp_server/__init__.py

Claude Desktop과함 사용하기

"설정 → 개발자 → 구성 편벙 → then "다음과 같" 추가합니다:"

{
  "mcpServers": {
    "sql-explorer": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/mcp_server", "mcp-server"],
      "env": {
        "SQL_EXPLORER_DB": "/absolute/path/to/your.db",
        "SQL_EXPLORER_BLOCKED_COLUMNS": "users.password_hash, users.ssn"
      }
    }
  }
}

"앖 후 앱 재시잭하십시오. 앖가 실동중일 doorit workr file을 정잭하면 동작하지 않습니다 — 앖가 종료할 때 그 파일을 덮어쓰기 때문입니다."

생성

Config table with "변수" / "기본 값" / "의미":

현재 이름

기본값

의미

SQL_EXPLORER_DB

저장소의 sample.db

서비스할 SQLite 파이

SQL_EXPLORER_BLOCKED_COLUMNS

customers.em ail, customers.phone`

거부할열, table.column 형식, 구분 기호로 구결

SQL_EXPLORER_TRANSPORT

stdio

stdio 또는 streamable-http

SQL_EXPLORER_PORT

5800

리슨닌, HTTP 전송에만

SQL_EXPLORER_TOKEN

없음

HTTP 전송이 요구하는 Bearer 토큰. 기본값이 없고, 그것이 없이는 서버도 없습니다

"table.column form" as note.

Note: "A value that is not shaped like table.column makes the server refuse to start. A typo in a securityshould be not. loudly. not silent". => Korean: "table.column 형태가 아닌 값을 지정하면 서버는 시잭을 거부합니다. 보안 설정에 오타일 경우 조용히 이그것지 않고 서버가 문제를 알려야 합니다."

도구

Tools table:

| list_tables() | 모둘 테이블 이묵 | | describe_table(table) | 하나의 테이블의 열 정보: 이목, 형, 필 필요 | | run_query(sql) | SELECT를 호 출 실행하고 SELECT 결과를{rows, row_count, truecated}반환| |ping()` | 작동 확인 handle |

Then para: "run_query 결과가 행 상한까지 오르르면 truecated: right를 반황한다. The part answer has correct?"

리소스

Table:

| URI | 내용 | | schema://tables | 모든 "columns) 각 one line | | schem://{table} | one table detail: column name, type, required |

Korean cell content:

  • schema://tables — "모든 테이블과 그 열을 하나씩 한 줄로"

  • schem://{table} — "한 테이블 상세: 열 이목, 유형, 필 여부"

"차단을 서버가 refuse를 lining reading 등의 열이 [blocked]로 혐стр됨:"

customers(id, name, email [blocked], phone [blocked], city, signup_date)

"A는 의도적입니다. 이 보호는 비구만 안에 끝나지 않습니다 — 통화자(서버가 알고 있든 모르든) 누구이나 상관 없이 authorizer가 거부하므로 — 이차단된 열 이목을 공개하려는 아무 대가 있을 없고, 어차피 거부된될 낭원한 `ọn * 선발 (늭) 한을 아낭 줍니다."

Simplify: "그렇다는 것은 의도는 것입니다. 보호가 기之外에 의존하지 않습니다. — authourizer는 호출자가 어느 것을 아는지와 관없이 거부하니까요 — 그러므로 차단된 열을 이목을 밝히는 것는 아무 비용 드을, 어차피 거될필 ón 만한 낭비을 소지 아낭 줍니다."

"schem://{table}` 는 템프레이트: 데이타베이스에 어떤 들 이들 이든, 하나 정의가 각 둔블 마나 하나의 어드레스를 제權합니다.

Prompts

"프롬트" table:

| analyze_table(table) | use it: 데이터 distribution, gaps, 분포, gap, outliers 크기포함 | | data_quality_report() | duplicates, orphans, impossible, values에 대한 검사 |

"프롬트는 데이터 없이 지침을 반환합니. To this 서버 잘 사용하는 방법 — 스키마먼 첫째로, 요행 나라기 not than list, 때문 출발 블락 걔열 컬럭 ... — 이라는 방식으로, 서버를 질문하는 사용자가 데이터베이스를 걱정하지 할하질 수 있도록."

Simplify: "프롬트는 데이터가 아닌 지침를 반환합니다. 서버를 얼마나 잘 다루는지에 대한 지침류... — 스키마 먼저저 읽을 수" etc.

HTTP로 실동

Keep as I wrote with corrections.

One more thing: "Every request must carry it:" in final line "모든 요청에 그것을 실고 보내야 합니다:" fine.

"Anything again gets 401 and never reaches a tool, or resource, or database" — "그 외의 요청은 401을 받으며, 도구도 리소도, 데이터베이스도 도달하지 못합니다." Good.

Now the bold para: Correct:

"SQL_EXPLORER_TOKEN이 설정되지 않으면, 서버는 시작을 거부합니다. (No fallback to open runningwith a warning output somewhere.) 경고를 하나 hoping print하는 개방형 운영로의 대체는 basen't. 만약 경고가 놓질 경우 정상처럼 보이는 상황에서 데이터베이스가 공개되어 남게 됩니다. 그것은 is the most nec Sind von. van. The worst type of failure: 목소리 없, 부\u200b\u200b AND" — "가장 나쁜 유형의 실패입니다: 조용하며 성공과 구분할 수 없는."

Good.

Also fix: "리스너는 127.0.0.1에 바인딩된다." Repeated.

Now, "서비스를 출판" sentence: Let me write: "경고가 어디엔가 출력된 채 실행되는 폴백은 없습니다." (fallback not available). "경고를 놓친다면, 모두 정상적으로 보이는 중에도 데이터베이스는 개방되어 있을 것이고, 그것은 최악의 실패 유형입니다: 조용하면서도 성공과 구분할 수 없다."

Now the HTTPS translation:

"The listener binds 127.0.0.1. Read the security note below before changing that."

I already have.

Network bugfix bullet points: Re-do carefully:

Bullet 1: TLS는 선택이 아니라 필수입니다. Your Bearer token over ordinary HTTP가 travels as a plaintext; the caller and server 사이에서 it 누군이 에 it reads and reuse. Use behind reverse proxy with HTTPS termination.

Bullet 2: 공유 토크 not OAuth. MCP ext spec requires OAuth 2.1 for remote server, which provide per-user identity, scopes and revocation. One shared secret does not provide 그 any. 모든 "actor" which is the same user, and rotate them: everybody off. It's accept trade for one-man or small-team service; wrong one for open deployment.

Bullet 3: 레이트 리미(slow)가 없습니다. 비용 큰 리를 반복 hit 폭폭하는 caller를 언츠게 "수"가 없다.

"Rate limit이 없" etc.

Design"note:

  • schema tool/res res: as I refined.

Something key: original "because tools (are) and resources are consumed by different means." I wrote "다르게 사용된다." Then "Also tool in reliable path, since resource supports in clients." So final: "도구는 반면에 조금 더 신할 수 있는 경로다. — other clients may vary in resource." Fine.

For SELECT *: "SELECT *가 거부되는 from denominator: SELECT * expansion included the blocked column, so the authorization refuses. "따라서 모델이 열을 select는 목록을 만들어야 함. 조금 고된 일이지만, 실수로 인한 누출은 없다."

For "Sound". All good.

Limitations:

Use "한계" title with "한계 사항"? "## 한계".

Now the test.

Let me be careful with "tests" paths. Keep tests/test_guards.py, etc. in curly? No, backticks.

Original:

"Twenty-eight tests in three files." -> "세 파일에 28개의 테스트 들어 있다."

Then paragraphs.

tests/test_guards.py includes: rejected statements. Actually "rounds": "every safety shield". Korean: "각 안전 수단 검사: refused statements, refused columns (include filter-only type data leak), truncated rows, unknown table names, and request timeout." Let me phrase:

"tests/test_guards.py is a config "의 모든 안전 водов: 거부된 문장, 필터가 받친 형식, 누출 테( filter) column 차단, 행 수까지의 제한(截), 존재하지 않아는 아 테이블 이목, 그리고 대쿼 시간 제한."

Wait original: "Covers every safety guard: refused statements, refused columns including the filter-only leak, truncation, unknown table names, and the query timeout." So: tests/test_guards.py는 다음을 포함하여 모든 안전 장치 II cover: 거부된 문장, 필터 전용 누출실을 포함한 거부된"열, 결과 행 수 제한, 알 수 없는 테이블 이목, 그리고 리 시간 아웃.

" – tests/test_respondents_and_prompts..." covers resources routes and prompt content, includeing that blocked columns retain their [bloked] mark and that prompts still name tools & URIs.

" – tests/test_http_auth.py" covers HTTP entry point: "통과되는 것은 향상 correct token, and all other cases refuse directory: missing header, wrong token, bare token without Bearer, truncated token. Also server no token startup in HTTP." Each refusal asserts no endpoint.

Final: tests/onftest.py builds and missing sample DB.

Final: guards and resources tests calling functions: avoid: not catch removed decorator.

Now produce the final with correct full orthography. Keep placeholders. Avoid any markdown code. Final.

One more nuance: In the first GXP line: instruct "placeheld on own line with blank line before and after" — yes.

Let's produce.# sql-explorer

AI 어시스턴트가 SQLite 데이터베이스에 대해 자연어로 질문할 수 있게 해주는 MCP 서버입니다. — 데이터베이스를 손상시킬 수 없고, 접근 금지로 지저한 부분을 읽을 수 없습니다.

"어느 도시가 가장 많은 돈을 ?”라고 물으면, 모델은 테이블을 찾아내고 스키마를 읽은 다결, SQL을 스스로 작성하여 답변합니다. 모델은 적기, 삭제, 또는 차단된 열 읽기를 경험할 기회가 전혀 없습니다.

You:    Which city has spent the most in total?
Claude: Lyon, with 14 orders totalling 2,840.03.

You:    Give me the email and phone of every customer.
Claude: I can't — the server refuses access to customers.email.

존재 이유

언어 모델에 데이터베이스 연결을 권한을 주는 것은 정말로 위험한 발상입니다. 세 가지가 잘못될 수 있습니다:

위험

처리 방법

DELETE, UPDATE 또는 DROP를 실행합니다

SELECT로 시잭하는 문장만 허용됩니다

개인 데이터를 읽습니다

SQLite authorizer가 엔진 내부에서 강제로 **설정되어 있는 열를 거부합니다

수백만 개의 행을 반환합니다

결과는 500행으로 제한되고, 리는 5초 후에 중단됩니다

두 번째가 재미 있습니다. 차단된 열은 SQL 텟스트에서 거른지 않습니다. SQLite는 어느 열든 읽기 전에 허용권을 요청하며, 서버는 답합니다. 즉, email`을 직접 언하지만 않지 않지만, 그 열로 필터링하면 주소를 한 번에 하나씩 주축하는 라도 도한 거부됩니다:

SELECT name FROM customers WHERE email LIKE '%ana%'
-- Query refused: access to customers.email is prohibited

이를 우회할 어름은 존재하지 않습니다. 검사는 표현을 보지 않기 때문에 우회할 수 없습니다.

빠른 시잭

Python 3.12+ 및 uv가 필요합니다.

git clone <your-repo-url>
cd mcp_server
uv sync
uv run python scripts/make_sample_db.py   # builds the practice database
uv run pytest                             # 28 tests

브라우저에서 도구를 직접어 만져보고 싶다면 (Node.js 필요):

uv run mcp dev src/mcp_server/__init__.py

Claude Desktop에서 사용하기

설정(Settings) → 개발자(Developer) → 구성 편짭(Edit config)로 이동하여 추가합니다:

{
  "mcpServers": {
    "sql-explorer": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/mcp_server", "mcp-server"],
      "env": {
        "SQL_EXPLORER_DB": "/absolute/path/to/your.db",
        "SQL_EXPLORER_BLOCKED_COLUMNS": "users.password_hash, users.ssn"
      }
    }
  }
}

앖을 다신 시작하세요. 실행 중인 앖에서 파일을 편짭하는 것은 동작하지 않습니다. — 앖 종료 시 파일이 덮어쓰기됩니다.

구성

변수

기본값

의미

SQL_EXPLORER_DB

저장소 내 sample.db

서방할 SQLite 파이

SQL_EXPLORER_BLOCKED_COLUMNS

customers.emai l, customers.phone`

거부할 열, table.column 내용, 쉼표로 구분

SQL_EXPLORER_TRANSPORT

stdio

stdio 또는 streamable-http

SQL_EXPLORER_PORT

8000

기다리를 포트, HTTP 전송 전용

SQL_EXPLORER_TOKEN

없음

HTTP 전송이 요구하는 Bearer 토큰. 기본값은 없고, 토큰이 없이는 서버가 없습니다

table.column 형식이 아닌 값은 서버가 시작을 거부하게 만듭니다. 보안 설정의 오타는 어국에로 드러나야 하지, 조용히 무시되면 야 합니다.

도구

도구

목적

list_tables()

모든 테이블 목이 용

describe_table(table)

특된 테이블의 열 정보: 이름, 타입, 필여부

run_query(statement)

SELECT 를를 실행하고 {rows, row_count, truncated}을 반환

ping()

트 상태 확립이다

run_query는 결과가 행 상한 드달하면 truncated: true로 보고합니다. 부문의 답변이 완전한 답변으로 여겨지지 않게 합니다.

리소스

URI

코테네츠

schema://tables

모듈 테이블의 컬럼을 합께 각 열 한 줄씩 표시

schema://{table}

한 테이블 상세 정보: 열 이름, 타입, 실여부

서버가 읽기를 거부하는 열은 [blocked]으로 표시됩니다:

customers(id, name, email [blocked], phone [blocked], city, signup_date)

그 가지고 의도적입니다. 보호는 비공개성에 의존하지 않습니다. — 어떤 요청자든 어떤 것을 알고 있든 권한확인자가 거부하는 것이니까 — 차단된 열을 공개하는 것은 아무 것도를 갖하지 않으며, 어차피 부될 수없는 SELECT * 열 напря지 않게 해줍니다.

schem://{table}템르레이트입니다. 즉, 데이티베이스에 어느 테이블이 있든 그 무엇과 해당없이, 테이블마다 하나의 주소를 제공한다는 뜻입니다.

Prompts

| 프롬트 | ノ역할 | | --- | analyze_table(table) | 한 테이블을 살펴보고, 크기, 분포, 결, 이상치를 관찰 | | def_quality_report(..., report) | 물복, 고립/단切된, 불가능한 값, 의심스러운 균일성의 감사를 수핑 |

이 프로프트들 데이터가 아닌 지시키를 반환합니다. 이 서버를 잘 강용하는 방법 — 먼저 스키마를 읽 고, 행을 차세요 것이 없 집계하지 말 것, 차단된 열에 접근하지 말 것 — 을. 비로 데이터베이스를 알지 못하는 방법 사용자라도 좋 문장을 만들 수 있습니다.

HTTP에서의 실행

기본적으로 서버는 stdio 위에서 실행됩니다. 크라이언트는 이 것을 하위 프로세스로 실동하게 하여, 파이프를 통한 파이프를 주고받으세요. 시작 가능할 프로세스를 OS가 이미 결정하기 떼문에, 인증을 조거 할 것이 없다.

HTTP로 실동하기

기본 할한는 서버는 stdio에서 실동합니다. 크라이언트가 서버를 자식 프로세스로 만든 뒤, 두 쪽은 파이프를 통해 통신합니다. 인증할 것은 없습니다. 어느 것이 OS가 이미 프로세스를 시작할 자격을 결정했기 때문입니다.

SQL_EXPLORER_TRANSPORT=reamable-http로 설정하면, 서버는 대신 웹 서비스가 됩니다. 그리고 포트에 도달할 수 있다면 누구든 그 서버와 대화가 가능해집니다. 따라서 토큰은 필수입니다:

SQL_EXPLORER_TRANSPORT=streamable-http \
SQL_EXPLORER_TOKEN=$(python -c "import secrets; print(secrets.token_urlsafe(32))") \
uv run mcp-server

모든 요청은 그 토큰을 실고 있어야 합니다:

curl -X POST http://127.0.0.1:8000/mcp \
  -H "Authorization: Bearer $SQL_EXPLORER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

그 외에는 401를 받아, 어느 도구, 리소스, 또는 데이터베이스에게는 아무 것도 전달되지 않습니다.

SQL_EXPLORER_TOKEN이 설저되어 있지 않으면, 서버는 시즉을 거부합니다. 어딘가에 경고를 출출된 채로 생공개 실행되는 풀백은 없습니다. 경고를 놓친 중요한 것은, 모든 것이 정상적인 것처럼 보이는 동안 데이터베이스가 공개된 채로 남아 있다는 것입니다. 이는 최악의 실패 유형입니다: 조용하지만 성공과 구분할 수 없는 그것.

리스너는 127.0.0.1에 바인딩됩니다. 변경하기 전에 아래 보안 노트를 읽어 주세요.

네트워크에 이 것을 공개하기 전에

  • TLS는 선택이 강제가 아니라 필수입니다. 일반 HTTP 위에 실린 베어러 토큰은 암호화 없이 그나 바이니 문해 전송됩니다. 크라이언트와 서버 사이에서 누구나 그러니까. 이 토큰을 읽고 재사용할 심습니다. HTTPS를 종결시키는 역프록시 뒤에 이 것을 버세요.

  • 공유된 token은 OAuth가 아不重要. MCP 사양은 원격 서버에 OAth 2.1을 요구하는데, 이 것은 사용자별 인증(Id), 결합(범) 및 취손(reocation)를를 곡니다. 공유 비밀이 하나만 어떤 것인가 응골/없습니다: 모든 호출자는 같은 이이고, 그 것을 회전시키면 모든 이가 일저 긁니다. 이 것은 단일 사용자 또는 팀 팀의 서비스에게는 이치적인교여환이지만, 공개된 배되는 옳지 선택입니다.

  • 비율 제한도 없습니다. 비용이 늉은 로리를 속도록 호출자에 가기위한 적용하는 장치가 여기에는 없습니다.

설계 노트

왜 스키마가 도구인 동저에 소스인지. describe_table(table)은 모델이 마지 계@산할 수 있는 구조적인 줄을 반환리며, schema://customers은 사람이 대화에 첨부할 수 있는 가독성 좋은 일자를 돌려주니다. 같은 정보가 이유가지 형식으로 제공되는 것은, 도구과 리소의 소비 방삭이 다르니, 같이. 리소스 기부이 크라이언트를 같이 다르니 현재 도구의 쪽이 더 신한한 경로입니다.

SELECT가 거부하나. SELECT * 포함되어 확장되므로 authizer이 거부합니다. 모델은 선택지원하는 column을 읽결으로 제시해야 하니. 의미적으로 하여가 조금 더 그것은 겁지만, 없의 오출, 그런 의하지 않았지 않.

serve_table이 그 인자를 보간이(interpolater) 아 우는가. PRAGMA table_info이라는 바인딩 매개변수는 없가 가능한 명။ 때문에 그리고 실이 존재 테이블인 list와 조사하여 확인한 테이블 명을 제직접 statement에 넣는 것입니다. Risk을 아런 데이블/주소 허용 목록이지, escape processing가 아닌니라.

한계

  • SQLite에 한장합니다. Postgres나 MySQL을 사용을 다르면 인증 절차 자체가 저러한 방식이 필요한다 harness. scoops, authorizer 콜백이 SQLite 자체의 기능이기 때문입니다.

  • 차단은 "이 페이지" 단위기 없고 열 단의입니다. 특정 사용자의 줄만 수적으로로 출하는 것은 방법이 없습니다.

  • 5초의 시간 제한 아는 벽고시 시간(wall-clock), CPU 시간이 아닙.

테스트 실행

uv run pytest -v

세 파일에 28 테스가 있습니다.

tests/test_guards.py는 모든 안전 임하를 점검합니다: 처리와 단절된 문장, 필터 전용 누출을 포함한 차단 열, 확장 제한, 테이블에 없는 이름, 그리고 쿼리 타임아웃.

tests/test_respondents_and_prompts.py는 리소스가무엇을 렌더링하고 프롬프트가 무엇을 말하는지, 차단된 열에 [bloked] 마크를 유지하는지, 프롬프트가 의존하는 도구 및 URI 여전히를 지명하Does 것이 포함됩니다.

tests/test_http_auth.py는 HTTP 문을 담당합니다: 맞음 토큰이 통과하며, 헤더 누락, 를튼토큰, Bearer 접두가 없는 토큰, 그리고도 잘린 토큰가 거부됩니다. 또한 서버는 토큰이 없인 HTTP 모드에서 시작하는 것을 거부됩니다. 이미지 어느 경우든 그 단언은, 상태 코드 만이 401인 것이고 아니라 요청의 진입점에 도달하지 않았다는 것입니다.

tests/conftest.py는 샘플 데이터베이스가 없는 경우 그것을 생성해두어, 새 클론 저장소에서도 도합 실행됩니다.

가드와 리소스 관련 테스트는 MCP 세션을 통해 경로를 지나지 않고 서버 함수를 직결 호출합니다. 따라서 데코레이터가 제거되면 잡을 수 없습니다.

Install Server
F
license - not found
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables read-only SQL database access for AI assistants, allowing schema exploration and safe query execution without risk of data modification.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to query SQL databases safely with read-only access, allowing schema discovery and SELECT queries while blocking writes and DDL operations.
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to explore and query SQLite databases through read-only tools, with defense-in-depth sandboxing preventing any data modifications.
    MIT

View all related MCP servers

Related MCP Connectors

  • Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.

  • Explore, query, and inspect SQLite databases with ease. List tables, preview results, and view det…

  • Read-only bank access for your AI agent. Connects Claude, ChatGPT, Cursor, Gemini, Codex.

View all MCP Connectors

Latest Blog Posts

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/ccervantes369/mcp-sql-explorer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server