Skip to content

Commit de15454

Browse files
author
延枚
committed
Add resource member MCP tools for flow operations
1 parent 0805b64 commit de15454

File tree

7 files changed

+338
-3
lines changed

7 files changed

+338
-3
lines changed

common/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,15 @@ export {
123123
GetPipelineJobRunLogSchema,
124124

125125
// Service connection schemas
126-
ListServiceConnectionsSchema
126+
ListServiceConnectionsSchema,
127+
128+
// Resource member schemas
129+
DeleteResourceMemberSchema,
130+
UpdateResourceMemberSchema,
131+
CreateResourceMemberSchema,
132+
UpdateResourceOwnerSchema,
133+
ResourceMemberSchema,
134+
ResourceMemberBaseSchema
127135
} from "../operations/flow/types.js";
128136

129137
// Packages types

operations/flow/resourceMember.ts

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import * as utils from "../../common/utils.js";
2+
import { z } from "zod";
3+
4+
// 定义资源成员的Zod模式
5+
export const ResourceMemberSchema = z.object({
6+
username: z.string().nullable().optional().describe("用户名"),
7+
userId: z.string().nullable().optional().describe("用户id"),
8+
role: z.string().nullable().optional().describe("用户角色"),
9+
});
10+
11+
// 定义API请求参数的Zod模式
12+
export const ResourceMemberBaseSchema = z.object({
13+
organizationId: z.string().describe("企业Id"),
14+
resourceType: z.string().describe("资源类型 pipeline 流水线 hostGroup 主机组"),
15+
resourceId: z.string().describe("资源Id"),
16+
});
17+
18+
export const DeleteResourceMemberSchema = ResourceMemberBaseSchema.extend({
19+
userId: z.string().describe("用户Id"),
20+
});
21+
22+
export const UpdateResourceMemberSchema = ResourceMemberBaseSchema.extend({
23+
roleName: z.string().describe("角色部署组 hostGroup: user(成员,使用权限) admin(管理员,使用编辑权限) 流水线 pipeline: admin(管理员,查看、运行、编辑权限) member(运行权限) viewer(查看权限)"),
24+
userId: z.string().describe("用户id"),
25+
});
26+
27+
export const CreateResourceMemberSchema = ResourceMemberBaseSchema.extend({
28+
roleName: z.string().describe("角色部署组 hostGroup: user(成员,使用权限) admin(管理员,使用编辑权限) owner(拥有者,所有权限) 流水线 pipeline: owner(拥有者,所有权限) admin(管理员,查看、运行、编辑权限) member(运行权限) viewer(查看权限)"),
29+
userId: z.string().describe("用户id"),
30+
});
31+
32+
export const UpdateResourceOwnerSchema = ResourceMemberBaseSchema.extend({
33+
newOwnerId: z.string().describe("新拥有者用户Id"),
34+
});
35+
36+
// 定义资源成员类型
37+
export type ResourceMember = z.infer<typeof ResourceMemberSchema>;
38+
export type DeleteResourceMemberParams = z.infer<typeof DeleteResourceMemberSchema>;
39+
export type UpdateResourceMemberParams = z.infer<typeof UpdateResourceMemberSchema>;
40+
export type CreateResourceMemberParams = z.infer<typeof CreateResourceMemberSchema>;
41+
export type UpdateResourceOwnerParams = z.infer<typeof UpdateResourceOwnerSchema>;
42+
43+
/**
44+
* 删除资源成员
45+
* @param organizationId 企业Id
46+
* @param resourceType 资源类型 pipeline 流水线 hostGroup 主机组
47+
* @param resourceId 资源Id
48+
* @param userId 用户Id
49+
* @returns 是否成功
50+
*/
51+
export async function deleteResourceMemberFunc(
52+
organizationId: string,
53+
resourceType: string,
54+
resourceId: string,
55+
userId: string
56+
): Promise<boolean> {
57+
const url = `/oapi/v1/flow/organizations/${organizationId}/resourceMembers/resourceTypes/${resourceType}/resourceIds/${resourceId}`;
58+
59+
const queryParams = { userId };
60+
const fullUrl = utils.buildUrl(url, queryParams);
61+
62+
const response = await utils.yunxiaoRequest(fullUrl, {
63+
method: "DELETE",
64+
});
65+
66+
return Boolean(response);
67+
}
68+
69+
/**
70+
* 获取资源成员列表
71+
* @param organizationId 企业Id
72+
* @param resourceType 资源类型 pipeline 流水线 hostGroup 主机组
73+
* @param resourceId 资源Id
74+
* @returns 资源成员列表
75+
*/
76+
export async function listResourceMembersFunc(
77+
organizationId: string,
78+
resourceType: string,
79+
resourceId: string
80+
): Promise<ResourceMember[]> {
81+
const url = `/oapi/v1/flow/organizations/${organizationId}/resourceMembers/resourceTypes/${resourceType}/resourceIds/${resourceId}`;
82+
83+
const response = await utils.yunxiaoRequest(url, {
84+
method: "GET",
85+
});
86+
87+
if (Array.isArray(response)) {
88+
return response.map(item => ResourceMemberSchema.parse(item));
89+
}
90+
91+
// 如果响应不是数组,但包含数据,尝试解析单个对象
92+
try {
93+
return [ResourceMemberSchema.parse(response)];
94+
} catch {
95+
return [];
96+
}
97+
}
98+
99+
/**
100+
* 更新资源成员
101+
* @param organizationId 企业Id
102+
* @param resourceType 资源类型 pipeline 流水线 hostGroup 主机组
103+
* @param resourceId 资源Id
104+
* @param roleName 角色
105+
* @param userId 用户id
106+
* @returns 是否成功
107+
*/
108+
export async function updateResourceMemberFunc(
109+
organizationId: string,
110+
resourceType: string,
111+
resourceId: string,
112+
roleName: string,
113+
userId: string
114+
): Promise<boolean> {
115+
const url = `/oapi/v1/flow/organizations/${organizationId}/resourceMembers/resourceTypes/${resourceType}/resourceIds/${resourceId}`;
116+
117+
const queryParams = { roleName, userId };
118+
const fullUrl = utils.buildUrl(url, queryParams);
119+
120+
const response = await utils.yunxiaoRequest(fullUrl, {
121+
method: "PUT",
122+
});
123+
124+
return Boolean(response);
125+
}
126+
127+
/**
128+
* 插入资源成员
129+
* @param organizationId 企业Id
130+
* @param resourceType 资源类型 pipeline 流水线 hostGroup 主机组
131+
* @param resourceId 资源Id
132+
* @param roleName 角色
133+
* @param userId 用户id
134+
* @returns 是否成功
135+
*/
136+
export async function createResourceMemberFunc(
137+
organizationId: string,
138+
resourceType: string,
139+
resourceId: string,
140+
roleName: string,
141+
userId: string
142+
): Promise<boolean> {
143+
const url = `/oapi/v1/flow/organizations/${organizationId}/resourceMembers/resourceTypes/${resourceType}/resourceIds/${resourceId}`;
144+
145+
const queryParams = { roleName, userId };
146+
const fullUrl = utils.buildUrl(url, queryParams);
147+
148+
const response = await utils.yunxiaoRequest(fullUrl, {
149+
method: "POST",
150+
});
151+
152+
return Boolean(response);
153+
}
154+
155+
/**
156+
* 移交资源对象拥有者
157+
* @param organizationId 企业Id
158+
* @param resourceType 资源类型 pipeline 流水线 hostGroup 主机组
159+
* @param resourceId 资源Id
160+
* @param newOwnerId 新拥有者用户Id
161+
* @returns 是否成功
162+
*/
163+
export async function updateResourceOwnerFunc(
164+
organizationId: string,
165+
resourceType: string,
166+
resourceId: string,
167+
newOwnerId: string
168+
): Promise<boolean> {
169+
const url = `/oapi/v1/flow/organizations/${organizationId}/resourceMembers/resourceTypes/${resourceType}/resourceIds/${resourceId}/transfer/owner`;
170+
171+
const queryParams = { newOwnerId };
172+
const fullUrl = utils.buildUrl(url, queryParams);
173+
174+
const response = await utils.yunxiaoRequest(fullUrl, {
175+
method: "POST",
176+
});
177+
178+
return Boolean(response);
179+
}

operations/flow/types.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,37 @@ export const PipelineJobRunLogSchema = z.object({
336336
more: z.boolean().nullable().optional().describe("Whether there are more logs available")
337337
});
338338

339+
// Resource member schemas
340+
export const ResourceMemberSchema = z.object({
341+
username: z.string().nullable().optional().describe("用户名"),
342+
userId: z.string().nullable().optional().describe("用户id"),
343+
role: z.string().nullable().optional().describe("用户角色"),
344+
});
345+
346+
export const ResourceMemberBaseSchema = z.object({
347+
organizationId: z.string().describe("企业Id"),
348+
resourceType: z.string().describe("资源类型 pipeline 流水线 hostGroup 主机组"),
349+
resourceId: z.string().describe("资源Id"),
350+
});
351+
352+
export const DeleteResourceMemberSchema = ResourceMemberBaseSchema.extend({
353+
userId: z.string().describe("用户Id"),
354+
});
355+
356+
export const UpdateResourceMemberSchema = ResourceMemberBaseSchema.extend({
357+
roleName: z.string().describe("角色部署组 hostGroup: user(成员,使用权限) admin(管理员,使用编辑权限) 流水线 pipeline: admin(管理员,查看、运行、编辑权限) member(运行权限) viewer(查看权限)"),
358+
userId: z.string().describe("用户id"),
359+
});
360+
361+
export const CreateResourceMemberSchema = ResourceMemberBaseSchema.extend({
362+
roleName: z.string().describe("角色部署组 hostGroup: user(成员,使用权限) admin(管理员,使用编辑权限) owner(拥有者,所有权限) 流水线 pipeline: owner(拥有者,所有权限) admin(管理员,查看、运行、编辑权限) member(运行权限) viewer(查看权限)"),
363+
userId: z.string().describe("用户id"),
364+
});
365+
366+
export const UpdateResourceOwnerSchema = ResourceMemberBaseSchema.extend({
367+
newOwnerId: z.string().describe("新拥有者用户Id"),
368+
});
369+
339370
// Flow Update pipeline schema
340371
export const UpdatePipelineSchema = z.object({
341372
organizationId: z.string().describe("Organization ID"),
@@ -424,6 +455,13 @@ export const ListHostGroupsSchema = z.object({
424455

425456
export type HostGroup = z.infer<typeof HostGroupSchema>;
426457

458+
// Resource member type exports
459+
export type ResourceMember = z.infer<typeof ResourceMemberSchema>;
460+
export type DeleteResourceMemberParams = z.infer<typeof DeleteResourceMemberSchema>;
461+
export type UpdateResourceMemberParams = z.infer<typeof UpdateResourceMemberSchema>;
462+
export type CreateResourceMemberParams = z.infer<typeof CreateResourceMemberSchema>;
463+
export type UpdateResourceOwnerParams = z.infer<typeof UpdateResourceOwnerSchema>;
464+
427465
// Flow type exports
428466
export type PipelineDetail = z.infer<typeof PipelineDetailSchema>;
429467
export type PipelineListItem = z.infer<typeof PipelineListItemSchema>;

tool-handlers/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { handleAppStackChangeRequestTools } from './appstack-change-requests.js'
1414
import { handleAppStackDeploymentResourceTools } from './appstack-deployment-resources.js';
1515
import { handleAppStackChangeOrderTools } from './appstack-change-orders.js';
1616
import { handleEffortTools } from './effort.js';
17+
import { handleResourceMemberTools } from './resourceMember.js';
1718

1819
export const handleToolRequest = async (request: any) => {
1920
// Try each handler in sequence until one returns a result
@@ -33,7 +34,8 @@ export const handleToolRequest = async (request: any) => {
3334
handleAppStackChangeRequestTools,
3435
handleAppStackDeploymentResourceTools,
3536
handleAppStackChangeOrderTools,
36-
handleEffortTools
37+
handleEffortTools,
38+
handleResourceMemberTools
3739
];
3840

3941
for (const handler of handlers) {

tool-handlers/resourceMember.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as resourceMember from '../operations/flow/resourceMember.js';
2+
import * as types from '../common/types.js';
3+
4+
export const handleResourceMemberTools = async (request: any) => {
5+
switch (request.params.name) {
6+
case "delete_resource_member": {
7+
const args = types.DeleteResourceMemberSchema.parse(request.params.arguments);
8+
const result = await resourceMember.deleteResourceMemberFunc(
9+
args.organizationId,
10+
args.resourceType,
11+
args.resourceId,
12+
args.userId
13+
);
14+
return {
15+
content: [{ type: "text", text: JSON.stringify({ success: result }) }],
16+
};
17+
}
18+
19+
case "list_resource_members": {
20+
const args = types.ResourceMemberBaseSchema.parse(request.params.arguments);
21+
const members = await resourceMember.listResourceMembersFunc(
22+
args.organizationId,
23+
args.resourceType,
24+
args.resourceId
25+
);
26+
return {
27+
content: [{ type: "text", text: JSON.stringify(members, null, 2) }],
28+
};
29+
}
30+
31+
case "update_resource_member": {
32+
const args = types.UpdateResourceMemberSchema.parse(request.params.arguments);
33+
const result = await resourceMember.updateResourceMemberFunc(
34+
args.organizationId,
35+
args.resourceType,
36+
args.resourceId,
37+
args.roleName,
38+
args.userId
39+
);
40+
return {
41+
content: [{ type: "text", text: JSON.stringify({ success: result }) }],
42+
};
43+
}
44+
45+
case "create_resource_member": {
46+
const args = types.CreateResourceMemberSchema.parse(request.params.arguments);
47+
const result = await resourceMember.createResourceMemberFunc(
48+
args.organizationId,
49+
args.resourceType,
50+
args.resourceId,
51+
args.roleName,
52+
args.userId
53+
);
54+
return {
55+
content: [{ type: "text", text: JSON.stringify({ success: result }) }],
56+
};
57+
}
58+
59+
case "update_resource_owner": {
60+
const args = types.UpdateResourceOwnerSchema.parse(request.params.arguments);
61+
const result = await resourceMember.updateResourceOwnerFunc(
62+
args.organizationId,
63+
args.resourceType,
64+
args.resourceId,
65+
args.newOwnerId
66+
);
67+
return {
68+
content: [{ type: "text", text: JSON.stringify({ success: result }) }],
69+
};
70+
}
71+
72+
default:
73+
return null;
74+
}
75+
};

tool-registry/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { getAppStackChangeRequestTools } from './appstack-change-requests.js';
1414
import { getAppStackDeploymentResourceTools } from './appstack-deployment-resources.js';
1515
import { getAppStackChangeOrderTools } from './appstack-change-orders.js';
1616
import { getEffortTools } from './effort.js';
17+
import { getResourceMemberTools } from './resourceMember.js';
1718

1819
export const getAllTools = () => [
1920
...getCodeManagementTools(),
@@ -31,5 +32,6 @@ export const getAllTools = () => [
3132
...getAppStackChangeRequestTools(),
3233
...getAppStackDeploymentResourceTools(),
3334
...getAppStackChangeOrderTools(),
34-
...getEffortTools()
35+
...getEffortTools(),
36+
...getResourceMemberTools()
3537
];

tool-registry/resourceMember.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { z } from 'zod';
2+
import { zodToJsonSchema } from 'zod-to-json-schema';
3+
import * as types from '../common/types.js';
4+
5+
export const getResourceMemberTools = () => [
6+
{
7+
name: "delete_resource_member",
8+
description: "[Resource Member Management] Delete a resource member",
9+
inputSchema: zodToJsonSchema(types.DeleteResourceMemberSchema),
10+
},
11+
{
12+
name: "list_resource_members",
13+
description: "[Resource Member Management] Get a list of resource members",
14+
inputSchema: zodToJsonSchema(types.ResourceMemberBaseSchema),
15+
},
16+
{
17+
name: "update_resource_member",
18+
description: "[Resource Member Management] Update a resource member",
19+
inputSchema: zodToJsonSchema(types.UpdateResourceMemberSchema),
20+
},
21+
{
22+
name: "create_resource_member",
23+
description: "[Resource Member Management] Create a resource member",
24+
inputSchema: zodToJsonSchema(types.CreateResourceMemberSchema),
25+
},
26+
{
27+
name: "update_resource_owner",
28+
description: "[Resource Member Management] Transfer resource owner",
29+
inputSchema: zodToJsonSchema(types.UpdateResourceOwnerSchema),
30+
},
31+
];

0 commit comments

Comments
 (0)