使用说明
MCP Database Server
This project is a remote MCP server for safe, read-only database access. It is built with Next.js App Router, TypeScript, and a Node.js runtime so it can run on Vercel.
What this project does
The server exposes a Claude-compatible remote MCP endpoint at /api/mcp.
The MCP transport is stateless so it works correctly on Vercel-style serverless deployments without in-memory session affinity.
Claude or any MCP client can use it to:
- list tables
- inspect table schemas
- inspect foreign-key relationships
- list stored procedures
- run safe read-only SQL queries
The backend never connects to databases in write mode and rejects unsafe SQL before execution.
Tech stack
- Next.js App Router
- TypeScript
- Node.js runtime
- MCP server SDK
- PostgreSQL driver:
pg - MSSQL driver:
mssql - No ORM
Project structure
app/api/mcp/route.ts- MCP HTTP handlerlib/config.ts- central configuration and env accesslib/db/postgres.ts- PostgreSQL connection pool and query helperlib/db/mssql.ts- MSSQL connection pool and query helperlib/tools/db/- database MCP tools (introspection, queries, connections)lib/tools/db/runQuery.ts- safe query execution toollib/tools/db/listTables.ts- list tables toollib/tools/db/getSchema.ts- table schema toollib/tools/db/getRelationships.ts- FK relationship discovery toollib/tools/db/listStoredProcedures.ts- stored procedure listing toollib/tools/github/- GitHub code intelligence toolslib/validators/queryValidator.ts- read-only SQL validationlib/types.ts- shared types for requests and responses
Setup
- Install dependencies:
npm install
- Copy
.env.exampleto.env - Paste your credentials into
.env - Run locally:
- Cursor / Grok (recommended): stdio — the client starts the server, no
start-mcp.ps1npm run mcp:stdio:build- point the MCP client at
node dist/mcp-stdio.mjs(see.cursor/mcp.jsonand.grok/config.toml)
- HTTP / remote:
./start-mcp.ps1ornpm run dev, thenhttp://localhost:3939/api/mcp
- Cursor / Grok (recommended): stdio — the client starts the server, no
Environment variables
All runtime settings are controlled from one place only: .env and lib/config.ts.
POSTGRES_DEFAULT=PROD.Main.MAIN_DB
POSTGRES_URLS={
"UAT": {
"Main": {
"MAIN_DB": "postgresql://USER:PASSWORD@HOST:5432/MAIN_DB"
}
},
"PROD": {
"Main": {
"MAIN_DB": "postgresql://USER:PASSWORD@HOST:5432/MAIN_DB",
"REPORTING_DB": "postgresql://USER:PASSWORD@HOST:5432/REPORTING_DB"
}
}
}
POSTGRES_URL=postgresql://USER:PASSWORD@HOST:5432/MAIN_DB
MSSQL_CONNECTIONS={"main":"Data Source=13.235.202.125;Initial Catalog=REPORT_DB_FROMKG;User ID=sa;Password=your_password;Encrypt=false;TrustServerCertificate=true","analytics":"Data Source=13.235.202.125;Initial Catalog=ANALYTICS_DB;User ID=sa;Password=your_password;Encrypt=false;TrustServerCertificate=true"}
MSSQL_DEFAULT=main
MSSQL_CONNECTION_STRING=Data Source=13.235.202.125;Initial Catalog=REPORT_DB_FROMKG;User ID=sa;Password=your_password;Encrypt=false;TrustServerCertificate=true
GITHUB_PAT=replace_with_github_pat
GITHUB_ORG_NAME=myorg
GITHUB_ALLOWED_ORGS=myorg
GITHUB_ALLOWED_REPOS=owner1/repo1,owner2/repo2,owner3/*
GITHUB_MAX_FILE_SIZE_BYTES=1000000
GITHUB_TREE_MAX_DEPTH=3
GITHUB_ORG_REPO_PAGE_SIZE=30
GITHUB_REPO_RESOLUTION_MAX_SCANS=3
GITHUB_SUMMARY_CONTEXT_LINES=3
GITHUB_SUMMARY_PREVIEW_BYTES=2000
UPSTASH_REDIS_REST_URL=https://your-upstash-instance.upstash.io
UPSTASH_REDIS_REST_TOKEN=replace_with_upstash_token
MCP_CACHE_L1=true
MCP_CACHE_L1_MAX_ENTRIES=256
MCP_UI_ORIGIN=https://your-allowed-ui.example.com
SQLITE_ALLOWED_DIR=C:\path\to\allowed\sqlite\dir
Set POSTGRES_URLS to a JSON object of named connections. Pretty-printed / multiline JSON in .env is supported. Nested objects flatten to dotted aliases:
- Flat map:
{"main":"postgresql://..."}→connection=main - Server map:
{"srv1":{"main":"postgresql://..."}}→connection=srv1.main - Env map:
{"PROD":{"Main":{"MAIN_DB":"postgresql://..."}}}→connection=PROD.Main.MAIN_DB
If you omit connection, POSTGRES_DEFAULT is used (it must match a flattened alias). POSTGRES_URL still works as a backward-compatible single-database fallback.
Set MSSQL_CONNECTIONS the same way (flat or nested JSON). Pass the matching connection name when calling an MSSQL tool; if you omit it, MSSQL_DEFAULT is used. MSSQL_CONNECTION_STRING still works as a backward-compatible single-database fallback.
Set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN to enable the shared L2 cache. MCP_CACHE_L1=true keeps the optional in-memory L1 cache on for warm instances.
Set GITHUB_PAT, GITHUB_ORG_NAME, and GITHUB_ALLOWED_REPOS to enable the read-only GitHub tools. The allowlist accepts exact owner/repo entries and org-wide owner/* patterns. GITHUB_ALLOWED_ORGS lets you restrict org-level listing. GITHUB_MAX_FILE_SIZE_BYTES keeps file fetches bounded, GITHUB_TREE_MAX_DEPTH limits repository tree traversal, GITHUB_ORG_REPO_PAGE_SIZE bounds org listing pages, and GITHUB_SUMMARY_CONTEXT_LINES / GITHUB_SUMMARY_PREVIEW_BYTES keep summaries compact.
Centralized config behavior
The file lib/config.ts contains all application settings used by the server.
It defines:
- PostgreSQL connection string or named connection map
- MSSQL connection string or named connection map
- max row limit for query execution
- default query limits and timeouts
Changing .env is enough to reconfigure the backend.
Tools that accept schema use the schema supplied by the caller. PostgreSQL falls back to public and MSSQL falls back to dbo when it is omitted. list_schemas returns every non-system schema visible to the configured database user.
Supported tools
1. run_query
Input:
{
"db": "postgres",
"query": "SELECT * FROM users"
}
Behavior:
- validates the SQL
- blocks unsafe statements
- injects
LIMIT 50for PostgreSQL when needed - injects
TOP (50)for MSSQL when needed - executes the query through the correct pool
- returns rows and metadata
2. list_tables
Lists tables from the chosen database:
- PostgreSQL:
pg_catalog.pg_tables - MSSQL:
INFORMATION_SCHEMA.TABLES
3. get_table_schema
Returns column metadata for a selected table.
4. get_relationships
Returns foreign-key relationships using system catalogs.
5. list_stored_procedures
Lists stored procedures where the connected database supports them.
Connect Claude
Use the deployed HTTPS endpoint as a remote MCP server URL in Claude.
- Open Claude's connector setup.
- Choose the custom connector option.
- Paste your deployed endpoint URL, for example:
https://your-vercel-domain.vercel.app/api/mcp
- Save the connector and authenticate if your deployment requires it.
Set MCP_UI_ORIGIN to the exact UI origin you want to allow; wildcard origins are not used.
If you are testing locally, use your dev server URL instead:
http://localhost:3000/api/mcp
MCP tools
Claude will see these tools through the MCP protocol:
list_schemasget_database_inforun_querylist_tablesdb_execute_stored_proceduresearch_tablessearch_columnsget_table_schemaget_table_summaryget_view_definitionget_view_summaryget_procedure_summaryget_function_summaryget_sample_rowsexplain_querycompare_schemaget_column_statssearch_viewsget_row_countget_foreign_key_summarysearch_functionssearch_proceduresget_table_sample_by_columnsget_dependency_graphget_relation_pathcompare_object_versionsget_relationshipsget_indexesget_constraintslist_stored_proceduresgithub_get_commit_historygithub_get_file_historygithub_compare_refsgithub_get_pull_request_commentsgithub_get_function_bodygithub_grep_filegithub_search_filesgithub_search_symbolsgithub_find_referencesgithub_get_method_definitiongithub_get_class_definitiongithub_get_interface_implementationsgithub_get_method_callersgithub_get_method_calleesgithub_read_linesgithub_get_project_referencesgithub_get_dependency_graphgithub_find_dependency_pathgithub_trace_call_chain
The endpoint also keeps the previous custom JSON body format for backwards compatibility.
True line-by-line blame is still not available from the current serverless deployment model. For that, you would need either a self-hosted server with a checked-out git repository or a GitHub GraphQL-based implementation that exposes blame data.
Legacy API contract
Send a POST request to /api/mcp with this shape:
{
"tool": "run_query",
"input": {}
}
Example tool requests:
list_tables
{
"tool": "list_tables",
"input": {
"db": "postgres"
}
}
run_query
{
"tool": "run_query",
"input": {
"db": "postgres",
"query": "SELECT * FROM users"
}
}
get_table_schema
{
"tool": "get_table_schema",
"input": {
"db": "mssql",
"table": "Users",
"schema": "dbo"
}
}
get_relationships
{
"tool": "get_relationships",
"input": {
"db": "postgres",
"schema": "public"
}
}
list_stored_procedures
{
"tool": "list_stored_procedures",
"input": {
"db": "postgres"
}
}
Response format
Every tool returns the same envelope:
{
"success": true,
"data": {},
"error": null
}
On failure:
{
"success": false,
"data": null,
"error": "Reason message"
}
Security rules
- read-only queries only
- allow only
SELECT,WITH, andEXPLAIN - reject
INSERT,UPDATE,DELETE,DROP,ALTER,TRUNCATE,MERGE, and similar write operations - reject multiple statements
- reject SQL comments
- reject dangerous keywords such as
exec,grant, andxp_ - use read-only database users only
- grant the database user access only to schemas the MCP server may expose
Performance notes
- PostgreSQL uses a persistent
pg.Pool - MSSQL uses cached
ConnectionPoolinstances per connection alias - connections are reused across requests
- imports are kept lightweight
Deployment
This backend is ready for Vercel deployment.
Node runtime
The API route is forced to use the Node.js runtime.
Vercel note
If needed, the deployment uses vercel.json to pin the function runtime.
Test requests
Load tables
Use the list_tables payload for either database.
Safe query
{
"tool": "run_query",
"input": {
"db": "postgres",
"query": "SELECT * FROM users LIMIT 5"
}
}
Schema lookup
{
"tool": "get_table_schema",
"input": {
"db": "postgres",
"table": "users",
"schema": "public"
}
}
Troubleshooting
- Make sure the Claude connector URL is the deployed HTTPS endpoint, not the repo URL
- If the server says a DB is not configured, check
.env - If queries are rejected, verify that they start with
SELECT,WITH, orEXPLAIN - If schemas are rejected, confirm the schema is in the allowed list
- If Vercel deployment fails, ensure the function is running on Node.js, not Edge
Commands
npm installnpm run devnpm run buildnpm run start