SLayer
Agent-native semantic layer, letting AI agents query databases through specifying intent instead of writing SQL, then compiling structured queries into correct, dialect-aware SQL. Dynamic and expressive, supporting multi-stage queries, time-shifts, and complex join schemas.
README
<p align="center"> <img src="https://raw.githubusercontent.com/MotleyAI/slayer/main/docs/images/slayer-hero.png" alt="SLayer — AI agent operating a semantic layer" width="600"> </p>
SLayer is a semantic layer that lets AI agents query your database correctly.
If you find SLayer useful, a ⭐ helps others discover it!
How it works
SLayer sits between your database and whatever consumes the data – AI agents, internal tools, dashboards, or scripts. You define your data models (or let SLayer auto-generate them from the schema), and query using a structured API of measures, dimensions, and filters instead of writing SQL directly.
SLayer compiles these queries into the correct SQL for your database, handling joins, aggregations, time-based calculations, and dialect differences so that consumers don't have to.
SLayer is
- dynamic: models can be updated at any time and used immediately; aggregations are defined in queries, not models
- simple: query structure is intuitive and easily understood by LLMs and humans
- expressive: supports queries like "month-on-month % increase in total revenue, compared to the previous year"
- embeddable: can be used as a standalone service or imported as a Python module with no extra server
- flexible: exposes MCP, REST API, CLI and Python interfaces; supports most popular databases
See also: automatic model ingestion, queries-as-models, auto-applied filters, and more.
Why not just let agents write SQL? Because they get it wrong often enough to matter – see our blog post and dbt's benchmark analysis.
Quickstart
We recommend using uv, especially if you don't work in a Python project.
To run the server:
uvx --from 'motley-slayer[all]' slayer serve
Or to add the MCP server:
claude mcp add slayer -- uvx --from 'motley-slayer[all]' slayer mcp
Then configure a datasource or ask your agent to help you do it.
Read more on how to get started with MCP, CLI, REST API, Python in the docs.
Interfaces
REST API
# Query
curl -X POST http://localhost:5143/query \
-H "Content-Type: application/json" \
-d '{"model": "orders", "fields": [{"formula": "*:count"}], "dimensions": [{"name": "status"}]}'
# List models (returns name + description)
curl http://localhost:5143/models
# Get a single datasource (credentials masked)
curl http://localhost:5143/datasources/my_postgres
See more in the docs.
MCP Server
SLayer supports two MCP transports, HTTP (served alongside the API) and stdio (serverless, spawned by the agent).
# 1. stdio-based, does not require a running server
claude mcp add slayer -- slayer mcp
# 2. HTTP-based (SSE), provided SLayer server is already running
claude mcp add slayer-remote --transport sse --url http://localhost:5143/mcp/sse
SLayer does not expose credentials to consumers once created.
Both transports expose the same tools, allowing to inspect, create and update datasources and models and run queries. More info in the docs.
Python Client
Useful for agents working in code execution environments, e.g. for AI data analytics, as well as any Python apps.
from slayer.client.slayer_client import SlayerClient
from slayer.core.query import SlayerQuery, ColumnRef
# Remote mode (connects to running server)
client = SlayerClient(url="http://localhost:5143")
# Or local mode (no server needed)
from slayer.storage.yaml_storage import YAMLStorage
client = SlayerClient(storage=YAMLStorage(base_dir="./my_models"))
# Query data
query = SlayerQuery(
model="orders",
fields=[{"formula": "*:count"}, {"formula": "revenue:sum"}],
dimensions=[ColumnRef(name="status")],
limit=10,
)
df = client.query_df(query)
print(df)
CLI
# Run a query directly from the terminal
slayer query '{"model": "orders", "fields": [{"formula": "*:count"}], "dimensions": [{"name": "status"}]}'
# Or from a file
slayer query @query.json --format json
These commands do not depend on a running server.
Models
By default, models are defined as YAML files. Add an optional description to help users and agents understand complex models:
name: orders
sql_table: public.orders
data_source: my_postgres
description: "Core orders table with revenue metrics"
dimensions:
- name: id
sql: id
type: number
primary_key: true
- name: status
sql: status
type: string
- name: created_at
sql: created_at
type: time
measures:
- name: revenue
sql: amount
- name: quantity
sql: qty
Fields
The fields parameter specifies what data columns to return.
{
"model": "orders",
"dimensions": ["status"],
"time_dimensions": [{"dimension": "created_at", "granularity": "month"}],
"fields": [
{"formula": "*:count"},
{"formula": "revenue:sum"},
{"formula": "revenue:sum / *:count", "name": "aov", "label": "Average Order Value"},
{"formula": "cumsum(revenue:sum)"},
{"formula": "change_pct(revenue:sum)"},
{"formula": "last(revenue:sum)", "name": "latest_rev"},
{"formula": "time_shift(revenue:sum, -1, 'year')", "name": "rev_last_year"},
{"formula": "time_shift(revenue:sum, -2)", "name": "rev_2_periods_ago"},
{"formula": "lag(revenue:sum, 1)", "name": "rev_prev_row"},
{"formula": "rank(revenue:sum)"},
{"formula": "change(cumsum(revenue:sum))", "name": "cumsum_delta"}
]
}
Available functions: cumsum, time_shift, change, lag, and more – see docs. Formulas support arbitrary nesting — e.g., change(cumsum(revenue:sum)) or cumsum(revenue:sum) / *:count.
Filters
Filters use simple formula strings — no verbose JSON objects:
{
"model": "orders",
"fields": [{"formula": "*:count"}, {"formula": "revenue:sum"}],
"filters": [
"status == 'completed'",
"amount > 100"
]
}
Filters support a variety of operators, composition, pattern matching. Transforms & computed columns can also be used for filtering. See docs for more.
Auto-Ingestion
Connect to a database and generate models automatically. SLayer introspects the schema, detects foreign key relationships, and creates models with explicit join metadata.
For example, given tables orders → customers → regions (via FKs), the orders model will automatically include:
- Joined dimensions:
customers.name,regions.name, etc. (dotted syntax) - Count-distinct measures:
customers.*:count_distinct,regions.*:count_distinct - Explicit joins — LEFT JOINs are constructed dynamically at query time
# Via CLI
slayer ingest --datasource my_postgres --schema public
# Via API
curl -X POST http://localhost:5143/ingest \
-d '{"datasource": "my_postgres", "schema_name": "public"}'
Via MCP, agents can do this conversationally:
create_datasource(name="mydb", type="postgres", host="localhost", database="app", username="user", password="pass")ingest_datasource_models(datasource_name="mydb", schema_name="public")models_summary(datasource_name="mydb")→inspect_model(model_name="orders")→query(...)
Datasource Setup
By default, datasources are configured as individual YAML files in the datasources/ directory:
# datasources/my_postgres.yaml
name: my_postgres
type: postgres
host: ${DB_HOST}
port: 5432
database: ${DB_NAME}
username: ${DB_USER}
password: ${DB_PASSWORD}
Environment variable references (${VAR}) are resolved at read time.
See more in the docs.
Storage Backends
SLayer ships with two storage backends:
- YAMLStorage (default) — models and datasources as YAML files on disk. Great for version control.
- SQLiteStorage — everything in a single SQLite file. Good for embedded use or when you don't want to manage files.
SLayer allows easily implementing your own storage backends, which is useful for features such as tenant isolation.
See the documentation page for storage backends for more.
Roadmap
| # | Step | Status |
|---|---|---|
| 1 | Dynamic joins | ✅ |
| 2 | Multi-stage queries | ✅ |
| 3 | Cross-model measures | ✅ |
| 4 | Aggregation at query time | ✅ |
| 5 | Smart output formatting (currency, percentages) | ✅ |
| 6 | Unpivoting | ❌ |
| 7 | Auto-propagating filters | ❌ |
| 8 | Asof joins | ❌ |
| 9 | Chart generation (eCharts) | ❌ |
Examples
The examples/ directory contains runnable examples that also serve as integration tests:
| Example | Description |
|---|---|
| embedded | SQLite, no server needed |
| postgres | Docker Compose with Postgres + REST API |
| mysql | Docker Compose with MySQL + REST API |
| clickhouse | Docker Compose with ClickHouse + REST API |
Tutorials
The docs/examples/ directory contains Jupyter notebooks that walk through SLayer's features step by step.
| Notebook | Topic |
|---|---|
| SQL vs DSL | How model SQL and query DSL stay cleanly separated |
| Auto-Ingestion | Schema introspection, FK graph discovery, automatic model generation |
| Time Operations | change, change_pct, time_shift, lag, lead, last — composable time transforms |
| Joins | Dot syntax, multi-hop dimensions, diamond join disambiguation |
| Joined Measures | Cross-model measures with sub-query isolation |
| Multistage Queries | Query chaining, queries-as-models, ModelExtension |
Claude Code Skills
SLayer includes Claude Code skills in .claude/skills/ to help Claude understand the codebase:
- slayer-overview — architecture, package structure, MCP tools list
- slayer-query — how to construct queries with fields, dimensions, filters, time dimensions
- slayer-models — model definitions, datasource configs, auto-ingestion, incremental editing
Known limitations
SLayer currently has no caching or pre-aggregation engine. If you need to process lots of requests to large databases at sub-second latency, consider adding a caching layer or pre-aggregation engine.
License
MIT — see LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。