内容
# FireDAC MCP 服务器
将 **任何 FireDAC 可以连接的数据库** 转换为 MCP 服务器,AI 助手可以查询和(可选)修改 — 由单个 **连接字符串** 和选择的 **访问模式** 驱动。
您为服务器提供一个 FireDAC 连接字符串和一个模式(`readonly` / `readwrite` / `full`)。它打开连接,在整个生命周期中拥有它,并协调来自 AI 客户端的每个调用 — 在进入时强制执行访问模式和 SQL 安全分类器,在退出时将结果集编组为 JSON。
由于它完全由连接字符串和 FireDAC 的 **引擎无关** 元数据 API 驱动,**同一个二进制文件** 适用于:
| 引擎 | 示例 `DriverID` |
|---|---|
| SQLite | `SQLite` |
| PostgreSQL | `PG` |
| MySQL / MariaDB | `MySQL` |
| SQL Server | `MSSQL` |
| Oracle | `Ora` |
| Firebird / InterBase | `FB` / `IB` |
| 任何带有 ODBC 驱动程序的数据库 | `ODBC` |
物理驱动程序链接单元由 `FireDACMCPServer.dpr` 链接;添加或删除它们以控制构建支持哪些引擎。
## 文件
| 文件 | 用途 |
|---|---|
| `FireDACMCPServer.dpr` | 入口点:命令行解析、驱动程序链接、服务器连接。 |
| `DBConnectionManager.pas` | 引擎无关的核心:连接处理、SQL 分类器、访问模式强制执行、参数绑定、结果编组、工具注册。 |
| `FireDACMCPServer.dproj` | Delphi 项目(Win32 控制台)。 |
## 构建
在 IDE 中打开 `FireDACMCPServer.dproj` 并构建(Shift+F9),**或** 从命令行:
```
"C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\rsvars.bat"
msbuild FireDACMCPServer.dproj /t:Build /p:Config=Debug /p:Platform=Win32
```
可执行文件位于 `Win32\Debug\FireDACMCPServer.exe`。
## 用法
```
FireDACMCPServer [选项]
```
| 选项 | 描述 |
|---|---|
| `-conn="<连接字符串>"` | FireDAC 连接字符串。除非使用 `-conn-env`,否则必填。 |
| `-conn-env=<环境变量>` | 从环境变量中读取连接字符串,而不是在命令行上(将密码排除在命令行和客户端配置文件之外)。 |
| `-mode=<readonly|readwrite|full>` | 访问级别。默认:**readonly**。 |
| `-maxrows=<n>` | `run_query` 返回的行数的硬上限(默认 1000)。 |
| `-timeout=<毫秒>` | 每个命令的执行超时时间,单位为毫秒。 |
| `-allow-multi` | 允许在单个调用中包含多个 `;` 分隔的语句(默认关闭)。 |
| `-help` | 显示帮助并退出。 |
### 访问模式
| 模式 | AI 可以执行的操作 | 暴露的工具 |
|---|---|---|
| `readonly` *(默认)* | 仅限 `SELECT` 和元数据。**不注册任何变异工具** — AI 无法更改任何内容。 | `db_info`、`list_tables`、`describe_table`、`run_query` |
| `readwrite` | 上述 **+** `INSERT` / `UPDATE` / `DELETE` / `MERGE`(DML)。 | 上述 **+** `run_statement` |
| `full` | 上述 **+** DDL(`CREATE` / `ALTER` / `DROP` / `TRUNCATE`)和其他受阻语句(`PRAGMA`、`ATTACH` 等)。 | 上述(`run_statement` 也接受 DDL) |
## 示例
**SQLite,只读(安全默认值):**
```
FireDACMCPServer -conn="DriverID=SQLite;Database=C:\data\app.db"
```
**PostgreSQL,读写,密码来自环境变量:**
```
set PG_CONN=DriverID=PG;Server=localhost;Database=sales;User_Name=app;Password=secret
FireDACMCPServer -conn-env=PG_CONN -mode=readwrite
```
**SQL Server,只读,Windows 身份验证:**
```
FireDACMCPServer -conn="DriverID=MSSQL;Server=localhost;Database=Northwind;OSAuthent=Yes;ODBCAdvanced=TrustServerCertificate=yes"
```
> **SQL Server + ODBC 驱动程序 18 注意:** 驱动程序 18 默认加密并验证服务器证书,因此针对具有自签名证书的本地实例,您将看到 *"SSL 提供程序:证书链由不受信任的颁发机构颁发。"* 通过 `ODBCAdvanced=TrustServerCertificate=yes` (保留加密)或使用 `Encrypt=No` 禁用加密传递证书。FireDAC 自己的 `TrustServerCertificate` 参数 **不** 会转发到 ODBC 驱动程序 — 使用 `ODBCAdvanced`。
## 注册到 MCP 客户端(stdio)
在客户端配置文件(`claude_desktop_config.json`、`.mcp.json` 等)中添加一个条目:
```json
{
"mcpServers": {
"database": {
"command": "C:\\path\\to\\FireDACMCPServer.exe",
"args": [
"-conn-env=APP_DB_CONN",
"-mode=readonly"
],
"env": {
"APP_DB_CONN": "DriverID=SQLite;Database=C:\\data\\app.db"
}
}
}
}
```
您也可以将 [MCP Inspector](https://github.com/modelcontextprotocol/inspector) 指向可执行文件:
```
npx @modelcontextprotocol/inspector FireDACMCPServer.exe -conn="DriverID=SQLite;Database=demo.db" -mode=full
```
## 工具
### `db_info` *(只读,幂等)*
返回驱动程序 ID、访问模式、行限制和 **密码已编辑** 的连接字符串。
### `list_tables` *(只读)*
列出任何引擎上的表和视图(通过 FireDAC 元数据,而不是引擎特定的 SQL)。可选的 `schema` 参数按模式过滤。
### `describe_table` *(只读)*
返回每个列的 `name`、`type`、`size`、`nullable` 和 `readOnly` 标志。
- `table` *(必填)* — 表名,可选模式限定。
### `run_query` *(只读)*
执行只读语句(`SELECT` / `WITH` / `EXPLAIN` / `SHOW`)。
- `sql` *(必填)* — 为值使用 `:name` 占位符。
- `params` *(可选)* — 绑定这些占位符的 JSON 对象,例如 `{"id": 42}`。
- `max_rows` *(可选)* — 由服务器的 `-maxrows` 限制。
返回:
```json
{
"columns": [ { "name": "id", "type": "ftInteger" }, ... ],
"rows": [ { "id": 1, "name": "Alice", "age": 30 }, ... ],
"rowCount": 1,
"truncated": false
}
```
### `run_statement` *(仅在读写/全模式下注册;破坏性)*
执行数据或模式更改语句。
- `sql` *(必填)* — `INSERT` / `UPDATE` / `DELETE` / `MERGE` (读写)或 DDL(全)。使用 `:name` 占位符。
- `params` *(可选)* — 绑定这些占位符的 JSON 对象。
返回 `{ "success": true, "category": "dml" | "ddl", "rowsAffected": N }`.
### `connect` *(仅在延迟模式下 — 见下文)*
在启动时未配置数据库连接时打开数据库连接。
- `connection_string` *(可选)* — 完整的 FireDAC 连接字符串。如果给定,则忽略以下离散参数。
- `driver_id`、`server`、`database`、`user`、`password` *(可选)* — 用于在省略 `connection_string` 时组装连接字符串。空 `user` 表示 OS/Windows 身份验证。对于 `MSSQL`,会自动添加 `ODBCAdvanced=TrustServerCertificate=yes`。
- `options` *(可选)* — 要追加的额外 `Key=Value;...` 对。
- `mode` *(可选)* — `readonly` | `readwrite` | `full` (默认 `readonly`)。
返回 `{ "connected": true, "driverId": "...", "accessMode": "..." }`.
## 延迟连接(在运行时请求连接)
如果您在 **没有** `-conn`/`-conn-env` 的情况下启动服务器,它不会失败 — 它以 **延迟模式** 启动:
- 它公开 `connect` 工具和正常的数据库工具。
- 在 `connect` 成功之前,每个数据库工具都返回一个明确的 *"尚未建立数据库连接。请先调用 connect 工具。"* 消息。
- AI(由用户提示)调用 `connect` 并带有连接字符串 — 或单个驱动程序/服务器/数据库/用户/密码参数和模式 — 然后数据库工具开始对该连接进行操作。
这允许单个注册服务器在运行时请求其目标数据库,而不是将其写入客户端配置中。示例客户端条目:
```json
{
"mcpServers": {
"database-on-demand": {
"command": "C:\\path\\to\\FireDACMCPServer.exe",
"args": ["-maxrows=500"]
}
}
}
```
然后,在客户端: *"连接到 localhost 上的 MCPSandbox 数据库,读写模式"* → AI 调用 `connect` 并开始工作。
> **为什么使用 `connect` 工具而不是服务器发起的诱导?** MCP 规范有一个 `elicitation/create` 请求,服务器可以使用它来弹出客户端上的表单。 这需要 **双向** 传输;Claude Desktop 使用的 stdio 传输严格为 request→response,无法传递服务器发起的请求(或 `tools/list_changed` 通知)。因此,`connect` 工具是请求运行时连接的稳健且普遍支持的方式。 在双向传输上,您可以使用 `TTMSMCPServer.RequestElicitation` 代替驱动相同的流程。
## 健壮性和安全性
该演示旨在成为一个 *安全* 的桥梁,而不仅仅是一个可用的桥梁:
- **按构造能力 gating。** 在只读模式下,永远不会注册变异工具,因此模型甚至无法尝试写入。
- **SQL 分类器。** 每个语句在注释和字符串字面值被剥离后进行分类,因此关键字/分号扫描不能被引号或注释中的文本所欺骗。`run_query` 只接受读取;`run_statement` 强制执行当前模式允许的操作。
- **不允许语句堆叠。** 除非设置了 `-allow-multi`,否则拒绝 `SELECT 1; DROP TABLE users` — 这阻止了经典的 piggy-backed 注入。
- **阻止转义语句。** 在完整模式以外,拒绝 `ATTACH` / `DETACH` / `PRAGMA`-writes / `VACUUM` / `GRANT` / `EXEC` …
- **参数化值。** 调用者通过 `params` 绑定字面值;值永远不会被字符串连接成 SQL。
- **有界输出。** 结果集上限(`max_rows`)并报告 `truncated`;大型 BLOB 被 base64 编码直到上限,然后被总结。
- **秘密卫生。** 连接字符串仅在密码被编辑后才会被显示,并且 `-conn-env` 将其排除在进程参数之外。
- **弹性连接。** `AutoReconnect` 从断开的连接中恢复;在只读模式下,数据集也被以只读方式打开作为深度防御。
### 生产使用建议
- 优先使用 **专用数据库用户**,其授予的权限与选择的模式相匹配(只读 DB 登录名在只读模式后是安全保护措施)。
- 通过 `-conn-env` 传递连接字符串,而不是在命令行上。
- 保持 `readonly` 作为默认值,只有在必要时才提高模式。
## 扩展
- **更多引擎:** 将匹配的 `FireDAC.Phys.*` 单元对添加到 `FireDACMCPServer.dpr` 中的 `uses` 子句中。
- **更多工具:** 向 `TDBConnectionManager` 添加一个方法,并在 `RegisterTools` 中注册它。遵循现有的模式 — 通过 `GuardStatement` 分类任何 SQL,并使用 `DatasetToJSON` 编组结果。
- **事务 / 存储过程 / 模式资源** 是在这个基础上自然而然的下一步。
本演示是 TMS MCP SDK 的一部分,受到 TMS 软件许可协议的约束。