import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { RipplingClient } from "../clients/rippling-client.js";
import { RipplingApiError } from "../utils/errors.js";
export function registerLeaveTools(
server: McpServer,
client: RipplingClient
): void {
server.tool(
"get_leave_balances",
"Get leave balances for a specific employee including PTO, sick leave, and other leave types",
{
roleId: z
.string()
.describe("The employee's role ID to get leave balances for"),
},
async ({ roleId }) => {
try {
const balances = await client.getLeaveBalances(roleId);
return {
content: [
{
type: "text",
text: JSON.stringify(balances, null, 2),
},
],
};
} catch (error) {
if (error instanceof RipplingApiError) return error.toToolResult();
throw error;
}
}
);
server.tool(
"list_leave_requests",
"List leave requests with optional filters for status, date range, and requester",
{
status: z
.enum(["PENDING", "APPROVED", "DECLINED"])
.optional()
.describe("Filter by request status"),
startDate: z
.string()
.optional()
.describe("Filter by start date (ISO format, e.g. 2025-01-01)"),
endDate: z
.string()
.optional()
.describe("Filter by end date (ISO format, e.g. 2025-12-31)"),
requestedBy: z
.string()
.optional()
.describe("Filter by requester role ID"),
limit: z
.number()
.min(1)
.max(100)
.optional()
.describe("Max results per page (1-100, default 50)"),
offset: z
.number()
.min(0)
.optional()
.describe("Pagination offset (default 0)"),
},
async ({ status, startDate, endDate, requestedBy, limit, offset }) => {
try {
const requests = await client.listLeaveRequests({
status,
startDate,
endDate,
requestedBy,
limit,
offset,
});
return {
content: [
{
type: "text",
text: JSON.stringify(requests, null, 2),
},
],
};
} catch (error) {
if (error instanceof RipplingApiError) return error.toToolResult();
throw error;
}
}
);
server.tool(
"process_leave_request",
"Approve or decline a pending leave request",
{
requestId: z.string().describe("The leave request ID to process"),
action: z
.enum(["APPROVE", "DECLINE"])
.describe("Whether to approve or decline the request"),
},
async ({ requestId, action }) => {
try {
const result = await client.processLeaveRequest(requestId, action);
return {
content: [
{
type: "text",
text: `Leave request ${requestId} has been ${action === "APPROVE" ? "approved" : "declined"}.\n\n${JSON.stringify(result, null, 2)}`,
},
],
};
} catch (error) {
if (error instanceof RipplingApiError) return error.toToolResult();
throw error;
}
}
);
server.tool(
"list_leave_types",
"List all leave types configured for the company (PTO, sick, etc.)",
{},
async () => {
try {
const types = await client.listLeaveTypes();
return {
content: [
{
type: "text",
text: JSON.stringify(types, null, 2),
},
],
};
} catch (error) {
if (error instanceof RipplingApiError) return error.toToolResult();
throw error;
}
}
);
}