Entree: Database Query Server
An MCP server that lets AI assistants query a SQLite database safely. Learn schema introspection, parameterized queries, and read-only guards.
title: "Entree: Database Query Server" description: "An MCP server that lets AI assistants query a SQLite database safely. Learn schema introspection, parameterized queries, and read-only guards." order: 4 category: "entree" level: "intermediate" duration: "25 min" date: "2026-04-01" tags:
- tools
- resources
- database
- sqlite keywords:
- mcp database server
- mcp-framework sqlite
- database query mcp
- ai database access
What You Get
A secure MCP server that gives Claude read-only access to a SQLite database. It includes schema introspection as a resource and a safe query tool with parameterized statements.
Tools included:
query— run a read-only SQL query against the databaselist_tables— list all tables in the database
Resources included:
db://schema— full database schema as a browsable resource
Quick Start
npx mcp-framework create database-server
cd database-server
npm install better-sqlite3
npm install -D @types/better-sqlite3
The Query Tool
Create src/tools/QueryTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
import Database from "better-sqlite3";
const QueryInput = z.object({
sql: z.string().describe("SQL query to execute (read-only)"),
});
class QueryTool extends MCPTool<typeof QueryInput> {
name = "query";
description = "Run a read-only SQL query against the database";
schema = { input: QueryInput };
async execute(input: z.infer<typeof QueryInput>) {
const sql = input.sql.trim().toUpperCase();
// Safety: only allow SELECT statements
if (!sql.startsWith("SELECT")) {
throw new Error(
"Only SELECT queries are allowed. This server is read-only."
);
}
const db = new Database(process.env.DB_PATH || "./data.db", {
readonly: true,
});
try {
const rows = db.prepare(input.sql).all();
return {
rowCount: rows.length,
rows: rows.slice(0, 100), // Limit results
};
} finally {
db.close();
}
}
}
export default QueryTool;
The List Tables Tool
Create src/tools/ListTablesTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
import Database from "better-sqlite3";
class ListTablesTool extends MCPTool<typeof z.ZodObject<{}>> {
name = "list_tables";
description = "List all tables in the database";
schema = { input: z.object({}) };
async execute() {
const db = new Database(process.env.DB_PATH || "./data.db", {
readonly: true,
});
try {
const tables = db
.prepare(
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
)
.all();
return { tables };
} finally {
db.close();
}
}
}
export default ListTablesTool;
The Schema Resource
Create src/resources/SchemaResource.ts:
import { MCPResource } from "mcp-framework";
import Database from "better-sqlite3";
class SchemaResource extends MCPResource {
uri = "db://schema";
name = "Database Schema";
description = "Full schema of the connected database";
mimeType = "text/plain";
async read() {
const db = new Database(process.env.DB_PATH || "./data.db", {
readonly: true,
});
try {
const tables = db
.prepare("SELECT sql FROM sqlite_master WHERE type='table'")
.all() as { sql: string }[];
return {
text: tables.map((t) => t.sql).join("\n\n"),
};
} finally {
db.close();
}
}
}
export default SchemaResource;
Security Notes
Important: This server opens the database in read-only mode and rejects non-SELECT queries. For production use, consider adding query timeouts, result size limits, and SQL injection protection beyond the basic SELECT check.
Build & Connect
npm run build
{
"mcpServers": {
"database": {
"command": "node",
"args": ["./dist/index.js"],
"env": {
"DB_PATH": "/path/to/your/database.db"
}
}
}
}
What You Learn
- Exposing database access as MCP tools
- Read-only safety guards for AI access
- Using MCP resources for schema introspection
- Environment variable configuration
- Resource cleanup with try/finally patterns
Next Up
Combine database skills with API integration in the GitHub Server, or go all-in with the Full Developer Tools Suite.
Built with mcp-framework (3.3M+ downloads) by @QuantGeekDev. Validated by Anthropic.