Skip to main content
Glama
phases.ts7.85 kB
import { z } from 'zod'; import { createTool } from '../base.js'; import { floatApi } from '../../services/float-api.js'; import { phaseSchema, phasesResponseSchema } from '../../types/float.js'; // List phases with optional filtering export const listPhases = createTool( 'list-phases', 'List all phases with optional filtering by project, status, or date range', z.object({ project_id: z.number().optional().describe('Filter by project ID'), status: z .number() .optional() .describe('Filter by phase status (0=Draft, 1=Tentative, 2=Confirmed)'), start_date: z.string().optional().describe('Filter by start date (YYYY-MM-DD)'), end_date: z.string().optional().describe('Filter by end date (YYYY-MM-DD)'), active: z.number().optional().describe('Filter by active status (0=archived, 1=active)'), page: z.number().optional().describe('Page number for pagination'), 'per-page': z.number().optional().describe('Number of items per page (max 200)'), }), async (params) => { const response = await floatApi.getPaginated('/phases', params, phasesResponseSchema); return response; } ); // Get phase details export const getPhase = createTool( 'get-phase', 'Get detailed information about a specific phase', z.object({ phase_id: z.union([z.string(), z.number()]).describe('The phase ID (phase_id)'), }), async (params) => { const phase = await floatApi.get(`/phases/${params.phase_id}`, phaseSchema); return phase; } ); // Create phase export const createPhase = createTool( 'create-phase', 'Create a new phase within a project', z.object({ project_id: z.number().describe('The ID of the project this phase belongs to'), name: z.string().describe('Phase name'), start_date: z.string().describe('Phase start date (YYYY-MM-DD)'), end_date: z.string().describe('Phase end date (YYYY-MM-DD)'), status: z.number().optional().describe('Phase status (0=Draft, 1=Tentative, 2=Confirmed)'), notes: z.string().optional().describe('Phase notes and description'), non_billable: z.number().optional().describe('Non-billable flag (0=billable, 1=non-billable)'), color: z.string().optional().describe('Phase color (hex code)'), default_hourly_rate: z.string().optional().describe('Default hourly rate for this phase'), budget_total: z.number().optional().describe('Total budget for this phase'), active: z.number().optional().describe('Active status (1=active, 0=archived)'), }), async (params) => { const phase = await floatApi.post('/phases', params, phaseSchema); return phase; } ); // Update phase export const updatePhase = createTool( 'update-phase', 'Update an existing phase', z.object({ phase_id: z.union([z.string(), z.number()]).describe('The phase ID (phase_id)'), project_id: z.number().optional().describe('The ID of the project this phase belongs to'), name: z.string().optional().describe('Phase name'), start_date: z.string().optional().describe('Phase start date (YYYY-MM-DD)'), end_date: z.string().optional().describe('Phase end date (YYYY-MM-DD)'), status: z.number().optional().describe('Phase status (0=Draft, 1=Tentative, 2=Confirmed)'), notes: z.string().optional().describe('Phase notes and description'), non_billable: z.number().optional().describe('Non-billable flag (0=billable, 1=non-billable)'), color: z.string().optional().describe('Phase color (hex code)'), default_hourly_rate: z.string().optional().describe('Default hourly rate for this phase'), budget_total: z.number().optional().describe('Total budget for this phase'), active: z.number().optional().describe('Active status (1=active, 0=archived)'), }), async (params) => { const { phase_id, ...updateData } = params; const phase = await floatApi.patch(`/phases/${phase_id}`, updateData, phaseSchema); return phase; } ); // Delete phase export const deletePhase = createTool( 'delete-phase', 'Delete a phase (archives it in Float)', z.object({ phase_id: z.union([z.string(), z.number()]).describe('The phase ID (phase_id)'), }), async (params) => { await floatApi.delete(`/phases/${params.phase_id}`); return { success: true, message: 'Phase archived successfully' }; } ); // Additional helper tools for phase management // List phases by project export const listPhasesByProject = createTool( 'list-phases-by-project', 'List all phases for a specific project', z.object({ project_id: z.number().describe('The project ID to get phases for'), status: z .number() .optional() .describe('Filter by phase status (0=Draft, 1=Tentative, 2=Confirmed)'), active: z.number().optional().describe('Filter by active status (0=archived, 1=active)'), }), async (params) => { const response = await floatApi.getPaginated('/phases', params, phasesResponseSchema); return response; } ); // Get phases within date range export const getPhasesByDateRange = createTool( 'get-phases-by-date-range', 'Get phases that fall within a specific date range', z.object({ start_date: z.string().describe('Start date for the range (YYYY-MM-DD)'), end_date: z.string().describe('End date for the range (YYYY-MM-DD)'), project_id: z.number().optional().describe('Filter by project ID'), status: z .number() .optional() .describe('Filter by phase status (0=Draft, 1=Tentative, 2=Confirmed)'), }), async (params) => { const response = await floatApi.getPaginated('/phases', params, phasesResponseSchema); return response; } ); // Get active phases export const getActivePhases = createTool( 'get-active-phases', 'Get all active phases, optionally filtered by project', z.object({ project_id: z.number().optional().describe('Filter by project ID'), status: z .number() .optional() .describe('Filter by phase status (0=Draft, 1=Tentative, 2=Confirmed)'), }), async (params) => { const response = await floatApi.getPaginated( '/phases', { ...params, active: 1 }, phasesResponseSchema ); return response; } ); // Get phase dependencies (phases that depend on this phase) export const getPhaseSchedule = createTool( 'get-phase-schedule', 'Get scheduling information for phases including dependencies and timeline', z.object({ project_id: z.number().describe('The project ID to get phase schedule for'), include_tasks: z.boolean().optional().describe('Include tasks within phases'), }), async (params) => { // Get all phases for the project const phases = await floatApi.getPaginated( '/phases', { project_id: params.project_id, active: 1 }, phasesResponseSchema ); // Sort phases by start date const sortedPhases = phases.sort((a, b) => { const dateA = new Date(a.start_date || '1970-01-01'); const dateB = new Date(b.start_date || '1970-01-01'); return dateA.getTime() - dateB.getTime(); }); // If tasks are requested, we would need to fetch tasks for each phase // This would require additional API calls to /tasks?phase_id=X if (params.include_tasks) { // Note: This would require the tasks endpoint to support phase_id filtering // For now, we'll return phases only with a note about tasks return { phases: sortedPhases, note: 'To include tasks, use the list-tasks tool with phase_id parameter for each phase', }; } return { phases: sortedPhases, total_phases: sortedPhases.length, project_timeline: { earliest_start: sortedPhases.length > 0 ? sortedPhases[0]?.start_date : null, latest_end: sortedPhases.length > 0 ? sortedPhases[sortedPhases.length - 1]?.end_date : null, }, }; } );

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/asachs01/float-mcp'

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