MCP Toolbox 中 clickhouse-sql 工具:以预编译语句连接 LLM 与 ClickHouse
【免费下载链接】mcp-toolboxMCP Toolbox for Databases is an open source MCP server for databases.项目地址: https://gitcode.com/GitHub_Trending/ge/mcp-toolbox
本文基于 MCP Toolbox 官方文档 clickhouse-sql 工具说明,系统讲解clickhouse-sql工具的完整配置语法:普通参数(预编译语句占位符)、模板参数(SQL 文本定制)与向量化参数(embeddedBy)三类能力的用法与限制。读完本文,你可以直接编写可运行的 ClickHouse 工具配置,并理解 Toolbox 在底层如何把参数解析、模板替换、向量格式化串成一次database/sql查询。
工具定位:它与其他 ClickHouse 工具的区别
MCP Toolbox 对 ClickHouse 提供四类工具,定义在 internal/tools/clickhouse 下:
| 工具类型 | 用途 | 是否支持参数 |
|---|---|---|
clickhouse-execute-sql | 执行一条完整 SQL | 不支持 |
clickhouse-list-databases | 列出所有数据库 | 不支持 |
clickhouse-list-tables | 列出指定库中的表 | 不支持 |
clickhouse-sql | 执行带参数的 SQL 模板 | 支持普通参数与模板参数 |
clickhouse-sql的独特之处在于它同时支持两类参数:
- 普通参数(
parameters):作为预编译语句的值(prepared statement values)绑定到 SQL 中的占位符; - 模板参数(
templateParameters):在 SQL 执行前替换语句文本中的{{占位符}},用于定制列名、表名等无法参数化的部分。
这与clickhouse-execute-sql形成互补:后者的 SQL 是写死的,而clickhouse-sql让 LLM 只需提供少量受控参数,既能灵活查询,又避免了让模型直接拼接整条 SQL 带来的注入风险。
前置条件:配置一个 ClickHouse Source
clickhouse-sql的source字段必须指向一个type: clickhouse的数据源。Source 配置字段与取值范围以 ClickHouse Source 文档 和 source 源码 为准:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | string | 是 | 必须为clickhouse |
| host | string | 是 | IP 或主机名,如127.0.0.1或clickhouse.example.com |
| port | string | 是 | 端口,HTTPS 默认8443,HTTP 默认8123 |
| database | string | 是 | 要连接的数据库名 |
| user | string | 是 | ClickHouse 用户名 |
| password | string | 否 | 用户密码 |
| protocol | string | 否 | https(默认)或http,见 协议校验逻辑 |
| secure | boolean | 否 | 是否使用 TLS,默认false |
一个典型的 source 配置如下(推荐用${ENV_NAME}环境变量引用注入密钥):
kind: source name: my-clickhouse-instance type: clickhouse host: clickhouse.example.com port: "8443" database: analytics user: ${CLICKHOUSE_USER} password: ${CLICKHOUSE_PASSWORD} protocol: https secure: true从源码结构看,连接池在 initClickHouseConnectionPool 中创建:若protocol未填写则回退为https;DSN 采用scheme://user:pass@host:port/db形式,HTTPS 时附加?secure=true&skip_verify=false;连接池固定为最多 25 个打开连接、5 个空闲连接、连接最长生命周期 5 分钟。
基础配置:statement 与普通参数
工具的最小可用配置由四个必填字段组成:type: clickhouse-sql、source、description、statement。一个查询用户行为分析的工具示例:
kind: tool name: my_analytics_query type: clickhouse-sql source: my-clickhouse-instance description: Get user analytics for a specific date range statement: | SELECT user_id, count(*) as event_count, max(timestamp) as last_event FROM events WHERE date >= ? AND date <= ? GROUP BY user_id ORDER BY event_count DESC LIMIT ? parameters: - name: start_date description: Start date for the query (YYYY-MM-DD format) - name: end_date description: End date for the query (YYYY-MM-DD format) - name: limit description: Maximum number of results to return关键约定:
- SQL 中的
?占位符按出现顺序与parameters列表中的参数一一对应。上方语句中date >= ?对应start_date,date <= ?对应end_date,LIMIT ?对应limit; description是必填项,会被传给 LLM 作为工具的语义描述——从 Initialize 实现 可见,缺失description会直接初始化失败;- 参数可以额外声明
type: string等类型与required约束,完整参数语法与本文一致,本文示例遵循官方文档写法。
模板参数:让 LLM 定制 SQL 文本
对于列名、表名这类无法用预编译占位符表达的部分,templateParameters允许 LLM 提供文本,在执行前替换进 statement:
kind: tool name: flexible_table_query type: clickhouse-sql source: my-clickhouse-instance description: Query any table with flexible columns statement: | SELECT {{columns}} FROM {{table_name}} WHERE created_date >= ? LIMIT ? templateParameters: - name: columns description: Comma-separated list of columns to select - name: table_name description: Name of the table to query parameters: - name: start_date description: Start date filter - name: limit description: Maximum number of results从 Invoke 执行链 可以确认处理顺序:
parameters.ResolveTemplateParams先用模板参数渲染{{columns}}、{{table_name}},得到最终 SQL 文本;parameters.GetParams再把普通参数抽取为有序值列表;- 调用 source 的
RunSQL(ctx, newStatement, newParams)执行。
也就是说,模板参数先于预编译绑定发生:{{ }}只出现在 SQL 文本层,?只出现在绑定值层,两者互不干扰。需要留意的是,模板参数直接拼接进 SQL 文本,其安全性取决于你在description中对取值形态的约束(例如"逗号分隔的列名"),配置时应尽量收窄 LLM 可填入的内容。
向量化查询:embeddedBy 与 Array(Float32)
clickhouse-sql还有一个文档明确的能力:透明地把字符串参数嵌入为向量。Toolbox 会通过原生 embedding model 配置 把声明了embeddedBy的参数文本编码成向量,并以原生Array(Float32)类型绑定到?占位符——这样你就可以直接写 ClickHouse 的向量函数(如cosineDistance、L2Distance),无需任何字符串解析。
源码依据有两处:
- EmbedParams 方法 在调用前对参数执行嵌入,并使用
embeddingmodels.FormatVectorForClickHouse做向量格式化; - 单元测试 覆盖了带
embeddedBy+valueFromParam的参数解析场景,确认配置能正确落进Parameters。
完整工作流:建表、嵌入、检索
第 1 步:准备目标表。假设向量表结构如下:
CREATE TABLE documents ( id UUID DEFAULT generateUUIDv4(), content String, embedding Array(Float32) ) ENGINE = MergeTree ORDER BY tuple();第 2 步:在配置中定义 embedding model。
kind: embeddingModel name: gemini-model type: gemini apiKey: ${GOOGLE_API_KEY} model: gemini-embedding-001 dimension: 768embedding model 的实现位于 internal/embeddingmodels,type: gemini的解析见 gemini.go。
第 3 步:定义写入工具。技巧是把content镜像到一个第二参数text_to_embed上,并用valueFromParam: content声明取值来源,再在该参数上挂embeddedBy提示——LLM 只需要提供content,向量由这个参数承载:
kind: tool name: insert_doc type: clickhouse-sql source: my-clickhouse-instance description: Indexes a new document and its vector embedding. statement: | INSERT INTO documents (content, embedding) VALUES (?, ?) parameters: - name: content type: string description: The text content to store. - name: text_to_embed type: string description: The text content used to generate the vector. valueFromParam: content embeddedBy: gemini-model第 4 步:定义检索工具。查询文本由 LLM 直接给出,嵌入后按余弦距离排序:
kind: tool name: search_docs type: clickhouse-sql source: my-clickhouse-instance description: Finds the most semantically similar document to a query. statement: | SELECT content, cosineDistance(embedding, ?) AS distance FROM documents ORDER BY distance ASC LIMIT 1 parameters: - name: query type: string description: The search query. embeddedBy: gemini-model文档中同时给出了两条硬性限制:
- 只有
string类型的参数才能声明embeddedBy; - embedding model 必须定义在与工具相同的配置文件里(
kind: embeddingModel)。
字段参考(Reference)
以下为官方文档中的完整字段表,编写配置时可对照检查:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | string | 是 | 必须为clickhouse-sql |
| source | string | 是 | 要执行 SQL 的 ClickHouse source 名称 |
| description | string | 是 | 传给 LLM 的工具描述 |
| statement | string | 是 | 要执行的 SQL 语句模板 |
| parameters | array of Parameter | 否 | 预编译语句的值参数 |
| templateParameters | array of Parameter | 否 | SQL 文本定制参数 |
执行链路速览:从配置到 SQL 执行
把全文串起来,一次clickhouse-sql调用的完整链路是:
- 配置解析:
init阶段把clickhouse-sql注册进 tools 注册表,YAML 解码进Config结构体(Config 定义,注意parameters与templateParameters是并列字段); - 初始化:
Initialize校验description、合并两类参数生成参数 manifest;未配置annotations时默认使用 destructive 标注(GetAnnotationsOrDefault 调用); - 调用:
Invoke依次完成模板渲染、参数抽取,最后调用 Source.RunSQL。
RunSQL的实现细节值得注意:它基于 Go 的database/sql与clickhouse-go驱动执行QueryContext,把每一行结果扫描为map[string]any返回(列名为 key),并对String/FixedString列做[]byte到string的转换(结果映射逻辑)。因此工具返回给 LLM 的是一组"列名 → 值"的行对象,天然适合 JSON 序列化展示。
实战建议
- 占位符顺序即参数顺序:
?按出现顺序绑定parameters,调整语句时务必同步调整参数列表顺序; - 用 description 收窄 LLM 输入:例如日期参数注明
YYYY-MM-DD format,模板参数注明取值形态,这是引导 LLM 正确调用的关键; - 写操作要有预期:source 的
IsReadOnly返回false(源码),INSERT/UPDATE/DELETE均可通过该工具执行,工具默认带 destructive 标注,配置annotations可按需调整; - 向量场景遵守两条限制:
embeddedBy仅限string参数,且 embedding model 与工具必须在同一配置文件内定义。
相关文档与代码入口:ClickHouse 集成首页、ClickHouse Source 配置、工具实现、数据源实现、单元测试。
【免费下载链接】mcp-toolboxMCP Toolbox for Databases is an open source MCP server for databases.项目地址: https://gitcode.com/GitHub_Trending/ge/mcp-toolbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考