UNPKG

redmine-mcp-tools

Version:

A comprehensive Model Context Protocol (MCP) server for Redmine integration. Provides 25+ specialized tools for complete Redmine API access including issue management, project administration, time tracking, and user management. Built with TypeScript and d

212 lines (211 loc) 8.76 kB
import { asNumber, extractPaginationParams, ValidationError, } from "./types.js"; /** * Creates handlers for user operations */ export function createUsersHandlers(context) { const { client } = context; return { /** * Lists users with pagination and filters */ list_users: async (args) => { try { if (typeof args !== 'object' || args === null) { throw new ValidationError("Arguments must be an object"); } const argsObj = args; const { limit, offset } = extractPaginationParams(argsObj); const queryParams = { limit, offset, }; if ('status' in argsObj) queryParams.status = asNumber(argsObj.status); if ('name' in argsObj) queryParams.name = String(argsObj.name); if ('group_id' in argsObj) queryParams.group_id = asNumber(argsObj.group_id); const queryString = client.encodeQueryParams(queryParams); const url = `users.json${queryString ? '?' + queryString : ''}`; const response = await client.performRequest(url); return { content: [{ type: "text", text: `Found ${response.total_count || 0} users (showing ${response.users?.length || 0}):\n\n` + JSON.stringify(response, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error listing users: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }, /** * Get a specific user */ show_user: async (args) => { try { if (typeof args !== 'object' || args === null) { throw new ValidationError("Arguments must be an object"); } const argsObj = args; const userId = asNumber(argsObj.user_id); const queryParams = {}; if ('include' in argsObj) queryParams.include = String(argsObj.include); const queryString = client.encodeQueryParams(queryParams); const url = `users/${userId}.json${queryString ? '?' + queryString : ''}`; const response = await client.performRequest(url); return { content: [{ type: "text", text: `User #${userId}:\n\n` + JSON.stringify(response.user, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error getting user: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }, /** * Create a new user */ create_user: async (args) => { try { if (typeof args !== 'object' || args === null) { throw new ValidationError("Arguments must be an object"); } const argsObj = args; const userData = { login: String(argsObj.login), firstname: String(argsObj.firstname), lastname: String(argsObj.lastname), mail: String(argsObj.mail), }; if ('password' in argsObj) userData.password = String(argsObj.password); if ('auth_source_id' in argsObj) userData.auth_source_id = asNumber(argsObj.auth_source_id); if ('mail_notification' in argsObj) userData.mail_notification = String(argsObj.mail_notification); if ('must_change_passwd' in argsObj) userData.must_change_passwd = Boolean(argsObj.must_change_passwd); if ('generate_password' in argsObj) userData.generate_password = Boolean(argsObj.generate_password); const response = await client.performRequest('users.json', { method: 'POST', body: JSON.stringify({ user: userData }) }); return { content: [{ type: "text", text: `User created successfully:\n\n` + JSON.stringify(response.user, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error creating user: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }, /** * Update an existing user */ update_user: async (args) => { try { if (typeof args !== 'object' || args === null) { throw new ValidationError("Arguments must be an object"); } const argsObj = args; const userId = asNumber(argsObj.user_id); const userData = {}; if ('login' in argsObj) userData.login = String(argsObj.login); if ('firstname' in argsObj) userData.firstname = String(argsObj.firstname); if ('lastname' in argsObj) userData.lastname = String(argsObj.lastname); if ('mail' in argsObj) userData.mail = String(argsObj.mail); if ('password' in argsObj) userData.password = String(argsObj.password); if ('auth_source_id' in argsObj) userData.auth_source_id = asNumber(argsObj.auth_source_id); if ('mail_notification' in argsObj) userData.mail_notification = String(argsObj.mail_notification); if ('must_change_passwd' in argsObj) userData.must_change_passwd = Boolean(argsObj.must_change_passwd); if ('admin' in argsObj) userData.admin = Boolean(argsObj.admin); if ('status' in argsObj) userData.status = asNumber(argsObj.status); await client.performRequest(`users/${userId}.json`, { method: 'PUT', body: JSON.stringify({ user: userData }) }); return { content: [{ type: "text", text: `User #${userId} updated successfully` }] }; } catch (error) { return { content: [{ type: "text", text: `Error updating user: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }, /** * Delete a user */ delete_user: async (args) => { try { if (typeof args !== 'object' || args === null) { throw new ValidationError("Arguments must be an object"); } const argsObj = args; const userId = asNumber(argsObj.user_id); await client.performRequest(`users/${userId}.json`, { method: 'DELETE' }); return { content: [{ type: "text", text: `User #${userId} deleted successfully` }] }; } catch (error) { return { content: [{ type: "text", text: `Error deleting user: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }, }; }