@asanstefanski/everhour-mcp-server
Version:
Complete Everhour API integration for Model Context Protocol (MCP) with 100% endpoint coverage
157 lines • 6.44 kB
JavaScript
import { z } from 'zod';
// Zod schemas for input validation - /team/users supports props parameter
const ListUsersSchema = z.object({
props: z.array(z.string()).optional().describe('Specific user properties to return (e.g., ["id", "name", "email"])')
});
// Helper function to filter user properties based on props parameter
const filterUserProperties = (user, props) => {
if (!props || props.length === 0) {
// Return all properties if no specific props requested
return {
id: user.id,
name: user.name,
email: user.email,
headline: user.headline,
role: user.role,
status: user.status,
type: user.type,
avatarUrl: user.avatarUrl,
avatarUrlLarge: user.avatarUrlLarge,
timezone: user.timezone,
rate: user.rate,
capacity: user.capacity,
isEmailVerified: user.isEmailVerified,
enableResourcePlanner: user.enableResourcePlanner,
favorite: user.favorite,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
cost: user.cost,
costHistory: user.costHistory,
resourcePlannerAccess: user.resourcePlannerAccess,
timeTrackingPolicy: user.timeTrackingPolicy,
groups: user.groups,
budget: user.budget,
permissions: user.permissions,
};
}
// Return only requested properties
const filtered = {};
props.forEach(prop => {
if (prop in user) {
filtered[prop] = user[prop];
}
});
return filtered;
};
export const userTools = {
everhour_get_current_user: {
name: 'everhour_get_current_user',
description: 'Get the current user profile using the /me endpoint.',
readonly: true,
operationType: 'read',
affectedResources: ['users'],
inputSchema: {
type: 'object',
properties: {},
},
handler: async (client, args) => {
try {
const user = await client.getCurrentUser();
return {
content: [
{
type: 'text',
text: JSON.stringify({
user: {
id: user.id,
name: user.name,
email: user.email,
headline: user.headline,
role: user.role,
status: user.status,
type: user.type,
avatarUrl: user.avatarUrl,
avatarUrlLarge: user.avatarUrlLarge,
timezone: user.timezone,
rate: user.rate,
capacity: user.capacity,
isEmailVerified: user.isEmailVerified,
enableResourcePlanner: user.enableResourcePlanner,
favorite: user.favorite,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
cost: user.cost,
costHistory: user.costHistory,
resourcePlannerAccess: user.resourcePlannerAccess,
timeTrackingPolicy: user.timeTrackingPolicy,
groups: user.groups,
budget: user.budget,
permissions: user.permissions,
},
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting current user: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
},
everhour_list_team_users: {
name: 'everhour_list_team_users',
description: 'List all team users using the /team/users endpoint. Supports selective property filtering via props parameter.',
readonly: true,
operationType: 'read',
affectedResources: ['users'],
inputSchema: {
type: 'object',
properties: {
props: {
type: 'array',
items: {
type: 'string'
},
description: 'Specific user properties to return. Available properties: id, name, email, headline, role, status, type, avatarUrl, avatarUrlLarge, timezone, rate, capacity, isEmailVerified, enableResourcePlanner, favorite, createdAt, updatedAt, cost, costHistory, resourcePlannerAccess, timeTrackingPolicy, groups, budget, permissions'
}
},
},
handler: async (client, args) => {
const params = ListUsersSchema.parse(args);
try {
const users = await client.getUsers(params);
return {
content: [
{
type: 'text',
text: JSON.stringify({
users: users.map(user => filterUserProperties(user, params.props)),
total: users.length,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error listing team users: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
},
};
//# sourceMappingURL=users.js.map