跳到主要内容

BFF 保存功能

Backend Function (BFF) 保存功能是一个可选开关,允许 AI 通过 MCP 工具创建和修改 Backend Function 脚本。

注意

此功能默认未启用,需要在 MCP 配置中显式开启。启用后,AI 可以自动保存 BFF 脚本到平台,需要谨慎使用。


为什么需要独立开关?

Backend Function 是运行在服务端的代码,具有一定的敏感性和风险:

  • 提升效率:AI 可以直接创建和修改 BFF 脚本,无需手动复制粘贴
  • ⚠️ 潜在风险:错误的 BFF 脚本可能影响生产环境
  • ⚠️ 权限控制:不是所有团队成员都应有 BFF 修改权限
  • ⚠️ 审计需求:需要追踪谁(包括 AI)修改了 BFF 脚本

因此,我们将 BFF 保存功能设计为可选开关,让团队根据实际情况决定是否启用。


启用方式

方式 1:npx 启动(推荐)

在 MCP 配置中添加 --enable-bff-save 参数:

Claude Desktop / Claude Code 配置示例

{
"mcpServers": {
"lovrabet-dataset": {
"command": "npx",
"args": [
"-y",
"@lovrabet/dataset-mcp-server",
"--enable-bff-save"
],
"env": {
"LOVRABET_APP_CODE": "your-app-code"
}
}
}
}

Cursor / Windsurf 配置示例

{
"mcpServers": {
"lovrabet-dataset": {
"command": "npx",
"args": [
"-y",
"@lovrabet/dataset-mcp-server",
"--enable-bff-save"
],
"env": {
"LOVRABET_APP_CODE": "your-app-code"
}
}
}
}

方式 2:全局安装启动

如果已全局安装 @lovrabet/dataset-mcp-server

{
"mcpServers": {
"lovrabet-dataset": {
"command": "lovrabet-dataset-mcp",
"args": ["--enable-bff-save"],
"env": {
"LOVRABET_APP_CODE": "your-app-code"
}
}
}
}

方式 3:从源码启动

{
"mcpServers": {
"lovrabet-dataset": {
"command": "node",
"args": [
"/path/to/lovrabet-dataset-mcp/dist/index.js",
"--enable-bff-save"
],
"env": {
"LOVRABET_APP_CODE": "your-app-code"
}
}
}
}

废弃的参数

⚠️ --dangerously-bff-save(已废弃)

旧参数 --dangerously-bff-save 已废弃,功能与 --enable-bff-save 完全相同。

如果你的配置中使用了旧参数,建议迁移:

// ❌ 旧参数(已废弃)
"args": ["--dangerously-bff-save"]

// ✅ 新参数(推荐)
"args": ["--enable-bff-save"]

启用后的工具

启用 --enable-bff-save 后,MCP 将提供以下 3 个额外工具:

1. list_bff_scripts - 列出所有 Backend Function

获取应用下所有 BFF 脚本列表(仅 ENDPOINT 类型)。

参数

{
appCode?: string; // 应用代码(可选,使用环境变量)
cookie?: string; // 认证 Cookie(可选,使用登录后的存储)
}

返回示例

[
{
"id": 123,
"name": "getUserInfo",
"description": "获取用户详细信息",
"scriptType": "ENDPOINT",
"createTime": "2026-03-20 10:30:00",
"updateTime": "2026-03-26 14:20:00",
"createUser": "user@example.com"
}
]

使用场景

  • 浏览现有 BFF 脚本
  • 查找可复用的后端函数
  • 修改前确认脚本 ID

2. get_bff_script_info - 获取脚本详情

根据 ID 获取 BFF 脚本的完整信息,包括源代码。

参数

{
id: number; // BFF 脚本 ID(必填)
appCode?: string; // 应用代码(可选)
cookie?: string; // 认证 Cookie(可选)
}

返回示例

{
"id": 123,
"name": "getUserInfo",
"description": "获取用户详细信息",
"scriptContent": "export default async function(params, context) {\n const userId = params.userId;\n const user = await context.client.models.customer.getOne({ id: userId });\n return { success: true, data: user };\n}",
"scriptType": "ENDPOINT",
"createTime": "2026-03-20 10:30:00",
"updateTime": "2026-03-26 14:20:00",
"createUser": "user@example.com",
"updateUser": "user@example.com"
}

使用场景

  • 修改前查看现有代码
  • 学习参考其他脚本实现
  • 调试问题脚本

3. save_or_update_bff_script - 保存或更新 Backend Function

保存新的 BFF 脚本或更新现有脚本。

参数

{
id?: number; // 脚本 ID(更新时必填,新建时省略)
description: string; // 功能描述(必填)
scriptContent: string; // JavaScript/TypeScript 代码(必填)
appCode?: string; // 应用代码(可选)
cookie?: string; // 认证 Cookie(可选)
}

返回示例(成功)

{
"success": true,
"id": 124,
"message": "BFF 脚本保存成功"
}

返回示例(冲突)

{
"success": false,
"blocked": true,
"message": "最后提交者为 other@example.com,请手动操作"
}

重要机制

  1. 自动缓存清除:保存成功后自动调用 Runtime API 清除脚本缓存
  2. 强制校验:保存前强制校验数据集和字段引用
  3. 冲突检测:检测最后提交者是否为当前用户(见下文)
  4. 阻断机制:如果返回 blocked: true,AI 不得自动重试

冲突检测机制

4 级冲突检测

当保存 BFF 脚本时,MCP 会通过 toolbox API 检测冲突:

等级场景风险AI 行为
NONE新建脚本🟢 无直接保存
LOW自己的脚本🟢 低允许保存
HIGH他人最近修改(少于30天)🔴 高阻断,提示用户
MEDIUM他人较早修改(超过30天)🟡 中阻断,提示用户

冲突处理流程

保存请求

├─ 新建 → ✅ 直接保存

└─ 更新 → 检查最后提交者

├─ 自己 → ✅ 允许保存

└─ 他人 → 检查时间

├─ 少于30天 → 🔴 blocked: true

└─ 超过30天 → 🟡 blocked: true

AI 行为规范

当返回 blocked: true

  1. 应该做

    • 告知用户存在冲突
    • 提示最后提交者信息
    • 建议用户手动操作或沟通协调
    • 提供查看现有代码的方法
  2. 禁止做

    • 自动重试保存
    • 忽略冲突警告
    • 强制覆盖他人代码

示例提示

⚠️ 检测到冲突!

**冲突信息**:
- 脚本 ID: 123
- 最后提交者: colleague@company.com
- 修改时间: 2小时前

**建议操作**:
1. 与 colleague@company.com 沟通协调
2. 或在平台界面手动操作

我不会自动覆盖他人代码。

BFF 代码编写规范

基本结构

export default async function(params, context) {
// 1. 参数验证
const userId = params.userId;
if (!userId) {
return { success: false, message: "userId is required" };
}

// 2. 数据访问(使用 context.client)
const user = await context.client.models.customer.getOne({
id: userId
});

// 3. 业务逻辑
if (!user) {
return { success: false, message: "User not found" };
}

// 4. 返回结果
return {
success: true,
data: user
};
}

两种运行时上下文

1. Frontend SDK(前端)

// 返回包装器
const data = await client.sql.execute({ sqlCode: 'xxx' });
if (!data.execSuccess) {
throw new Error('SQL execution failed');
}
const results = data.execResult || [];

2. Backend Function(后端)

// 直接返回数组,无包装器
const rows = await context.client.sql.execute({ sqlCode: 'xxx' });
// rows 是 T[] 类型,错误直接抛异常

重要差异

  • SQL 执行:BFF 直接返回数组 T[],SDK 返回 { execSuccess, execResult }
  • 错误处理:BFF 错误抛异常,SDK 返回 { execSuccess: false }
  • 数据操作:两者调用方法相同,仅返回结构不同

使用示例

示例 1:创建新的 BFF 脚本

用户请求

创建一个 BFF 函数,根据用户 ID 获取用户信息和订单数量

AI 执行步骤

  1. 生成代码:
export default async function(params, context) {
const userId = params.userId;
if (!userId) {
return { success: false, message: "userId is required" };
}

// 获取用户信息
const user = await context.client.models.customer.getOne({
id: userId
});

if (!user) {
return { success: false, message: "User not found" };
}

// 统计订单数量
const orders = await context.client.models.order.filter({
where: { customer_id: { $eq: userId } },
select: ["id"]
});

return {
success: true,
data: {
user: user,
orderCount: orders.length
}
};
}
  1. 调用 save_or_update_bff_script
{
"description": "根据用户ID获取用户信息和订单数量",
"scriptContent": "export default async function(params, context) { ... }"
}
  1. 返回结果:
{
"success": true,
"id": 125,
"message": "BFF 脚本保存成功"
}

示例 2:更新现有 BFF 脚本(无冲突)

用户请求

修改 BFF 脚本 #123,添加错误处理

AI 执行步骤

  1. 调用 get_bff_script_info({ id: 123 })
  2. 修改代码(添加 try-catch)
  3. 调用 save_or_update_bff_script
{
"id": 123,
"description": "获取用户详细信息(带错误处理)",
"scriptContent": "export default async function(params, context) { try { ... } catch (error) { return { success: false, message: error.message }; } }"
}

示例 3:更新现有 BFF 脚本(有冲突)

场景:最后提交者是同事,2小时前修改过。

AI 执行步骤

  1. 调用 get_bff_script_info({ id: 123 })
  2. 修改代码
  3. 调用 save_or_update_bff_script
  4. 返回 blocked: true
{
"success": false,
"blocked": true,
"message": "最后提交者为 colleague@company.com,请手动操作"
}
  1. AI 应告知用户
⚠️ 检测到冲突!

**冲突信息**:
- 脚本 ID: 123
- 最后提交者: colleague@company.com
- 修改时间: 2小时前

**建议操作**:
1. 与 colleague@company.com 沟通协调
2. 或在平台界面手动操作

我不会自动覆盖他人代码。

最佳实践

1. 编码规范

  • ✅ 参数验证放在函数开头
  • ✅ 使用 context.client 访问数据
  • ✅ 统一返回结构 { success, data/message }
  • ✅ 添加清晰的函数描述
  • ✅ 处理所有可能的错误

2. 冲突避免

  • ✅ 修改前先调用 get_bff_script_info 查看详情
  • ✅ 大型修改提前沟通协调
  • ✅ 使用描述性的命名和注释
  • ✅ 定期清理不再使用的脚本

3. 性能优化

  • ✅ 使用 select 只查询必要字段
  • ✅ 批量操作使用 filter 而非循环
  • ✅ 避免深层嵌套查询
  • ✅ 合理使用 SQL 查询

安全建议

生产环境

  1. 限制权限:只给需要的人启用 BFF 保存功能
  2. 代码审查:AI 生成的 BFF 脚本应该有人工审查
  3. 测试环境:先在 daily 环境测试,再应用到 production
  4. 备份机制:重要脚本修改前先备份

团队协作

  1. 沟通协调:修改他人脚本前先沟通
  2. 版本控制:在脚本中添加版本和修改记录
  3. 审计日志:定期查看 BFF 脚本的修改历史
  4. 规范命名:使用清晰的命名规范

故障排除

问题 1:BFF 工具不可用

原因:未启用 --enable-bff-save 参数

解决

  1. 检查 MCP 配置文件
  2. 确认 args 中包含 --enable-bff-save
  3. 重启 MCP 服务器

问题 2:保存返回 blocked: true

原因:他人最近修改过该脚本

解决

  1. 查看返回的冲突信息
  2. 与最后提交者沟通
  3. 在平台界面手动操作

问题 3:脚本缓存未清除

原因:保存后缓存自动清除,但可能存在延迟

解决

  1. 等待 1-2 分钟
  2. 清除浏览器缓存
  3. 重试请求

相关文档


最后更新: 2026-03-26 版本: v1.0