MCP (Model Context Protocol) server for multiple database types, designed with a modular architecture for easy extensibility.
📖 Read in Vietnamese: README.vi.md
The server provides the following tools:
- query: Execute SELECT queries and return results
- execute_sql: Execute any SQL command (INSERT, UPDATE, DELETE, CREATE, etc.)
- list_tables: List all tables in the database
- describe_table: Get detailed information about a table's schema
The project is split into separate modules:
src/
├── index.ts # Entry point, initializes adapter based on DB_TYPE
├── server.ts # MCP server implementation
└── adapters/
├── base.ts # Base adapter interface
├── postgres.ts # PostgreSQL adapter implementation
├── mysql.ts # MySQL adapter implementation
├── sqlite.ts # SQLite adapter implementation
├── redis.ts # Redis adapter implementation
├── mongo.ts # MongoDB adapter implementation
└── ldap.ts # LDAP adapter implementation
Each database has its own adapter implementing the DatabaseAdapter interface:
PostgresAdapter: PostgreSQL support with 13 SQL toolsMySQLAdapter: MySQL/MariaDB support with 13 SQL toolsSQLiteAdapter: SQLite support with 13 SQL tools (using better-sqlite3)RedisAdapter: Redis support with 16 Redis toolsMongoAdapter: MongoDB support with 15 MongoDB toolsLDAPAdapter: LDAP support with 6 LDAP tools
- Install dependencies:
npm install- Build the project:
npm run build-
DB_TYPE: Database type (default:postgres)postgresorpostgresql: PostgreSQLmysqlormysql2: MySQL/MariaDBsqlite: SQLiteredis: Redismongodbormongo: MongoDBldap: LDAP
-
READ_ONLY_MODE: Read-only mode (default:true- safer)trueor not set: Only allows reads, blocks all write operations (default)falseor0: Allows both read and write (must be set explicitly)
-
POSTGRES_CONNECTION_STRING: Connection string for PostgreSQL -
MYSQL_CONNECTION_STRINGorMYSQL_URL: Connection string for MySQL -
SQLITE_CONNECTION_STRINGorSQLITE_URL: Connection string for SQLite (file path) -
REDIS_CONNECTION_STRINGorREDIS_URL: Connection string for Redis -
MONGODB_CONNECTION_STRINGorMONGODB_URL: Connection string for MongoDB -
LDAP_CONNECTION_STRINGorLDAP_URL: Connection string for LDAP -
LDAP_BIND_DN: Bind DN for LDAP authentication (optional) -
LDAP_BIND_PASSWORD: Bind password for LDAP authentication (optional) -
DATABASE_URL: Connection string (fallback for PostgreSQL, MySQL, or SQLite)
Examples:
# PostgreSQL with read-only mode (default, no need to set READ_ONLY_MODE)
export DB_TYPE="postgres"
export POSTGRES_CONNECTION_STRING="postgresql://user:password@localhost:5432/mydb"
# READ_ONLY_MODE defaults to true
# Redis with write access (must be set explicitly)
export DB_TYPE="redis"
export REDIS_CONNECTION_STRING="redis://localhost:6379"
export READ_ONLY_MODE="false"
# MySQL with read-only mode (default)
export DB_TYPE="mysql"
export MYSQL_CONNECTION_STRING="mysql://user:password@localhost:3306/mydb"
# READ_ONLY_MODE defaults to true
# SQLite with read-only mode (default)
export DB_TYPE="sqlite"
export SQLITE_CONNECTION_STRING="sqlite://./database.sqlite"
# READ_ONLY_MODE defaults to true
# MongoDB with read-only mode (default)
export DB_TYPE="mongodb"
export MONGODB_CONNECTION_STRING="mongodb://localhost:27017/mydb"
# READ_ONLY_MODE defaults to trueAfter publishing, you can run the server directly with npx without installing:
npx @nam088/mcp-database-serverRun the server locally:
npm startOr run in development mode with watch:
npm run devAdd the server to your MCP client configuration (e.g., Claude Desktop). You can use either npx (recommended) or node with a local path.
The easiest way is to use npx, which will automatically download and run the package:
{
"mcpServers": {
"postgres-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "postgres",
"POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}Note: The -y flag automatically accepts package installation if not already present.
If you prefer to install locally or use a specific path:
{
"mcpServers": {
"postgres-readonly": {
"command": "node",
"args": ["/path/to/database-server/dist/index.js"],
"env": {
"DB_TYPE": "postgres",
"POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}No need to set READ_ONLY_MODE as this is the default:
{
"mcpServers": {
"postgres-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "postgres",
"POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}Note: You must explicitly set READ_ONLY_MODE to "false" to allow write operations.
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "postgres",
"POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/mydb",
"READ_ONLY_MODE": "false"
}
}
}
}{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "postgres",
"DATABASE_URL": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}{
"mcpServers": {
"redis-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "redis",
"REDIS_CONNECTION_STRING": "redis://localhost:6379",
"READ_ONLY_MODE": "true"
}
}
}
}Note: You must explicitly set READ_ONLY_MODE to "false" to allow write operations.
{
"mcpServers": {
"redis": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "redis",
"REDIS_CONNECTION_STRING": "redis://localhost:6379",
"READ_ONLY_MODE": "false"
}
}
}
}{
"mcpServers": {
"redis": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "redis",
"REDIS_URL": "redis://:password@localhost:6379/0"
}
}
}
}{
"mcpServers": {
"redis": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "redis",
"REDIS_CONNECTION_STRING": "rediss://user:password@redis.example.com:6380"
}
}
}
}{
"mcpServers": {
"mongodb-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mongodb",
"MONGODB_CONNECTION_STRING": "mongodb://localhost:27017/mydb",
"READ_ONLY_MODE": "true"
}
}
}
}Note: You must explicitly set READ_ONLY_MODE to "false" to allow write operations.
{
"mcpServers": {
"mongodb": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mongodb",
"MONGODB_CONNECTION_STRING": "mongodb://localhost:27017/mydb",
"READ_ONLY_MODE": "false"
}
}
}
}{
"mcpServers": {
"mongodb": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mongodb",
"MONGODB_CONNECTION_STRING": "mongodb://username:password@localhost:27017/mydb?authSource=admin"
}
}
}
}{
"mcpServers": {
"mongodb": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mongodb",
"MONGODB_CONNECTION_STRING": "mongodb://host1:27017,host2:27017,host3:27017/mydb?replicaSet=myReplicaSet"
}
}
}
}{
"mcpServers": {
"mongodb-atlas": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mongodb",
"MONGODB_CONNECTION_STRING": "mongodb+srv://username:password@cluster.mongodb.net/mydb?retryWrites=true&w=majority"
}
}
}
}No need to set READ_ONLY_MODE as this is the default:
{
"mcpServers": {
"mysql-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mysql",
"MYSQL_CONNECTION_STRING": "mysql://user:password@localhost:3306/mydb"
}
}
}
}Note: You must explicitly set READ_ONLY_MODE to "false" to allow write operations.
{
"mcpServers": {
"mysql": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mysql",
"MYSQL_CONNECTION_STRING": "mysql://user:password@localhost:3306/mydb",
"READ_ONLY_MODE": "false"
}
}
}
}{
"mcpServers": {
"mysql": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mysql",
"DATABASE_URL": "mysql://user:password@localhost:3306/mydb"
}
}
}
}No need to set READ_ONLY_MODE as this is the default:
{
"mcpServers": {
"sqlite-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "sqlite",
"SQLITE_CONNECTION_STRING": "sqlite://./database.sqlite"
}
}
}
}Note: You must explicitly set READ_ONLY_MODE to "false" to allow write operations.
{
"mcpServers": {
"sqlite": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "sqlite",
"SQLITE_CONNECTION_STRING": "sqlite://./database.sqlite",
"READ_ONLY_MODE": "false"
}
}
}
}{
"mcpServers": {
"sqlite": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "sqlite",
"SQLITE_CONNECTION_STRING": "/path/to/database.sqlite"
}
}
}
}Note: The project uses ldapts instead of ldapjs (which has been decommissioned) to ensure sustainability and better support.
No need to set READ_ONLY_MODE as this is the default:
{
"mcpServers": {
"ldap-readonly": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "ldap",
"LDAP_CONNECTION_STRING": "ldap://localhost:389"
}
}
}
}Note: You must explicitly set READ_ONLY_MODE to "false" to allow write operations.
{
"mcpServers": {
"ldap": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "ldap",
"LDAP_CONNECTION_STRING": "ldap://localhost:389",
"READ_ONLY_MODE": "false"
}
}
}
}{
"mcpServers": {
"ldap": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "ldap",
"LDAP_CONNECTION_STRING": "ldap://localhost:389",
"LDAP_BIND_DN": "cn=admin,dc=example,dc=com",
"LDAP_BIND_PASSWORD": "password123"
}
}
}
}{
"mcpServers": {
"ldap": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "ldap",
"LDAP_CONNECTION_STRING": "ldaps://ldap.example.com:636"
}
}
}
}{
"mcpServers": {
"ldap-ad": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "ldap",
"LDAP_CONNECTION_STRING": "ldap://ad.example.com:389",
"LDAP_BIND_DN": "CN=Service Account,CN=Users,DC=example,DC=com",
"LDAP_BIND_PASSWORD": "password123"
}
}
}
}You can configure multiple databases in the same MCP client:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "postgres",
"POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/mydb",
"READ_ONLY_MODE": "true"
}
},
"redis": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "redis",
"REDIS_CONNECTION_STRING": "redis://localhost:6379",
"READ_ONLY_MODE": "false"
}
},
"mysql": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mysql",
"MYSQL_CONNECTION_STRING": "mysql://user:password@localhost:3306/mydb"
}
},
"sqlite": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "sqlite",
"SQLITE_CONNECTION_STRING": "sqlite://./database.sqlite"
}
},
"mongodb": {
"command": "npx",
"args": ["-y", "@nam088/mcp-database-server"],
"env": {
"DB_TYPE": "mongodb",
"MONGODB_CONNECTION_STRING": "mongodb://localhost:27017/mydb"
}
}
}
}READ_ONLY_MODE is true or not set (default), the server will block all write operations:
PostgreSQL, MySQL, SQLite:
- ✅ Allowed:
query(SELECT) - ❌ Blocked:
execute_sql(INSERT, UPDATE, DELETE, CREATE, etc.)
Redis:
- ✅ Allowed:
redis_get,redis_keys,redis_exists,redis_ttl,redis_type,redis_dbsize,redis_info,redis_hget,redis_hgetall,redis_lrange,redis_smembers,redis_zrange - ❌ Blocked:
redis_set,redis_del,redis_expire,redis_hset
MongoDB:
- ✅ Allowed:
mongo_find,mongo_find_one,mongo_count,mongo_aggregate,mongo_list_collections,mongo_get_collection_stats,mongo_get_indexes,mongo_get_database_stats - ❌ Blocked:
mongo_insert_one,mongo_insert_many,mongo_update_one,mongo_update_many,mongo_delete_one,mongo_delete_many,mongo_create_index
LDAP:
- ✅ Allowed:
ldap_search,ldap_authenticate,ldap_compare - ❌ Blocked:
ldap_add,ldap_modify,ldap_delete
When attempting to execute a write operation in read-only mode, the server will return an error:
Error: Server is running in read-only mode. Write operations are disabled.
To add support for a new database:
- Create a new adapter file in
src/adapters/(e.g.,mysql.ts) - Implement the
DatabaseAdapterinterface frombase.ts - Add a new case in
src/index.tsto initialize the adapter
Example:
// src/adapters/mysql.ts
import { DatabaseAdapter, QueryResult, ExecuteResult, TableSchema } from "./base.js";
export class MySQLAdapter implements DatabaseAdapter {
// Implement methods from DatabaseAdapter
async query(sql: string): Promise<QueryResult> { ... }
async execute(sql: string, params?: any[]): Promise<ExecuteResult> { ... }
async listTables(schema?: string): Promise<string[]> { ... }
async describeTable(table: string, schema?: string): Promise<TableSchema> { ... }
}Then add to src/index.ts:
case "mysql":
return new MySQLAdapter(connectionString);Execute a SELECT query:
{
"name": "query",
"arguments": {
"sql": "SELECT * FROM users LIMIT 10"
}
}Execute a SQL command:
{
"name": "execute_sql",
"arguments": {
"sql": "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')"
}
}List tables:
{
"name": "list_tables",
"arguments": {
"schema": "public"
}
}Describe table schema:
{
"name": "describe_table",
"arguments": {
"table": "users",
"schema": "public"
}
}MIT