Skip to main content
Glama
auth.tools.ts6.17 kB
import { Injectable } from '@nestjs/common'; import { Tool } from '@rekog/mcp-nest'; import { z } from 'zod'; import { AuthService } from './auth.service'; import { ApiClientService } from '@/shared/http/api-client.service'; import { ResponseUtil } from '@/common/utils/response.util'; /** * MCP Tools for user authentication * Provides comprehensive tool for user info, projects, and modules */ @Injectable() export class AuthTools { constructor( private readonly authService: AuthService, private readonly apiClient: ApiClientService, ) {} @Tool({ name: 'whoami', description: 'Get current authenticated user information with automatically fetched projects and modules. Returns user details (name, email, roles, manager), their assigned projects, and modules within those projects. Automatically refreshes authentication token on every call. This is the primary tool for verifying authentication and discovering available work contexts. Calls: POST /api/auth/refresh, GET /api/projects/user/{userId}, and GET /api/modules/by-project?projectId={id}', parameters: z.object({}), }) async whoami() { try { let user: any; let token: string; // Try to get existing user and token from config try { user = this.authService.getCurrentUser(); token = this.authService.getToken(); } catch (error) { // No token in config, try to login with env credentials return await this.authenticateAndFetchUserData(); } // If we have token, try to refresh it to get fresh token if (user && token) { try { const refreshedToken = await this.authService.refreshToken(); if (refreshedToken) { token = refreshedToken; // Also get updated user from config try { user = this.authService.getCurrentUser(); } catch (e) { // Continue with existing user if update fails } } } catch (error) { // Token refresh failed (possibly expired), try to re-authenticate with env credentials return await this.authenticateAndFetchUserData(); } } // Now fetch user projects and modules with the token return await this.fetchUserDataWithToken(user, token); } catch (error) { return ResponseUtil.error( `Unexpected error: ${error.message || 'Failed to retrieve user information'}`, ); } } /** * Authenticate using environment credentials and fetch user data * Called when no token exists in config or token refresh fails */ private async authenticateAndFetchUserData(): Promise<any> { const username = process.env.TIMESHEET_USERNAME; const password = process.env.TIMESHEET_PASSWORD; // Check if credentials are configured if (!username || !password) { return ResponseUtil.error( 'User not authenticated. Please configure TIMESHEET_USERNAME and TIMESHEET_PASSWORD in your MCP client environment variables.', ); } // Try to login with env credentials try { const loginResult = await this.authService.login(username, password); if (!loginResult.success || !loginResult.user) { return ResponseUtil.error( 'Authentication failed: Invalid username or password. Please verify your credentials in the MCP client configuration.', ); } // Login successful, get fresh user and token from config try { const user = this.authService.getCurrentUser(); const token = this.authService.getToken(); return await this.fetchUserDataWithToken(user, token); } catch (error) { return ResponseUtil.error( `Authentication succeeded but failed to retrieve user data: ${error.message}`, ); } } catch (error) { // Login failed const errorMessage = error.message || 'Unknown error'; if (errorMessage.includes('Invalid credentials') || errorMessage.includes('invalid')) { return ResponseUtil.error( 'Authentication failed: Invalid username or password. Please verify your TIMESHEET_USERNAME and TIMESHEET_PASSWORD in the MCP client configuration.', ); } else if (errorMessage.includes('No response') || errorMessage.includes('ECONNREFUSED')) { return ResponseUtil.error( 'Cannot connect to timesheet API. Please verify the API is accessible and check your network connection.', ); } else { return ResponseUtil.error( `Authentication error: ${errorMessage}. Please verify your credentials and API connection.`, ); } } } /** * Fetch user projects and modules with authenticated token */ private async fetchUserDataWithToken(user: any, token: string): Promise<any> { // Fetch user projects and modules let projectsResponse = null; let modulesResponse = null; try { projectsResponse = await this.apiClient.getUserProjects(user.id, token); // If user has projects, fetch modules for the first project if (projectsResponse?.data && projectsResponse.data.length > 0) { const firstProject = projectsResponse.data[0]; const projectId = firstProject.id || firstProject.project_id; if (projectId) { modulesResponse = await this.apiClient.getModules(projectId, token); } } } catch (error) { // Log error but don't fail the entire whoami call console.warn('Failed to fetch projects/modules:', error.message); } return ResponseUtil.success('✓ User authenticated successfully! (Token refreshed)', { user: { id: user.id, name: user.name, username: user.username, email: user.email, roles: user.roles || [], managerId: user.managerId, }, projects: projectsResponse?.data || [], modules: modulesResponse?.data ? modulesResponse.data.map((module: any) => ({ id: module.module_id, name: module.module_name, project_id: module.project_id, })) : [], }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arshad-khan1/Timesheet-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server