Skip to content

Commit 90c4edd

Browse files
authored
Merge pull request #553 from TencentCloudBase/automation/attribution-issue-mns2u4ei-343hkw-mcp
fix: MCP 域名管理工具缺少轮询指引和异步状态反馈
2 parents 9e5835c + c4fafb1 commit 90c4edd

3 files changed

Lines changed: 461 additions & 63 deletions

File tree

mcp/src/tools/env.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,4 +1180,89 @@ describe("env tools - envQuery", () => {
11801180
Bucket: null,
11811181
});
11821182
});
1183+
1184+
it("envDomainManagement(create) should return structured polling guidance", async () => {
1185+
const createEnvDomain = vi.fn().mockResolvedValue({
1186+
RequestId: "req-create-domain",
1187+
});
1188+
mockGetCloudBaseManager.mockResolvedValue({
1189+
env: {
1190+
createEnvDomain,
1191+
},
1192+
});
1193+
1194+
const { tools } = createMockServer();
1195+
const payload = JSON.parse(
1196+
(
1197+
await tools.envDomainManagement.handler({
1198+
action: "create",
1199+
domains: ["integration.example.com"],
1200+
})
1201+
).content[0].text,
1202+
);
1203+
1204+
expect(createEnvDomain).toHaveBeenCalledWith(["integration.example.com"]);
1205+
expect(payload).toMatchObject({
1206+
ok: true,
1207+
code: "DOMAIN_UPDATE_PENDING",
1208+
operation: "create",
1209+
targetDomains: ["integration.example.com"],
1210+
asyncState: "PENDING",
1211+
propagation: {
1212+
requiresPolling: true,
1213+
pollTool: "envQuery",
1214+
pollAction: "domains",
1215+
pollIntervalSuggestionSeconds: 10,
1216+
timeoutSuggestionSeconds: 600,
1217+
},
1218+
next_step: {
1219+
tool: "envQuery",
1220+
action: "domains",
1221+
suggested_args: {
1222+
action: "domains",
1223+
},
1224+
},
1225+
});
1226+
expect(payload.message).toContain("继续轮询 envQuery(action=\"domains\")");
1227+
});
1228+
1229+
it("envDomainManagement(delete) should return structured polling guidance", async () => {
1230+
const deleteEnvDomain = vi.fn().mockResolvedValue({
1231+
RequestId: "req-delete-domain",
1232+
});
1233+
mockGetCloudBaseManager.mockResolvedValue({
1234+
env: {
1235+
deleteEnvDomain,
1236+
},
1237+
});
1238+
1239+
const { tools } = createMockServer();
1240+
const payload = JSON.parse(
1241+
(
1242+
await tools.envDomainManagement.handler({
1243+
action: "delete",
1244+
domains: ["integration.example.com"],
1245+
})
1246+
).content[0].text,
1247+
);
1248+
1249+
expect(deleteEnvDomain).toHaveBeenCalledWith(["integration.example.com"]);
1250+
expect(payload).toMatchObject({
1251+
ok: true,
1252+
code: "DOMAIN_DELETE_PENDING",
1253+
operation: "delete",
1254+
targetDomains: ["integration.example.com"],
1255+
asyncState: "PENDING",
1256+
propagation: {
1257+
requiresPolling: true,
1258+
pollTool: "envQuery",
1259+
pollAction: "domains",
1260+
},
1261+
next_step: {
1262+
tool: "envQuery",
1263+
action: "domains",
1264+
},
1265+
});
1266+
expect(payload.message).toContain("直到目标域名不再出现");
1267+
});
11831268
});

mcp/src/tools/env.ts

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,74 @@ function simplifyEnvDomains(domains: unknown) {
191191
});
192192
}
193193

194+
function buildEnvDomainManagementResult(params: {
195+
action: "create" | "delete";
196+
domains: string[];
197+
result: unknown;
198+
}) {
199+
const { action, domains, result } = params;
200+
const rawResult =
201+
result && typeof result === "object" && !Array.isArray(result)
202+
? (result as Record<string, unknown>)
203+
: { result };
204+
205+
if (action === "create") {
206+
return {
207+
...rawResult,
208+
ok: true,
209+
code: "DOMAIN_UPDATE_PENDING",
210+
operation: action,
211+
targetDomains: domains,
212+
asyncState: "PENDING",
213+
message:
214+
'安全域名已提交添加请求。该变更通常需要约 10 分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名状态为 ENABLE。',
215+
propagation: {
216+
requiresPolling: true,
217+
pollTool: "envQuery",
218+
pollAction: "domains",
219+
pollIntervalSuggestionSeconds: 10,
220+
timeoutSuggestionSeconds: 600,
221+
successCondition:
222+
'目标域名出现在 envQuery(action="domains") 返回中,且 Status 为 ENABLE。',
223+
},
224+
next_step: {
225+
tool: "envQuery",
226+
action: "domains",
227+
suggested_args: {
228+
action: "domains",
229+
},
230+
},
231+
};
232+
}
233+
234+
return {
235+
...rawResult,
236+
ok: true,
237+
code: "DOMAIN_DELETE_PENDING",
238+
operation: action,
239+
targetDomains: domains,
240+
asyncState: "PENDING",
241+
message:
242+
'安全域名已提交删除请求。该变更可能需要数分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名不再出现。',
243+
propagation: {
244+
requiresPolling: true,
245+
pollTool: "envQuery",
246+
pollAction: "domains",
247+
pollIntervalSuggestionSeconds: 10,
248+
timeoutSuggestionSeconds: 600,
249+
successCondition:
250+
'目标域名不再出现在 envQuery(action="domains") 返回中。',
251+
},
252+
next_step: {
253+
tool: "envQuery",
254+
action: "domains",
255+
suggested_args: {
256+
action: "domains",
257+
},
258+
},
259+
};
260+
}
261+
194262
function formatDeviceAuthHint(deviceAuthInfo?: DeviceFlowAuthInfo): string {
195263
if (!deviceAuthInfo) {
196264
return "";
@@ -1414,7 +1482,7 @@ export function registerEnvTools(server: ExtendedMcpServer) {
14141482
{
14151483
title: "环境域名管理",
14161484
description:
1417-
"管理云开发环境的安全域名,支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)当浏览器 Web 应用需要从本地 Vite / dev server 或自定义域名直接访问 CloudBase 资源时,应先用 envQuery(action=domains) 检查当前实际浏览器 origin 对应的 host:port 是否已在白名单中,再按该实际值添加。",
1485+
"管理云开发环境的安全域名,支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)当浏览器 Web 应用需要从本地 Vite / dev server 或自定义域名直接访问 CloudBase 资源时,应先用 envQuery(action=domains) 检查当前实际浏览器 origin 对应的 host:port 是否已在白名单中,再按该实际值添加。新增或删除后通常需要继续轮询 envQuery(action=domains) 确认状态收敛;安全域名一般约 10 分钟生效。",
14181486
inputSchema: {
14191487
action: z
14201488
.enum(["create", "delete"])
@@ -1455,14 +1523,13 @@ export function registerEnvTools(server: ExtendedMcpServer) {
14551523
throw new Error(`不支持的操作类型: ${action}`);
14561524
}
14571525

1458-
return {
1459-
content: [
1460-
{
1461-
type: "text",
1462-
text: `${JSON.stringify(result, null, 2)}\n\n请注意安全域名需要10分钟才能生效,用户也应该了解这一点。`,
1463-
},
1464-
],
1465-
};
1526+
return buildJsonToolResult(
1527+
buildEnvDomainManagementResult({
1528+
action,
1529+
domains,
1530+
result,
1531+
}),
1532+
);
14661533
} catch (error) {
14671534
const toolPayloadResult = toolPayloadErrorToResult(error);
14681535
if (toolPayloadResult) {

0 commit comments

Comments
 (0)