import { Injectable } from '@nestjs/common';
import { Tool } from '@rekog/mcp-nest';
import { z } from 'zod';
import { AuthService } from '@/auth/auth.service';
import { DailyUpdatesService } from './daily-updates.service';
import { ResponseUtil } from '@/common/utils/response.util';
/**
* MCP Tools for daily standup/scrum updates
* Provides descriptive tool name for LLM decision making:
* - create_daily_scrum_standup_update: Create a daily standup update with progress, priorities, and blockers
*/
@Injectable()
export class DailyUpdatesTools {
constructor(
private readonly authService: AuthService,
private readonly dailyUpdatesService: DailyUpdatesService,
) {}
/**
* Authenticate using environment credentials if no token exists
*/
private async ensureAuthenticated(): Promise<{ user: any; token: string } | null> {
try {
// Try to get existing token
let user = this.authService.getCurrentUser();
let token = this.authService.getToken();
// Try to refresh token
try {
const refreshedToken = await this.authService.refreshToken();
if (refreshedToken) {
token = refreshedToken;
try {
user = this.authService.getCurrentUser();
} catch (e) {
// Continue with existing user
}
}
} catch (error) {
// Token refresh failed, try to login with env credentials
return await this.authenticateWithEnvCredentials();
}
return { user, token };
} catch (error) {
// No token in config, try to login with env credentials
return await this.authenticateWithEnvCredentials();
}
}
/**
* Authenticate using environment variables
*/
private async authenticateWithEnvCredentials(): Promise<{ user: any; token: string } | null> {
const username = process.env.TIMESHEET_USERNAME;
const password = process.env.TIMESHEET_PASSWORD;
if (!username || !password) {
return null;
}
try {
const loginResult = await this.authService.login(username, password);
if (!loginResult.success || !loginResult.user) {
return null;
}
try {
const user = this.authService.getCurrentUser();
const token = this.authService.getToken();
return { user, token };
} catch (error) {
return null;
}
} catch (error) {
return null;
}
}
@Tool({
name: 'create_daily_scrum_standup_update',
description:
'Create a daily scrum standup update to report yesterday\'s progress, today\'s priorities, and any blockers or impediments. This tool helps track daily work progress and team communication. Automatically handles authentication with fresh token. Calls: POST /api/daily-updates/create',
parameters: z.object({
date: z.string().describe('Date in yyyy-MM-dd format (e.g., 2025-11-04)'),
yesterdays_progress: z
.string()
.describe('Summary of work completed yesterday - what was accomplished'),
todays_priorities: z
.string()
.describe('Main priorities and goals for today - what you plan to work on'),
task_blockers: z
.string()
.describe('Any blockers, impediments, or issues preventing progress - or "None" if no blockers'),
}),
})
async createDailyScrumStandupUpdate(params: {
date: string;
yesterdays_progress: string;
todays_priorities: string;
task_blockers: string;
}) {
try {
const auth = await this.ensureAuthenticated();
if (!auth || !auth.user || !auth.token) {
const username = process.env.TIMESHEET_USERNAME;
const password = process.env.TIMESHEET_PASSWORD;
if (!username || !password) {
return ResponseUtil.error(
'User not authenticated. Please configure TIMESHEET_USERNAME and TIMESHEET_PASSWORD in your MCP client environment variables.',
);
}
return ResponseUtil.error(
'Authentication failed: Invalid username or password. Please verify your credentials in the MCP client configuration.',
);
}
const result = await this.dailyUpdatesService.createDailyScrumUpdate(params);
return ResponseUtil.success(
'✓ Daily scrum standup update created successfully!',
result,
);
} catch (error) {
return ResponseUtil.error(
error.message || 'Failed to create daily scrum update',
);
}
}
}