snow-flow 1.1.68 → 1.1.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp/servicenow-intelligent-mcp.js +102 -49
- package/dist/mcp/servicenow-intelligent-mcp.js.map +1 -1
- package/dist/mcp/servicenow-operations-mcp.js +556 -0
- package/dist/mcp/servicenow-operations-mcp.js.map +1 -1
- package/dist/orchestrator/flow-composer.d.ts +6 -0
- package/dist/orchestrator/flow-composer.d.ts.map +1 -1
- package/dist/orchestrator/flow-composer.js +106 -9
- package/dist/orchestrator/flow-composer.js.map +1 -1
- package/dist/strategies/global-scope-strategy.d.ts.map +1 -1
- package/dist/strategies/global-scope-strategy.js +8 -1
- package/dist/strategies/global-scope-strategy.js.map +1 -1
- package/dist/version.d.ts +6 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +30 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
|
@@ -694,6 +694,157 @@ class ServiceNowOperationsMCP {
|
|
|
694
694
|
}
|
|
695
695
|
}
|
|
696
696
|
}
|
|
697
|
+
},
|
|
698
|
+
// User and Group Management Tools
|
|
699
|
+
{
|
|
700
|
+
name: 'snow_create_user_group',
|
|
701
|
+
description: 'Create a new user group in ServiceNow',
|
|
702
|
+
inputSchema: {
|
|
703
|
+
type: 'object',
|
|
704
|
+
properties: {
|
|
705
|
+
name: {
|
|
706
|
+
type: 'string',
|
|
707
|
+
description: 'Group name (e.g., "Need Approval")'
|
|
708
|
+
},
|
|
709
|
+
description: {
|
|
710
|
+
type: 'string',
|
|
711
|
+
description: 'Group description'
|
|
712
|
+
},
|
|
713
|
+
email: {
|
|
714
|
+
type: 'string',
|
|
715
|
+
description: 'Group email address (optional)'
|
|
716
|
+
},
|
|
717
|
+
manager: {
|
|
718
|
+
type: 'string',
|
|
719
|
+
description: 'Group manager sys_id or user_name (optional)'
|
|
720
|
+
},
|
|
721
|
+
parent: {
|
|
722
|
+
type: 'string',
|
|
723
|
+
description: 'Parent group sys_id (optional)'
|
|
724
|
+
},
|
|
725
|
+
type: {
|
|
726
|
+
type: 'string',
|
|
727
|
+
description: 'Group type (optional)',
|
|
728
|
+
enum: ['', 'catalog', 'change', 'incident', 'problem', 'request']
|
|
729
|
+
},
|
|
730
|
+
active: {
|
|
731
|
+
type: 'boolean',
|
|
732
|
+
description: 'Is group active',
|
|
733
|
+
default: true
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
required: ['name']
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
name: 'snow_create_user',
|
|
741
|
+
description: 'Create a new user in ServiceNow',
|
|
742
|
+
inputSchema: {
|
|
743
|
+
type: 'object',
|
|
744
|
+
properties: {
|
|
745
|
+
user_name: {
|
|
746
|
+
type: 'string',
|
|
747
|
+
description: 'Unique username for login'
|
|
748
|
+
},
|
|
749
|
+
first_name: {
|
|
750
|
+
type: 'string',
|
|
751
|
+
description: 'User first name'
|
|
752
|
+
},
|
|
753
|
+
last_name: {
|
|
754
|
+
type: 'string',
|
|
755
|
+
description: 'User last name'
|
|
756
|
+
},
|
|
757
|
+
email: {
|
|
758
|
+
type: 'string',
|
|
759
|
+
description: 'User email address'
|
|
760
|
+
},
|
|
761
|
+
department: {
|
|
762
|
+
type: 'string',
|
|
763
|
+
description: 'Department name or sys_id (optional)'
|
|
764
|
+
},
|
|
765
|
+
manager: {
|
|
766
|
+
type: 'string',
|
|
767
|
+
description: 'Manager sys_id or user_name (optional)'
|
|
768
|
+
},
|
|
769
|
+
phone: {
|
|
770
|
+
type: 'string',
|
|
771
|
+
description: 'Phone number (optional)'
|
|
772
|
+
},
|
|
773
|
+
title: {
|
|
774
|
+
type: 'string',
|
|
775
|
+
description: 'Job title (optional)'
|
|
776
|
+
},
|
|
777
|
+
location: {
|
|
778
|
+
type: 'string',
|
|
779
|
+
description: 'Location name or sys_id (optional)'
|
|
780
|
+
},
|
|
781
|
+
active: {
|
|
782
|
+
type: 'boolean',
|
|
783
|
+
description: 'Is user active',
|
|
784
|
+
default: true
|
|
785
|
+
},
|
|
786
|
+
password: {
|
|
787
|
+
type: 'string',
|
|
788
|
+
description: 'Initial password (will require change on first login)'
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
required: ['user_name', 'first_name', 'last_name', 'email']
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
name: 'snow_assign_user_to_group',
|
|
796
|
+
description: 'Add a user to a group in ServiceNow',
|
|
797
|
+
inputSchema: {
|
|
798
|
+
type: 'object',
|
|
799
|
+
properties: {
|
|
800
|
+
user: {
|
|
801
|
+
type: 'string',
|
|
802
|
+
description: 'User sys_id or user_name'
|
|
803
|
+
},
|
|
804
|
+
group: {
|
|
805
|
+
type: 'string',
|
|
806
|
+
description: 'Group sys_id or name'
|
|
807
|
+
}
|
|
808
|
+
},
|
|
809
|
+
required: ['user', 'group']
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
name: 'snow_remove_user_from_group',
|
|
814
|
+
description: 'Remove a user from a group in ServiceNow',
|
|
815
|
+
inputSchema: {
|
|
816
|
+
type: 'object',
|
|
817
|
+
properties: {
|
|
818
|
+
user: {
|
|
819
|
+
type: 'string',
|
|
820
|
+
description: 'User sys_id or user_name'
|
|
821
|
+
},
|
|
822
|
+
group: {
|
|
823
|
+
type: 'string',
|
|
824
|
+
description: 'Group sys_id or name'
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
required: ['user', 'group']
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
name: 'snow_list_group_members',
|
|
832
|
+
description: 'List all members of a group',
|
|
833
|
+
inputSchema: {
|
|
834
|
+
type: 'object',
|
|
835
|
+
properties: {
|
|
836
|
+
group: {
|
|
837
|
+
type: 'string',
|
|
838
|
+
description: 'Group sys_id or name'
|
|
839
|
+
},
|
|
840
|
+
active_only: {
|
|
841
|
+
type: 'boolean',
|
|
842
|
+
description: 'Only show active users',
|
|
843
|
+
default: true
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
required: ['group']
|
|
847
|
+
}
|
|
697
848
|
}
|
|
698
849
|
],
|
|
699
850
|
};
|
|
@@ -735,6 +886,16 @@ class ServiceNowOperationsMCP {
|
|
|
735
886
|
return await this.handleLinkCatalogToFlow(args);
|
|
736
887
|
case 'snow_cleanup_test_artifacts':
|
|
737
888
|
return await this.handleCleanupTestArtifacts(args);
|
|
889
|
+
case 'snow_create_user_group':
|
|
890
|
+
return await this.handleCreateUserGroup(args);
|
|
891
|
+
case 'snow_create_user':
|
|
892
|
+
return await this.handleCreateUser(args);
|
|
893
|
+
case 'snow_assign_user_to_group':
|
|
894
|
+
return await this.handleAssignUserToGroup(args);
|
|
895
|
+
case 'snow_remove_user_from_group':
|
|
896
|
+
return await this.handleRemoveUserFromGroup(args);
|
|
897
|
+
case 'snow_list_group_members':
|
|
898
|
+
return await this.handleListGroupMembers(args);
|
|
738
899
|
default:
|
|
739
900
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Tool ${name} not found`);
|
|
740
901
|
}
|
|
@@ -2898,6 +3059,401 @@ ${JSON.stringify(testResults, null, 2)}
|
|
|
2898
3059
|
// This would need to get the instance URL from credentials
|
|
2899
3060
|
return 'https://instance.service-now.com';
|
|
2900
3061
|
}
|
|
3062
|
+
async handleCreateUserGroup(args) {
|
|
3063
|
+
const { name, description, email, manager, parent, type, active = true } = args;
|
|
3064
|
+
logger_js_1.logger.info(`Creating user group: ${name}`);
|
|
3065
|
+
try {
|
|
3066
|
+
// Check if group already exists
|
|
3067
|
+
const existingGroup = await this.client.get('/api/now/table/sys_user_group', {
|
|
3068
|
+
sysparm_query: `name=${name}`,
|
|
3069
|
+
sysparm_limit: 1
|
|
3070
|
+
});
|
|
3071
|
+
if (existingGroup.result?.length > 0) {
|
|
3072
|
+
return {
|
|
3073
|
+
content: [{
|
|
3074
|
+
type: 'text',
|
|
3075
|
+
text: `✅ Group "${name}" already exists!\n\nSys ID: ${existingGroup.result[0].sys_id}\nManager: ${existingGroup.result[0].manager?.display_value || 'None'}\nType: ${existingGroup.result[0].type || 'Standard'}\nActive: ${existingGroup.result[0].active}\n\nNo action taken.`
|
|
3076
|
+
}]
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
// Prepare group data
|
|
3080
|
+
const groupData = {
|
|
3081
|
+
name,
|
|
3082
|
+
active: active.toString()
|
|
3083
|
+
};
|
|
3084
|
+
if (description)
|
|
3085
|
+
groupData.description = description;
|
|
3086
|
+
if (email)
|
|
3087
|
+
groupData.email = email;
|
|
3088
|
+
if (type)
|
|
3089
|
+
groupData.type = type;
|
|
3090
|
+
// Handle manager lookup
|
|
3091
|
+
if (manager) {
|
|
3092
|
+
const managerUser = await this.findUserBySysIdOrUsername(manager);
|
|
3093
|
+
if (managerUser) {
|
|
3094
|
+
groupData.manager = managerUser.sys_id;
|
|
3095
|
+
}
|
|
3096
|
+
else {
|
|
3097
|
+
logger_js_1.logger.warn(`Manager "${manager}" not found, creating group without manager`);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
// Handle parent group lookup
|
|
3101
|
+
if (parent) {
|
|
3102
|
+
const parentGroup = await this.findGroupBySysIdOrName(parent);
|
|
3103
|
+
if (parentGroup) {
|
|
3104
|
+
groupData.parent = parentGroup.sys_id;
|
|
3105
|
+
}
|
|
3106
|
+
else {
|
|
3107
|
+
logger_js_1.logger.warn(`Parent group "${parent}" not found, creating group without parent`);
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
// Create the group
|
|
3111
|
+
const result = await this.client.post('/api/now/table/sys_user_group', groupData);
|
|
3112
|
+
if (result.result) {
|
|
3113
|
+
const groupUrl = `${process.env.SNOW_INSTANCE ? `https://${process.env.SNOW_INSTANCE.replace(/\/$/, '')}.service-now.com` : ''}/sys_user_group.do?sys_id=${result.result.sys_id}`;
|
|
3114
|
+
return {
|
|
3115
|
+
content: [{
|
|
3116
|
+
type: 'text',
|
|
3117
|
+
text: `✅ **User Group Created Successfully!**\n\n**Group Name:** ${result.result.name}\n**Sys ID:** ${result.result.sys_id}\n**Type:** ${result.result.type || 'Standard'}\n**Active:** ${result.result.active}\n${result.result.manager ? `**Manager:** ${result.result.manager.display_value}` : ''}\n${result.result.parent ? `**Parent Group:** ${result.result.parent.display_value}` : ''}\n\n**View Group:** ${groupUrl}\n\nYou can now assign users to this group using \`snow_assign_user_to_group\`.`
|
|
3118
|
+
}]
|
|
3119
|
+
};
|
|
3120
|
+
}
|
|
3121
|
+
else {
|
|
3122
|
+
throw new Error('Failed to create group - no result returned');
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
catch (error) {
|
|
3126
|
+
return {
|
|
3127
|
+
content: [{
|
|
3128
|
+
type: 'text',
|
|
3129
|
+
text: `❌ **Failed to create user group**\n\nError: ${error instanceof Error ? error.message : String(error)}\n\nTip: Ensure you have the necessary permissions to create groups (admin or user_admin role).`
|
|
3130
|
+
}]
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
async handleCreateUser(args) {
|
|
3135
|
+
const { user_name, first_name, last_name, email, department, manager, phone, title, location, active = true, password } = args;
|
|
3136
|
+
logger_js_1.logger.info(`Creating user: ${user_name}`);
|
|
3137
|
+
try {
|
|
3138
|
+
// Check if user already exists
|
|
3139
|
+
const existingUser = await this.client.get('/api/now/table/sys_user', {
|
|
3140
|
+
sysparm_query: `user_name=${user_name}`,
|
|
3141
|
+
sysparm_limit: 1
|
|
3142
|
+
});
|
|
3143
|
+
if (existingUser.result?.length > 0) {
|
|
3144
|
+
return {
|
|
3145
|
+
content: [{
|
|
3146
|
+
type: 'text',
|
|
3147
|
+
text: `✅ User "${user_name}" already exists!\n\nSys ID: ${existingUser.result[0].sys_id}\nName: ${existingUser.result[0].first_name} ${existingUser.result[0].last_name}\nEmail: ${existingUser.result[0].email}\nActive: ${existingUser.result[0].active}\n\nNo action taken.`
|
|
3148
|
+
}]
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
// Prepare user data
|
|
3152
|
+
const userData = {
|
|
3153
|
+
user_name,
|
|
3154
|
+
first_name,
|
|
3155
|
+
last_name,
|
|
3156
|
+
email,
|
|
3157
|
+
active: active.toString()
|
|
3158
|
+
};
|
|
3159
|
+
if (phone)
|
|
3160
|
+
userData.phone = phone;
|
|
3161
|
+
if (title)
|
|
3162
|
+
userData.title = title;
|
|
3163
|
+
if (password)
|
|
3164
|
+
userData.user_password = password;
|
|
3165
|
+
// Handle manager lookup
|
|
3166
|
+
if (manager) {
|
|
3167
|
+
const managerUser = await this.findUserBySysIdOrUsername(manager);
|
|
3168
|
+
if (managerUser) {
|
|
3169
|
+
userData.manager = managerUser.sys_id;
|
|
3170
|
+
}
|
|
3171
|
+
else {
|
|
3172
|
+
logger_js_1.logger.warn(`Manager "${manager}" not found, creating user without manager`);
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
// Handle department lookup
|
|
3176
|
+
if (department) {
|
|
3177
|
+
const dept = await this.findDepartment(department);
|
|
3178
|
+
if (dept) {
|
|
3179
|
+
userData.department = dept.sys_id;
|
|
3180
|
+
}
|
|
3181
|
+
else {
|
|
3182
|
+
logger_js_1.logger.warn(`Department "${department}" not found, creating user without department`);
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
// Handle location lookup
|
|
3186
|
+
if (location) {
|
|
3187
|
+
const loc = await this.findLocation(location);
|
|
3188
|
+
if (loc) {
|
|
3189
|
+
userData.location = loc.sys_id;
|
|
3190
|
+
}
|
|
3191
|
+
else {
|
|
3192
|
+
logger_js_1.logger.warn(`Location "${location}" not found, creating user without location`);
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
// Create the user
|
|
3196
|
+
const result = await this.client.post('/api/now/table/sys_user', userData);
|
|
3197
|
+
if (result.result) {
|
|
3198
|
+
const userUrl = `${process.env.SNOW_INSTANCE ? `https://${process.env.SNOW_INSTANCE.replace(/\/$/, '')}.service-now.com` : ''}/sys_user.do?sys_id=${result.result.sys_id}`;
|
|
3199
|
+
return {
|
|
3200
|
+
content: [{
|
|
3201
|
+
type: 'text',
|
|
3202
|
+
text: `✅ **User Created Successfully!**\n\n**Username:** ${result.result.user_name}\n**Name:** ${result.result.first_name} ${result.result.last_name}\n**Email:** ${result.result.email}\n**Sys ID:** ${result.result.sys_id}\n**Active:** ${result.result.active}\n${result.result.manager ? `**Manager:** ${result.result.manager.display_value}` : ''}\n${result.result.department ? `**Department:** ${result.result.department.display_value}` : ''}\n${password ? '\n⚠️ **Note:** User will be required to change password on first login.' : ''}\n\n**View User:** ${userUrl}\n\nYou can now assign this user to groups using \`snow_assign_user_to_group\`.`
|
|
3203
|
+
}]
|
|
3204
|
+
};
|
|
3205
|
+
}
|
|
3206
|
+
else {
|
|
3207
|
+
throw new Error('Failed to create user - no result returned');
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
catch (error) {
|
|
3211
|
+
return {
|
|
3212
|
+
content: [{
|
|
3213
|
+
type: 'text',
|
|
3214
|
+
text: `❌ **Failed to create user**\n\nError: ${error instanceof Error ? error.message : String(error)}\n\nTip: Ensure you have the necessary permissions to create users (admin or user_admin role).`
|
|
3215
|
+
}]
|
|
3216
|
+
};
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
async handleAssignUserToGroup(args) {
|
|
3220
|
+
const { user, group } = args;
|
|
3221
|
+
logger_js_1.logger.info(`Assigning user ${user} to group ${group}`);
|
|
3222
|
+
try {
|
|
3223
|
+
// Find the user
|
|
3224
|
+
const userRecord = await this.findUserBySysIdOrUsername(user);
|
|
3225
|
+
if (!userRecord) {
|
|
3226
|
+
return {
|
|
3227
|
+
content: [{
|
|
3228
|
+
type: 'text',
|
|
3229
|
+
text: `❌ User "${user}" not found. Please check the username or sys_id.`
|
|
3230
|
+
}]
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
// Find the group
|
|
3234
|
+
const groupRecord = await this.findGroupBySysIdOrName(group);
|
|
3235
|
+
if (!groupRecord) {
|
|
3236
|
+
return {
|
|
3237
|
+
content: [{
|
|
3238
|
+
type: 'text',
|
|
3239
|
+
text: `❌ Group "${group}" not found. Please check the group name or sys_id.\n\nTip: You can create a new group using \`snow_create_user_group\`.`
|
|
3240
|
+
}]
|
|
3241
|
+
};
|
|
3242
|
+
}
|
|
3243
|
+
// Check if user is already in group
|
|
3244
|
+
const existingMembership = await this.client.get('/api/now/table/sys_user_grmember', {
|
|
3245
|
+
sysparm_query: `user=${userRecord.sys_id}^group=${groupRecord.sys_id}`,
|
|
3246
|
+
sysparm_limit: 1
|
|
3247
|
+
});
|
|
3248
|
+
if (existingMembership.result?.length > 0) {
|
|
3249
|
+
return {
|
|
3250
|
+
content: [{
|
|
3251
|
+
type: 'text',
|
|
3252
|
+
text: `ℹ️ User "${userRecord.user_name}" is already a member of group "${groupRecord.name}".\n\nNo action taken.`
|
|
3253
|
+
}]
|
|
3254
|
+
};
|
|
3255
|
+
}
|
|
3256
|
+
// Add user to group
|
|
3257
|
+
const result = await this.client.post('/api/now/table/sys_user_grmember', {
|
|
3258
|
+
user: userRecord.sys_id,
|
|
3259
|
+
group: groupRecord.sys_id
|
|
3260
|
+
});
|
|
3261
|
+
if (result.result) {
|
|
3262
|
+
return {
|
|
3263
|
+
content: [{
|
|
3264
|
+
type: 'text',
|
|
3265
|
+
text: `✅ **User Added to Group Successfully!**\n\n**User:** ${userRecord.first_name} ${userRecord.last_name} (${userRecord.user_name})\n**Group:** ${groupRecord.name}\n**Membership Sys ID:** ${result.result.sys_id}\n\nThe user now has all permissions associated with the "${groupRecord.name}" group.`
|
|
3266
|
+
}]
|
|
3267
|
+
};
|
|
3268
|
+
}
|
|
3269
|
+
else {
|
|
3270
|
+
throw new Error('Failed to add user to group - no result returned');
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
catch (error) {
|
|
3274
|
+
return {
|
|
3275
|
+
content: [{
|
|
3276
|
+
type: 'text',
|
|
3277
|
+
text: `❌ **Failed to assign user to group**\n\nError: ${error instanceof Error ? error.message : String(error)}\n\nTip: Ensure you have the necessary permissions to manage group membership.`
|
|
3278
|
+
}]
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
async handleRemoveUserFromGroup(args) {
|
|
3283
|
+
const { user, group } = args;
|
|
3284
|
+
logger_js_1.logger.info(`Removing user ${user} from group ${group}`);
|
|
3285
|
+
try {
|
|
3286
|
+
// Find the user
|
|
3287
|
+
const userRecord = await this.findUserBySysIdOrUsername(user);
|
|
3288
|
+
if (!userRecord) {
|
|
3289
|
+
return {
|
|
3290
|
+
content: [{
|
|
3291
|
+
type: 'text',
|
|
3292
|
+
text: `❌ User "${user}" not found. Please check the username or sys_id.`
|
|
3293
|
+
}]
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
// Find the group
|
|
3297
|
+
const groupRecord = await this.findGroupBySysIdOrName(group);
|
|
3298
|
+
if (!groupRecord) {
|
|
3299
|
+
return {
|
|
3300
|
+
content: [{
|
|
3301
|
+
type: 'text',
|
|
3302
|
+
text: `❌ Group "${group}" not found. Please check the group name or sys_id.`
|
|
3303
|
+
}]
|
|
3304
|
+
};
|
|
3305
|
+
}
|
|
3306
|
+
// Find the membership record
|
|
3307
|
+
const membership = await this.client.get('/api/now/table/sys_user_grmember', {
|
|
3308
|
+
sysparm_query: `user=${userRecord.sys_id}^group=${groupRecord.sys_id}`,
|
|
3309
|
+
sysparm_limit: 1
|
|
3310
|
+
});
|
|
3311
|
+
if (!membership.result || membership.result.length === 0) {
|
|
3312
|
+
return {
|
|
3313
|
+
content: [{
|
|
3314
|
+
type: 'text',
|
|
3315
|
+
text: `ℹ️ User "${userRecord.user_name}" is not a member of group "${groupRecord.name}".\n\nNo action taken.`
|
|
3316
|
+
}]
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
// Remove user from group
|
|
3320
|
+
await this.client.delete(`/api/now/table/sys_user_grmember/${membership.result[0].sys_id}`);
|
|
3321
|
+
return {
|
|
3322
|
+
content: [{
|
|
3323
|
+
type: 'text',
|
|
3324
|
+
text: `✅ **User Removed from Group Successfully!**\n\n**User:** ${userRecord.first_name} ${userRecord.last_name} (${userRecord.user_name})\n**Group:** ${groupRecord.name}\n\nThe user no longer has permissions associated with the "${groupRecord.name}" group.`
|
|
3325
|
+
}]
|
|
3326
|
+
};
|
|
3327
|
+
}
|
|
3328
|
+
catch (error) {
|
|
3329
|
+
return {
|
|
3330
|
+
content: [{
|
|
3331
|
+
type: 'text',
|
|
3332
|
+
text: `❌ **Failed to remove user from group**\n\nError: ${error instanceof Error ? error.message : String(error)}\n\nTip: Ensure you have the necessary permissions to manage group membership.`
|
|
3333
|
+
}]
|
|
3334
|
+
};
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
async handleListGroupMembers(args) {
|
|
3338
|
+
const { group, active_only = true } = args;
|
|
3339
|
+
logger_js_1.logger.info(`Listing members of group: ${group}`);
|
|
3340
|
+
try {
|
|
3341
|
+
// Find the group
|
|
3342
|
+
const groupRecord = await this.findGroupBySysIdOrName(group);
|
|
3343
|
+
if (!groupRecord) {
|
|
3344
|
+
return {
|
|
3345
|
+
content: [{
|
|
3346
|
+
type: 'text',
|
|
3347
|
+
text: `❌ Group "${group}" not found. Please check the group name or sys_id.`
|
|
3348
|
+
}]
|
|
3349
|
+
};
|
|
3350
|
+
}
|
|
3351
|
+
// Get group members
|
|
3352
|
+
let query = `group=${groupRecord.sys_id}`;
|
|
3353
|
+
if (active_only) {
|
|
3354
|
+
query += '^user.active=true';
|
|
3355
|
+
}
|
|
3356
|
+
const members = await this.client.get('/api/now/table/sys_user_grmember', {
|
|
3357
|
+
sysparm_query: query,
|
|
3358
|
+
sysparm_fields: 'user.user_name,user.first_name,user.last_name,user.email,user.title,user.active,user.sys_id',
|
|
3359
|
+
sysparm_limit: 100
|
|
3360
|
+
});
|
|
3361
|
+
if (!members.result || members.result.length === 0) {
|
|
3362
|
+
return {
|
|
3363
|
+
content: [{
|
|
3364
|
+
type: 'text',
|
|
3365
|
+
text: `ℹ️ **Group "${groupRecord.name}" has no members.**\n\nYou can add users to this group using \`snow_assign_user_to_group\`.`
|
|
3366
|
+
}]
|
|
3367
|
+
};
|
|
3368
|
+
}
|
|
3369
|
+
// Format member list
|
|
3370
|
+
let response = `👥 **Members of "${groupRecord.name}" Group**\n\n`;
|
|
3371
|
+
response += `**Total Members:** ${members.result.length}${active_only ? ' (active only)' : ''}\n\n`;
|
|
3372
|
+
members.result.forEach((member, index) => {
|
|
3373
|
+
const u = member.user;
|
|
3374
|
+
response += `${index + 1}. **${u.first_name} ${u.last_name}** (${u.user_name})\n`;
|
|
3375
|
+
response += ` - Email: ${u.email}\n`;
|
|
3376
|
+
if (u.title)
|
|
3377
|
+
response += ` - Title: ${u.title}\n`;
|
|
3378
|
+
response += ` - Active: ${u.active}\n`;
|
|
3379
|
+
response += ` - Sys ID: ${u.sys_id}\n\n`;
|
|
3380
|
+
});
|
|
3381
|
+
if (members.result.length === 100) {
|
|
3382
|
+
response += `\n⚠️ **Note:** Results limited to 100 members. The group may have additional members.`;
|
|
3383
|
+
}
|
|
3384
|
+
return {
|
|
3385
|
+
content: [{
|
|
3386
|
+
type: 'text',
|
|
3387
|
+
text: response
|
|
3388
|
+
}]
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
catch (error) {
|
|
3392
|
+
return {
|
|
3393
|
+
content: [{
|
|
3394
|
+
type: 'text',
|
|
3395
|
+
text: `❌ **Failed to list group members**\n\nError: ${error instanceof Error ? error.message : String(error)}`
|
|
3396
|
+
}]
|
|
3397
|
+
};
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
// Helper methods
|
|
3401
|
+
async findUserBySysIdOrUsername(identifier) {
|
|
3402
|
+
// First try as sys_id
|
|
3403
|
+
if (identifier.match(/^[a-f0-9]{32}$/)) {
|
|
3404
|
+
const result = await this.client.get(`/api/now/table/sys_user/${identifier}`);
|
|
3405
|
+
if (result.result)
|
|
3406
|
+
return result.result;
|
|
3407
|
+
}
|
|
3408
|
+
// Then try as username
|
|
3409
|
+
const result = await this.client.get('/api/now/table/sys_user', {
|
|
3410
|
+
sysparm_query: `user_name=${identifier}`,
|
|
3411
|
+
sysparm_limit: 1
|
|
3412
|
+
});
|
|
3413
|
+
return result.result?.[0] || null;
|
|
3414
|
+
}
|
|
3415
|
+
async findGroupBySysIdOrName(identifier) {
|
|
3416
|
+
// First try as sys_id
|
|
3417
|
+
if (identifier.match(/^[a-f0-9]{32}$/)) {
|
|
3418
|
+
const result = await this.client.get(`/api/now/table/sys_user_group/${identifier}`);
|
|
3419
|
+
if (result.result)
|
|
3420
|
+
return result.result;
|
|
3421
|
+
}
|
|
3422
|
+
// Then try as name
|
|
3423
|
+
const result = await this.client.get('/api/now/table/sys_user_group', {
|
|
3424
|
+
sysparm_query: `name=${identifier}`,
|
|
3425
|
+
sysparm_limit: 1
|
|
3426
|
+
});
|
|
3427
|
+
return result.result?.[0] || null;
|
|
3428
|
+
}
|
|
3429
|
+
async findDepartment(identifier) {
|
|
3430
|
+
// First try as sys_id
|
|
3431
|
+
if (identifier.match(/^[a-f0-9]{32}$/)) {
|
|
3432
|
+
const result = await this.client.get(`/api/now/table/cmn_department/${identifier}`);
|
|
3433
|
+
if (result.result)
|
|
3434
|
+
return result.result;
|
|
3435
|
+
}
|
|
3436
|
+
// Then try as name
|
|
3437
|
+
const result = await this.client.get('/api/now/table/cmn_department', {
|
|
3438
|
+
sysparm_query: `name=${identifier}`,
|
|
3439
|
+
sysparm_limit: 1
|
|
3440
|
+
});
|
|
3441
|
+
return result.result?.[0] || null;
|
|
3442
|
+
}
|
|
3443
|
+
async findLocation(identifier) {
|
|
3444
|
+
// First try as sys_id
|
|
3445
|
+
if (identifier.match(/^[a-f0-9]{32}$/)) {
|
|
3446
|
+
const result = await this.client.get(`/api/now/table/cmn_location/${identifier}`);
|
|
3447
|
+
if (result.result)
|
|
3448
|
+
return result.result;
|
|
3449
|
+
}
|
|
3450
|
+
// Then try as name
|
|
3451
|
+
const result = await this.client.get('/api/now/table/cmn_location', {
|
|
3452
|
+
sysparm_query: `name=${identifier}`,
|
|
3453
|
+
sysparm_limit: 1
|
|
3454
|
+
});
|
|
3455
|
+
return result.result?.[0] || null;
|
|
3456
|
+
}
|
|
2901
3457
|
async run() {
|
|
2902
3458
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
2903
3459
|
await this.server.connect(transport);
|