Skip to main content
Glama

Read-only Database MCP

by Crei03
mcp-server.ts4 kB
// Minimal MCP server exposing read-only database helpers over stdio. // Uses the @modelcontextprotocol/sdk server transport; if the SDK API changes, // adjust the tool registration calls accordingly. import { z } from "zod"; import { getConfig } from "./storage.js"; import { listTables, previewTable, runSelect } from "./db.js"; type McpToolHandler = (args: any) => Promise<{ content: Array<{ type: string; text: string }> }>; async function createTool( server: any, name: string, description: string, inputSchemaZod: z.ZodTypeAny, legacyJsonSchema: Record<string, unknown>, handler: McpToolHandler, ) { // Prefer modern registerTool API, fall back to legacy tool/addTool. if (typeof server.registerTool === "function") { server.registerTool( name, { description, inputSchema: inputSchemaZod }, async (args: any) => handler(args), ); return; } const register = server.tool ? server.tool.bind(server) : server.addTool.bind(server); register( { name, description, inputSchema: legacyJsonSchema, }, async (args: any) => handler(args), ); } async function main() { // Lazy import keeps this file side-effect free for UI/server users. const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp"); const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio"); const transport = new StdioServerTransport(); const server = new McpServer({ name: "db-mcp", version: "0.1.0" }); await createTool( server, "list_tables", "List tables for a configured database name.", z.object({ db: z.string().describe("Config name"), }), { type: "object", required: ["db"], properties: { db: { type: "string", description: "Config name" }, }, }, async ({ db }) => { const config = getConfig(db); if (!config) { throw new Error(`Unknown db config: ${db}`); } const tables = await listTables(config); return { content: [{ type: "text", text: JSON.stringify(tables, null, 2) }] }; }, ); await createTool( server, "preview_table", "Preview up to 20 rows from a table in a configured database.", z.object({ db: z.string().describe("Config name"), table: z.string().describe("Table name"), limit: z.number().optional().describe("Max rows (default 20)"), }), { type: "object", required: ["db", "table"], properties: { db: { type: "string", description: "Config name" }, table: { type: "string", description: "Table name" }, limit: { type: "number", description: "Max rows (default 20)" }, }, }, async ({ db, table, limit }) => { const config = getConfig(db); if (!config) { throw new Error(`Unknown db config: ${db}`); } const preview = await previewTable(config, table, limit || 20); return { content: [{ type: "text", text: JSON.stringify(preview, null, 2) }] }; }, ); await createTool( server, "run_select", "Run a SELECT-only query against a configured database (all other statements are rejected).", z.object({ db: z.string().describe("Config name"), sql: z.string().describe("SELECT statement (must start with SELECT)"), }), { type: "object", required: ["db", "sql"], properties: { db: { type: "string", description: "Config name" }, sql: { type: "string", description: "SELECT statement" }, }, }, async ({ db, sql }) => { const config = getConfig(db); if (!config) { throw new Error(`Unknown db config: ${db}`); } const rows = await runSelect(config, sql); return { content: [{ type: "text", text: JSON.stringify(rows, null, 2) }] }; }, ); console.error("db-mcp server ready on stdio"); await server.connect(transport); } main().catch((err) => { console.error(err); process.exit(1); });

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/Crei03/mcp-db'

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