SQLite MCP Server
by santos-404
Verified
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import zodToJsonSchema from "zod-to-json-schema";
import { z } from "zod";
import { VERSION } from "./utils/version.js";
import * as types from './utils/types.js';
import { SqliteDatabase } from "./utils/SqliteDatabase.js";
import { getArgumentValue } from "./utils/parseArguments.js";
const dbPath: string | undefined = getArgumentValue("--db-path");
if (!dbPath) throw new Error("A dbpath must be specified by the argument: --db-path");
const db: SqliteDatabase = new SqliteDatabase(dbPath);
const server = new Server(
{
name: "sqlite-mcp-server",
version: VERSION,
},
{
capabilities: {
tools: {},
}
}
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "read_query",
description: "Execute a SELECT query on a table of the SQLite database",
inputSchema: zodToJsonSchema(types.ReadQuerySchema)
},
{
name: "list_tables",
description: "List all tables on the SQLite database",
inputSchema: zodToJsonSchema(types.ReadQuerySchema)
}
]
}
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
if (!args)
throw new Error("Arguments are required");
switch (name) { // switch-case because there will be multiple options
case "read_query": {
const { query, params } = args as { query: string; params?: any[] };
if (typeof query !== "string")
throw new Error("Invalid arguments: expected 'query' to be a string");
if (!query.trim().toUpperCase().startsWith("SELECT"))
throw new Error("Only SELECT queries are allowed for read_query");
const results = await db.executeQuery(query, params);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
case "list_tables": {
const query = "SELECT name FROM sqlite_master WHERE type='table';"
const results = await db.executeQuery(query);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
} catch (error) {
if (error instanceof z.ZodError) {
throw new Error(`Invalid input: ${JSON.stringify(error.errors)}`);
}
throw error;
}
});
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
runServer().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});