intermediate25 minentree

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 database
  • list_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.