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
JavaScript
#!/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