@burdenoff/mcp-libs 2026.1008.3 → 2026.1009.1

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.
@@ -584,6 +584,201 @@ var ME = `
584
584
  me { id email username isActive emailVerified }
585
585
  }
586
586
  `;
587
+ var CURRENT_USER = `
588
+ query currentUser {
589
+ currentUser {
590
+ id email firstName lastName username phoneNumber name
591
+ emailVerified mfaEnabled isAdmin role status createdAt lastLoginAt
592
+ }
593
+ }
594
+ `;
595
+ var UPDATE_CURRENT_USER_PROFILE = `
596
+ mutation updateCurrentUserProfile($input: UpdateUserInput!) {
597
+ updateCurrentUserProfile(input: $input) {
598
+ id name firstName lastName username phoneNumber timezone language
599
+ }
600
+ }
601
+ `;
602
+ var AUTH_AUDIT_LOGS = `
603
+ query authAuditLogs($pagination: PaginationInput) {
604
+ authAuditLogs(pagination: $pagination) {
605
+ id action resource resourceType resourceId description
606
+ ipAddress userAgent metadata createdAt
607
+ }
608
+ }
609
+ `;
610
+ var ACTIVE_SESSIONS = `
611
+ query activeSessions($pagination: PaginationInput) {
612
+ activeSessions(pagination: $pagination) {
613
+ id status ipAddress userAgent location lastActivityAt expiresAt createdAt isCurrent
614
+ }
615
+ }
616
+ `;
617
+ var REVOKE_SESSION = `
618
+ mutation revokeSession($id: ID!) {
619
+ revokeSession(id: $id)
620
+ }
621
+ `;
622
+ var CURRENT_USER_MFA_METHODS = `
623
+ query currentUserMFAMethods($pagination: PaginationInput) {
624
+ currentUserMFAMethods(pagination: $pagination) {
625
+ id method status createdAt updatedAt
626
+ }
627
+ }
628
+ `;
629
+ var SETUP_MFA = `
630
+ mutation setupMFA($method: MFAMethod!) {
631
+ setupMFA(method: $method) {
632
+ method backupCodes qrCode secret
633
+ }
634
+ }
635
+ `;
636
+ var ENABLE_MFA = `
637
+ mutation enableMFA($code: String!) {
638
+ enableMFA(code: $code)
639
+ }
640
+ `;
641
+ var DISABLE_MFA = `
642
+ mutation disableMFA {
643
+ disableMFA
644
+ }
645
+ `;
646
+ var MY_API_KEYS = `
647
+ query myApiKeys($pagination: PaginationInput) {
648
+ myApiKeys(pagination: $pagination) {
649
+ apiKeys { id name prefix appId appName scopes expiresAt lastUsedAt createdAt }
650
+ }
651
+ }
652
+ `;
653
+ var APP_API_KEYS = `
654
+ query appApiKeys($appId: ID!, $pagination: PaginationInput) {
655
+ appApiKeys(appId: $appId, pagination: $pagination) {
656
+ apiKeys { id name prefix appId appName scopes expiresAt lastUsedAt createdAt }
657
+ }
658
+ }
659
+ `;
660
+ var GENERATE_API_KEY = `
661
+ mutation generateAPIKey($input: GenerateAPIKeyInput!) {
662
+ generateAPIKey(input: $input) {
663
+ keyId apiKey apiSecret
664
+ }
665
+ }
666
+ `;
667
+ var REVOKE_API_KEY = `
668
+ mutation revokeAPIKey($keyId: String!) {
669
+ revokeAPIKey(keyId: $keyId)
670
+ }
671
+ `;
672
+ var ROTATE_API_KEY = `
673
+ mutation rotateAPIKey($keyId: String!) {
674
+ rotateAPIKey(keyId: $keyId) {
675
+ apiSecret
676
+ }
677
+ }
678
+ `;
679
+ var CURRENT_USER_DELEGATIONS = `
680
+ query currentUserDelegations($pagination: PaginationInput) {
681
+ currentUserDelegations(pagination: $pagination) {
682
+ id appId userId grantedBy grantedAt expiresAt scopes workspaceIds
683
+ status revokedAt revokedBy
684
+ app { id name }
685
+ }
686
+ }
687
+ `;
688
+ var GRANT_DELEGATION = `
689
+ mutation grantDelegation($input: GrantDelegationInput!) {
690
+ grantDelegation(input: $input) {
691
+ id appId userId grantedBy grantedAt expiresAt scopes workspaceIds status
692
+ }
693
+ }
694
+ `;
695
+ var REVOKE_DELEGATION = `
696
+ mutation revokeDelegation($id: ID!, $reason: String) {
697
+ revokeDelegation(id: $id, reason: $reason)
698
+ }
699
+ `;
700
+ var CURRENT_USER_APPS = `
701
+ query currentUserApps($pagination: PaginationInput) {
702
+ currentUserApps(pagination: $pagination) {
703
+ apps { id clientId name description type actorType status ownerUserId redirectUris scopes createdAt updatedAt }
704
+ }
705
+ }
706
+ `;
707
+ var GET_APP = `
708
+ query app($id: ID!) {
709
+ app(id: $id) {
710
+ id clientId name description type actorType status ownerUserId redirectUris scopes
711
+ }
712
+ }
713
+ `;
714
+ var CREATE_APP = `
715
+ mutation createApp($input: CreateAppInput!) {
716
+ createApp(input: $input) {
717
+ app { id clientId name type status }
718
+ clientSecret
719
+ }
720
+ }
721
+ `;
722
+ var UPDATE_APP = `
723
+ mutation updateApp($id: ID!, $input: UpdateAppInput!) {
724
+ updateApp(id: $id, input: $input) {
725
+ id name description redirectUris scopes status
726
+ }
727
+ }
728
+ `;
729
+ var DEACTIVATE_APP = `
730
+ mutation deactivateApp($id: ID!) {
731
+ deactivateApp(id: $id)
732
+ }
733
+ `;
734
+ var GET_SSO_CONFIG = `
735
+ query getSSOConfig($tenantId: String!) {
736
+ getSSOConfig(tenantId: $tenantId) {
737
+ id identifier tenantId entityId ssoUrl sloUrl certificate enabled metadata
738
+ }
739
+ }
740
+ `;
741
+ var SAVE_SSO_CONFIG = `
742
+ mutation saveSSOConfig($tenantId: String!, $input: SSOConfigInput!) {
743
+ saveSSOConfig(tenantId: $tenantId, input: $input) {
744
+ id identifier entityId ssoUrl sloUrl certificate enabled
745
+ }
746
+ }
747
+ `;
748
+ var DELETE_SSO_CONFIG = `
749
+ mutation deleteSSOConfig($tenantId: String!) {
750
+ deleteSSOConfig(tenantId: $tenantId)
751
+ }
752
+ `;
753
+ var LIST_USERS = `
754
+ query users($filter: UserFilterInput, $pagination: PaginationInput) {
755
+ users(filter: $filter, pagination: $pagination) {
756
+ users { id email firstName lastName username role status createdAt }
757
+ totalCount hasMore
758
+ }
759
+ }
760
+ `;
761
+ var GET_USER = `
762
+ query user($id: ID!) {
763
+ user(id: $id) {
764
+ id email firstName lastName username role status emailVerified lastLoginAt
765
+ }
766
+ }
767
+ `;
768
+ var UPDATE_USER = `
769
+ mutation updateUser($id: ID!, $input: AdminUpdateUserInput!) {
770
+ updateUser(id: $id, input: $input) {
771
+ id email firstName lastName username role status
772
+ }
773
+ }
774
+ `;
775
+ var INVITE_USER = `
776
+ mutation inviteUser($input: InviteUserInput!) {
777
+ inviteUser(input: $input) {
778
+ id email status invitedAt expiresAt
779
+ }
780
+ }
781
+ `;
587
782
 
588
783
  // src/modules/auth/more-tools.ts
589
784
  function err(ctx, name, message, error) {
@@ -824,6 +1019,837 @@ function registerAuthMoreTools(server, ctx, track) {
824
1019
  }
825
1020
  );
826
1021
  }
1022
+ function err2(ctx, name, message, error) {
1023
+ ctx.logger.error(`${name} failed`, { error });
1024
+ return errorResult(`${message}: ${error instanceof Error ? error.message : String(error)}`);
1025
+ }
1026
+ function registerAuthExtraTools(server, ctx, track) {
1027
+ server.registerTool(
1028
+ track(mcpToolName(ctx.productName, "auth_profile_get")),
1029
+ {
1030
+ title: "Get Profile",
1031
+ description: "Show the current authenticated user (id, email, name, role, status).",
1032
+ inputSchema: {}
1033
+ },
1034
+ async () => {
1035
+ try {
1036
+ const d = await ctx.gql.global.request(
1037
+ CURRENT_USER
1038
+ );
1039
+ return jsonResult(d.currentUser);
1040
+ } catch (e) {
1041
+ return err2(ctx, "auth_profile_get", "Failed to fetch profile", e);
1042
+ }
1043
+ }
1044
+ );
1045
+ server.registerTool(
1046
+ track(mcpToolName(ctx.productName, "auth_profile_update")),
1047
+ {
1048
+ title: "Update Profile",
1049
+ description: "Update the current user profile (any subset of fields).",
1050
+ inputSchema: {
1051
+ firstName: zod.z.string().optional(),
1052
+ lastName: zod.z.string().optional(),
1053
+ name: zod.z.string().optional(),
1054
+ username: zod.z.string().optional(),
1055
+ phoneNumber: zod.z.string().optional(),
1056
+ timezone: zod.z.string().optional(),
1057
+ language: zod.z.string().optional()
1058
+ }
1059
+ },
1060
+ async (args) => {
1061
+ try {
1062
+ const input = {};
1063
+ if (args.firstName !== void 0) input.firstName = args.firstName;
1064
+ if (args.lastName !== void 0) input.lastName = args.lastName;
1065
+ if (args.name !== void 0) input.name = args.name;
1066
+ if (args.username !== void 0) input.username = args.username;
1067
+ if (args.phoneNumber !== void 0) input.phoneNumber = args.phoneNumber;
1068
+ if (args.timezone !== void 0) input.timezone = args.timezone;
1069
+ if (args.language !== void 0) input.language = args.language;
1070
+ if (Object.keys(input).length === 0) {
1071
+ return errorResult("No updates specified \u2014 provide at least one field.");
1072
+ }
1073
+ const d = await ctx.gql.global.request(UPDATE_CURRENT_USER_PROFILE, { input });
1074
+ return jsonResult({ status: "success", user: d.updateCurrentUserProfile });
1075
+ } catch (e) {
1076
+ return err2(ctx, "auth_profile_update", "Failed to update profile", e);
1077
+ }
1078
+ }
1079
+ );
1080
+ server.registerTool(
1081
+ track(mcpToolName(ctx.productName, "auth_sessions_list")),
1082
+ {
1083
+ title: "List Active Sessions",
1084
+ description: "List active sessions for the current user (browser/device sessions).",
1085
+ inputSchema: {
1086
+ limit: zod.z.number().optional().describe("Page size (default 50)"),
1087
+ offset: zod.z.number().optional()
1088
+ }
1089
+ },
1090
+ async ({ limit, offset }) => {
1091
+ try {
1092
+ const d = await ctx.gql.global.request(ACTIVE_SESSIONS, {
1093
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1094
+ });
1095
+ return jsonResult({ sessions: d.activeSessions, total: d.activeSessions.length });
1096
+ } catch (e) {
1097
+ return err2(ctx, "auth_sessions_list", "Failed to list sessions", e);
1098
+ }
1099
+ }
1100
+ );
1101
+ server.registerTool(
1102
+ track(mcpToolName(ctx.productName, "auth_sessions_revoke")),
1103
+ {
1104
+ title: "Revoke Session",
1105
+ description: "Revoke (sign out) a single session by id.",
1106
+ inputSchema: { id: zod.z.string().describe("Session ID to revoke") }
1107
+ },
1108
+ async ({ id }) => {
1109
+ try {
1110
+ await ctx.gql.global.request(REVOKE_SESSION, { id });
1111
+ return jsonResult({ status: "success", message: `Session ${id} revoked.` });
1112
+ } catch (e) {
1113
+ return err2(ctx, "auth_sessions_revoke", "Failed to revoke session", e);
1114
+ }
1115
+ }
1116
+ );
1117
+ server.registerTool(
1118
+ track(mcpToolName(ctx.productName, "auth_mfa_list")),
1119
+ {
1120
+ title: "List MFA Methods",
1121
+ description: "List MFA methods enrolled for the current user.",
1122
+ inputSchema: {
1123
+ limit: zod.z.number().optional().describe("Page size (default 50)"),
1124
+ offset: zod.z.number().optional()
1125
+ }
1126
+ },
1127
+ async ({ limit, offset }) => {
1128
+ try {
1129
+ const d = await ctx.gql.global.request(CURRENT_USER_MFA_METHODS, {
1130
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1131
+ });
1132
+ return jsonResult({
1133
+ methods: d.currentUserMFAMethods,
1134
+ total: d.currentUserMFAMethods.length
1135
+ });
1136
+ } catch (e) {
1137
+ return err2(ctx, "auth_mfa_list", "Failed to list MFA methods", e);
1138
+ }
1139
+ }
1140
+ );
1141
+ server.registerTool(
1142
+ track(mcpToolName(ctx.productName, "auth_mfa_enroll")),
1143
+ {
1144
+ title: "Enroll MFA",
1145
+ description: "Begin MFA enrollment. Returns the qrCode, secret, and one-time backup codes the user must save BEFORE calling auth_mfa_verify.",
1146
+ inputSchema: {
1147
+ method: zod.z.enum(["TOTP", "SMS", "EMAIL"]).describe("MFA method to enroll")
1148
+ }
1149
+ },
1150
+ async ({ method }) => {
1151
+ try {
1152
+ const d = await ctx.gql.global.request(
1153
+ SETUP_MFA,
1154
+ { method }
1155
+ );
1156
+ return jsonResult({
1157
+ status: "enrollment_started",
1158
+ enrollment: d.setupMFA,
1159
+ message: "Save your backup codes; verify with auth_mfa_verify."
1160
+ });
1161
+ } catch (e) {
1162
+ return err2(ctx, "auth_mfa_enroll", "Failed to enroll MFA", e);
1163
+ }
1164
+ }
1165
+ );
1166
+ server.registerTool(
1167
+ track(mcpToolName(ctx.productName, "auth_mfa_verify")),
1168
+ {
1169
+ title: "Verify MFA Enrollment",
1170
+ description: "Verify MFA enrollment by submitting the code from the authenticator.",
1171
+ inputSchema: { code: zod.z.string().describe("OTP code from authenticator") }
1172
+ },
1173
+ async ({ code }) => {
1174
+ try {
1175
+ await ctx.gql.global.request(ENABLE_MFA, { code });
1176
+ return jsonResult({ status: "success", message: "MFA enabled." });
1177
+ } catch (e) {
1178
+ return err2(ctx, "auth_mfa_verify", "Failed to verify MFA", e);
1179
+ }
1180
+ }
1181
+ );
1182
+ server.registerTool(
1183
+ track(mcpToolName(ctx.productName, "auth_mfa_disable")),
1184
+ {
1185
+ title: "Disable MFA",
1186
+ description: "Disable MFA for the current user.",
1187
+ inputSchema: {}
1188
+ },
1189
+ async () => {
1190
+ try {
1191
+ await ctx.gql.global.request(DISABLE_MFA);
1192
+ return jsonResult({ status: "success", message: "MFA disabled." });
1193
+ } catch (e) {
1194
+ return err2(ctx, "auth_mfa_disable", "Failed to disable MFA", e);
1195
+ }
1196
+ }
1197
+ );
1198
+ server.registerTool(
1199
+ track(mcpToolName(ctx.productName, "auth_api_keys_list")),
1200
+ {
1201
+ title: "List API Keys",
1202
+ description: "List API keys for the current user; pass appId to scope to a specific app.",
1203
+ inputSchema: {
1204
+ appId: zod.z.string().optional().describe("Restrict to keys owned by an app id"),
1205
+ limit: zod.z.number().optional(),
1206
+ offset: zod.z.number().optional()
1207
+ }
1208
+ },
1209
+ async ({ appId, limit, offset }) => {
1210
+ try {
1211
+ const pagination = { limit: limit ?? 50, offset: offset ?? 0 };
1212
+ if (appId) {
1213
+ const d2 = await ctx.gql.global.request(APP_API_KEYS, { appId, pagination });
1214
+ return jsonResult({
1215
+ keys: d2.appApiKeys.apiKeys,
1216
+ total: d2.appApiKeys.apiKeys.length
1217
+ });
1218
+ }
1219
+ const d = await ctx.gql.global.request(MY_API_KEYS, { pagination });
1220
+ return jsonResult({
1221
+ keys: d.myApiKeys.apiKeys,
1222
+ total: d.myApiKeys.apiKeys.length
1223
+ });
1224
+ } catch (e) {
1225
+ return err2(ctx, "auth_api_keys_list", "Failed to list API keys", e);
1226
+ }
1227
+ }
1228
+ );
1229
+ server.registerTool(
1230
+ track(mcpToolName(ctx.productName, "auth_api_keys_create")),
1231
+ {
1232
+ title: "Create API Key",
1233
+ description: "Generate a new API key for an app. Returns apiKey + apiSecret \u2014 the secret is only shown once.",
1234
+ inputSchema: {
1235
+ name: zod.z.string().describe("Friendly name for the key"),
1236
+ appId: zod.z.string().describe("Owning app id"),
1237
+ scopes: zod.z.array(zod.z.string()).optional().describe("Scope strings"),
1238
+ expiresAt: zod.z.string().optional().describe("ISO expiry date")
1239
+ }
1240
+ },
1241
+ async ({ name, appId, scopes, expiresAt }) => {
1242
+ try {
1243
+ const input = { name, appId };
1244
+ if (scopes !== void 0) input.scope = scopes;
1245
+ if (expiresAt !== void 0) input.expiresAt = expiresAt;
1246
+ const d = await ctx.gql.global.request(GENERATE_API_KEY, { input });
1247
+ return jsonResult({
1248
+ status: "success",
1249
+ message: "API key generated. The apiSecret is only shown ONCE \u2014 store it now.",
1250
+ key: d.generateAPIKey
1251
+ });
1252
+ } catch (e) {
1253
+ return err2(ctx, "auth_api_keys_create", "Failed to create API key", e);
1254
+ }
1255
+ }
1256
+ );
1257
+ server.registerTool(
1258
+ track(mcpToolName(ctx.productName, "auth_api_keys_revoke")),
1259
+ {
1260
+ title: "Revoke API Key",
1261
+ description: "Revoke an API key by its keyId.",
1262
+ inputSchema: { keyId: zod.z.string().describe("Key ID to revoke") }
1263
+ },
1264
+ async ({ keyId }) => {
1265
+ try {
1266
+ await ctx.gql.global.request(REVOKE_API_KEY, { keyId });
1267
+ return jsonResult({ status: "success", message: `API key ${keyId} revoked.` });
1268
+ } catch (e) {
1269
+ return err2(ctx, "auth_api_keys_revoke", "Failed to revoke API key", e);
1270
+ }
1271
+ }
1272
+ );
1273
+ server.registerTool(
1274
+ track(mcpToolName(ctx.productName, "auth_api_keys_rotate")),
1275
+ {
1276
+ title: "Rotate API Key",
1277
+ description: "Rotate an API key \u2014 invalidates the previous secret and returns a new one (shown only once).",
1278
+ inputSchema: { keyId: zod.z.string().describe("Key ID to rotate") }
1279
+ },
1280
+ async ({ keyId }) => {
1281
+ try {
1282
+ const d = await ctx.gql.global.request(
1283
+ ROTATE_API_KEY,
1284
+ { keyId }
1285
+ );
1286
+ return jsonResult({
1287
+ status: "success",
1288
+ message: "API key rotated. Save the new secret \u2014 it is only shown once.",
1289
+ apiSecret: d.rotateAPIKey.apiSecret
1290
+ });
1291
+ } catch (e) {
1292
+ return err2(ctx, "auth_api_keys_rotate", "Failed to rotate API key", e);
1293
+ }
1294
+ }
1295
+ );
1296
+ server.registerTool(
1297
+ track(mcpToolName(ctx.productName, "auth_audit_log_query")),
1298
+ {
1299
+ title: "Query Auth Audit Log",
1300
+ description: "Recent auth audit events for the current user.",
1301
+ inputSchema: {
1302
+ limit: zod.z.number().optional().describe("Page size (default 50)"),
1303
+ offset: zod.z.number().optional()
1304
+ }
1305
+ },
1306
+ async ({ limit, offset }) => {
1307
+ try {
1308
+ const d = await ctx.gql.global.request(AUTH_AUDIT_LOGS, {
1309
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1310
+ });
1311
+ return jsonResult({ events: d.authAuditLogs, total: d.authAuditLogs.length });
1312
+ } catch (e) {
1313
+ return err2(ctx, "auth_audit_log_query", "Failed to query audit log", e);
1314
+ }
1315
+ }
1316
+ );
1317
+ server.registerTool(
1318
+ track(mcpToolName(ctx.productName, "auth_delegations_list")),
1319
+ {
1320
+ title: "List Delegations",
1321
+ description: "Delegations granted by/to the current user.",
1322
+ inputSchema: {
1323
+ limit: zod.z.number().optional().describe("Page size (default 50)"),
1324
+ offset: zod.z.number().optional()
1325
+ }
1326
+ },
1327
+ async ({ limit, offset }) => {
1328
+ try {
1329
+ const d = await ctx.gql.global.request(CURRENT_USER_DELEGATIONS, {
1330
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1331
+ });
1332
+ return jsonResult({
1333
+ delegations: d.currentUserDelegations,
1334
+ total: d.currentUserDelegations.length
1335
+ });
1336
+ } catch (e) {
1337
+ return err2(ctx, "auth_delegations_list", "Failed to list delegations", e);
1338
+ }
1339
+ }
1340
+ );
1341
+ server.registerTool(
1342
+ track(mcpToolName(ctx.productName, "auth_delegations_grant")),
1343
+ {
1344
+ title: "Grant Delegation",
1345
+ description: "Grant a delegation to an app (consent on behalf of a user).",
1346
+ inputSchema: {
1347
+ appId: zod.z.string().describe("App id receiving delegation"),
1348
+ userId: zod.z.string().describe("User to delegate as"),
1349
+ scopes: zod.z.array(zod.z.string()).optional(),
1350
+ workspaceIds: zod.z.array(zod.z.string()).optional(),
1351
+ expiresAt: zod.z.string().optional().describe("ISO expiry")
1352
+ }
1353
+ },
1354
+ async ({ appId, userId, scopes, workspaceIds, expiresAt }) => {
1355
+ try {
1356
+ const input = { appId, userId };
1357
+ if (scopes !== void 0) input.scopes = scopes;
1358
+ if (workspaceIds !== void 0) input.workspaceIds = workspaceIds;
1359
+ if (expiresAt !== void 0) input.expiresAt = expiresAt;
1360
+ const d = await ctx.gql.global.request(
1361
+ GRANT_DELEGATION,
1362
+ { input }
1363
+ );
1364
+ return jsonResult({ status: "success", delegation: d.grantDelegation });
1365
+ } catch (e) {
1366
+ return err2(ctx, "auth_delegations_grant", "Failed to grant delegation", e);
1367
+ }
1368
+ }
1369
+ );
1370
+ server.registerTool(
1371
+ track(mcpToolName(ctx.productName, "auth_delegations_revoke")),
1372
+ {
1373
+ title: "Revoke Delegation",
1374
+ description: "Revoke a delegation by its id.",
1375
+ inputSchema: {
1376
+ id: zod.z.string().describe("Delegation ID"),
1377
+ reason: zod.z.string().optional()
1378
+ }
1379
+ },
1380
+ async ({ id, reason }) => {
1381
+ try {
1382
+ await ctx.gql.global.request(REVOKE_DELEGATION, {
1383
+ id,
1384
+ ...reason !== void 0 ? { reason } : {}
1385
+ });
1386
+ return jsonResult({ status: "success", message: `Delegation ${id} revoked.` });
1387
+ } catch (e) {
1388
+ return err2(ctx, "auth_delegations_revoke", "Failed to revoke delegation", e);
1389
+ }
1390
+ }
1391
+ );
1392
+ server.registerTool(
1393
+ track(mcpToolName(ctx.productName, "auth_apps_list")),
1394
+ {
1395
+ title: "List Apps",
1396
+ description: "List OAuth/system apps owned by the current user.",
1397
+ inputSchema: {
1398
+ limit: zod.z.number().optional(),
1399
+ offset: zod.z.number().optional()
1400
+ }
1401
+ },
1402
+ async ({ limit, offset }) => {
1403
+ try {
1404
+ const d = await ctx.gql.global.request(CURRENT_USER_APPS, {
1405
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1406
+ });
1407
+ return jsonResult({
1408
+ apps: d.currentUserApps.apps,
1409
+ total: d.currentUserApps.apps.length
1410
+ });
1411
+ } catch (e) {
1412
+ return err2(ctx, "auth_apps_list", "Failed to list apps", e);
1413
+ }
1414
+ }
1415
+ );
1416
+ server.registerTool(
1417
+ track(mcpToolName(ctx.productName, "auth_apps_get")),
1418
+ {
1419
+ title: "Get App",
1420
+ description: "Get a single app by its id.",
1421
+ inputSchema: { id: zod.z.string().describe("App ID") }
1422
+ },
1423
+ async ({ id }) => {
1424
+ try {
1425
+ const d = await ctx.gql.global.request(
1426
+ GET_APP,
1427
+ { id }
1428
+ );
1429
+ if (!d.app) {
1430
+ return errorResult(`App ${id} not found.`);
1431
+ }
1432
+ return jsonResult(d.app);
1433
+ } catch (e) {
1434
+ return err2(ctx, "auth_apps_get", "Failed to get app", e);
1435
+ }
1436
+ }
1437
+ );
1438
+ server.registerTool(
1439
+ track(mcpToolName(ctx.productName, "auth_apps_create")),
1440
+ {
1441
+ title: "Create App",
1442
+ description: "Create an OAuth or system app. Returns the app + clientSecret (shown only once).",
1443
+ inputSchema: {
1444
+ name: zod.z.string().describe("App name"),
1445
+ description: zod.z.string().optional(),
1446
+ type: zod.z.enum(["OAUTH", "SYSTEM"]).optional().describe("App type (default OAUTH)"),
1447
+ actorType: zod.z.enum(["USER", "APP", "SERVICE"]).optional().describe("Actor type (default APP)"),
1448
+ redirectUris: zod.z.array(zod.z.string()).optional().describe("OAuth redirect URIs"),
1449
+ scopes: zod.z.array(zod.z.string()).optional()
1450
+ }
1451
+ },
1452
+ async ({ name, description, type, actorType, redirectUris, scopes }) => {
1453
+ try {
1454
+ const input = {
1455
+ name,
1456
+ type: type ?? "OAUTH",
1457
+ actorType: actorType ?? "APP"
1458
+ };
1459
+ if (description !== void 0) input.description = description;
1460
+ if (redirectUris !== void 0) input.redirectUris = redirectUris;
1461
+ if (scopes !== void 0) input.scopes = scopes;
1462
+ const d = await ctx.gql.global.request(CREATE_APP, { input });
1463
+ return jsonResult({
1464
+ status: "success",
1465
+ message: "App created. clientSecret only shown once \u2014 store it now.",
1466
+ app: d.createApp.app,
1467
+ clientSecret: d.createApp.clientSecret
1468
+ });
1469
+ } catch (e) {
1470
+ return err2(ctx, "auth_apps_create", "Failed to create app", e);
1471
+ }
1472
+ }
1473
+ );
1474
+ server.registerTool(
1475
+ track(mcpToolName(ctx.productName, "auth_apps_update")),
1476
+ {
1477
+ title: "Update App",
1478
+ description: "Update an app (name, description, redirect URIs, scopes, status).",
1479
+ inputSchema: {
1480
+ id: zod.z.string().describe("App ID"),
1481
+ name: zod.z.string().optional(),
1482
+ description: zod.z.string().optional(),
1483
+ redirectUris: zod.z.array(zod.z.string()).optional(),
1484
+ scopes: zod.z.array(zod.z.string()).optional(),
1485
+ status: zod.z.string().optional().describe("Status (e.g. ACTIVE, INACTIVE)")
1486
+ }
1487
+ },
1488
+ async ({ id, name, description, redirectUris, scopes, status }) => {
1489
+ try {
1490
+ const input = {};
1491
+ if (name !== void 0) input.name = name;
1492
+ if (description !== void 0) input.description = description;
1493
+ if (redirectUris !== void 0) input.redirectUris = redirectUris;
1494
+ if (scopes !== void 0) input.scopes = scopes;
1495
+ if (status !== void 0) input.status = status.toUpperCase();
1496
+ if (Object.keys(input).length === 0) {
1497
+ return errorResult("No updates specified \u2014 provide at least one field.");
1498
+ }
1499
+ const d = await ctx.gql.global.request(
1500
+ UPDATE_APP,
1501
+ { id, input }
1502
+ );
1503
+ return jsonResult({ status: "success", app: d.updateApp });
1504
+ } catch (e) {
1505
+ return err2(ctx, "auth_apps_update", "Failed to update app", e);
1506
+ }
1507
+ }
1508
+ );
1509
+ server.registerTool(
1510
+ track(mcpToolName(ctx.productName, "auth_apps_deactivate")),
1511
+ {
1512
+ title: "Deactivate App",
1513
+ description: "Deactivate an app by its id (revoke is not currently a separate mutation).",
1514
+ inputSchema: { id: zod.z.string().describe("App ID") }
1515
+ },
1516
+ async ({ id }) => {
1517
+ try {
1518
+ await ctx.gql.global.request(DEACTIVATE_APP, { id });
1519
+ return jsonResult({ status: "success", message: `App ${id} deactivated.` });
1520
+ } catch (e) {
1521
+ return err2(ctx, "auth_apps_deactivate", "Failed to deactivate app", e);
1522
+ }
1523
+ }
1524
+ );
1525
+ server.registerTool(
1526
+ track(mcpToolName(ctx.productName, "auth_apps_authorize_url")),
1527
+ {
1528
+ title: "Build OAuth Authorize URL",
1529
+ description: "Build the OAuth authorization URL for an app (browser-only flow). Returns the URL to open in a browser; this tool does not perform any server call.",
1530
+ inputSchema: {
1531
+ clientId: zod.z.string().describe("OAuth client id"),
1532
+ redirectUri: zod.z.string().describe("Redirect URI (must be registered)"),
1533
+ scopes: zod.z.array(zod.z.string()).optional(),
1534
+ state: zod.z.string().optional().describe("Opaque state value"),
1535
+ responseType: zod.z.string().optional().describe('Default "code"')
1536
+ }
1537
+ },
1538
+ async ({ clientId, redirectUri, scopes, state, responseType }) => {
1539
+ const cfg = ctx.config.read();
1540
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1541
+ const params = new URLSearchParams({
1542
+ client_id: clientId,
1543
+ redirect_uri: redirectUri,
1544
+ response_type: responseType ?? "code"
1545
+ });
1546
+ if (scopes && scopes.length > 0) params.set("scope", scopes.join(" "));
1547
+ if (state) params.set("state", state);
1548
+ const url = `${issuer.replace(/\/$/, "")}/oauth/authorize?${params.toString()}`;
1549
+ return jsonResult({ url });
1550
+ }
1551
+ );
1552
+ server.registerTool(
1553
+ track(mcpToolName(ctx.productName, "auth_sso_get")),
1554
+ {
1555
+ title: "Get SSO Config",
1556
+ description: "Get SSO (SAML/OIDC) configuration for a tenant.",
1557
+ inputSchema: { tenantId: zod.z.string().describe("Tenant ID") }
1558
+ },
1559
+ async ({ tenantId }) => {
1560
+ try {
1561
+ const d = await ctx.gql.global.request(
1562
+ GET_SSO_CONFIG,
1563
+ { tenantId }
1564
+ );
1565
+ return jsonResult(d.getSSOConfig);
1566
+ } catch (e) {
1567
+ return err2(ctx, "auth_sso_get", "Failed to get SSO config", e);
1568
+ }
1569
+ }
1570
+ );
1571
+ server.registerTool(
1572
+ track(mcpToolName(ctx.productName, "auth_sso_configure")),
1573
+ {
1574
+ title: "Configure SSO",
1575
+ description: "Save (upsert) SSO configuration for a tenant.",
1576
+ inputSchema: {
1577
+ tenantId: zod.z.string().describe("Tenant ID"),
1578
+ entityId: zod.z.string().describe("SAML EntityID / OIDC issuer"),
1579
+ ssoUrl: zod.z.string().describe("SSO endpoint URL"),
1580
+ sloUrl: zod.z.string().optional().describe("SLO endpoint URL"),
1581
+ certificate: zod.z.string().optional().describe("X.509 certificate PEM"),
1582
+ enabled: zod.z.boolean().optional().describe("Enable after save (default false)")
1583
+ }
1584
+ },
1585
+ async ({ tenantId, entityId, ssoUrl, sloUrl, certificate, enabled }) => {
1586
+ try {
1587
+ const input = {
1588
+ entityId,
1589
+ ssoUrl,
1590
+ enabled: enabled ?? false
1591
+ };
1592
+ if (sloUrl !== void 0) input.sloUrl = sloUrl;
1593
+ if (certificate !== void 0) input.certificate = certificate;
1594
+ const d = await ctx.gql.global.request(
1595
+ SAVE_SSO_CONFIG,
1596
+ { tenantId, input }
1597
+ );
1598
+ return jsonResult({ status: "success", config: d.saveSSOConfig });
1599
+ } catch (e) {
1600
+ return err2(ctx, "auth_sso_configure", "Failed to save SSO config", e);
1601
+ }
1602
+ }
1603
+ );
1604
+ server.registerTool(
1605
+ track(mcpToolName(ctx.productName, "auth_sso_test")),
1606
+ {
1607
+ title: "Test SSO",
1608
+ description: "Build the SSO test login URL for a tenant. Returns the URL to open in a browser; this tool does not perform any server call.",
1609
+ inputSchema: { tenantId: zod.z.string().describe("Tenant ID") }
1610
+ },
1611
+ async ({ tenantId }) => {
1612
+ const cfg = ctx.config.read();
1613
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1614
+ const url = `${issuer.replace(/\/$/, "")}/sso/${encodeURIComponent(tenantId)}/test`;
1615
+ return jsonResult({ url, message: "Open this URL in a browser to test SSO." });
1616
+ }
1617
+ );
1618
+ server.registerTool(
1619
+ track(mcpToolName(ctx.productName, "auth_sso_delete")),
1620
+ {
1621
+ title: "Delete SSO Config",
1622
+ description: "Delete SSO configuration for a tenant.",
1623
+ inputSchema: { tenantId: zod.z.string().describe("Tenant ID") }
1624
+ },
1625
+ async ({ tenantId }) => {
1626
+ try {
1627
+ await ctx.gql.global.request(DELETE_SSO_CONFIG, { tenantId });
1628
+ return jsonResult({ status: "success", message: `SSO config for ${tenantId} deleted.` });
1629
+ } catch (e) {
1630
+ return err2(ctx, "auth_sso_delete", "Failed to delete SSO config", e);
1631
+ }
1632
+ }
1633
+ );
1634
+ server.registerTool(
1635
+ track(mcpToolName(ctx.productName, "auth_users_list")),
1636
+ {
1637
+ title: "List Users (admin)",
1638
+ description: "List users with optional filters. Requires admin permission.",
1639
+ inputSchema: {
1640
+ email: zod.z.string().optional(),
1641
+ username: zod.z.string().optional(),
1642
+ role: zod.z.string().optional(),
1643
+ status: zod.z.string().optional(),
1644
+ search: zod.z.string().optional(),
1645
+ limit: zod.z.number().optional(),
1646
+ offset: zod.z.number().optional()
1647
+ }
1648
+ },
1649
+ async ({ email, username, role, status, search, limit, offset }) => {
1650
+ try {
1651
+ const filter = {};
1652
+ if (email !== void 0) filter.email = email;
1653
+ if (username !== void 0) filter.username = username;
1654
+ if (role !== void 0) filter.role = role.toUpperCase();
1655
+ if (status !== void 0) filter.status = status.toUpperCase();
1656
+ if (search !== void 0) filter.search = search;
1657
+ const d = await ctx.gql.global.request(LIST_USERS, {
1658
+ filter: Object.keys(filter).length > 0 ? filter : void 0,
1659
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1660
+ });
1661
+ return jsonResult({
1662
+ users: d.users.users,
1663
+ totalCount: d.users.totalCount,
1664
+ hasMore: d.users.hasMore
1665
+ });
1666
+ } catch (e) {
1667
+ return err2(ctx, "auth_users_list", "Failed to list users", e);
1668
+ }
1669
+ }
1670
+ );
1671
+ server.registerTool(
1672
+ track(mcpToolName(ctx.productName, "auth_users_get")),
1673
+ {
1674
+ title: "Get User (admin)",
1675
+ description: "Get a user by id. Requires admin permission.",
1676
+ inputSchema: { id: zod.z.string().describe("User ID") }
1677
+ },
1678
+ async ({ id }) => {
1679
+ try {
1680
+ const d = await ctx.gql.global.request(GET_USER, { id });
1681
+ if (!d.user) {
1682
+ return errorResult(`User ${id} not found.`);
1683
+ }
1684
+ return jsonResult(d.user);
1685
+ } catch (e) {
1686
+ return err2(ctx, "auth_users_get", "Failed to get user", e);
1687
+ }
1688
+ }
1689
+ );
1690
+ server.registerTool(
1691
+ track(mcpToolName(ctx.productName, "auth_users_invite")),
1692
+ {
1693
+ title: "Invite User (admin)",
1694
+ description: "Send an invitation email to a new user.",
1695
+ inputSchema: {
1696
+ email: zod.z.string().describe("Invitee email"),
1697
+ role: zod.z.string().optional().describe("Role to assign on accept"),
1698
+ firstName: zod.z.string().optional(),
1699
+ lastName: zod.z.string().optional(),
1700
+ workspaceIds: zod.z.array(zod.z.string()).optional()
1701
+ }
1702
+ },
1703
+ async ({ email, role, firstName, lastName, workspaceIds }) => {
1704
+ try {
1705
+ const input = { email };
1706
+ if (role !== void 0) input.role = role.toUpperCase();
1707
+ if (firstName !== void 0) input.firstName = firstName;
1708
+ if (lastName !== void 0) input.lastName = lastName;
1709
+ if (workspaceIds !== void 0) input.workspaceIds = workspaceIds;
1710
+ const d = await ctx.gql.global.request(
1711
+ INVITE_USER,
1712
+ { input }
1713
+ );
1714
+ return jsonResult({ status: "success", invitation: d.inviteUser });
1715
+ } catch (e) {
1716
+ return err2(ctx, "auth_users_invite", "Failed to invite user", e);
1717
+ }
1718
+ }
1719
+ );
1720
+ server.registerTool(
1721
+ track(mcpToolName(ctx.productName, "auth_users_update")),
1722
+ {
1723
+ title: "Update User (admin)",
1724
+ description: "Update a user (admin). Pass any subset of mutable fields.",
1725
+ inputSchema: {
1726
+ id: zod.z.string().describe("User ID"),
1727
+ firstName: zod.z.string().optional(),
1728
+ lastName: zod.z.string().optional(),
1729
+ username: zod.z.string().optional(),
1730
+ phoneNumber: zod.z.string().optional(),
1731
+ role: zod.z.string().optional(),
1732
+ status: zod.z.string().optional(),
1733
+ emailVerified: zod.z.boolean().optional()
1734
+ }
1735
+ },
1736
+ async ({ id, firstName, lastName, username, phoneNumber, role, status, emailVerified }) => {
1737
+ try {
1738
+ const input = {};
1739
+ if (firstName !== void 0) input.firstName = firstName;
1740
+ if (lastName !== void 0) input.lastName = lastName;
1741
+ if (username !== void 0) input.username = username;
1742
+ if (phoneNumber !== void 0) input.phoneNumber = phoneNumber;
1743
+ if (role !== void 0) input.role = role.toUpperCase();
1744
+ if (status !== void 0) input.status = status.toUpperCase();
1745
+ if (emailVerified !== void 0) input.emailVerified = emailVerified;
1746
+ if (Object.keys(input).length === 0) {
1747
+ return errorResult("No updates specified \u2014 provide at least one field.");
1748
+ }
1749
+ const d = await ctx.gql.global.request(UPDATE_USER, {
1750
+ id,
1751
+ input
1752
+ });
1753
+ return jsonResult({ status: "success", user: d.updateUser });
1754
+ } catch (e) {
1755
+ return err2(ctx, "auth_users_update", "Failed to update user", e);
1756
+ }
1757
+ }
1758
+ );
1759
+ server.registerTool(
1760
+ track(mcpToolName(ctx.productName, "auth_security_summary")),
1761
+ {
1762
+ title: "Account Security Summary",
1763
+ description: "One-shot account security overview: profile, MFA methods, active sessions, recent audit log, API keys, delegations.",
1764
+ inputSchema: {
1765
+ recentLimit: zod.z.number().optional().describe("How many recent audit events / sessions to include (default 10)")
1766
+ }
1767
+ },
1768
+ async ({ recentLimit }) => {
1769
+ const limit = recentLimit ?? 10;
1770
+ const pagination = { limit, offset: 0 };
1771
+ const summary = {};
1772
+ try {
1773
+ const profile = await ctx.gql.global.request(CURRENT_USER).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1774
+ summary.profile = profile;
1775
+ const mfa = await ctx.gql.global.request(CURRENT_USER_MFA_METHODS, { pagination }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1776
+ summary.mfa = mfa;
1777
+ const sessions = await ctx.gql.global.request(ACTIVE_SESSIONS, {
1778
+ pagination
1779
+ }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1780
+ summary.sessions = sessions;
1781
+ const audit = await ctx.gql.global.request(AUTH_AUDIT_LOGS, {
1782
+ pagination
1783
+ }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1784
+ summary.auditLog = audit;
1785
+ const keys = await ctx.gql.global.request(MY_API_KEYS, {
1786
+ pagination
1787
+ }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1788
+ summary.apiKeys = keys;
1789
+ const delegations = await ctx.gql.global.request(CURRENT_USER_DELEGATIONS, { pagination }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1790
+ summary.delegations = delegations;
1791
+ return jsonResult(summary);
1792
+ } catch (e) {
1793
+ return err2(ctx, "auth_security_summary", "Failed to build security summary", e);
1794
+ }
1795
+ }
1796
+ );
1797
+ server.registerTool(
1798
+ track(mcpToolName(ctx.productName, "auth_register_get_url")),
1799
+ {
1800
+ title: "Build Registration URL",
1801
+ description: "Build the registration URL (browser-only flow). Returns the URL to open in a browser; this tool does not perform any server call.",
1802
+ inputSchema: {
1803
+ email: zod.z.string().optional().describe("Pre-fill the email field")
1804
+ }
1805
+ },
1806
+ async ({ email }) => {
1807
+ const cfg = ctx.config.read();
1808
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1809
+ const params = new URLSearchParams();
1810
+ if (email) params.set("email", email);
1811
+ const qs = params.toString();
1812
+ const url = `${issuer.replace(/\/$/, "")}/register${qs ? `?${qs}` : ""}`;
1813
+ return jsonResult({ url });
1814
+ }
1815
+ );
1816
+ server.registerTool(
1817
+ track(mcpToolName(ctx.productName, "auth_reset_password_get_url")),
1818
+ {
1819
+ title: "Build Password Reset URL",
1820
+ description: "Build the password reset URL (browser-only flow). Returns the URL to open in a browser; this tool does not perform any server call.",
1821
+ inputSchema: {
1822
+ email: zod.z.string().optional().describe("Pre-fill the email field")
1823
+ }
1824
+ },
1825
+ async ({ email }) => {
1826
+ const cfg = ctx.config.read();
1827
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1828
+ const params = new URLSearchParams();
1829
+ if (email) params.set("email", email);
1830
+ const qs = params.toString();
1831
+ const url = `${issuer.replace(/\/$/, "")}/reset-password${qs ? `?${qs}` : ""}`;
1832
+ return jsonResult({ url });
1833
+ }
1834
+ );
1835
+ server.registerTool(
1836
+ track(mcpToolName(ctx.productName, "auth_magic_link_get_url")),
1837
+ {
1838
+ title: "Build Magic-Link URL",
1839
+ description: "Build the magic-link login URL (browser-only flow). Returns the URL to open in a browser; this tool does not perform any server call.",
1840
+ inputSchema: {
1841
+ email: zod.z.string().describe("Email to send the magic link to")
1842
+ }
1843
+ },
1844
+ async ({ email }) => {
1845
+ const cfg = ctx.config.read();
1846
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1847
+ const params = new URLSearchParams({ email });
1848
+ const url = `${issuer.replace(/\/$/, "")}/magic-link?${params.toString()}`;
1849
+ return jsonResult({ url });
1850
+ }
1851
+ );
1852
+ }
827
1853
 
828
1854
  // src/modules/auth/index.ts
829
1855
  var authModule = {
@@ -839,6 +1865,7 @@ var authModule = {
839
1865
  };
840
1866
  registerAuthTools(server, ctx, track);
841
1867
  registerAuthMoreTools(server, ctx, track);
1868
+ registerAuthExtraTools(server, ctx, track);
842
1869
  return { tools, resources: [], prompts: [] };
843
1870
  }
844
1871
  };