Keycloak MCP Server
- src
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import KcAdminClient from '@keycloak/keycloak-admin-client';
import { z } from 'zod';
const server = new Server(
{
name: "keycloak-admin",
version: "0.0.1",
},
{
capabilities: {
tools: {},
},
}
);
// Initialize Keycloak client
const kcAdminClient = new KcAdminClient({
baseUrl: process.env.KEYCLOAK_URL || 'http://localhost:8080',
realmName: 'master'
});
// Tool schemas
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 ListUsersSchema = z.object({
realm: z.string()
});
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "create-user",
description: "Create a new user in a specific realm",
inputSchema: {
type: "object",
properties: {
realm: { type: "string" },
username: { type: "string" },
email: { type: "string", format: "email" },
firstName: { type: "string" },
lastName: { type: "string" }
},
required: ["realm", "username", "email", "firstName", "lastName"]
}
},
{
name: "delete-user",
description: "Delete a user from a specific realm",
inputSchema: {
type: "object",
properties: {
realm: { type: "string" },
userId: { type: "string" }
},
required: ["realm", "userId"]
}
},
{
name: "list-realms",
description: "List all available realms",
inputSchema: {
type: "object",
properties: {},
required: []
}
},
{
name: "list-users",
description: "List users in a specific realm",
inputSchema: {
type: "object",
properties: {
realm: { type: "string" }
},
required: ["realm"]
}
}
]
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
// Authenticate before each request
await kcAdminClient.auth({
username: process.env.KEYCLOAK_ADMIN || 'admin',
password: process.env.KEYCLOAK_ADMIN_PASSWORD || 'admin',
grantType: 'password',
clientId: 'admin-cli',
});
const { name, arguments: args } = request.params;
try {
switch (name) {
case "create-user": {
const { realm, username, email, firstName, lastName } = CreateUserSchema.parse(args);
kcAdminClient.setConfig({
realmName: realm
});
const user = await kcAdminClient.users.create({
realm,
username,
email,
firstName,
lastName,
enabled: true
});
return {
content: [{
type: "text",
text: `User created successfully. User ID: ${user.id}`
}]
};
}
case "delete-user": {
const { realm, userId } = DeleteUserSchema.parse(args);
kcAdminClient.setConfig({
realmName: realm
});
await kcAdminClient.users.del({
id: userId,
realm
});
return {
content: [{
type: "text",
text: `User ${userId} deleted successfully from realm ${realm}`
}]
};
}
case "list-realms": {
const realms = await kcAdminClient.realms.find();
return {
content: [{
type: "text",
text: `Available realms:\n${realms.map(r => `- ${r.realm}`).join('\n')}`
}]
};
}
case "list-users": {
const { realm } = ListUsersSchema.parse(args);
kcAdminClient.setConfig({
realmName: realm
});
const users = await kcAdminClient.users.find();
return {
content: [{
type: "text",
text: `Users in realm ${realm}:\n${users.map(u => `- ${u.username} (${u.id})`).join('\n')}`
}]
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
if (error instanceof z.ZodError) {
return {
isError: true,
content: [{
type: "text",
text: `Invalid arguments: ${error.errors.map(e => `${e.path.join(".")}: ${e.message}`).join(", ")}`
}]
};
}
throw error;
}
});
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Keycloak MCP Server running on stdio");