scopedb-mcp
Provides scoped database access for AI agents, allowing them to query and mutate data within defined boundaries using Supabase as the database backend.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@scopedb-mcpShow me Alice's latest order status."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ScopeDB MCP
Give AI database access without giving it your whole database.
Config-driven MCP server and TypeScript library for scoped, auditable AI data access.
ScopeDB lets AI fetch the data it needs on its own, but only inside the boundaries you define in YAML:
scopes:
support:
tables:
users: { access: read, columns: [name] }
orders: { access: read, columns: [product, amount, status] }
settings: { max_rows: 50, max_joins: 1 }The result is a better default for AI products:
No manual context assembly — stop hardcoding what data to fetch before every model call.
No full-database exposure — the AI only sees allowed tables, columns, rows, and operations.
No raw SQL prompting — queries are structured, validated, and bounded by scope settings.
No code rewrite when requirements change — update the config, not your app logic.
Why ScopeDB
Approach | What you get | What breaks |
Manual context assembly | Tight control | Rigid code, lots of glue logic, AI cannot explore follow-up questions |
Raw SQL / full DB access | Flexible querying | Security risk, token bloat, accidental exposure of sensitive data |
ScopeDB | AI autonomy with scoped access | You define the boundary once, and the tools stay inside it |
Related MCP server: mcp-db-server
How Teams Usually Solve This Today
Traditionally, teams piece this together from multiple layers:
Database-level controls like RLS, views, read-only roles, or restricted schemas
Application-level APIs like
getRecentOrders(userId)orupdateOrderStatus(orderId)Manual context assembly that fetches data ahead of each model call
That approach works, but it usually means a lot of glue code between your database, your backend, and your AI layer.
ScopeDB is not trying to replace fundamentals like RLS. It packages the AI-facing part of that stack into one reusable layer: declare the boundary once, generate tools from config, and let the model operate autonomously inside those rules. If you already use RLS, ScopeDB sits above it as the scoped access layer for AI.
What It Feels Like
One app can expose different database capabilities to different AI workflows without writing custom query code for each one:
Scope | AI can do | AI cannot do |
| Read customer names and order status | See emails, salaries, or internal notes |
| Join tables, aggregate revenue, compare trends | Read hidden columns outside the analytics view |
| Update specific fields like | Write arbitrary columns or mutate every table |
Example:
User asks: "Show me Alice's latest order."
In
support, the AI can answer by readingusers.nameandorders.status.If it tries: "What is Alice's salary?" ScopeDB rejects the request because
salaryis not visible.
What You Get
Scoped table and column visibility for support agents, analytics tools, and internal copilots
Row-level filters for multi-tenant or user-specific data access
Controlled JOINs and aggregation for analytics use cases
Write access to specific columns only when you want AI to make safe updates
Two integration modes: standalone MCP server or TypeScript library inside your backend
Use Cases
Scenario | Description |
Backend AI Features | AI autonomously fetches relevant data to generate responses — no manual context assembly, no unnecessary exposure |
Support Agent | Sees customer names and order status only — no emails, salaries, or internal notes |
Data Analytics | Cross-table JOINs and aggregation, but cost prices and internal notes hidden |
Admin Dashboard | Write access to specific columns only (e.g., order status) |
Multi-tenant SaaS |
|
Internal Tools | Natural language database queries — no SQL required |
How The Boundary Is Enforced
Request → Scope Isolation → Permission Guard → Structured Query Builder → Row Filter Injection → Resource LimitsScope Isolation — each scope only sees tables and columns declared in config
Permission Guard — validates access mode, column access, operator whitelist
Structured Queries — no raw SQL; all parameters validated before query construction
Row Filter Injection — table-level + scope-level filters automatically merged and injected
Resource Limits — max_rows / max_joins prevent oversized queries
Quick Start
1. Install
pnpm install scopedb-mcp
# or
npm install scopedb-mcp2. Create Config
Create scopedb.config.yaml:
version: 1
database:
adapter: supabase
url: ${SUPABASE_URL}
key: ${SUPABASE_SERVICE_KEY}
tables:
users:
description: "User profiles"
columns:
id: { type: uuid }
name: { type: text, description: "Full name" }
email: { type: text, description: "Email address" }
salary: { type: integer, description: "Annual salary" }
row_filter: "deleted_at IS NULL"
orders:
description: "Order records"
columns:
id: { type: uuid }
user_id: { type: uuid, references: users.id }
product: { type: text, description: "Product name" }
amount: { type: integer, description: "Total amount" }
status: { type: text, description: "pending / confirmed / shipped" }
scopes:
support:
description: "Customer support — minimal access"
tables:
users: { access: read, columns: [name] }
orders: { access: read, columns: [product, amount, status] }
settings:
max_rows: 50
max_joins: 1
analytics:
description: "Analytics — aggregation allowed, no sensitive data"
tables:
users: { access: read, columns: [name] }
orders: { access: read, columns: [user_id, product, amount, status] }
settings:
max_rows: 500
max_joins: 3
allow_aggregate: true
admin:
description: "Admin — write access to specific columns"
tables:
orders:
access: [read, write]
columns: [user_id, product, amount, status]
writable_columns: [status]
settings:
max_rows: 1000
settings:
default_scope: support
max_rows: 200
timeout_ms: 5000
result_format: compact3. Connect to Claude Code
claude mcp add scopedb-support \
-e SUPABASE_URL=https://xxx.supabase.co \
-e SUPABASE_SERVICE_KEY=your-key \
-e SCOPEDB_CONFIG=./scopedb.config.yaml \
-e SCOPEDB_SCOPE=support \
-- node /path/to/scopedb-mcp/dist/server/mcp.jsOr add to Claude Desktop config:
{
"mcpServers": {
"scopedb-support": {
"command": "node",
"args": ["/path/to/scopedb-mcp/dist/server/mcp.js"],
"env": {
"SUPABASE_URL": "https://xxx.supabase.co",
"SUPABASE_SERVICE_KEY": "your-key",
"SCOPEDB_CONFIG": "./scopedb.config.yaml",
"SCOPEDB_SCOPE": "support"
}
}
}
}4. Start Using
Once connected, the AI automatically gets these tools:
db_describe— View table schemas visible to the current scopedb_query— Structured queries (filters, sorting, JOINs, aggregation)db_mutate— Data mutations (only when scope includes write access)
Just ask in natural language:
"Show me the last 10 orders"
"Total order amounts by department"
"Change order #123 status to shipped"Configuration
Database
database:
adapter: supabase # Currently supports supabase
url: ${SUPABASE_URL} # Environment variable expansion supported
key: ${SUPABASE_SERVICE_KEY}Table Definitions
tables:
table_name:
description: "Table description (visible to AI)"
columns:
column_name:
type: text # uuid / text / integer / boolean / timestamp / jsonb
description: "Column description" # Optional, helps AI understand semantics
references: other.id # Optional, foreign key (enables JOINs)
row_filter: "deleted_at IS NULL" # Optional, table-level filter (shared by all scopes)Scope Definitions
Scopes are the core concept — defining precise data access boundaries for different roles.
scopes:
scope_name:
description: "Role description"
context_params: [current_user_id] # Optional, runtime-injected parameters
tables:
table_name:
access: read # read / write / [read, write]
columns: [col1, col2] # Visible columns (whitelist)
writable_columns: [col1] # Writable columns (write mode only)
row_filter: "user_id = :current_user_id" # Scope-level row filter
settings:
max_rows: 100 # Maximum rows returned
max_joins: 2 # Maximum JOINs allowed
allow_aggregate: true # Whether aggregation queries are allowedContext Parameters
For multi-tenant scenarios — inject user identity at runtime:
scopes:
end_user:
context_params: [current_user_id]
tables:
orders:
access: read
columns: [product, amount, status]
row_filter: "user_id = :current_user_id"Pass context at startup:
claude mcp add scopedb-user \
-e SCOPEDB_CONTEXT='{"current_user_id":"user-uuid-here"}' \
...Global Settings
settings:
default_scope: support # Default scope name
max_rows: 200 # Global max rows (scope settings override)
max_joins: 2 # Global max JOINs
timeout_ms: 5000 # Query timeout (milliseconds)
result_format: compact # compact: cols+rows separated, saves tokens
allow_aggregate: false # Global aggregation toggle
log: true # Query logging (to stderr)Programmatic Usage (Backend Integration)
Use ScopeDB as a library in your backend — no MCP protocol needed. Resolve a scope based on the user's role, convert tools to your AI provider's format, and let the AI call them in a loop.
import {
loadConfig, resolveScope, generateTools,
handleDescribe, handleQuery, handleMutate,
SupabaseAdapter,
} from "scopedb-mcp";
// 1. Load config & create adapter
const config = loadConfig("./scopedb.config.yaml");
const adapter = new SupabaseAdapter(config.database.url, config.database.key!);
// 2. Resolve scope based on user role (from JWT, session, etc.)
const scope = resolveScope(config, userRole); // "support" | "analytics" | "admin"
// 3. Generate tool definitions → convert to OpenAI function calling format
const tools = generateTools(scope).map((t) => ({
type: "function" as const,
function: { name: t.name, description: t.description, parameters: t.inputSchema },
}));
// 4. Call your AI provider (OpenRouter, OpenAI, etc.) with tools
const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ model: "anthropic/claude-sonnet-4", messages, tools }),
});
// 5. When AI returns tool_calls, execute via ScopeDB handlers
const ctx = { scope, adapter, log: true };
for (const tc of assistantMessage.tool_calls) {
const args = JSON.parse(tc.function.arguments);
// Permission guard + row filter injection happens automatically
const result = await handleQuery(ctx, args);
// Feed result back to AI...
}scope determines the permission boundary. Different users get different scopes — permission checks, row filters, column visibility are all enforced automatically.
See examples/backend-openrouter.ts for a complete working example.
ScopeDB can also run as a standalone MCP server:
import { serve } from "scopedb-mcp";
await serve({ configPath: "./scopedb.config.yaml", scopeName: "analytics" });Development
pnpm install # Install dependencies
pnpm build # Build
pnpm test # Run tests
pnpm typecheck # Type check
pnpm dev # Watch modeProject Structure
src/
├── config/ # Config loading & validation (YAML + Zod)
├── scope/ # Scope resolution & context parameter substitution
├── engine/ # Permission guard + query builder + result formatter
├── adapters/ # Database adapters (Supabase)
├── compiler/ # MCP tool definition generation + description compression
└── server/ # MCP Server (stdio transport)Roadmap
Supabase adapter
Structured queries + permission validation
Row-level filter injection
Aggregation (count / sum / avg / min / max / group_by)
MCP Server (stdio)
HTTP transport
CLI tools (init / serve / test / schema)
Native Postgres adapter
MySQL adapter
Library mode (embedded AI conversations)
Contributing
Contributions are welcome!
Fork this repository
Create a feature branch:
git checkout -b feature/your-featureEnsure tests pass:
pnpm test && pnpm typecheckSubmit a PR
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/xieweicong/scopedb-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server