scopedb-mcp

scopedb-mcp

Config-driven MCP server that gives AI scoped, auditable database access without exposing the entire database.

Category
访问服务器

README

<div align="center">

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.

License: MIT TypeScript MCP

中文 | 日本語

</div>


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

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) or updateOrderStatus(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
support Read customer names and order status See emails, salaries, or internal notes
analytics Join tables, aggregate revenue, compare trends Read hidden columns outside the analytics view
admin Update specific fields like orders.status Write arbitrary columns or mutate every table

Example:

User asks: "Show me Alice's latest order."

In support, the AI can answer by reading users.name and orders.status.

If it tries: "What is Alice's salary?" ScopeDB rejects the request because salary is 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 context_params injects user_id — each user sees only their own data
Internal Tools Natural language database queries — no SQL required

How The Boundary Is Enforced

<div align="center">

Request → Scope Isolation → Permission Guard → Structured Query Builder → Row Filter Injection → Resource Limits

</div>

  1. Scope Isolation — each scope only sees tables and columns declared in config
  2. Permission Guard — validates access mode, column access, operator whitelist
  3. Structured Queries — no raw SQL; all parameters validated before query construction
  4. Row Filter Injection — table-level + scope-level filters automatically merged and injected
  5. Resource Limits — max_rows / max_joins prevent oversized queries

Quick Start

1. Install

pnpm install scopedb-mcp
# or
npm install scopedb-mcp

2. 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: compact

3. 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.js

Or 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 scope
  • db_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 allowed

Context 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 mode

Project 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

  • [x] Supabase adapter
  • [x] Structured queries + permission validation
  • [x] Row-level filter injection
  • [x] Aggregation (count / sum / avg / min / max / group_by)
  • [x] 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!

  1. Fork this repository
  2. Create a feature branch: git checkout -b feature/your-feature
  3. Ensure tests pass: pnpm test && pnpm typecheck
  4. Submit a PR

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选