Harjoitus 16: MCP + Read-only Database¶
Tavoite
Luoda MCP-palvelin, joka sallii vain SELECT-operaatiot testitietokantaan, ja estää kaikki kirjoitusoperaatiot.
Taustaa¶
Tärkein turvallisuusperiaate MCP-liitännössä:
Production DB:n kirjoituspolku on täysin erillään test-tietokannasta.
Kun MCP tarjoaa vain lukuoikeudet:
✅ Ei voi kirjoittaa tuotantoon
✅ Voidaan turvallisesti debugata
✅ Testit voivat suorittaa kyselyitä ilman riskiä
Tehtävä¶
Luo MCP-palvelin, joka:
✅ Sallii SELECT-kyselyt
❌ Estää INSERT/UPDATE/DELETE/DROP
✅ Käytetään testitietokantaan (test_db)
Ratkaisu¶
MCP-palvelimescripti: mcp-readonly-db.py¶
#!/usr/bin/env python3
"""MCP-palvelin, joka tarjoaa read-only-tietokannan."""
import sqlite3
import json
import re
conn = sqlite3.connect("test.db")
cursor = conn.cursor()
def is_read_only(query: str) -> bool:
"""Tarkista onko kysely READ-ONLY-muotoinen."""
write_patterns = [
r'\bINSERT\b', r'\bUPDATE\b', r'\bDELETE\b',
r'\bDROP\b', r'\bALTER\b', r'\bCREATE\b',
r'\bTRUNCATE\b', r'\bGRANT\b', r'\bREVOKE\b'
]
return not any(re.search(p, query, re.IGNORECASE) for p in write_patterns)
def main():
# Simuloitu MCP JSON-RPC viesti
request = json.load(sys.stdin)
method = request.get("method")
if method == "tools/call":
tool_name = request["params"]["name"]
args = request["params"]["arguments"]
query = args.get("query", "")
if not is_read_only(query):
print(json.dumps({
"error": "VAIN READ-ONLY kyselyt ovat sallittuja.",
"query": query,
"status": "denied"
}))
sys.exit(1)
result = cursor.execute(query).fetchall()
print(json.dumps({
"result": result,
"status": "success"
}))
main()
Rekisteröinti Claude Coden kanssa¶
claude mcp add --transport http readonly-db http://localhost:8081/mcp
Käyttö Claude Codessa¶
claude "Lue käyttäjätaulun schema MCP:n kautta"
Claude vastaa:
{
"columns": ["id", "username", "email", "created_at"],
"row_count": 142,
"sample": [{"id": 1, "username": "alice", "email": "alice@example.com"}]
}
Yritettävä kirjoitusta:
claude "Poista käyttäjä ID 5 tietokannasta"
→ ❌ ERROR: VAIN READ-ONLY kyselyt ovat sallittuja.
Lähde: Esimerkki 16 [S1], [S13]