@burdenoff/mcp-libs 2026.1008.3 → 2026.1008.4

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.
@@ -182,6 +182,201 @@ var ME = `
182
182
  me { id email username isActive emailVerified }
183
183
  }
184
184
  `;
185
+ var CURRENT_USER = `
186
+ query currentUser {
187
+ currentUser {
188
+ id email firstName lastName username phoneNumber name
189
+ emailVerified mfaEnabled isAdmin role status createdAt lastLoginAt
190
+ }
191
+ }
192
+ `;
193
+ var UPDATE_CURRENT_USER_PROFILE = `
194
+ mutation updateCurrentUserProfile($input: UpdateUserInput!) {
195
+ updateCurrentUserProfile(input: $input) {
196
+ id name firstName lastName username phoneNumber timezone language
197
+ }
198
+ }
199
+ `;
200
+ var AUTH_AUDIT_LOGS = `
201
+ query authAuditLogs($pagination: PaginationInput) {
202
+ authAuditLogs(pagination: $pagination) {
203
+ id action resource resourceType resourceId description
204
+ ipAddress userAgent metadata createdAt
205
+ }
206
+ }
207
+ `;
208
+ var ACTIVE_SESSIONS = `
209
+ query activeSessions($pagination: PaginationInput) {
210
+ activeSessions(pagination: $pagination) {
211
+ id status ipAddress userAgent location lastActivityAt expiresAt createdAt isCurrent
212
+ }
213
+ }
214
+ `;
215
+ var REVOKE_SESSION = `
216
+ mutation revokeSession($id: ID!) {
217
+ revokeSession(id: $id)
218
+ }
219
+ `;
220
+ var CURRENT_USER_MFA_METHODS = `
221
+ query currentUserMFAMethods($pagination: PaginationInput) {
222
+ currentUserMFAMethods(pagination: $pagination) {
223
+ id method status createdAt updatedAt
224
+ }
225
+ }
226
+ `;
227
+ var SETUP_MFA = `
228
+ mutation setupMFA($method: MFAMethod!) {
229
+ setupMFA(method: $method) {
230
+ method backupCodes qrCode secret
231
+ }
232
+ }
233
+ `;
234
+ var ENABLE_MFA = `
235
+ mutation enableMFA($code: String!) {
236
+ enableMFA(code: $code)
237
+ }
238
+ `;
239
+ var DISABLE_MFA = `
240
+ mutation disableMFA {
241
+ disableMFA
242
+ }
243
+ `;
244
+ var MY_API_KEYS = `
245
+ query myApiKeys($pagination: PaginationInput) {
246
+ myApiKeys(pagination: $pagination) {
247
+ apiKeys { id name prefix appId appName scopes expiresAt lastUsedAt createdAt }
248
+ }
249
+ }
250
+ `;
251
+ var APP_API_KEYS = `
252
+ query appApiKeys($appId: ID!, $pagination: PaginationInput) {
253
+ appApiKeys(appId: $appId, pagination: $pagination) {
254
+ apiKeys { id name prefix appId appName scopes expiresAt lastUsedAt createdAt }
255
+ }
256
+ }
257
+ `;
258
+ var GENERATE_API_KEY = `
259
+ mutation generateAPIKey($input: GenerateAPIKeyInput!) {
260
+ generateAPIKey(input: $input) {
261
+ keyId apiKey apiSecret
262
+ }
263
+ }
264
+ `;
265
+ var REVOKE_API_KEY = `
266
+ mutation revokeAPIKey($keyId: String!) {
267
+ revokeAPIKey(keyId: $keyId)
268
+ }
269
+ `;
270
+ var ROTATE_API_KEY = `
271
+ mutation rotateAPIKey($keyId: String!) {
272
+ rotateAPIKey(keyId: $keyId) {
273
+ apiSecret
274
+ }
275
+ }
276
+ `;
277
+ var CURRENT_USER_DELEGATIONS = `
278
+ query currentUserDelegations($pagination: PaginationInput) {
279
+ currentUserDelegations(pagination: $pagination) {
280
+ id appId userId grantedBy grantedAt expiresAt scopes workspaceIds
281
+ status revokedAt revokedBy
282
+ app { id name }
283
+ }
284
+ }
285
+ `;
286
+ var GRANT_DELEGATION = `
287
+ mutation grantDelegation($input: GrantDelegationInput!) {
288
+ grantDelegation(input: $input) {
289
+ id appId userId grantedBy grantedAt expiresAt scopes workspaceIds status
290
+ }
291
+ }
292
+ `;
293
+ var REVOKE_DELEGATION = `
294
+ mutation revokeDelegation($id: ID!, $reason: String) {
295
+ revokeDelegation(id: $id, reason: $reason)
296
+ }
297
+ `;
298
+ var CURRENT_USER_APPS = `
299
+ query currentUserApps($pagination: PaginationInput) {
300
+ currentUserApps(pagination: $pagination) {
301
+ apps { id clientId name description type actorType status ownerUserId redirectUris scopes createdAt updatedAt }
302
+ }
303
+ }
304
+ `;
305
+ var GET_APP = `
306
+ query app($id: ID!) {
307
+ app(id: $id) {
308
+ id clientId name description type actorType status ownerUserId redirectUris scopes
309
+ }
310
+ }
311
+ `;
312
+ var CREATE_APP = `
313
+ mutation createApp($input: CreateAppInput!) {
314
+ createApp(input: $input) {
315
+ app { id clientId name type status }
316
+ clientSecret
317
+ }
318
+ }
319
+ `;
320
+ var UPDATE_APP = `
321
+ mutation updateApp($id: ID!, $input: UpdateAppInput!) {
322
+ updateApp(id: $id, input: $input) {
323
+ id name description redirectUris scopes status
324
+ }
325
+ }
326
+ `;
327
+ var DEACTIVATE_APP = `
328
+ mutation deactivateApp($id: ID!) {
329
+ deactivateApp(id: $id)
330
+ }
331
+ `;
332
+ var GET_SSO_CONFIG = `
333
+ query getSSOConfig($tenantId: String!) {
334
+ getSSOConfig(tenantId: $tenantId) {
335
+ id identifier tenantId entityId ssoUrl sloUrl certificate enabled metadata
336
+ }
337
+ }
338
+ `;
339
+ var SAVE_SSO_CONFIG = `
340
+ mutation saveSSOConfig($tenantId: String!, $input: SSOConfigInput!) {
341
+ saveSSOConfig(tenantId: $tenantId, input: $input) {
342
+ id identifier entityId ssoUrl sloUrl certificate enabled
343
+ }
344
+ }
345
+ `;
346
+ var DELETE_SSO_CONFIG = `
347
+ mutation deleteSSOConfig($tenantId: String!) {
348
+ deleteSSOConfig(tenantId: $tenantId)
349
+ }
350
+ `;
351
+ var LIST_USERS = `
352
+ query users($filter: UserFilterInput, $pagination: PaginationInput) {
353
+ users(filter: $filter, pagination: $pagination) {
354
+ users { id email firstName lastName username role status createdAt }
355
+ totalCount hasMore
356
+ }
357
+ }
358
+ `;
359
+ var GET_USER = `
360
+ query user($id: ID!) {
361
+ user(id: $id) {
362
+ id email firstName lastName username role status emailVerified lastLoginAt
363
+ }
364
+ }
365
+ `;
366
+ var UPDATE_USER = `
367
+ mutation updateUser($id: ID!, $input: AdminUpdateUserInput!) {
368
+ updateUser(id: $id, input: $input) {
369
+ id email firstName lastName username role status
370
+ }
371
+ }
372
+ `;
373
+ var INVITE_USER = `
374
+ mutation inviteUser($input: InviteUserInput!) {
375
+ inviteUser(input: $input) {
376
+ id email status invitedAt expiresAt
377
+ }
378
+ }
379
+ `;
185
380
 
186
381
  // src/modules/auth/more-tools.ts
187
382
  function err(ctx, name, message, error) {
@@ -422,6 +617,837 @@ function registerAuthMoreTools(server, ctx, track) {
422
617
  }
423
618
  );
424
619
  }
620
+ function err2(ctx, name, message, error) {
621
+ ctx.logger.error(`${name} failed`, { error });
622
+ return errorResult(`${message}: ${error instanceof Error ? error.message : String(error)}`);
623
+ }
624
+ function registerAuthExtraTools(server, ctx, track) {
625
+ server.registerTool(
626
+ track(mcpToolName(ctx.productName, "auth_profile_get")),
627
+ {
628
+ title: "Get Profile",
629
+ description: "Show the current authenticated user (id, email, name, role, status).",
630
+ inputSchema: {}
631
+ },
632
+ async () => {
633
+ try {
634
+ const d = await ctx.gql.global.request(
635
+ CURRENT_USER
636
+ );
637
+ return jsonResult(d.currentUser);
638
+ } catch (e) {
639
+ return err2(ctx, "auth_profile_get", "Failed to fetch profile", e);
640
+ }
641
+ }
642
+ );
643
+ server.registerTool(
644
+ track(mcpToolName(ctx.productName, "auth_profile_update")),
645
+ {
646
+ title: "Update Profile",
647
+ description: "Update the current user profile (any subset of fields).",
648
+ inputSchema: {
649
+ firstName: z.string().optional(),
650
+ lastName: z.string().optional(),
651
+ name: z.string().optional(),
652
+ username: z.string().optional(),
653
+ phoneNumber: z.string().optional(),
654
+ timezone: z.string().optional(),
655
+ language: z.string().optional()
656
+ }
657
+ },
658
+ async (args) => {
659
+ try {
660
+ const input = {};
661
+ if (args.firstName !== void 0) input.firstName = args.firstName;
662
+ if (args.lastName !== void 0) input.lastName = args.lastName;
663
+ if (args.name !== void 0) input.name = args.name;
664
+ if (args.username !== void 0) input.username = args.username;
665
+ if (args.phoneNumber !== void 0) input.phoneNumber = args.phoneNumber;
666
+ if (args.timezone !== void 0) input.timezone = args.timezone;
667
+ if (args.language !== void 0) input.language = args.language;
668
+ if (Object.keys(input).length === 0) {
669
+ return errorResult("No updates specified \u2014 provide at least one field.");
670
+ }
671
+ const d = await ctx.gql.global.request(UPDATE_CURRENT_USER_PROFILE, { input });
672
+ return jsonResult({ status: "success", user: d.updateCurrentUserProfile });
673
+ } catch (e) {
674
+ return err2(ctx, "auth_profile_update", "Failed to update profile", e);
675
+ }
676
+ }
677
+ );
678
+ server.registerTool(
679
+ track(mcpToolName(ctx.productName, "auth_sessions_list")),
680
+ {
681
+ title: "List Active Sessions",
682
+ description: "List active sessions for the current user (browser/device sessions).",
683
+ inputSchema: {
684
+ limit: z.number().optional().describe("Page size (default 50)"),
685
+ offset: z.number().optional()
686
+ }
687
+ },
688
+ async ({ limit, offset }) => {
689
+ try {
690
+ const d = await ctx.gql.global.request(ACTIVE_SESSIONS, {
691
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
692
+ });
693
+ return jsonResult({ sessions: d.activeSessions, total: d.activeSessions.length });
694
+ } catch (e) {
695
+ return err2(ctx, "auth_sessions_list", "Failed to list sessions", e);
696
+ }
697
+ }
698
+ );
699
+ server.registerTool(
700
+ track(mcpToolName(ctx.productName, "auth_sessions_revoke")),
701
+ {
702
+ title: "Revoke Session",
703
+ description: "Revoke (sign out) a single session by id.",
704
+ inputSchema: { id: z.string().describe("Session ID to revoke") }
705
+ },
706
+ async ({ id }) => {
707
+ try {
708
+ await ctx.gql.global.request(REVOKE_SESSION, { id });
709
+ return jsonResult({ status: "success", message: `Session ${id} revoked.` });
710
+ } catch (e) {
711
+ return err2(ctx, "auth_sessions_revoke", "Failed to revoke session", e);
712
+ }
713
+ }
714
+ );
715
+ server.registerTool(
716
+ track(mcpToolName(ctx.productName, "auth_mfa_list")),
717
+ {
718
+ title: "List MFA Methods",
719
+ description: "List MFA methods enrolled for the current user.",
720
+ inputSchema: {
721
+ limit: z.number().optional().describe("Page size (default 50)"),
722
+ offset: z.number().optional()
723
+ }
724
+ },
725
+ async ({ limit, offset }) => {
726
+ try {
727
+ const d = await ctx.gql.global.request(CURRENT_USER_MFA_METHODS, {
728
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
729
+ });
730
+ return jsonResult({
731
+ methods: d.currentUserMFAMethods,
732
+ total: d.currentUserMFAMethods.length
733
+ });
734
+ } catch (e) {
735
+ return err2(ctx, "auth_mfa_list", "Failed to list MFA methods", e);
736
+ }
737
+ }
738
+ );
739
+ server.registerTool(
740
+ track(mcpToolName(ctx.productName, "auth_mfa_enroll")),
741
+ {
742
+ title: "Enroll MFA",
743
+ description: "Begin MFA enrollment. Returns the qrCode, secret, and one-time backup codes the user must save BEFORE calling auth_mfa_verify.",
744
+ inputSchema: {
745
+ method: z.enum(["TOTP", "SMS", "EMAIL"]).describe("MFA method to enroll")
746
+ }
747
+ },
748
+ async ({ method }) => {
749
+ try {
750
+ const d = await ctx.gql.global.request(
751
+ SETUP_MFA,
752
+ { method }
753
+ );
754
+ return jsonResult({
755
+ status: "enrollment_started",
756
+ enrollment: d.setupMFA,
757
+ message: "Save your backup codes; verify with auth_mfa_verify."
758
+ });
759
+ } catch (e) {
760
+ return err2(ctx, "auth_mfa_enroll", "Failed to enroll MFA", e);
761
+ }
762
+ }
763
+ );
764
+ server.registerTool(
765
+ track(mcpToolName(ctx.productName, "auth_mfa_verify")),
766
+ {
767
+ title: "Verify MFA Enrollment",
768
+ description: "Verify MFA enrollment by submitting the code from the authenticator.",
769
+ inputSchema: { code: z.string().describe("OTP code from authenticator") }
770
+ },
771
+ async ({ code }) => {
772
+ try {
773
+ await ctx.gql.global.request(ENABLE_MFA, { code });
774
+ return jsonResult({ status: "success", message: "MFA enabled." });
775
+ } catch (e) {
776
+ return err2(ctx, "auth_mfa_verify", "Failed to verify MFA", e);
777
+ }
778
+ }
779
+ );
780
+ server.registerTool(
781
+ track(mcpToolName(ctx.productName, "auth_mfa_disable")),
782
+ {
783
+ title: "Disable MFA",
784
+ description: "Disable MFA for the current user.",
785
+ inputSchema: {}
786
+ },
787
+ async () => {
788
+ try {
789
+ await ctx.gql.global.request(DISABLE_MFA);
790
+ return jsonResult({ status: "success", message: "MFA disabled." });
791
+ } catch (e) {
792
+ return err2(ctx, "auth_mfa_disable", "Failed to disable MFA", e);
793
+ }
794
+ }
795
+ );
796
+ server.registerTool(
797
+ track(mcpToolName(ctx.productName, "auth_api_keys_list")),
798
+ {
799
+ title: "List API Keys",
800
+ description: "List API keys for the current user; pass appId to scope to a specific app.",
801
+ inputSchema: {
802
+ appId: z.string().optional().describe("Restrict to keys owned by an app id"),
803
+ limit: z.number().optional(),
804
+ offset: z.number().optional()
805
+ }
806
+ },
807
+ async ({ appId, limit, offset }) => {
808
+ try {
809
+ const pagination = { limit: limit ?? 50, offset: offset ?? 0 };
810
+ if (appId) {
811
+ const d2 = await ctx.gql.global.request(APP_API_KEYS, { appId, pagination });
812
+ return jsonResult({
813
+ keys: d2.appApiKeys.apiKeys,
814
+ total: d2.appApiKeys.apiKeys.length
815
+ });
816
+ }
817
+ const d = await ctx.gql.global.request(MY_API_KEYS, { pagination });
818
+ return jsonResult({
819
+ keys: d.myApiKeys.apiKeys,
820
+ total: d.myApiKeys.apiKeys.length
821
+ });
822
+ } catch (e) {
823
+ return err2(ctx, "auth_api_keys_list", "Failed to list API keys", e);
824
+ }
825
+ }
826
+ );
827
+ server.registerTool(
828
+ track(mcpToolName(ctx.productName, "auth_api_keys_create")),
829
+ {
830
+ title: "Create API Key",
831
+ description: "Generate a new API key for an app. Returns apiKey + apiSecret \u2014 the secret is only shown once.",
832
+ inputSchema: {
833
+ name: z.string().describe("Friendly name for the key"),
834
+ appId: z.string().describe("Owning app id"),
835
+ scopes: z.array(z.string()).optional().describe("Scope strings"),
836
+ expiresAt: z.string().optional().describe("ISO expiry date")
837
+ }
838
+ },
839
+ async ({ name, appId, scopes, expiresAt }) => {
840
+ try {
841
+ const input = { name, appId };
842
+ if (scopes !== void 0) input.scope = scopes;
843
+ if (expiresAt !== void 0) input.expiresAt = expiresAt;
844
+ const d = await ctx.gql.global.request(GENERATE_API_KEY, { input });
845
+ return jsonResult({
846
+ status: "success",
847
+ message: "API key generated. The apiSecret is only shown ONCE \u2014 store it now.",
848
+ key: d.generateAPIKey
849
+ });
850
+ } catch (e) {
851
+ return err2(ctx, "auth_api_keys_create", "Failed to create API key", e);
852
+ }
853
+ }
854
+ );
855
+ server.registerTool(
856
+ track(mcpToolName(ctx.productName, "auth_api_keys_revoke")),
857
+ {
858
+ title: "Revoke API Key",
859
+ description: "Revoke an API key by its keyId.",
860
+ inputSchema: { keyId: z.string().describe("Key ID to revoke") }
861
+ },
862
+ async ({ keyId }) => {
863
+ try {
864
+ await ctx.gql.global.request(REVOKE_API_KEY, { keyId });
865
+ return jsonResult({ status: "success", message: `API key ${keyId} revoked.` });
866
+ } catch (e) {
867
+ return err2(ctx, "auth_api_keys_revoke", "Failed to revoke API key", e);
868
+ }
869
+ }
870
+ );
871
+ server.registerTool(
872
+ track(mcpToolName(ctx.productName, "auth_api_keys_rotate")),
873
+ {
874
+ title: "Rotate API Key",
875
+ description: "Rotate an API key \u2014 invalidates the previous secret and returns a new one (shown only once).",
876
+ inputSchema: { keyId: z.string().describe("Key ID to rotate") }
877
+ },
878
+ async ({ keyId }) => {
879
+ try {
880
+ const d = await ctx.gql.global.request(
881
+ ROTATE_API_KEY,
882
+ { keyId }
883
+ );
884
+ return jsonResult({
885
+ status: "success",
886
+ message: "API key rotated. Save the new secret \u2014 it is only shown once.",
887
+ apiSecret: d.rotateAPIKey.apiSecret
888
+ });
889
+ } catch (e) {
890
+ return err2(ctx, "auth_api_keys_rotate", "Failed to rotate API key", e);
891
+ }
892
+ }
893
+ );
894
+ server.registerTool(
895
+ track(mcpToolName(ctx.productName, "auth_audit_log_query")),
896
+ {
897
+ title: "Query Auth Audit Log",
898
+ description: "Recent auth audit events for the current user.",
899
+ inputSchema: {
900
+ limit: z.number().optional().describe("Page size (default 50)"),
901
+ offset: z.number().optional()
902
+ }
903
+ },
904
+ async ({ limit, offset }) => {
905
+ try {
906
+ const d = await ctx.gql.global.request(AUTH_AUDIT_LOGS, {
907
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
908
+ });
909
+ return jsonResult({ events: d.authAuditLogs, total: d.authAuditLogs.length });
910
+ } catch (e) {
911
+ return err2(ctx, "auth_audit_log_query", "Failed to query audit log", e);
912
+ }
913
+ }
914
+ );
915
+ server.registerTool(
916
+ track(mcpToolName(ctx.productName, "auth_delegations_list")),
917
+ {
918
+ title: "List Delegations",
919
+ description: "Delegations granted by/to the current user.",
920
+ inputSchema: {
921
+ limit: z.number().optional().describe("Page size (default 50)"),
922
+ offset: z.number().optional()
923
+ }
924
+ },
925
+ async ({ limit, offset }) => {
926
+ try {
927
+ const d = await ctx.gql.global.request(CURRENT_USER_DELEGATIONS, {
928
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
929
+ });
930
+ return jsonResult({
931
+ delegations: d.currentUserDelegations,
932
+ total: d.currentUserDelegations.length
933
+ });
934
+ } catch (e) {
935
+ return err2(ctx, "auth_delegations_list", "Failed to list delegations", e);
936
+ }
937
+ }
938
+ );
939
+ server.registerTool(
940
+ track(mcpToolName(ctx.productName, "auth_delegations_grant")),
941
+ {
942
+ title: "Grant Delegation",
943
+ description: "Grant a delegation to an app (consent on behalf of a user).",
944
+ inputSchema: {
945
+ appId: z.string().describe("App id receiving delegation"),
946
+ userId: z.string().describe("User to delegate as"),
947
+ scopes: z.array(z.string()).optional(),
948
+ workspaceIds: z.array(z.string()).optional(),
949
+ expiresAt: z.string().optional().describe("ISO expiry")
950
+ }
951
+ },
952
+ async ({ appId, userId, scopes, workspaceIds, expiresAt }) => {
953
+ try {
954
+ const input = { appId, userId };
955
+ if (scopes !== void 0) input.scopes = scopes;
956
+ if (workspaceIds !== void 0) input.workspaceIds = workspaceIds;
957
+ if (expiresAt !== void 0) input.expiresAt = expiresAt;
958
+ const d = await ctx.gql.global.request(
959
+ GRANT_DELEGATION,
960
+ { input }
961
+ );
962
+ return jsonResult({ status: "success", delegation: d.grantDelegation });
963
+ } catch (e) {
964
+ return err2(ctx, "auth_delegations_grant", "Failed to grant delegation", e);
965
+ }
966
+ }
967
+ );
968
+ server.registerTool(
969
+ track(mcpToolName(ctx.productName, "auth_delegations_revoke")),
970
+ {
971
+ title: "Revoke Delegation",
972
+ description: "Revoke a delegation by its id.",
973
+ inputSchema: {
974
+ id: z.string().describe("Delegation ID"),
975
+ reason: z.string().optional()
976
+ }
977
+ },
978
+ async ({ id, reason }) => {
979
+ try {
980
+ await ctx.gql.global.request(REVOKE_DELEGATION, {
981
+ id,
982
+ ...reason !== void 0 ? { reason } : {}
983
+ });
984
+ return jsonResult({ status: "success", message: `Delegation ${id} revoked.` });
985
+ } catch (e) {
986
+ return err2(ctx, "auth_delegations_revoke", "Failed to revoke delegation", e);
987
+ }
988
+ }
989
+ );
990
+ server.registerTool(
991
+ track(mcpToolName(ctx.productName, "auth_apps_list")),
992
+ {
993
+ title: "List Apps",
994
+ description: "List OAuth/system apps owned by the current user.",
995
+ inputSchema: {
996
+ limit: z.number().optional(),
997
+ offset: z.number().optional()
998
+ }
999
+ },
1000
+ async ({ limit, offset }) => {
1001
+ try {
1002
+ const d = await ctx.gql.global.request(CURRENT_USER_APPS, {
1003
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1004
+ });
1005
+ return jsonResult({
1006
+ apps: d.currentUserApps.apps,
1007
+ total: d.currentUserApps.apps.length
1008
+ });
1009
+ } catch (e) {
1010
+ return err2(ctx, "auth_apps_list", "Failed to list apps", e);
1011
+ }
1012
+ }
1013
+ );
1014
+ server.registerTool(
1015
+ track(mcpToolName(ctx.productName, "auth_apps_get")),
1016
+ {
1017
+ title: "Get App",
1018
+ description: "Get a single app by its id.",
1019
+ inputSchema: { id: z.string().describe("App ID") }
1020
+ },
1021
+ async ({ id }) => {
1022
+ try {
1023
+ const d = await ctx.gql.global.request(
1024
+ GET_APP,
1025
+ { id }
1026
+ );
1027
+ if (!d.app) {
1028
+ return errorResult(`App ${id} not found.`);
1029
+ }
1030
+ return jsonResult(d.app);
1031
+ } catch (e) {
1032
+ return err2(ctx, "auth_apps_get", "Failed to get app", e);
1033
+ }
1034
+ }
1035
+ );
1036
+ server.registerTool(
1037
+ track(mcpToolName(ctx.productName, "auth_apps_create")),
1038
+ {
1039
+ title: "Create App",
1040
+ description: "Create an OAuth or system app. Returns the app + clientSecret (shown only once).",
1041
+ inputSchema: {
1042
+ name: z.string().describe("App name"),
1043
+ description: z.string().optional(),
1044
+ type: z.enum(["OAUTH", "SYSTEM"]).optional().describe("App type (default OAUTH)"),
1045
+ actorType: z.enum(["USER", "APP", "SERVICE"]).optional().describe("Actor type (default APP)"),
1046
+ redirectUris: z.array(z.string()).optional().describe("OAuth redirect URIs"),
1047
+ scopes: z.array(z.string()).optional()
1048
+ }
1049
+ },
1050
+ async ({ name, description, type, actorType, redirectUris, scopes }) => {
1051
+ try {
1052
+ const input = {
1053
+ name,
1054
+ type: type ?? "OAUTH",
1055
+ actorType: actorType ?? "APP"
1056
+ };
1057
+ if (description !== void 0) input.description = description;
1058
+ if (redirectUris !== void 0) input.redirectUris = redirectUris;
1059
+ if (scopes !== void 0) input.scopes = scopes;
1060
+ const d = await ctx.gql.global.request(CREATE_APP, { input });
1061
+ return jsonResult({
1062
+ status: "success",
1063
+ message: "App created. clientSecret only shown once \u2014 store it now.",
1064
+ app: d.createApp.app,
1065
+ clientSecret: d.createApp.clientSecret
1066
+ });
1067
+ } catch (e) {
1068
+ return err2(ctx, "auth_apps_create", "Failed to create app", e);
1069
+ }
1070
+ }
1071
+ );
1072
+ server.registerTool(
1073
+ track(mcpToolName(ctx.productName, "auth_apps_update")),
1074
+ {
1075
+ title: "Update App",
1076
+ description: "Update an app (name, description, redirect URIs, scopes, status).",
1077
+ inputSchema: {
1078
+ id: z.string().describe("App ID"),
1079
+ name: z.string().optional(),
1080
+ description: z.string().optional(),
1081
+ redirectUris: z.array(z.string()).optional(),
1082
+ scopes: z.array(z.string()).optional(),
1083
+ status: z.string().optional().describe("Status (e.g. ACTIVE, INACTIVE)")
1084
+ }
1085
+ },
1086
+ async ({ id, name, description, redirectUris, scopes, status }) => {
1087
+ try {
1088
+ const input = {};
1089
+ if (name !== void 0) input.name = name;
1090
+ if (description !== void 0) input.description = description;
1091
+ if (redirectUris !== void 0) input.redirectUris = redirectUris;
1092
+ if (scopes !== void 0) input.scopes = scopes;
1093
+ if (status !== void 0) input.status = status.toUpperCase();
1094
+ if (Object.keys(input).length === 0) {
1095
+ return errorResult("No updates specified \u2014 provide at least one field.");
1096
+ }
1097
+ const d = await ctx.gql.global.request(
1098
+ UPDATE_APP,
1099
+ { id, input }
1100
+ );
1101
+ return jsonResult({ status: "success", app: d.updateApp });
1102
+ } catch (e) {
1103
+ return err2(ctx, "auth_apps_update", "Failed to update app", e);
1104
+ }
1105
+ }
1106
+ );
1107
+ server.registerTool(
1108
+ track(mcpToolName(ctx.productName, "auth_apps_deactivate")),
1109
+ {
1110
+ title: "Deactivate App",
1111
+ description: "Deactivate an app by its id (revoke is not currently a separate mutation).",
1112
+ inputSchema: { id: z.string().describe("App ID") }
1113
+ },
1114
+ async ({ id }) => {
1115
+ try {
1116
+ await ctx.gql.global.request(DEACTIVATE_APP, { id });
1117
+ return jsonResult({ status: "success", message: `App ${id} deactivated.` });
1118
+ } catch (e) {
1119
+ return err2(ctx, "auth_apps_deactivate", "Failed to deactivate app", e);
1120
+ }
1121
+ }
1122
+ );
1123
+ server.registerTool(
1124
+ track(mcpToolName(ctx.productName, "auth_apps_authorize_url")),
1125
+ {
1126
+ title: "Build OAuth Authorize URL",
1127
+ 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.",
1128
+ inputSchema: {
1129
+ clientId: z.string().describe("OAuth client id"),
1130
+ redirectUri: z.string().describe("Redirect URI (must be registered)"),
1131
+ scopes: z.array(z.string()).optional(),
1132
+ state: z.string().optional().describe("Opaque state value"),
1133
+ responseType: z.string().optional().describe('Default "code"')
1134
+ }
1135
+ },
1136
+ async ({ clientId, redirectUri, scopes, state, responseType }) => {
1137
+ const cfg = ctx.config.read();
1138
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1139
+ const params = new URLSearchParams({
1140
+ client_id: clientId,
1141
+ redirect_uri: redirectUri,
1142
+ response_type: responseType ?? "code"
1143
+ });
1144
+ if (scopes && scopes.length > 0) params.set("scope", scopes.join(" "));
1145
+ if (state) params.set("state", state);
1146
+ const url = `${issuer.replace(/\/$/, "")}/oauth/authorize?${params.toString()}`;
1147
+ return jsonResult({ url });
1148
+ }
1149
+ );
1150
+ server.registerTool(
1151
+ track(mcpToolName(ctx.productName, "auth_sso_get")),
1152
+ {
1153
+ title: "Get SSO Config",
1154
+ description: "Get SSO (SAML/OIDC) configuration for a tenant.",
1155
+ inputSchema: { tenantId: z.string().describe("Tenant ID") }
1156
+ },
1157
+ async ({ tenantId }) => {
1158
+ try {
1159
+ const d = await ctx.gql.global.request(
1160
+ GET_SSO_CONFIG,
1161
+ { tenantId }
1162
+ );
1163
+ return jsonResult(d.getSSOConfig);
1164
+ } catch (e) {
1165
+ return err2(ctx, "auth_sso_get", "Failed to get SSO config", e);
1166
+ }
1167
+ }
1168
+ );
1169
+ server.registerTool(
1170
+ track(mcpToolName(ctx.productName, "auth_sso_configure")),
1171
+ {
1172
+ title: "Configure SSO",
1173
+ description: "Save (upsert) SSO configuration for a tenant.",
1174
+ inputSchema: {
1175
+ tenantId: z.string().describe("Tenant ID"),
1176
+ entityId: z.string().describe("SAML EntityID / OIDC issuer"),
1177
+ ssoUrl: z.string().describe("SSO endpoint URL"),
1178
+ sloUrl: z.string().optional().describe("SLO endpoint URL"),
1179
+ certificate: z.string().optional().describe("X.509 certificate PEM"),
1180
+ enabled: z.boolean().optional().describe("Enable after save (default false)")
1181
+ }
1182
+ },
1183
+ async ({ tenantId, entityId, ssoUrl, sloUrl, certificate, enabled }) => {
1184
+ try {
1185
+ const input = {
1186
+ entityId,
1187
+ ssoUrl,
1188
+ enabled: enabled ?? false
1189
+ };
1190
+ if (sloUrl !== void 0) input.sloUrl = sloUrl;
1191
+ if (certificate !== void 0) input.certificate = certificate;
1192
+ const d = await ctx.gql.global.request(
1193
+ SAVE_SSO_CONFIG,
1194
+ { tenantId, input }
1195
+ );
1196
+ return jsonResult({ status: "success", config: d.saveSSOConfig });
1197
+ } catch (e) {
1198
+ return err2(ctx, "auth_sso_configure", "Failed to save SSO config", e);
1199
+ }
1200
+ }
1201
+ );
1202
+ server.registerTool(
1203
+ track(mcpToolName(ctx.productName, "auth_sso_test")),
1204
+ {
1205
+ title: "Test SSO",
1206
+ 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.",
1207
+ inputSchema: { tenantId: z.string().describe("Tenant ID") }
1208
+ },
1209
+ async ({ tenantId }) => {
1210
+ const cfg = ctx.config.read();
1211
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1212
+ const url = `${issuer.replace(/\/$/, "")}/sso/${encodeURIComponent(tenantId)}/test`;
1213
+ return jsonResult({ url, message: "Open this URL in a browser to test SSO." });
1214
+ }
1215
+ );
1216
+ server.registerTool(
1217
+ track(mcpToolName(ctx.productName, "auth_sso_delete")),
1218
+ {
1219
+ title: "Delete SSO Config",
1220
+ description: "Delete SSO configuration for a tenant.",
1221
+ inputSchema: { tenantId: z.string().describe("Tenant ID") }
1222
+ },
1223
+ async ({ tenantId }) => {
1224
+ try {
1225
+ await ctx.gql.global.request(DELETE_SSO_CONFIG, { tenantId });
1226
+ return jsonResult({ status: "success", message: `SSO config for ${tenantId} deleted.` });
1227
+ } catch (e) {
1228
+ return err2(ctx, "auth_sso_delete", "Failed to delete SSO config", e);
1229
+ }
1230
+ }
1231
+ );
1232
+ server.registerTool(
1233
+ track(mcpToolName(ctx.productName, "auth_users_list")),
1234
+ {
1235
+ title: "List Users (admin)",
1236
+ description: "List users with optional filters. Requires admin permission.",
1237
+ inputSchema: {
1238
+ email: z.string().optional(),
1239
+ username: z.string().optional(),
1240
+ role: z.string().optional(),
1241
+ status: z.string().optional(),
1242
+ search: z.string().optional(),
1243
+ limit: z.number().optional(),
1244
+ offset: z.number().optional()
1245
+ }
1246
+ },
1247
+ async ({ email, username, role, status, search, limit, offset }) => {
1248
+ try {
1249
+ const filter = {};
1250
+ if (email !== void 0) filter.email = email;
1251
+ if (username !== void 0) filter.username = username;
1252
+ if (role !== void 0) filter.role = role.toUpperCase();
1253
+ if (status !== void 0) filter.status = status.toUpperCase();
1254
+ if (search !== void 0) filter.search = search;
1255
+ const d = await ctx.gql.global.request(LIST_USERS, {
1256
+ filter: Object.keys(filter).length > 0 ? filter : void 0,
1257
+ pagination: { limit: limit ?? 50, offset: offset ?? 0 }
1258
+ });
1259
+ return jsonResult({
1260
+ users: d.users.users,
1261
+ totalCount: d.users.totalCount,
1262
+ hasMore: d.users.hasMore
1263
+ });
1264
+ } catch (e) {
1265
+ return err2(ctx, "auth_users_list", "Failed to list users", e);
1266
+ }
1267
+ }
1268
+ );
1269
+ server.registerTool(
1270
+ track(mcpToolName(ctx.productName, "auth_users_get")),
1271
+ {
1272
+ title: "Get User (admin)",
1273
+ description: "Get a user by id. Requires admin permission.",
1274
+ inputSchema: { id: z.string().describe("User ID") }
1275
+ },
1276
+ async ({ id }) => {
1277
+ try {
1278
+ const d = await ctx.gql.global.request(GET_USER, { id });
1279
+ if (!d.user) {
1280
+ return errorResult(`User ${id} not found.`);
1281
+ }
1282
+ return jsonResult(d.user);
1283
+ } catch (e) {
1284
+ return err2(ctx, "auth_users_get", "Failed to get user", e);
1285
+ }
1286
+ }
1287
+ );
1288
+ server.registerTool(
1289
+ track(mcpToolName(ctx.productName, "auth_users_invite")),
1290
+ {
1291
+ title: "Invite User (admin)",
1292
+ description: "Send an invitation email to a new user.",
1293
+ inputSchema: {
1294
+ email: z.string().describe("Invitee email"),
1295
+ role: z.string().optional().describe("Role to assign on accept"),
1296
+ firstName: z.string().optional(),
1297
+ lastName: z.string().optional(),
1298
+ workspaceIds: z.array(z.string()).optional()
1299
+ }
1300
+ },
1301
+ async ({ email, role, firstName, lastName, workspaceIds }) => {
1302
+ try {
1303
+ const input = { email };
1304
+ if (role !== void 0) input.role = role.toUpperCase();
1305
+ if (firstName !== void 0) input.firstName = firstName;
1306
+ if (lastName !== void 0) input.lastName = lastName;
1307
+ if (workspaceIds !== void 0) input.workspaceIds = workspaceIds;
1308
+ const d = await ctx.gql.global.request(
1309
+ INVITE_USER,
1310
+ { input }
1311
+ );
1312
+ return jsonResult({ status: "success", invitation: d.inviteUser });
1313
+ } catch (e) {
1314
+ return err2(ctx, "auth_users_invite", "Failed to invite user", e);
1315
+ }
1316
+ }
1317
+ );
1318
+ server.registerTool(
1319
+ track(mcpToolName(ctx.productName, "auth_users_update")),
1320
+ {
1321
+ title: "Update User (admin)",
1322
+ description: "Update a user (admin). Pass any subset of mutable fields.",
1323
+ inputSchema: {
1324
+ id: z.string().describe("User ID"),
1325
+ firstName: z.string().optional(),
1326
+ lastName: z.string().optional(),
1327
+ username: z.string().optional(),
1328
+ phoneNumber: z.string().optional(),
1329
+ role: z.string().optional(),
1330
+ status: z.string().optional(),
1331
+ emailVerified: z.boolean().optional()
1332
+ }
1333
+ },
1334
+ async ({ id, firstName, lastName, username, phoneNumber, role, status, emailVerified }) => {
1335
+ try {
1336
+ const input = {};
1337
+ if (firstName !== void 0) input.firstName = firstName;
1338
+ if (lastName !== void 0) input.lastName = lastName;
1339
+ if (username !== void 0) input.username = username;
1340
+ if (phoneNumber !== void 0) input.phoneNumber = phoneNumber;
1341
+ if (role !== void 0) input.role = role.toUpperCase();
1342
+ if (status !== void 0) input.status = status.toUpperCase();
1343
+ if (emailVerified !== void 0) input.emailVerified = emailVerified;
1344
+ if (Object.keys(input).length === 0) {
1345
+ return errorResult("No updates specified \u2014 provide at least one field.");
1346
+ }
1347
+ const d = await ctx.gql.global.request(UPDATE_USER, {
1348
+ id,
1349
+ input
1350
+ });
1351
+ return jsonResult({ status: "success", user: d.updateUser });
1352
+ } catch (e) {
1353
+ return err2(ctx, "auth_users_update", "Failed to update user", e);
1354
+ }
1355
+ }
1356
+ );
1357
+ server.registerTool(
1358
+ track(mcpToolName(ctx.productName, "auth_security_summary")),
1359
+ {
1360
+ title: "Account Security Summary",
1361
+ description: "One-shot account security overview: profile, MFA methods, active sessions, recent audit log, API keys, delegations.",
1362
+ inputSchema: {
1363
+ recentLimit: z.number().optional().describe("How many recent audit events / sessions to include (default 10)")
1364
+ }
1365
+ },
1366
+ async ({ recentLimit }) => {
1367
+ const limit = recentLimit ?? 10;
1368
+ const pagination = { limit, offset: 0 };
1369
+ const summary = {};
1370
+ try {
1371
+ const profile = await ctx.gql.global.request(CURRENT_USER).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1372
+ summary.profile = profile;
1373
+ const mfa = await ctx.gql.global.request(CURRENT_USER_MFA_METHODS, { pagination }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1374
+ summary.mfa = mfa;
1375
+ const sessions = await ctx.gql.global.request(ACTIVE_SESSIONS, {
1376
+ pagination
1377
+ }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1378
+ summary.sessions = sessions;
1379
+ const audit = await ctx.gql.global.request(AUTH_AUDIT_LOGS, {
1380
+ pagination
1381
+ }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1382
+ summary.auditLog = audit;
1383
+ const keys = await ctx.gql.global.request(MY_API_KEYS, {
1384
+ pagination
1385
+ }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1386
+ summary.apiKeys = keys;
1387
+ const delegations = await ctx.gql.global.request(CURRENT_USER_DELEGATIONS, { pagination }).catch((e) => ({ error: e instanceof Error ? e.message : String(e) }));
1388
+ summary.delegations = delegations;
1389
+ return jsonResult(summary);
1390
+ } catch (e) {
1391
+ return err2(ctx, "auth_security_summary", "Failed to build security summary", e);
1392
+ }
1393
+ }
1394
+ );
1395
+ server.registerTool(
1396
+ track(mcpToolName(ctx.productName, "auth_register_get_url")),
1397
+ {
1398
+ title: "Build Registration URL",
1399
+ description: "Build the registration URL (browser-only flow). Returns the URL to open in a browser; this tool does not perform any server call.",
1400
+ inputSchema: {
1401
+ email: z.string().optional().describe("Pre-fill the email field")
1402
+ }
1403
+ },
1404
+ async ({ email }) => {
1405
+ const cfg = ctx.config.read();
1406
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1407
+ const params = new URLSearchParams();
1408
+ if (email) params.set("email", email);
1409
+ const qs = params.toString();
1410
+ const url = `${issuer.replace(/\/$/, "")}/register${qs ? `?${qs}` : ""}`;
1411
+ return jsonResult({ url });
1412
+ }
1413
+ );
1414
+ server.registerTool(
1415
+ track(mcpToolName(ctx.productName, "auth_reset_password_get_url")),
1416
+ {
1417
+ title: "Build Password Reset URL",
1418
+ 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.",
1419
+ inputSchema: {
1420
+ email: z.string().optional().describe("Pre-fill the email field")
1421
+ }
1422
+ },
1423
+ async ({ email }) => {
1424
+ const cfg = ctx.config.read();
1425
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1426
+ const params = new URLSearchParams();
1427
+ if (email) params.set("email", email);
1428
+ const qs = params.toString();
1429
+ const url = `${issuer.replace(/\/$/, "")}/reset-password${qs ? `?${qs}` : ""}`;
1430
+ return jsonResult({ url });
1431
+ }
1432
+ );
1433
+ server.registerTool(
1434
+ track(mcpToolName(ctx.productName, "auth_magic_link_get_url")),
1435
+ {
1436
+ title: "Build Magic-Link URL",
1437
+ 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.",
1438
+ inputSchema: {
1439
+ email: z.string().describe("Email to send the magic link to")
1440
+ }
1441
+ },
1442
+ async ({ email }) => {
1443
+ const cfg = ctx.config.read();
1444
+ const issuer = ctx.env === "prod" ? ctx.defaults.oidcIssuerProd ?? cfg.globalEndpoint.replace("/graphql", "") : cfg.globalEndpoint.replace("/graphql", "");
1445
+ const params = new URLSearchParams({ email });
1446
+ const url = `${issuer.replace(/\/$/, "")}/magic-link?${params.toString()}`;
1447
+ return jsonResult({ url });
1448
+ }
1449
+ );
1450
+ }
425
1451
 
426
1452
  // src/modules/auth/index.ts
427
1453
  var authModule = {
@@ -437,6 +1463,7 @@ var authModule = {
437
1463
  };
438
1464
  registerAuthTools(server, ctx, track);
439
1465
  registerAuthMoreTools(server, ctx, track);
1466
+ registerAuthExtraTools(server, ctx, track);
440
1467
  return { tools, resources: [], prompts: [] };
441
1468
  }
442
1469
  };