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,请手动操作"
}
重要机制:
- 自动缓存清除:保存成功后自动调用 Runtime API 清除脚本缓存
- 强制校验:保存前强制校验数据集和字段引用
- 冲突检测:检测最后提交者是否为当前用户(见下文)
- 阻断机制:如果返回
blocked: true,AI 不得自动重试
冲突检测机制
4 级冲突检测
当保存 BFF 脚本时,MCP 会通过 toolbox API 检测冲突:
| 等级 | 场景 | 风险 | AI 行为 |
|---|---|---|---|
| NONE | 新建脚本 | 🟢 无 | 直接保存 |
| LOW | 自己的脚本 | 🟢 低 | 允许保存 |
| HIGH | 他人最近修改(少于30天) | 🔴 高 | 阻断,提示用户 |
| MEDIUM | 他人较早修改(超过30天) | 🟡 中 | 阻断,提示用户 |
冲突处理流程
保存请求
│
├─ 新建 → ✅ 直接保存
│
└─ 更新 → 检查最后提交者
│
├─ 自己 → ✅ 允许保存
│
└─ 他人 → 检查时间
│
├─ 少于30天 → 🔴 blocked: true
│
└─ 超过30天 → 🟡 blocked: true
AI 行为规范
当返回 blocked: true 时:
-
✅ 应该做:
- 告知用户存在冲突
- 提示最后提交者信息
- 建议用户手动操作或沟通协调
- 提供查看现有代码的方法
-
❌ 禁止做:
- 自动重试保存
- 忽略冲突警告
- 强制覆盖他人代码
示例提示:
⚠️ 检测到冲突!
**冲突信息**:
- 脚本 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 执行步骤:
- 生成代码:
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
}
};
}
- 调用
save_or_update_bff_script:
{
"description": "根据用户ID获取用户信息和订单数量",
"scriptContent": "export default async function(params, context) { ... }"
}
- 返回结果:
{
"success": true,
"id": 125,
"message": "BFF 脚本保存成功"
}
示例 2:更新现有 BFF 脚本(无冲突)
用户请求:
修改 BFF 脚本 #123,添加错误处理
AI 执行步骤:
- 调用
get_bff_script_info({ id: 123 }) - 修改代码(添加 try-catch)
- 调用
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 执行步骤:
- 调用
get_bff_script_info({ id: 123 }) - 修改代码
- 调用
save_or_update_bff_script - 返回
blocked: true:
{
"success": false,
"blocked": true,
"message": "最后提交者为 colleague@company.com,请手动操作"
}
- 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 查询
安全建议
生产环境
- 限制权限:只给需要的人启用 BFF 保存功能
- 代码审查:AI 生成的 BFF 脚本应该有人工审查
- 测试环境:先在 daily 环境测试,再应用到 production
- 备份机制:重要脚本修改前先备份
团队协作
- 沟通协调:修改他人脚本前先沟通
- 版本控制:在脚本中添加版本和修改记录
- 审计日志:定期查看 BFF 脚本的修改历史
- 规范命名:使用清晰的命名规范
故障排除
问题 1:BFF 工具不可用
原因:未启用 --enable-bff-save 参数
解决:
- 检查 MCP 配置文件
- 确认
args中包含--enable-bff-save - 重启 MCP 服务器
问题 2:保存返回 blocked: true
原因:他人最近修改过该脚本
解决:
- 查看返回的冲突信息
- 与最后提交者沟通
- 在平台界面手动操作
问题 3:脚本缓存未清除
原因:保存后缓存自动清除,但可能存在延迟
解决:
- 等待 1-2 分钟
- 清除浏览器缓存
- 重试请求
相关文档
最后更新: 2026-03-26 版本: v1.0