UNPKG

keycloak-mcp-server

Version:

A comprehensive Model Context Protocol server for Keycloak administration, providing 80+ tools to manage users, realms, clients, roles, groups, sessions, events, organizations, protocol mappers, user attributes, client scopes, and identity providers direc

1,298 lines 132 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListToolsRequestSchema, CallToolRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js"; import KcAdminClient from '@keycloak/keycloak-admin-client'; import { z } from 'zod'; // Environment variables const KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'http://localhost:8080'; const KEYCLOAK_ADMIN = process.env.KEYCLOAK_ADMIN || 'admin'; const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD || 'admin'; class KeycloakAdminManager { authConfig; baseUrl; constructor() { this.baseUrl = KEYCLOAK_URL; this.authConfig = { username: KEYCLOAK_ADMIN, password: KEYCLOAK_ADMIN_PASSWORD, grantType: 'password', clientId: 'admin-cli' }; } /** * Create a fresh admin client for each request with retry logic * This prevents token expiration and connection staleness issues */ async createFreshClient() { const maxRetries = 2; let lastError = null; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { console.error(`Creating fresh Keycloak client (attempt ${attempt}/${maxRetries})`); const client = new KcAdminClient({ baseUrl: this.baseUrl, requestOptions: { // Connection pooling settings for better performance headers: { 'Connection': 'close', // Force new connections to avoid stale connections } } }); // Authenticate with fresh session console.error('Authenticating with Keycloak server...'); await client.auth(this.authConfig); console.error('✅ Fresh Keycloak client created and authenticated successfully'); return client; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); console.error(`❌ Attempt ${attempt} failed:`, lastError.message); // If it's the last attempt, don't wait if (attempt < maxRetries) { // Wait before retry with exponential backoff const waitTime = Math.min(1000 * Math.pow(2, attempt - 1), 3000); console.error(`Waiting ${waitTime}ms before retry...`); await new Promise(resolve => setTimeout(resolve, waitTime)); } } } console.error('All authentication attempts failed'); throw new McpError(ErrorCode.InternalError, `Keycloak authentication failed after ${maxRetries} attempts: ${lastError?.message || 'Unknown error'}`); } /** * Execute an operation with a fresh client and comprehensive error handling */ async executeOperation(operation) { let client = null; const startTime = Date.now(); try { client = await this.createFreshClient(); console.error('🔧 Executing Keycloak operation...'); const result = await operation(client); const duration = Date.now() - startTime; console.error(`✅ Operation completed successfully in ${duration}ms`); return result; } catch (error) { const duration = Date.now() - startTime; console.error(`❌ Keycloak operation failed after ${duration}ms:`, error); // Handle specific Keycloak errors with comprehensive coverage based on research if (error instanceof Error) { const errorMsg = error.message.toLowerCase(); if (errorMsg.includes('network response was not ok')) { throw new McpError(ErrorCode.InternalError, 'Keycloak server connection failed. The server may be temporarily unavailable or experiencing network issues. Please check server status and try again in a moment.'); } if (errorMsg.includes('401') || errorMsg.includes('unauthorized')) { throw new McpError(ErrorCode.InternalError, 'Keycloak authentication failed. Please verify admin credentials and permissions.'); } if (errorMsg.includes('timeout') || errorMsg.includes('etimedout') || errorMsg.includes('econnreset')) { throw new McpError(ErrorCode.InternalError, 'Keycloak server timeout or connection reset. The server may be under load. Please try again.'); } if (errorMsg.includes('econnrefused') || errorMsg.includes('enotfound')) { throw new McpError(ErrorCode.InternalError, 'Cannot connect to Keycloak server. Please verify the server URL and ensure the server is running.'); } if (errorMsg.includes('403') || errorMsg.includes('forbidden')) { throw new McpError(ErrorCode.InternalError, 'Access denied. The admin user may lack sufficient permissions for this operation.'); } if (errorMsg.includes('ssl') || errorMsg.includes('certificate') || errorMsg.includes('handshake')) { throw new McpError(ErrorCode.InternalError, 'SSL/TLS connection error. Please check certificate configuration and trust settings.'); } } throw new McpError(ErrorCode.InternalError, `Keycloak operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { // Clean up - let garbage collection handle the client client = null; } } } // Global admin manager instance const adminManager = new KeycloakAdminManager(); // Zod schemas for all tools const CreateUserSchema = z.object({ realm: z.string(), username: z.string(), email: z.string().email(), firstName: z.string(), lastName: z.string(), }); const DeleteUserSchema = z.object({ realm: z.string(), userId: z.string(), }); const ListRealmsSchema = z.object({ random_string: z.string().optional(), }); const ListUsersSchema = z.object({ realm: z.string(), }); const UpdateUserSchema = z.object({ realm: z.string(), userId: z.string(), username: z.string().optional(), email: z.string().email().optional(), firstName: z.string().optional(), lastName: z.string().optional(), enabled: z.boolean().optional(), }); const GetUserSchema = z.object({ realm: z.string(), userId: z.string(), }); const ResetUserPasswordSchema = z.object({ realm: z.string(), userId: z.string(), newPassword: z.string(), temporary: z.boolean().optional(), }); const SearchUsersSchema = z.object({ realm: z.string(), search: z.string().optional(), username: z.string().optional(), email: z.string().optional(), firstName: z.string().optional(), lastName: z.string().optional(), max: z.number().optional(), }); const ListRolesSchema = z.object({ realm: z.string(), }); const AssignRoleToUserSchema = z.object({ realm: z.string(), userId: z.string(), roleName: z.string(), }); const RemoveRoleFromUserSchema = z.object({ realm: z.string(), userId: z.string(), roleName: z.string(), }); const GetUserRolesSchema = z.object({ realm: z.string(), userId: z.string(), }); const LogoutUserSchema = z.object({ realm: z.string(), userId: z.string(), }); const CreateRealmSchema = z.object({ realm: z.string(), displayName: z.string().optional(), enabled: z.boolean().optional(), }); const UpdateRealmSchema = z.object({ realm: z.string(), displayName: z.string().optional(), enabled: z.boolean().optional(), }); const DeleteRealmSchema = z.object({ realm: z.string(), }); const GetRealmSettingsSchema = z.object({ realm: z.string(), }); const CreateClientSchema = z.object({ realm: z.string(), clientId: z.string(), name: z.string().optional(), description: z.string().optional(), enabled: z.boolean().optional(), publicClient: z.boolean().optional(), redirectUris: z.array(z.string()).optional(), }); const UpdateClientSchema = z.object({ realm: z.string(), clientId: z.string(), name: z.string().optional(), description: z.string().optional(), enabled: z.boolean().optional(), publicClient: z.boolean().optional(), redirectUris: z.array(z.string()).optional(), }); const DeleteClientSchema = z.object({ realm: z.string(), clientId: z.string(), }); const ListClientsSchema = z.object({ realm: z.string(), }); const CreateRoleSchema = z.object({ realm: z.string(), roleName: z.string(), description: z.string().optional(), clientId: z.string().optional(), }); const UpdateRoleSchema = z.object({ realm: z.string(), roleName: z.string(), newName: z.string().optional(), description: z.string().optional(), clientId: z.string().optional(), }); const DeleteRoleSchema = z.object({ realm: z.string(), roleName: z.string(), clientId: z.string().optional(), }); const CreateGroupSchema = z.object({ realm: z.string(), name: z.string(), parentId: z.string().optional(), }); const UpdateGroupSchema = z.object({ realm: z.string(), groupId: z.string(), name: z.string().optional(), }); const DeleteGroupSchema = z.object({ realm: z.string(), groupId: z.string(), }); const ListGroupsSchema = z.object({ realm: z.string(), }); const ManageUserGroupsSchema = z.object({ realm: z.string(), userId: z.string(), groupId: z.string(), action: z.enum(['add', 'remove']), }); const ListSessionsSchema = z.object({ realm: z.string(), clientId: z.string().optional(), }); const GetUserSessionsSchema = z.object({ realm: z.string(), userId: z.string(), }); const ListEventsSchema = z.object({ realm: z.string(), type: z.string().optional(), max: z.number().optional(), }); const ClearEventsSchema = z.object({ realm: z.string(), }); // Protocol Mappers schemas const CreateProtocolMapperSchema = z.object({ realm: z.string(), clientId: z.string(), name: z.string(), protocol: z.string(), protocolMapper: z.string(), config: z.record(z.string()).optional(), }); const CreateClientScopeProtocolMapperSchema = z.object({ realm: z.string(), clientScopeId: z.string(), name: z.string(), protocol: z.string(), protocolMapper: z.string(), config: z.record(z.string()).optional(), }); const ListProtocolMappersSchema = z.object({ realm: z.string(), clientId: z.string(), }); const ListClientScopeProtocolMappersSchema = z.object({ realm: z.string(), clientScopeId: z.string(), }); const UpdateProtocolMapperSchema = z.object({ realm: z.string(), clientId: z.string(), mapperId: z.string(), name: z.string(), protocol: z.string(), protocolMapper: z.string(), config: z.record(z.string()).optional(), }); const UpdateClientScopeProtocolMapperSchema = z.object({ realm: z.string(), clientScopeId: z.string(), mapperId: z.string(), name: z.string(), protocol: z.string(), protocolMapper: z.string(), config: z.record(z.string()).optional(), }); const DeleteProtocolMapperSchema = z.object({ realm: z.string(), clientId: z.string(), mapperId: z.string(), }); const DeleteClientScopeProtocolMapperSchema = z.object({ realm: z.string(), clientScopeId: z.string(), mapperId: z.string(), }); // User Attributes schemas const SetUserAttributesSchema = z.object({ realm: z.string(), userId: z.string(), attributes: z.record(z.array(z.string())), }); const GetUserAttributesSchema = z.object({ realm: z.string(), userId: z.string(), }); // Client Scopes schemas const CreateClientScopeSchema = z.object({ realm: z.string(), name: z.string(), description: z.string().optional(), protocol: z.string().optional(), attributes: z.record(z.string()).optional(), }); const UpdateClientScopeSchema = z.object({ realm: z.string(), clientScopeId: z.string(), name: z.string().optional(), description: z.string().optional(), protocol: z.string().optional(), attributes: z.record(z.string()).optional(), }); const DeleteClientScopeSchema = z.object({ realm: z.string(), clientScopeId: z.string(), }); const ListClientScopesSchema = z.object({ realm: z.string(), }); const GetClientScopeSchema = z.object({ realm: z.string(), clientScopeId: z.string(), }); // Organizations schemas const CreateOrganizationSchema = z.object({ realm: z.string(), name: z.string(), description: z.string().optional(), enabled: z.boolean().optional(), attributes: z.record(z.array(z.string())).optional(), }); const UpdateOrganizationSchema = z.object({ realm: z.string(), orgId: z.string(), name: z.string().optional(), description: z.string().optional(), enabled: z.boolean().optional(), attributes: z.record(z.array(z.string())).optional(), }); const DeleteOrganizationSchema = z.object({ realm: z.string(), orgId: z.string(), }); const ListOrganizationsSchema = z.object({ realm: z.string(), search: z.string().optional(), first: z.number().optional(), max: z.number().optional(), }); const GetOrganizationSchema = z.object({ realm: z.string(), orgId: z.string(), }); const AddOrganizationMemberSchema = z.object({ realm: z.string(), orgId: z.string(), userId: z.string(), }); const RemoveOrganizationMemberSchema = z.object({ realm: z.string(), orgId: z.string(), userId: z.string(), }); const ListOrganizationMembersSchema = z.object({ realm: z.string(), orgId: z.string(), search: z.string().optional(), first: z.number().optional(), max: z.number().optional(), }); // Advanced Role Management schemas const CreateCompositeRoleSchema = z.object({ realm: z.string(), roleId: z.string(), roles: z.array(z.object({ id: z.string(), name: z.string(), })), }); const GetCompositeRolesSchema = z.object({ realm: z.string(), roleId: z.string(), search: z.string().optional(), first: z.number().optional(), max: z.number().optional(), }); const DeleteCompositeRolesSchema = z.object({ realm: z.string(), roleId: z.string(), roles: z.array(z.object({ id: z.string(), name: z.string(), })), }); const GetRoleByIdSchema = z.object({ realm: z.string(), roleId: z.string(), }); const UpdateRoleByIdSchema = z.object({ realm: z.string(), roleId: z.string(), name: z.string().optional(), description: z.string().optional(), composite: z.boolean().optional(), clientRole: z.boolean().optional(), containerId: z.string().optional(), attributes: z.record(z.array(z.string())).optional(), }); const DeleteRoleByIdSchema = z.object({ realm: z.string(), roleId: z.string(), }); const FindUsersWithRoleSchema = z.object({ realm: z.string(), roleName: z.string(), first: z.number().optional(), max: z.number().optional(), }); const AssignRoleToGroupSchema = z.object({ realm: z.string(), groupId: z.string(), roleName: z.string(), }); const RemoveRoleFromGroupSchema = z.object({ realm: z.string(), groupId: z.string(), roleName: z.string(), }); const GetGroupRolesSchema = z.object({ realm: z.string(), groupId: z.string(), }); const ListAvailableGroupRolesSchema = z.object({ realm: z.string(), groupId: z.string(), }); const ListCompositeGroupRolesSchema = z.object({ realm: z.string(), groupId: z.string(), }); // Group Attributes schemas const SetGroupAttributesSchema = z.object({ realm: z.string(), groupId: z.string(), attributes: z.record(z.array(z.string())), }); const GetGroupAttributesSchema = z.object({ realm: z.string(), groupId: z.string(), }); const CreateChildGroupSchema = z.object({ realm: z.string(), parentGroupId: z.string(), name: z.string(), attributes: z.record(z.array(z.string())).optional(), }); const ListSubGroupsSchema = z.object({ realm: z.string(), parentGroupId: z.string(), search: z.string().optional(), first: z.number().optional(), max: z.number().optional(), }); const ListGroupMembersSchema = z.object({ realm: z.string(), groupId: z.string(), first: z.number().optional(), max: z.number().optional(), }); // Identity Providers schemas const CreateIdentityProviderSchema = z.object({ realm: z.string(), alias: z.string(), displayName: z.string().optional(), providerId: z.string(), enabled: z.boolean().optional(), trustEmail: z.boolean().optional(), storeToken: z.boolean().optional(), addReadTokenRoleOnCreate: z.boolean().optional(), linkOnly: z.boolean().optional(), firstBrokerLoginFlowAlias: z.string().optional(), config: z.record(z.string()).optional(), }); const UpdateIdentityProviderSchema = z.object({ realm: z.string(), alias: z.string(), displayName: z.string().optional(), providerId: z.string().optional(), enabled: z.boolean().optional(), trustEmail: z.boolean().optional(), storeToken: z.boolean().optional(), addReadTokenRoleOnCreate: z.boolean().optional(), linkOnly: z.boolean().optional(), firstBrokerLoginFlowAlias: z.string().optional(), config: z.record(z.string()).optional(), }); const DeleteIdentityProviderSchema = z.object({ realm: z.string(), alias: z.string(), }); const ListIdentityProvidersSchema = z.object({ realm: z.string(), search: z.string().optional(), first: z.number().optional(), max: z.number().optional(), }); const GetIdentityProviderSchema = z.object({ realm: z.string(), alias: z.string(), }); const CreateIdentityProviderMapperSchema = z.object({ realm: z.string(), alias: z.string(), name: z.string(), identityProviderMapper: z.string(), config: z.record(z.string()).optional(), }); const UpdateIdentityProviderMapperSchema = z.object({ realm: z.string(), alias: z.string(), mapperId: z.string(), name: z.string(), identityProviderMapper: z.string(), config: z.record(z.string()).optional(), }); const DeleteIdentityProviderMapperSchema = z.object({ realm: z.string(), alias: z.string(), mapperId: z.string(), }); const ListIdentityProviderMappersSchema = z.object({ realm: z.string(), alias: z.string(), }); const GetIdentityProviderMapperSchema = z.object({ realm: z.string(), alias: z.string(), mapperId: z.string(), }); const ListIdentityProviderMapperTypesSchema = z.object({ realm: z.string(), alias: z.string(), }); const ImportIdentityProviderFromUrlSchema = z.object({ realm: z.string(), providerId: z.string(), fromUrl: z.string(), }); // Additional Resources schemas const CreateComponentSchema = z.object({ realm: z.string(), name: z.string(), providerId: z.string(), providerType: z.string(), parentId: z.string().optional(), config: z.record(z.array(z.string())).optional(), }); const UpdateComponentSchema = z.object({ realm: z.string(), componentId: z.string(), name: z.string().optional(), providerId: z.string().optional(), providerType: z.string().optional(), parentId: z.string().optional(), config: z.record(z.array(z.string())).optional(), }); const DeleteComponentSchema = z.object({ realm: z.string(), componentId: z.string(), }); const ListComponentsSchema = z.object({ realm: z.string(), name: z.string().optional(), parent: z.string().optional(), type: z.string().optional(), }); const GetComponentSchema = z.object({ realm: z.string(), componentId: z.string(), }); const ListComponentSubTypesSchema = z.object({ realm: z.string(), componentId: z.string(), type: z.string(), }); const GetServerInfoSchema = z.object({ dummy: z.string().optional(), }); const WhoAmISchema = z.object({ dummy: z.string().optional(), }); const GetAttackDetectionSchema = z.object({ realm: z.string(), userId: z.string(), }); const ClearAttackDetectionSchema = z.object({ realm: z.string(), userId: z.string(), }); const ClearAllAttackDetectionSchema = z.object({ realm: z.string(), }); const ClearUserCacheSchema = z.object({ realm: z.string(), userId: z.string(), }); const ClearKeysSchema = z.object({ realm: z.string(), }); const ClearRealmCacheSchema = z.object({ realm: z.string(), }); const CreateClientPolicySchema = z.object({ realm: z.string(), name: z.string(), description: z.string().optional(), enabled: z.boolean().optional(), conditions: z.array(z.any()).optional(), profiles: z.array(z.string()).optional(), }); const UpdateClientPolicySchema = z.object({ realm: z.string(), policyName: z.string(), name: z.string().optional(), description: z.string().optional(), enabled: z.boolean().optional(), conditions: z.array(z.any()).optional(), profiles: z.array(z.string()).optional(), }); const DeleteClientPolicySchema = z.object({ realm: z.string(), policyName: z.string(), }); const ListClientPoliciesSchema = z.object({ realm: z.string(), }); const GetClientPolicySchema = z.object({ realm: z.string(), policyName: z.string(), }); // Create and configure the server const server = new Server({ name: 'keycloak-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, }); // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ // User Management Tools { name: 'create-user', description: 'Create a new user in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, username: { type: 'string', description: 'Username' }, email: { type: 'string', description: 'Email address' }, firstName: { type: 'string', description: 'First name' }, lastName: { type: 'string', description: 'Last name' }, }, required: ['realm', 'username', 'email', 'firstName', 'lastName'], }, }, { name: 'delete-user', description: 'Delete a user from a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, }, required: ['realm', 'userId'], }, }, { name: 'list-users', description: 'List users in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, { name: 'update-user', description: 'Update user information in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, username: { type: 'string', description: 'Username' }, email: { type: 'string', description: 'Email address' }, firstName: { type: 'string', description: 'First name' }, lastName: { type: 'string', description: 'Last name' }, enabled: { type: 'boolean', description: 'User enabled status' }, }, required: ['realm', 'userId'], }, }, { name: 'get-user', description: 'Get user details by ID from a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, }, required: ['realm', 'userId'], }, }, { name: 'reset-user-password', description: 'Reset a user\'s password in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, newPassword: { type: 'string', description: 'New password' }, temporary: { type: 'boolean', description: 'Whether password is temporary' }, }, required: ['realm', 'userId', 'newPassword'], }, }, { name: 'search-users', description: 'Search users in a specific realm with filters', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, search: { type: 'string', description: 'Search term' }, username: { type: 'string', description: 'Username filter' }, email: { type: 'string', description: 'Email filter' }, firstName: { type: 'string', description: 'First name filter' }, lastName: { type: 'string', description: 'Last name filter' }, max: { type: 'number', description: 'Maximum results' }, }, required: ['realm'], }, }, { name: 'logout-user', description: 'Logout all sessions for a specific user', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, }, required: ['realm', 'userId'], }, }, // Realm Management Tools { name: 'list-realms', description: 'List all available realms', inputSchema: { type: 'object', properties: { random_string: { type: 'string', description: 'Dummy parameter for no-parameter tools' }, }, required: ['random_string'], }, }, { name: 'create-realm', description: 'Create a new realm with configurable settings', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, displayName: { type: 'string', description: 'Display name' }, enabled: { type: 'boolean', description: 'Enabled status' }, }, required: ['realm'], }, }, { name: 'update-realm', description: 'Update realm settings and configurations', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, displayName: { type: 'string', description: 'Display name' }, enabled: { type: 'boolean', description: 'Enabled status' }, }, required: ['realm'], }, }, { name: 'delete-realm', description: 'Delete an existing realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, { name: 'get-realm-settings', description: 'Retrieve detailed settings of a realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, // Client Management Tools { name: 'create-client', description: 'Register a new client/application in a realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, name: { type: 'string', description: 'Client name' }, description: { type: 'string', description: 'Client description' }, enabled: { type: 'boolean', description: 'Enabled status' }, publicClient: { type: 'boolean', description: 'Public client' }, redirectUris: { type: 'array', description: 'Redirect URIs' }, }, required: ['realm', 'clientId'], }, }, { name: 'update-client', description: 'Update client settings (redirect URIs, protocol mappers, etc.)', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, name: { type: 'string', description: 'Client name' }, description: { type: 'string', description: 'Client description' }, enabled: { type: 'boolean', description: 'Enabled status' }, publicClient: { type: 'boolean', description: 'Public client' }, redirectUris: { type: 'array', description: 'Redirect URIs' }, }, required: ['realm', 'clientId'], }, }, { name: 'delete-client', description: 'Remove a client from a realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, }, required: ['realm', 'clientId'], }, }, { name: 'list-clients', description: 'List all clients in a realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, // Role Management Tools { name: 'list-roles', description: 'List all roles in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, { name: 'create-role', description: 'Create roles at realm or client level', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, roleName: { type: 'string', description: 'Role name' }, description: { type: 'string', description: 'Role description' }, clientId: { type: 'string', description: 'Client ID for client roles' }, }, required: ['realm', 'roleName'], }, }, { name: 'update-role', description: 'Modify role attributes', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, roleName: { type: 'string', description: 'Current role name' }, newName: { type: 'string', description: 'New role name' }, description: { type: 'string', description: 'Role description' }, clientId: { type: 'string', description: 'Client ID for client roles' }, }, required: ['realm', 'roleName'], }, }, { name: 'delete-role', description: 'Delete roles', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, roleName: { type: 'string', description: 'Role name' }, clientId: { type: 'string', description: 'Client ID for client roles' }, }, required: ['realm', 'roleName'], }, }, { name: 'assign-role-to-user', description: 'Assign a role to a user in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, roleName: { type: 'string', description: 'Role name' }, }, required: ['realm', 'userId', 'roleName'], }, }, { name: 'remove-role-from-user', description: 'Remove a role from a user in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, roleName: { type: 'string', description: 'Role name' }, }, required: ['realm', 'userId', 'roleName'], }, }, { name: 'get-user-roles', description: 'Get all roles assigned to a user in a specific realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, }, required: ['realm', 'userId'], }, }, // Group Management Tools { name: 'create-group', description: 'Create user groups', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, name: { type: 'string', description: 'Group name' }, parentId: { type: 'string', description: 'Parent group ID' }, }, required: ['realm', 'name'], }, }, { name: 'update-group', description: 'Update group attributes', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, groupId: { type: 'string', description: 'Group ID' }, name: { type: 'string', description: 'Group name' }, }, required: ['realm', 'groupId'], }, }, { name: 'delete-group', description: 'Delete groups', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, groupId: { type: 'string', description: 'Group ID' }, }, required: ['realm', 'groupId'], }, }, { name: 'list-groups', description: 'List all groups in a realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, { name: 'manage-user-groups', description: 'Add or remove users from groups', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, groupId: { type: 'string', description: 'Group ID' }, action: { type: 'string', enum: ['add', 'remove'], description: 'Action to perform' }, }, required: ['realm', 'userId', 'groupId', 'action'], }, }, // Session & Event Management Tools { name: 'list-sessions', description: 'List all active sessions in a realm', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID filter' }, }, required: ['realm'], }, }, { name: 'get-user-sessions', description: 'List active sessions for a user', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, }, required: ['realm', 'userId'], }, }, { name: 'list-events', description: 'Retrieve authentication and admin events', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, type: { type: 'string', description: 'Event type filter' }, max: { type: 'number', description: 'Maximum results' }, }, required: ['realm'], }, }, { name: 'clear-events', description: 'Clear event logs', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, }, required: ['realm'], }, }, // Protocol Mappers Management Tools (CRITICAL for JWT organization problem) { name: 'create-protocol-mapper', description: 'Create a protocol mapper for a client (CRITICAL for JWT organization claims)', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, name: { type: 'string', description: 'Protocol mapper name' }, protocol: { type: 'string', description: 'Protocol (e.g., openid-connect)' }, protocolMapper: { type: 'string', description: 'Protocol mapper type (e.g., oidc-group-membership-mapper)' }, config: { type: 'object', description: 'Protocol mapper configuration' }, }, required: ['realm', 'clientId', 'name', 'protocol', 'protocolMapper'], }, }, { name: 'create-client-scope-protocol-mapper', description: 'Create a protocol mapper for a client scope', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientScopeId: { type: 'string', description: 'Client scope ID' }, name: { type: 'string', description: 'Protocol mapper name' }, protocol: { type: 'string', description: 'Protocol (e.g., openid-connect)' }, protocolMapper: { type: 'string', description: 'Protocol mapper type' }, config: { type: 'object', description: 'Protocol mapper configuration' }, }, required: ['realm', 'clientScopeId', 'name', 'protocol', 'protocolMapper'], }, }, { name: 'list-protocol-mappers', description: 'List protocol mappers for a client', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, }, required: ['realm', 'clientId'], }, }, { name: 'list-client-scope-protocol-mappers', description: 'List protocol mappers for a client scope', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientScopeId: { type: 'string', description: 'Client scope ID' }, }, required: ['realm', 'clientScopeId'], }, }, { name: 'update-protocol-mapper', description: 'Update a protocol mapper for a client', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, mapperId: { type: 'string', description: 'Protocol mapper ID' }, name: { type: 'string', description: 'Protocol mapper name' }, protocol: { type: 'string', description: 'Protocol' }, protocolMapper: { type: 'string', description: 'Protocol mapper type' }, config: { type: 'object', description: 'Protocol mapper configuration' }, }, required: ['realm', 'clientId', 'mapperId', 'name', 'protocol', 'protocolMapper'], }, }, { name: 'update-client-scope-protocol-mapper', description: 'Update a protocol mapper for a client scope', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientScopeId: { type: 'string', description: 'Client scope ID' }, mapperId: { type: 'string', description: 'Protocol mapper ID' }, name: { type: 'string', description: 'Protocol mapper name' }, protocol: { type: 'string', description: 'Protocol' }, protocolMapper: { type: 'string', description: 'Protocol mapper type' }, config: { type: 'object', description: 'Protocol mapper configuration' }, }, required: ['realm', 'clientScopeId', 'mapperId', 'name', 'protocol', 'protocolMapper'], }, }, { name: 'delete-protocol-mapper', description: 'Delete a protocol mapper from a client', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientId: { type: 'string', description: 'Client ID' }, mapperId: { type: 'string', description: 'Protocol mapper ID' }, }, required: ['realm', 'clientId', 'mapperId'], }, }, { name: 'delete-client-scope-protocol-mapper', description: 'Delete a protocol mapper from a client scope', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientScopeId: { type: 'string', description: 'Client scope ID' }, mapperId: { type: 'string', description: 'Protocol mapper ID' }, }, required: ['realm', 'clientScopeId', 'mapperId'], }, }, // User Attributes Management Tools (CRITICAL for organization data storage) { name: 'set-user-attributes', description: 'Set user attributes (CRITICAL for storing organization data)', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, attributes: { type: 'object', description: 'User attributes (key-value pairs where values are arrays)' }, }, required: ['realm', 'userId', 'attributes'], }, }, { name: 'get-user-attributes', description: 'Get user attributes including unmanaged attributes', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, userId: { type: 'string', description: 'User ID' }, }, required: ['realm', 'userId'], }, }, // Client Scopes Management Tools (CRITICAL for token scopes) { name: 'create-client-scope', description: 'Create a new client scope (CRITICAL for managing token scopes)', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, name: { type: 'string', description: 'Client scope name' }, description: { type: 'string', description: 'Client scope description' }, protocol: { type: 'string', description: 'Protocol (e.g., openid-connect)' }, attributes: { type: 'object', description: 'Client scope attributes' }, }, required: ['realm', 'name'], }, }, { name: 'update-client-scope', description: 'Update an existing client scope', inputSchema: { type: 'object', properties: { realm: { type: 'string', description: 'Realm name' }, clientScopeId: { type: 'string', description: 'Client scope ID' }, name: { type: 'string', desc