From b25e74207ea80519c46ae928c41360f7ee1deae2 Mon Sep 17 00:00:00 2001 From: bookerzhao Date: Tue, 2 Jun 2026 19:42:37 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(hosting):=20=F0=9F=9B=A0=EF=B8=8F=20han?= =?UTF-8?q?dle=20upload=20env=20readiness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mcp/src/tools/hosting.test.ts | 22 ++++++++++++++++++++++ mcp/src/tools/hosting.ts | 20 ++++++++++++++++++++ mcp/webpack/base.config.cjs | 5 +---- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/mcp/src/tools/hosting.test.ts b/mcp/src/tools/hosting.test.ts index c5fecf32..83292624 100644 --- a/mcp/src/tools/hosting.test.ts +++ b/mcp/src/tools/hosting.test.ts @@ -309,6 +309,28 @@ describe('hosting tools', () => { expect(mockSendDeployNotification).toHaveBeenCalled(); }); + it('manageHosting(action=upload) should fail fast when current env lacks static hosting storage config', async () => { + mockGetEnvInfo.mockResolvedValueOnce({ + EnvInfo: { + StaticStorages: null, + }, + }); + + const tools = createMockServer(); + const payload = JSON.parse((await tools.manageHosting.handler({ + action: 'upload', + localPath: '/tmp/site-dist', + cloudPath: '/todo', + ignore: ['node_modules', '.DS_Store', '*.map'], + })).content[0].text); + + expect(payload.success).toBe(false); + expect(payload.errorCode).toBe('HOSTING_UPLOAD_FAILED'); + expect(payload.message).toContain('当前环境 env-test 未发现静态托管资源配置'); + expect(payload.message).toContain('auth(action="set_env"'); + expect(mockUploadFiles).not.toHaveBeenCalled(); + }); + it('manageHosting(action=delete) should require explicit confirm=true', async () => { const tools = createMockServer(); const payload = JSON.parse((await tools.manageHosting.handler({ diff --git a/mcp/src/tools/hosting.ts b/mcp/src/tools/hosting.ts index 2f6b9ab8..f0c19117 100644 --- a/mcp/src/tools/hosting.ts +++ b/mcp/src/tools/hosting.ts @@ -424,6 +424,25 @@ async function resolveHostingStaticDomain(cloudbase: any, logger?: ExtendedMcpSe } } +async function assertHostingUploadEnvironmentReady( + cloudbase: any, + cloudBaseOptions?: { envId?: string }, + logger?: ExtendedMcpServer['logger'], +) { + const envId = await getEnvId(cloudBaseOptions); + const envInfo = await cloudbase.env.getEnvInfo() as ExtendedEnvInfo; + logCloudBaseResult(logger, envInfo); + + const staticStorage = envInfo.EnvInfo?.StaticStorages?.[0]; + if (staticStorage?.Bucket) { + return; + } + + throw new Error( + `当前环境 ${envId} 未发现静态托管资源配置,无法上传文件。请先确认 MCP 已绑定到已开通静态托管的 CloudBase 环境;如需切换环境,请调用 auth(action="set_env", envId="目标环境ID") 后重试。`, + ); +} + function buildFailureResult(action: string, error: unknown) { return buildJsonToolResult({ success: false, @@ -657,6 +676,7 @@ export function registerHostingTools(server: ExtendedMcpServer) { let result: unknown; try { + await assertHostingUploadEnvironmentReady(cloudbase, cloudBaseOptions, server.logger); result = await cloudbase.hosting.uploadFiles({ localPath: input.localPath, cloudPath: input.cloudPath, diff --git a/mcp/webpack/base.config.cjs b/mcp/webpack/base.config.cjs index 540faaf1..c0496ba5 100644 --- a/mcp/webpack/base.config.cjs +++ b/mcp/webpack/base.config.cjs @@ -20,9 +20,6 @@ function createBaseConfig() { // 处理 TypeScript ESM 导入中的 .js 扩展名 '.js': ['.ts', '.js'], }, - alias: { - 'graceful-fs': path.resolve(__dirname, '../node_modules/graceful-fs') - }, fallback: { // 在 Node.js 环境中我们不需要这些 polyfills "buffer": false, @@ -74,4 +71,4 @@ function createBaseConfig() { }; } -module.exports = createBaseConfig; \ No newline at end of file +module.exports = createBaseConfig; From 2015daf89decafdd369029876c3e867a7f2c0361 Mon Sep 17 00:00:00 2001 From: bookerzhao Date: Tue, 2 Jun 2026 19:43:50 +0800 Subject: [PATCH 2/3] =?UTF-8?q?chore(tools):=20=F0=9F=94=A7=20refresh=20ge?= =?UTF-8?q?nerated=20metadata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/mcp-tools.md | 14 ++++++++++---- scripts/tools.json | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/mcp-tools.md b/doc/mcp-tools.md index 133c116b..7dc0a670 100644 --- a/doc/mcp-tools.md +++ b/doc/mcp-tools.md @@ -2174,10 +2174,10 @@ CloudApp 域统一写入口。action=deployApp 会先 uploadCode 再 createApp --- ### `queryPermissions` -权限域统一只读入口。支持查询资源权限、角色列表/详情、应用用户列表/详情。 +查询 CloudBase 权限与用户配置,支持查询资源权限(数据库/云函数/存储桶等)、角色列表/详情、应用用户列表/详情。 -资源权限示例: -- 查询存储桶 ACL:`action="getResourcePermission", resourceType="storage", resourceId="bucket-name"`(返回 permission 字段:READONLY/PRIVATE/ADMINWRITE/ADMINONLY/CUSTOM) +示例: +- 查询存储桶权限:`action="getResourcePermission", resourceType="storage", resourceId="bucket-name"` #### 参数 @@ -2236,7 +2236,13 @@ CloudApp 域统一写入口。action=deployApp 会先 uploadCode 再 createApp --- ### `managePermissions` -权限域统一写入口。支持修改资源权限、角色管理、成员与策略增删、应用用户 CRUD。`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp(\{ username, password \})`,登录应使用 `auth.signInWithPassword(\{ username, password \})`。注意:`securityRule` 的详细语义取决于 `resourceType`;`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType="noSqlDatabase"` 的文档数据库安全规则。配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。 +管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。 + +示例: +- 设置存储桶为私有:`action="setResourcePermission", resourceType="storage", resourceId="bucket-name", permission="PRIVATE"` +- 创建角色:`action="createRole", roleName="admin", roleIdentity="admin"` + +注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp(\{ username, password \})`,登录应使用 `auth.signInWithPassword(\{ username, password \})`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。 #### 参数 diff --git a/scripts/tools.json b/scripts/tools.json index b1e81aef..a6d81362 100644 --- a/scripts/tools.json +++ b/scripts/tools.json @@ -2348,7 +2348,7 @@ }, { "name": "queryPermissions", - "description": "权限域统一只读入口。支持查询资源权限、角色列表/详情、应用用户列表/详情。\n\n资源权限示例:\n- 查询存储桶 ACL:`action=\"getResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\"`(返回 permission 字段:READONLY/PRIVATE/ADMINWRITE/ADMINONLY/CUSTOM)", + "description": "查询 CloudBase 权限与用户配置,支持查询资源权限(数据库/云函数/存储桶等)、角色列表/详情、应用用户列表/详情。\n\n示例:\n- 查询存储桶权限:`action=\"getResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\"`", "inputSchema": { "type": "object", "properties": { @@ -2412,7 +2412,7 @@ }, { "name": "managePermissions", - "description": "权限域统一写入口。支持修改资源权限、角色管理、成员与策略增删、应用用户 CRUD。`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。注意:`securityRule` 的详细语义取决于 `resourceType`;`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则。配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。", + "description": "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"setResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。", "inputSchema": { "type": "object", "properties": { From 111741b690f4083d4e134675ada232dca85822e9 Mon Sep 17 00:00:00 2001 From: bookerzhao Date: Tue, 2 Jun 2026 19:59:49 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix(permissions):=20=F0=9F=9B=A0=EF=B8=8F?= =?UTF-8?q?=20correct=20resource=20permission=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/mcp-tools.md | 2 +- mcp/src/tools/permissions.ts | 2 +- scripts/tools.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/mcp-tools.md b/doc/mcp-tools.md index 7dc0a670..c25d05c7 100644 --- a/doc/mcp-tools.md +++ b/doc/mcp-tools.md @@ -2239,7 +2239,7 @@ CloudApp 域统一写入口。action=deployApp 会先 uploadCode 再 createApp 管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。 示例: -- 设置存储桶为私有:`action="setResourcePermission", resourceType="storage", resourceId="bucket-name", permission="PRIVATE"` +- 设置存储桶为私有:`action="updateResourcePermission", resourceType="storage", resourceId="bucket-name", permission="PRIVATE"` - 创建角色:`action="createRole", roleName="admin", roleIdentity="admin"` 注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp(\{ username, password \})`,登录应使用 `auth.signInWithPassword(\{ username, password \})`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。 diff --git a/mcp/src/tools/permissions.ts b/mcp/src/tools/permissions.ts index 2022b832..58cdfaa6 100644 --- a/mcp/src/tools/permissions.ts +++ b/mcp/src/tools/permissions.ts @@ -562,7 +562,7 @@ export function registerPermissionTools(server: ExtendedMcpServer) { { title: "管理 CloudBase 权限与用户配置", description: - "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"setResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。", + "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。", inputSchema: { action: z.enum(MANAGE_PERMISSION_ACTIONS), resourceType: z diff --git a/scripts/tools.json b/scripts/tools.json index a6d81362..d3b12704 100644 --- a/scripts/tools.json +++ b/scripts/tools.json @@ -2412,7 +2412,7 @@ }, { "name": "managePermissions", - "description": "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"setResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。", + "description": "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单。前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。`securityRule` 的详细语义取决于 `resourceType`,请参考对应官方文档。", "inputSchema": { "type": "object", "properties": {