Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions mcp/src/tools/gateway.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ describe("gateway tools", () => {
],
});
mockGetDomainList.mockResolvedValue({
DefaultDomain: "env-test.app.tcloudbase.com",
DefaultDomain: "env-test.tcbaccess-in.tencentcloudbase.com",
EnableService: true,
ServiceSet: [
{
Domain: "api.example.com",
Domain: "env-test.app.tcloudbase.com",
},
],
});
Expand Down Expand Up @@ -174,12 +174,15 @@ describe("gateway tools", () => {
expect(payload).toMatchObject({
success: true,
message:
"已为目标 helloFn 创建网关访问路径。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。",
"已为目标 helloFn 创建网关访问路径。可访问 URL: https://env-test.app.tcloudbase.com/api/hello。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。",
data: {
action: "createAccess",
targetType: "function",
targetName: "helloFn",
path: "/api/hello",
urls: ["https://env-test.app.tcloudbase.com/api/hello"],
primaryUrl: "https://env-test.app.tcloudbase.com/api/hello",
domains: ["env-test.app.tcloudbase.com"],
},
nextActions: [
expect.objectContaining({
Expand Down Expand Up @@ -225,6 +228,8 @@ describe("gateway tools", () => {
targetType: "function",
targetName: "helloFn",
path: "/helloFn",
urls: ["https://env-test.app.tcloudbase.com/helloFn"],
primaryUrl: "https://env-test.app.tcloudbase.com/helloFn",
},
});
});
Expand Down Expand Up @@ -271,10 +276,10 @@ describe("gateway tools", () => {
targetType: "function",
targetName: "helloFn",
total: 1,
domains: ["env-test.app.tcloudbase.com", "api.example.com"],
domains: ["env-test.app.tcloudbase.com"],
allDomains: ["env-test.tcbaccess-in.tencentcloudbase.com", "env-test.app.tcloudbase.com"],
urls: [
"https://env-test.app.tcloudbase.com/api/hello",
"https://api.example.com/api/hello",
],
enableService: true,
},
Expand All @@ -287,6 +292,34 @@ describe("gateway tools", () => {
});
});

it("queryGateway(action=getAccess) should exclude internal domains from urls", async () => {
// Verify that internal domains (tencentcloudbase.com) are filtered out of urls
// but still available in allDomains
const result = await tools.queryGateway.handler({
action: "getAccess",
targetType: "function",
targetName: "helloFn",
});

const payload = JSON.parse(result.content[0].text);

// urls should NOT contain the internal domain
expect(payload.data.urls).not.toContain(
"https://env-test.tcbaccess-in.tencentcloudbase.com/api/hello",
);
// domains should NOT contain the internal domain
expect(payload.data.domains).not.toContain(
"env-test.tcbaccess-in.tencentcloudbase.com",
);
// allDomains should still contain both
expect(payload.data.allDomains).toContain(
"env-test.tcbaccess-in.tencentcloudbase.com",
);
expect(payload.data.allDomains).toContain(
"env-test.app.tcloudbase.com",
);
});

it("queryGateway(action=listRoutes) should list gateway routes", async () => {
const result = await tools.queryGateway.handler({
action: "listRoutes",
Expand Down
45 changes: 40 additions & 5 deletions mcp/src/tools/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,29 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
}
};

/**
* Internal domains (e.g. *.tcbaccess-in.tencentcloudbase.com) do not have
* public TLS certificates and cannot be accessed over HTTPS from external
* clients. Only *.tcloudbase.com domains are externally reachable.
*/
const isExternalDomain = (domain: string) =>
domain.endsWith(".tcloudbase.com") || domain === "tcloudbase.com";
Comment on lines +117 to +118
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include custom domains when building accessible gateway URLs

isExternalDomain() now whitelists only *.tcloudbase.com, which drops valid user-bound custom domains (for example api.example.com) returned by getDomainList().ServiceSet. In this same file, listCustomDomains still treats ServiceSet as the custom-domain source, so filtering them out here means queryGateway(action=getAccess) and manageGateway(action=createAccess) can return empty or incomplete urls/primaryUrl even when public access is correctly configured through a custom domain, regressing production setups that rely on non-tcloudbase.com hostnames.

Useful? React with 👍 / 👎.


const listGatewayDomains = async () => {
const cloudbase = await getManager();
const result = await cloudbase.access.getDomainList();
logCloudBaseResult(server.logger, result);

const domains = [
const allDomains = [
result.DefaultDomain,
...(result.ServiceSet || []).map((item) => item.Domain),
].filter(Boolean);
].filter(Boolean) as string[];

const domains = allDomains.filter(isExternalDomain);

return {
domains,
allDomains,
enableService: result.EnableService,
raw: result,
};
Expand Down Expand Up @@ -207,10 +218,11 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
{
action: input.action,
domains: result.domains,
allDomains: result.allDomains,
enableService: result.enableService,
raw: result.raw,
},
`已获取 ${result.domains.length} 个网关域名`,
`已获取 ${result.domains.length} 个外部可访问网关域名(共 ${result.allDomains.length} 个,已过滤内部域名)`,
[
{
tool: "queryGateway",
Expand Down Expand Up @@ -297,6 +309,7 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
apis: accessList.APISet || [],
total: accessList.Total || 0,
domains: domainInfo.domains,
allDomains: domainInfo.allDomains,
urls,
enableService:
accessList.EnableService ?? domainInfo.enableService ?? false,
Expand All @@ -305,7 +318,7 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
domainList: domainInfo.raw,
},
},
`已获取目标 ${input.targetName} 的网关访问配置`,
`已获取目标 ${input.targetName} 的网关访问配置(urls 仅包含外部可访问域名)`,
[
{
tool: "manageGateway",
Expand Down Expand Up @@ -355,15 +368,37 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
}
logCloudBaseResult(server.logger, result);

// Fetch domain list so we can return the accessible URL immediately
let domainInfo: Awaited<ReturnType<typeof listGatewayDomains>> | undefined;
try {
domainInfo = await listGatewayDomains();
} catch {
// Non-fatal: domain lookup failure should not block the createAccess response
}

const urls =
domainInfo && domainInfo.domains.length > 0
? domainInfo.domains.map(
(domain) => `https://${domain}${accessPath}`,
)
: [];

const primaryUrl = urls[0] || null;

return buildEnvelope(
{
action: input.action,
targetType: input.targetType,
targetName: input.targetName,
path: accessPath,
urls,
primaryUrl,
domains: domainInfo?.domains ?? [],
raw: result,
},
`已为目标 ${input.targetName} 创建网关访问路径。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`,
primaryUrl
? `已为目标 ${input.targetName} 创建网关访问路径。可访问 URL: ${primaryUrl}。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`
: `已为目标 ${input.targetName} 创建网关访问路径。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`,
[
{
tool: "queryGateway",
Expand Down
Loading