WrenAI 语义层接入 MCP:用wren serve mcp让 AI 客户端直接查询你的项目
【免费下载链接】WrenAIGenBI (Generative BI) for AI agents, an open-source, governed text-to-SQL through an open context layer that turns natural-language questions into trusted dashboards, charts, and SQL across 20+ data sources, such as BigQuery, Snowflake, PostgreSQL, ClickHouse, Amazon Redshift, Databricks and more.项目地址: https://gitcode.com/GitHub_Trending/wr/WrenAI
导读
WrenAI 通过开放的上下文层(Open Context Layer)把自然语言问题转译为可信的 SQL 与图表,而 MCP(Model Context Protocol)是 AI Agent 与外部工具之间的标准桥梁。本篇指南围绕 docs/core/guides/mcp.md 展开,完整讲解wren serve mcp的启动方式、客户端接入配置、可用的查询/模式/知识工具集,并结合 serve_cli.py 与 mcp_server.py 的源码实现,说明能力门控、行数截断、降级策略与安全边界。读完你将能在 Claude Desktop、Claude Code、Cursor 等任意 MCP 客户端中,让 Agent 通过语义模型(MDL)直接查询数据库,并在对话中复用项目沉淀的业务知识与 NL→SQL 记忆。
一、前置准备:一个可服务的 Wren 项目
wren serve mcp将 Wren 项目的查询(query)、模式(schema)与业务知识(business-knowledge)工具暴露给任何 MCP 客户端。它在进程内基于已编译的 MDL 与当前绑定的连接 profile 运行——不需要独立的 ibis-server,也不需要额外后端,只需你已安装好的 CLI 本身。启动前需要满足三个条件:
- 已构建的 MDL 产物:项目根目录下存在
target/mdl.json,由wren context build生成; - 已绑定的连接 profile:通过
wren profile add/wren context set-profile绑定(如果只需要 schema / 转译类工具,可用--no-connect跳过数据库连接); - 已安装
mcp可选依赖:
pip install 'wrenai[mcp]'若在core/wren源码检出目录下工作,则使用:
just install-extra mcp关于项目的标准初始化流程,可参考 manage_project.md:wren context init脚手架出 v5 项目布局(models/、views/、cubes/、knowledge/),wren context validate校验 YAML,wren context build编译到target/mdl.json,wren context set-profile把连接 profile 写入wren_project.yml。仓库中的 v5-jaffle 示例项目 就是一个典型的最小可服务项目:data_source: postgres,其knowledge/下包含业务规则、NL→SQL 对与知识索引等全部可供 MCP 读取的内容。
二、启动服务器:从 stdio 到 Streamable HTTP
2.1 默认 stdio 模式
cd my-project wren serve mcpstdio是默认传输方式——这是"客户端把wren作为子进程拉起"这一模式所期望的形态:MCP 客户端负责 spawn 进程,通过标准输入输出与服务器通信。
2.2 HTTP 模式
如果需要让其他工具连接到一台本地常驻服务器,改用 Streamable HTTP:
wren serve mcp --transport http --host 127.0.0.1 --port 80802.3 能力开关
--allow-write:开启store_query写入工具。默认关闭——不加该参数时服务器只读;--no-connect:纯转译(transpile-only)模式,服务器完全不触碰数据库,run_sql/dry_run/query_cube三个工具会被禁用,仅保留 schema 与dry_plan等能力。
2.4 启动横幅(banner)
启动时服务器会打印与本次实际调用完全匹配的、可直接复制的客户端注册命令——HTTP 模式下是claude mcp add/codex mcp add两行;stdio 模式下除这两行外还会附带一段 JSON 格式的mcpServers配置块。传--quiet(等价-q)可静默横幅。
从 serve_cli.py 的实现可以看到,该横幅总是输出到 stderr——因为在 stdio 传输下,stdout 是 MCP 协议通道,绝不能污染;同时它会用shlex.quote对每个 token 做 shell 转义,保证含空格的路径也能直接复制粘贴,并在设置了WREN_HOME环境变量时把-e WREN_HOME=...一并拼进注册命令。
2.5 完整的命令行参数
wren serve mcp的全部参数见 CLI 参考文档:
| Flag | 默认值 | 说明 |
|---|---|---|
--transport | stdio | 传输方式,stdio或http |
--host | 127.0.0.1 | 绑定地址,仅--transport http生效 |
--port | 8080 | 绑定端口,仅--transport http生效 |
--project | 自动发现 | 覆盖项目根目录 |
--profile | 当前激活 profile | 连接 profile 名称 |
--allow-write | 关闭 | 启用store_query写入工具 |
--no-connect | 关闭 | 转译模式:禁用run_sql、dry_run、query_cube |
--quiet/-q | 关闭 | 抑制客户端注册帮助横幅 |
2.6 启动流程的源码视角
serve_cli.py 中serve_mcp的启动顺序可以拆解为五步,理解它对排错很有帮助:
- 校验传输方式:非
stdio/http直接报错退出; - 校验依赖:尝试
import mcp,失败时提示pip install 'wrenai[mcp]'。这也解释了为什么mcp_server.py选择模块文件而非mcp/包命名——避免遮蔽顶层 MCP SDK 包(见 mcp_server.py 模块注释); - 发现项目并校验 MDL:
discover_project_path定位项目根,若target/mdl.json不存在则报错并提示"Hint: runwren context buildfirst"; - MDL 新鲜度检查:
_mdl_is_stale会比较wren_project.yml、relationships.yml、models/、views/、cubes/下所有源文件的 mtime 与target/mdl.json,发现更新即打印"MDL may be stale"警告,但仍继续服务旧 manifest(从不自动重建); - 解析 profile 并构建引擎:读取
~/.wren/profiles.yml中指定 profile,展开${ENV_VAR}密文占位符(缺失时给出明确的MissingSecretError),把{"datasource": ..., ...}序列化为connection_info交给_build_engine,最后注册atexit关闭引擎。
run_server内部(mcp_server.py)则按 transport 分派:stdio走mcp.run(transport="stdio"),http走streamable-http并写入 host/port 设置。
三、接入客户端:JSON 配置与注册命令
3.1 stdio:让客户端 spawn 服务器进程
启动横幅已经为你填好了下面的命令;本节解释其含义。大多数桌面 / IDE MCP 客户端接受一段 JSON 配置,通过 stdio spawn 服务器进程:
{ "mcpServers": { "wren": { "command": "wren", "args": ["serve", "mcp"], "cwd": "/path/to/your/project" } } }要点:
cwd必须位于项目内部;或者在args中传--project /path/to/project代替;- 添加配置后需要重启客户端才会生效;
- 若设置了
WREN_HOME,横幅给出的配置块还会附带"env": {"WREN_HOME": ...},确保子进程找到全局 CLI 状态。
3.2 HTTP:指向 Streamable HTTP 端点
对于需要被其他机器 / 进程连接的场景,运行:
wren serve mcp --transport http --port 8080客户端不再 spawn 进程,而是直连该 host/port 上的 Streamable HTTP 端点。注意两点安全约束:HTTP 默认只绑定127.0.0.1(本机回环),且当前版本不提供 bearer-token 鉴权——因此务必保持其本地运行,不要暴露到公网。
3.3 一键注册命令
服务启动横幅直接给出形如以下的注册命令(stdio 与 http 略有差异):
claude mcp add wren -- serve mcp --project /path/to/your/project codex mcp add wren -- serve mcp --project /path/to/your/project # HTTP 模式: claude mcp add --transport http wren http://127.0.0.1:8080/mcp codex mcp add wren --url http://127.0.0.1:8080/mcp调试阶段也可用 MCP Inspector(npx @modelcontextprotocol/inspector,Streamable HTTP 指向上述 URL)查看服务器暴露的工具与资源。
四、客户端获得的能力清单
4.1 查询工具(Query)
| 工具 | 说明 |
|---|---|
run_sql | 通过 Wren 语义层执行 SQL 并返回行数据。SQL 面向MDL 模型名而非原始数据库表书写;未传limit时默认上限 1000 行,硬上限 10000 行,负数 limit 直接拒绝 |
dry_run | 校验 SQL 合法性但不返回结果行,是执行前的廉价预检,失败时携带引擎错误信息 |
dry_plan | 仅做 SQL 展开(transpile),返回目标方言的 SQL,完全不碰数据库 |
query_cube | 结构化 cube(指标)查询并返回聚合结果,镜像wren cube query的语义 |
query_cube的参数规格(见 mcp_server.py 工具 docstring)值得单独说明:
cube与measures必填,缺一即抛ValueError;time_dimension使用 CLI 规格格式name:granularity[:start,end](支持粒度year/quarter/month/week/day/hour/minute);filters使用dim:op[:value]格式,in/not_in操作用逗号分隔多个值(支持的算子:eq、neq、in、not_in、gt、gte、lt、lte、contains、starts_with、is_null、is_not_null,见 cli.md);sql_only=True时只返回生成的 SQL 不执行。
4.2 模式工具(Schema)
get_mdl(完整编译 MDL JSON)、list_models(模型列表 + 列数)、describe_model(列、主键、ref_sql、关系)、get_data_source(项目数据源/方言)、list_cubes、describe_cube、list_functions(当前数据源注册的 SQL 函数,无需数据库连接)。从源码看,describe_model会自动补充模型或列上properties.description中的描述,方便 Agent 理解字段语义;list_functions则在会话上下文构建时按数据源注册函数表(见 mcp_server.py)。
4.3 知识工具(Knowledge)
get_instructions(来自knowledge/rules/*.md的业务规则)、recall_queries(按相似度召回已验证的 NL→SQL 范例)、get_context(按问题做语义化 schema 片段检索,是recall_queries的 schema 轴孪生)、describe_schema(纯文本 schema 描述,get_mdl的人类可读版本,适合直接粘进 LLM prompt)、list_stored_queries(枚举全部已存 NL→SQL 对,可按source标签过滤)、list_knowledge(列出可经wren://knowledge/{path}读取的文件)。加上仅在--allow-write下注册的store_query(持久化确认过的 NL→SQL 对,详见后文)。
4.4 资源(Resources)
wren://mdl— 编译后的 MDL JSON(application/json)wren://instructions—knowledge/rules/*.md中的业务规则(text/markdown)wren://project— 项目名 / catalog / schema / 数据源 / schema_version / knowledge_schema_version(application/json)wren://agents— 项目根下的AGENTS.md(若存在)wren://knowledge/{path}— 读取knowledge/下任意文件,如wren://knowledge/knowledge.yml、wren://knowledge/rules/general.md
值得注意的实现细节:MCP SDK 的{param}匹配单个路径段([^/]+),一个{path}占位符无法跨/,因此 mcp_server.py 用两个模板覆盖实际布局——wren://knowledge/{name}服务根级文件(如knowledge.yml),wren://knowledge/{subdir}/{name}服务一层子目录(rules/*.md、sql/*.md)。
4.5 提示词(Prompt):wren_workflow
wren_workflow是一份现成的 SOP(标准作业流程),引导 Agent 按"schema → instructions → recall → dry-run → run → store"的顺序回答数据问题。其步骤列表会根据启动参数动态裁剪(见 mcp_server.py 的_workflow_text):
- 默认连接模式:读取
wren://mdl/list_models/describe_model理解 schema →get_instructions获取业务规则 →recall_queries召回范例 →dry_run校验 →run_sql执行 → 命名指标优先query_cube; --no-connect模式下,dry_run/run_sql/query_cube步骤被替换为dry_plan(无数据库连接时的转译检查);--allow-write模式下追加可选步骤store_query。
步骤在门控后重新编号,保证始终是连续的 1..N。相关行为被 test_mcp_server.py 的test_workflow_text_*系列测试锁定。
五、源码级原理:能力门控、行数截断与降级
5.1 能力门控
build_server(mcp_server.py)按ServeContext状态决定注册哪些工具:
no_connect=True时跳过run_sql、dry_run、query_cube(_register_query_tools的if not ctx.no_connect:分支),但dry_plan始终注册;allow_write=False时根本不调用_register_write_tools,store_query不出现。
5.2 行数截断的 N+1 探测
run_sql走_query_with_limit_probe(mcp_server.py):请求 limit 先被钳制在MAX_ROW_LIMIT(10000)内,随后以effective_limit + 1向引擎取数——多取一行用于判断是否截断,超限则切片到有效 limit 并在结果里标记"truncated": true。负数 limit 在执行前即被拒绝(对应测试 test_run_sql_negative_limit_rejected)。
query_cube的执行路径则不同:_query_cube_with_limit_probe把行数上限直接嵌进生成的 SQL(LIMIT n+1),connector 收到的 limit 为None。这样既保持了生成 SQL 中LIMIT/OFFSET的合法顺序,又能约束先物化再切片型 connector 的行为(见 mcp_server.py 与测试 test_query_cube_execution_bakes_probe_into_sql_not_connector)。返回结构统一为{"columns": [...], "rows": [...], "row_count": N, "truncated": bool},datetime/Decimal/bytes/NaN 等类型会在_normalize_value中递归转换为 JSON 原生类型。
5.3 无 memory extra 时的优雅降级
知识工具设计为"可降级":
recall_queries优先走memoryextra 的语义(embedding)检索,未安装时退回对knowledge/sql/*.md的零依赖 token 重叠检索;get_context在未安装memory时退回完整纯文本 schema 描述(与describe_schema同源),并在返回中附带提示"Installwrenai[memory]and runwren memory indexfor embedding-based schema search on large schemas";describe_schema完全不需要额外依赖——它是get_mdl的纯文本对应物,专为粘贴进 LLM prompt 而设计;list_stored_queries在MemoryStore出错(含未装 extra)时退回直接读取knowledge/sql/*.md,且同样施加行数上限——测试 test_list_stored_queries_fallback_applies_default_cap 明确锁定了这一行为。
store_query写入时以 Markdown 为源(写knowledge/sql/*.md),若装了memory再尽力索引到 LanceDB;索引失败仅记 warning、不阻断(见 mcp_server.py)。
5.4 查询引擎链路
所有查询最终落到 engine.py 的WrenEngine:query先dry_plan转译,再交给按数据源分派的 connector 执行并返回 Arrow 表;dry_plan内部依次做 sqlglot 解析(目标方言)→ 模型解析(含大小写敏感/不敏感回退)→ 按引用表裁剪 manifest → 政策校验(validate_sql_policy与validate_planned_sql)→ CTE 重写展开为完整目标方言 SQL。这意味着 Agent 写出的"模型级" SQL 在到达数据库前会经历语义层的完整校验与展开。
六、安全边界与运维注意
- 凭据不跨 MCP 边界:连接凭据在启动时从 profile 解析一次、常驻服务端,跨过 MCP 边界的只有 SQL 文本、查询结果与元数据(见 cli.md);
- 从不自动重建 MDL:若项目源文件比
target/mdl.json新,服务器只打印 staleness 警告、继续服务旧 manifest。修改模型后请手动重跑wren context build; wren://knowledge/{path}路径逃逸防护:资源处理器用resolve()归一化后校验目标必须位于项目knowledge/目录内且为文件,形如../wren_project.yml的逃逸路径会被拒绝(见 mcp_server.py);- HTTP 仅限本地:默认绑定
127.0.0.1,且此版本无 bearer-token 鉴权,切勿暴露到非本地网络; - profile 缺失处理:
--profile指定的名字不存在、或缺datasource、或${VAR}密文解析失败时,服务器都会给出明确的错误提示后退出(见 serve_cli.py)。
七、端到端实战:从零接入 Claude Code
结合仓库内的 v5-jaffle 示例,完整流程如下:
# 1. 构建 MDL(示例项目已具备 models/、views/、knowledge/) cd examples/v5-jaffle wren context validate wren context build # 生成 target/mdl.json # 2. 绑定连接 profile(以 postgres 为例;仅 schema/转译可省略) wren profile add pg-dev --from-file dev.yml --activate wren context set-profile pg-dev # 3. 安装 MCP 依赖并启动 pip install 'wrenai[mcp]' wren serve mcp # 或 --transport http --port 8080随后把启动横幅给出的 JSONmcpServers块(含cwd指向项目根)粘贴进客户端的 MCP 配置并重启。之后 Agent 即可:
- 读取
wren://project/wren://mdl了解项目与数据模型; - 通过
list_models、describe_model、get_context理解可用字段与语义; - 调用
get_instructions拿到业务规则(示例项目中的 business-rules.md 声明了"订单金额以 USD 记录"、"客户名可能为 NULL"等约束); - 用
recall_queries复用已验证的范例查询(如 total-revenue.md 中的SELECT SUM(amount) AS total_revenue FROM orders); dry_run校验后run_sql执行,确认无误后在--allow-write模式下用store_query沉淀新的 NL→SQL 对,形成持续增强的记忆闭环。
八、常见问题速查
| 现象 | 原因与处理 |
|---|---|
| 启动报 "target/mdl.json missing" | 项目未构建,先wren context build |
| 启动报 "Install the MCP extra" | 缺mcp依赖,执行pip install 'wrenai[mcp]'或just install-extra mcp |
| 启动报 "profile 'X' not found" | --profile名不存在,wren profile list核对 |
| 启动报 "profile has no datasource" | profile 缺少datasource字段 |
| 启动警告 "MDL may be stale" | 模型源文件比 manifest 新,重跑wren context build |
| 客户端连不上 stdio 服务器 | 确认cwd在项目内、已重启客户端;stdout 是协议通道,勿与日志混淆 |
run_sql返回truncated: true | 结果超过请求 limit(默认 1000、上限 10000),调大limit或细化查询 |
参见
- CLI 参考 —
wren serve—— 全部 flag 与工具签名 - Manage project —— 项目布局与
target/mdl.json生命周期 - Connect your database —— 服务器查询所依赖的 profile 配置
- Cube guide ——
query_cube依赖的 cube YAML 结构与校验规则
【免费下载链接】WrenAIGenBI (Generative BI) for AI agents, an open-source, governed text-to-SQL through an open context layer that turns natural-language questions into trusted dashboards, charts, and SQL across 20+ data sources, such as BigQuery, Snowflake, PostgreSQL, ClickHouse, Amazon Redshift, Databricks and more.项目地址: https://gitcode.com/GitHub_Trending/wr/WrenAI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考