Litelead-mcp

getStaff Tool

Overview

The getStaff tool retrieves staff member records from the Firebase/Firestore database with support for pagination and sorting.

Location

tools/getStaff.js

Description

Retrieves staff members for the authenticated account with cursor-based pagination support. Staff members are employees who can be assigned to orders as technicians or responsible parties. Staff are retrieved from the Firestore path: /Accounts/{accountId}/Staff.

Input Schema

{
  limit?: number;                    // Number of records to retrieve (1-100, default: 50)
  cursor?: string;                   // Document ID for cursor-based pagination
  orderBy?: string;                  // Field to order by (default: "name")
  orderDirection?: "asc" | "desc";   // Sort direction (default: "asc")
  cursorDirection?: "next" | "previous";  // Direction for pagination (default: "next")
  includeTotal?: boolean;            // Include total count of all staff (default: false)
}

Parameters

Parameter Type Required Default Description
limit number No 50 Maximum number of staff to return (1-100)
cursor string No - Document ID to start pagination from
orderBy string No “name” Field name to sort by
orderDirection enum No “asc” Sort direction: “asc” or “desc”
cursorDirection enum No “next” Pagination direction: “next” or “previous”
includeTotal boolean No false Whether to include total count (expensive)

Output Schema

{
  staff: Staff[];
  pagination: PaginationMetadata;
}

Staff Object

{
  id: string;                    // Firestore document ID
  path: string;                  // Full Firestore path
  active?: boolean;              // Whether the staff member is active
  createdAt?: string | null;     // Creation timestamp (locale string)
  createdBy?: string;            // ID of the user who created this record
  email?: string;                // Staff member email (optional)
  mobilePhone?: string;          // Mobile phone number
  name?: string;                 // Staff member name (optional)
  ownedBy?: string;              // Owner ID
  phone?: string;                // Landline phone number
}

Note: Both name and email are optional fields. Some staff records may have only name, only email, or both.

Pagination Metadata

{
  limit: number;                 // Applied limit
  hasMore: boolean;              // Whether more results exist
  nextCursor: string | null;     // Cursor for next page
  previousCursor: string | null; // Cursor for previous page
  total?: number | null;         // Total count (if includeTotal was true)
}

Usage Examples

Basic Usage

// Get first 10 staff members
const result = await getStaff(context, {
  limit: 10
});

console.log(result.staff);         // Array of 10 staff members
console.log(result.pagination);    // Pagination metadata

Paginated Retrieval

// First page
const page1 = await getStaff(context, {
  limit: 20,
  orderBy: "name",
  orderDirection: "asc"
});

// Next page
const page2 = await getStaff(context, {
  limit: 20,
  cursor: page1.pagination.nextCursor,
  cursorDirection: "next"
});

Sort by Email

// Get staff sorted by email
const result = await getStaff(context, {
  limit: 10,
  orderBy: "email",
  orderDirection: "asc"
});

Get All Staff

// Get all staff members for dropdown/selection
const result = await getStaff(context, {
  limit: 100
});

console.log(`Found ${result.staff.length} staff members`);

With Total Count

const result = await getStaff(context, {
  limit: 10,
  includeTotal: true
});

console.log(`Account has ${result.pagination.total} total staff members`);

Find Staff by ID

// Get staff member by document ID
const allStaff = await getStaff(context, { limit: 100 });
const staffMember = allStaff.staff.find(s => s.id === "staff123");
console.log(staffMember.name, staffMember.email);

Implementation Details

Data Transformation

The tool transforms Firestore documents by:

  1. Adding the document id and full path
  2. Preserving all other fields as-is (including optional name and email)
const transformStaff = (doc) => ({
  id: doc.id,
  path: doc.ref.path,
  ...doc.data(),
});

Default Ordering

By default, staff are ordered by name in ascending order for alphabetical listing.

Optional Fields

Staff records may have minimal data:

Error Handling

Common Errors

Error Cause Solution
“Error fetching staff: [message]” Firestore query failed Check Firebase connection and permissions
“Failed to fetch staff.” Query error Verify authentication and account access
Validation error Invalid input parameters Ensure parameters match the input schema

Error Response

Errors are logged and a generic error message is thrown:

catch (error) {
  console.error("Error fetching staff:", error);
  throw new Error("Failed to fetch staff.");
}

Performance Considerations

  1. Small Dataset: Most accounts have fewer than 100 staff members
  2. Full Retrieval: Consider fetching all staff at once (limit: 100)
  3. Caching: Staff lists change infrequently and can be cached
  4. Total Count: Usually not necessary due to small dataset size

Firestore Collection Structure

/Accounts/{accountId}/Staff/{staffId}
  - name: string (optional)
  - email: string (optional)

Note: The schema is intentionally minimal. Additional fields may exist in the database but are not enforced by the Zod schema.

Use Cases

  1. Order Assignment: List staff for assigning technicians or responsible parties
  2. Staff Directory: Display staff members in a directory
  3. Staff Selection: Provide staff options in dropdowns
  4. Work Distribution: View all available staff for workload balancing
  5. Contact Information: Access staff contact details for communication

Integration with Orders

Staff members are referenced in orders via the technician_staff and responsible_staff fields:

// Get orders with staff information
const orders = await getOrders(context, { limit: 10 });

// Staff data is automatically embedded
orders.orders.forEach(order => {
  if (order.technician_staff) {
    console.log(`Technician: ${order.technician_staff.name}`);
  }
  if (order.responsible_staff) {
    console.log(`Responsible: ${order.responsible_staff.name}`);
  }
});

Example: Build Staff Selector

// Fetch all staff for a selection UI
const result = await getStaff(context, {
  limit: 100,
  orderBy: "name",
  orderDirection: "asc"
});

// Format for dropdown
const staffOptions = result.staff.map(s => ({
  value: s.id,
  label: s.name || s.email || s.id,
  email: s.email
}));

console.log(staffOptions);
// [
//   { value: "staff1", label: "John Doe", email: "john@example.com" },
//   { value: "staff2", label: "Jane Smith", email: "jane@example.com" },
//   ...
// ]

See Also