UNPKG

@asanstefanski/everhour-mcp-server

Version:

Complete Everhour API integration for Model Context Protocol (MCP) with 100% endpoint coverage

342 lines 12.4 kB
import { z } from 'zod'; // Zod schemas for input validation const ListClientsSchema = z.object({ page: z.number().optional(), limit: z.number().optional(), query: z.string().optional(), }); const GetClientSchema = z.object({ id: z.number(), }); const CreateClientSchema = z.object({ name: z.string().min(1, 'Client name is required'), businessDetails: z.object({ name: z.string().optional(), address: z.string().optional(), phone: z.string().optional(), website: z.string().optional(), }).optional(), }); const UpdateClientSchema = z.object({ id: z.number(), name: z.string().optional(), businessDetails: z.object({ name: z.string().optional(), address: z.string().optional(), phone: z.string().optional(), website: z.string().optional(), }).optional(), }); const DeleteClientSchema = z.object({ id: z.number(), }); export const clientTools = { everhour_list_clients: { name: 'everhour_list_clients', description: 'List all clients from Everhour. Supports pagination and search query.', readonly: true, operationType: 'read', affectedResources: ['clients'], inputSchema: { type: 'object', properties: { page: { type: 'number', description: 'Page number for pagination (default: 1)', }, limit: { type: 'number', description: 'Number of clients per page (default: 100)', }, query: { type: 'string', description: 'Search query to filter clients by name', }, }, }, handler: async (client, args) => { const params = ListClientsSchema.parse(args); try { const clients = await client.getClients(params); return { content: [ { type: 'text', text: JSON.stringify({ clients: clients.map(client => ({ id: client.id, name: client.name, businessDetails: client.businessDetails, projects: client.projects, createdAt: client.createdAt, updatedAt: client.updatedAt, })), total: clients.length, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error listing clients: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } }, }, everhour_get_client: { name: 'everhour_get_client', description: 'Get details of a specific client by ID.', readonly: true, operationType: 'read', affectedResources: ['clients'], inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'Client ID', }, }, required: ['id'], }, handler: async (client, args) => { const { id } = GetClientSchema.parse(args); try { const clientData = await client.getClient(id); return { content: [ { type: 'text', text: JSON.stringify({ client: { id: clientData.id, name: clientData.name, businessDetails: clientData.businessDetails, projects: clientData.projects, createdAt: clientData.createdAt, updatedAt: clientData.updatedAt, }, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error getting client: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } }, }, everhour_create_client: { name: 'everhour_create_client', description: 'Create a new client in Everhour.', readonly: false, operationType: 'write', affectedResources: ['clients'], inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Client name', }, businessDetails: { type: 'object', properties: { name: { type: 'string', description: 'Business name', }, address: { type: 'string', description: 'Business address', }, phone: { type: 'string', description: 'Business phone number', }, website: { type: 'string', description: 'Business website URL', }, }, description: 'Optional business details', }, }, required: ['name'], }, handler: async (client, args) => { const params = CreateClientSchema.parse(args); try { const clientData = await client.createClient(params); return { content: [ { type: 'text', text: JSON.stringify({ success: true, client: { id: clientData.id, name: clientData.name, businessDetails: clientData.businessDetails, projects: clientData.projects, createdAt: clientData.createdAt, }, message: `Client "${clientData.name}" created successfully`, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error creating client: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } }, }, everhour_update_client: { name: 'everhour_update_client', description: 'Update an existing client in Everhour.', readonly: false, operationType: 'write', affectedResources: ['clients'], inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'Client ID', }, name: { type: 'string', description: 'New client name', }, businessDetails: { type: 'object', properties: { name: { type: 'string', description: 'Business name', }, address: { type: 'string', description: 'Business address', }, phone: { type: 'string', description: 'Business phone number', }, website: { type: 'string', description: 'Business website URL', }, }, description: 'Business details', }, }, required: ['id'], }, handler: async (client, args) => { const { id, ...updateParams } = UpdateClientSchema.parse(args); try { const clientData = await client.updateClient(id, updateParams); return { content: [ { type: 'text', text: JSON.stringify({ success: true, client: { id: clientData.id, name: clientData.name, businessDetails: clientData.businessDetails, projects: clientData.projects, updatedAt: clientData.updatedAt, }, message: `Client "${clientData.name}" updated successfully`, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error updating client: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } }, }, everhour_delete_client: { name: 'everhour_delete_client', description: 'Delete a client from Everhour. This action cannot be undone.', readonly: false, operationType: 'delete', affectedResources: ['clients'], inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'Client ID', }, }, required: ['id'], }, handler: async (client, args) => { const { id } = DeleteClientSchema.parse(args); try { await client.deleteClient(id); return { content: [ { type: 'text', text: JSON.stringify({ success: true, message: `Client with ID "${id}" deleted successfully`, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error deleting client: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } }, }, }; //# sourceMappingURL=clients.js.map