DuckDB 里的 Luajit UDF,成了 AI 能调用的工具
AI 助手连上数据库之后,能查数据了。但遇到要"算"的活,还是抓瞎。
DuckDB 的 MCP server 能把表暴露给 AI,工具却只能写 SQL 模板——查数据可以,跑逻辑不行。我做了个组合:SQL 里的 Lua UDF 直接发布成 MCP tool。AI 一句话,就能调用 DuckDB 里的 Lua 函数,包括 ffi 拉 C 库的那种。
● ● ●
先说痛点
DuckDB 的 MCP 扩展(duckdb_mcp,社区开源,MIT)把 DuckDB 变成了一个 MCP server。Claude 这类助手连上来,能 list_tables、能写 SQL 查数据。它的 Custom Tools 功能可以发布自定义工具,但只能发布 SQL 模板——SELECT ... WHERE x = $param 这种。
SQL 模板解决"查数据",解决不了"算东西"。想让 AI 解个数独、算个签名、解析个私有格式?模板写不出来。
duckdb-luajit 是另一个方向的东西:在 SQL 里注册 Lua 函数,能 ffi 加载任意 C 库。我一直用它补 DuckDB 读不了的长尾格式。但它只是"数据库里的函数",AI 助手摸不到。
两样东西拼起来,正好。
● ● ●
合体:10 行 SQL
核心思路一句话:MCP 的 tool 模板里,调 luajit 注册的 UDF。
duckdb_mcp 提供管道,luajit 提供管道里的计算引擎。init SQL 长这样:
架构:AI 助手经 MCP 调用 DuckDB 里的 Lua UDF
LOAD 'luajit';-- 注册 Lua UDF:数独求解
SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve',
source := 'local s = dofile(''sudoku.lua'') return function(x) return s.solve(x) end');LOAD duckdb_mcp;
-- 把 Lua UDF 发布成 MCP tool
PRAGMA mcp_publish_tool(
'sudoku_solve',
'Solve a 9x9 Sudoku puzzle given an 81-character string (0 = empty).',
'SELECT luajit_s(''sudoku_solve'', $puzzle) AS solution',
'{"puzzle": {"type": "string", "description": "81-char Sudoku puzzle"}}',
'["puzzle"]'
);PRAGMA mcp_server_start('stdio');
mcp_publish_tool 的参数里,第三个是 SQL 模板,我让它调 luajit_s('sudoku_solve', ...)——luajit 的注册函数。就这么简单。
● ● ●
实测:AI 调用 Lua 解数独
stdio 模式起 server,喂几条 JSON-RPC 请求验证:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05"}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"sudoku_solve","arguments":{"puzzle":"000001002000020030004500600007600050080090006100005800001004000070900003400030020"}}}' \
| duckdb -unsigned -init init-mcp-server.sql
tools/list 返回的 tools 列表里,sudoku_solve 和内置的 query、list_tables 平起平坐。
tools/call sudoku_solve 传 81 位题目字符串,返回完整解:
359461782716829534824573619947682351583197246162345897631254978275918463498736125
解是对的。我拿它和已知答案对过。
HTTP 模式也试了:mcp_server_start('http', '0.0.0.0', 18080),浏览器就能调。健康检查 curl http://localhost:18080/health 返回 {"status":"ok"},POST 到 /mcp 走同样的 JSON-RPC。生产环境加个 auth_token 就行。
● ● ●
这意味着什么
AI 助手的能力边界从"查数据"扩展到了"跑逻辑"。
以前要让 AI 用某个私有计算逻辑,得专门写个 MCP server 包一层。现在不用:Lua 里现写的函数,注册进 DuckDB,publish 一下,AI 就能调。ffi 加载的 C 库能力同理——libcrypto 算签名、libcurl 拉数据、任何有稳定 C ABI 的库,都能变成 AI 的工具。
适合的场景:
- ●私有/一次性计算逻辑暴露给 AI(不用为每个逻辑写 server)
- ●ffi C 库能力变 AI 工具(DuckDB 原生做不到的)
- ●AI 查库发现问题 → 调 Lua 工具处理 → 结果回表,一条链路走完
边界也诚实说:duckdb_mcp 管管道,luajit 管计算;生产环境记得配认证;stdio 模式适合本机,HTTP 模式适合跨机器。
代码都在 duckdb-luajit-libs 仓库的 libs/mcp/ 目录,MIT 协议。配了 mcp-server.sql、示例 sudoku.lua、验证用的 test-calls.ldjson,clone 下来 duckdb -unsigned -init 就能跑。
DuckDB 社区扩展生态:duckdb/community-extensions
duckdb_mcp:github.com/teaguesterling/duckdb_mcp
duckdb-luajit:github.com/alitrack/duckdb-luajit
libs 仓库:github.com/alitrack/duckdb-luajit-libs
试试把你自己常用的 Lua 逻辑 publish 成 MCP tool。跑通了告诉我。