AroFlo: Get Schedules
aroflo_get_schedulesRetrieve and filter schedule data from AroFlo using WHERE clauses, ORDER sorting, JOIN relationships, and pagination controls to manage work schedules effectively.
Instructions
Query the AroFlo Schedules zone (GET). Use pipe-delimited WHERE clauses like "and|field|=|value", ORDER clauses like "field|asc", and JOIN areas like "lineitems". where/order/join accept either a single string or an array. mode: data|verbose|debug|raw (default: data). Set compact=true and optionally select=["field","nested.field"] to reduce payload size. See resource "aroflo://docs/api/" (example: "aroflo://docs/api/quotes") for valid fields/values.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| where | No | ||
| order | No | ||
| join | No | ||
| page | No | ||
| pageSize | No | ||
| autoPaginate | No | ||
| maxPages | No | ||
| maxResults | No | ||
| maxItemsTotal | No | ||
| validateWhere | No | ||
| mode | No | ||
| verbose | No | ||
| debug | No | ||
| raw | No | ||
| compact | No | ||
| select | No | ||
| maxItems | No | ||
| extra | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/mcp/tools/get-zones.ts:48-271 (handler)The `registerZoneGetTools` function registers tools for all zones defined in AROFLO_ZONES, including `aroflo_get_schedules`. It handles the tool registration, input validation, API calling with pagination, and result formatting.
export function registerZoneGetTools(server: McpServer, client: AroFloClient): void { for (const zone of AROFLO_ZONES) { // We already expose a dedicated tool with a richer schema for lastupdate. if (zone === 'LastUpdate') { continue; } const toolName = `aroflo_get_${zoneToToolSuffix(zone)}`; server.registerTool( toolName, { title: `AroFlo: Get ${zone}`, description: `Query the AroFlo ${zone} zone (GET). ` + `Use pipe-delimited WHERE clauses like "and|field|=|value", ORDER clauses like "field|asc", and JOIN areas like "lineitems". ` + `where/order/join accept either a single string or an array. ` + `mode: data|verbose|debug|raw (default: data). ` + `Set compact=true and optionally select=[\"field\",\"nested.field\"] to reduce payload size. ` + `See resource "aroflo://docs/api/<slug>" (example: "aroflo://docs/api/quotes") for valid fields/values.`, inputSchema, // MCP SDK expects output schemas to be object schemas (or raw object shapes). // `z.any()` causes output validation to crash under the current SDK. outputSchema: z.object({}).passthrough(), annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true } }, async (args) => { const mode = resolveOutputMode(args); const envelopeRequested = typeof args.mode === 'string' || Boolean(args.raw) || Boolean(args.verbose); try { const where = normalizeWhereParam(args.where); const order = normalizeOrderParam(args.order); const join = normalizeJoinParam(args.join); if (args.validateWhere !== false) { await validateWhereOrThrow({ zone, where }); } const autoPaginate = Boolean(args.autoPaginate); const startPage = args.page ?? 1; const pageSize = args.pageSize ?? (autoPaginate ? 200 : undefined); const maxResultsRaw = typeof args.maxItemsTotal === 'number' ? args.maxItemsTotal : args.maxResults; const maxResults = typeof args.maxResults === 'number' && typeof args.maxItemsTotal === 'number' ? Math.min(args.maxResults, args.maxItemsTotal) : maxResultsRaw; const maxPages = args.maxPages ?? (autoPaginate ? 25 : undefined); const debugInfo: Record<string, unknown> | undefined = args.debug ? { zone, normalized: { where, order, join, page: startPage, pageSize, extra: args.extra } } : undefined; let response = await client.get(zone, { where, order, join, page: startPage, pageSize, extra: args.extra }); let pagesFetched = 1; let truncated = false; let truncatedReason: string | undefined; let nextPage: number | undefined; if (autoPaginate) { let currentPage = startPage; let lastPageCount = extractZoneItems(zone, response.data).items.length; while (true) { const total = extractZoneItems(zone, response.data).items.length; if (typeof maxResults === 'number' && total >= maxResults) { truncated = true; truncatedReason = 'maxResults'; nextPage = currentPage + 1; break; } if (typeof maxPages === 'number' && pagesFetched >= maxPages) { truncated = true; truncatedReason = 'maxPages'; nextPage = currentPage + 1; break; } if (typeof pageSize === 'number' && lastPageCount < pageSize) { break; } currentPage += 1; const next = await client.get(zone, { where, order, join, page: currentPage, pageSize, extra: args.extra }); // If the next page contributes nothing, stop. const nextCount = extractZoneItems(zone, next.data).items.length; if (nextCount === 0) { break; } response = { ...response, data: mergeZoneResponseData(response.data, next.data).merged }; pagesFetched += 1; lastPageCount = nextCount; // Stop if the last page was short. if (typeof pageSize === 'number' && nextCount < pageSize) { break; } } } if (typeof maxResults === 'number') { const total = extractZoneItems(zone, response.data).items.length; if (total > maxResults) { const { truncated: newData } = truncateZoneArrays(response.data, maxResults); response = { ...response, data: newData }; truncated = true; truncatedReason = truncatedReason ?? 'maxResults'; } } let compactApplied = false; let effectiveResponse = response; const defaultSelect = zone === 'Tasks' && args.compact && (!args.select || args.select.length === 0) ? [ 'taskid', 'jobnumber', 'status', 'taskname', 'daterequested', 'createdutc', 'clientid', 'org.orgid', 'org.orgname', 'projectid', 'stageid', 'project.projectid', 'project.projectname', 'tasktotals.totalhrs' ] : undefined; const select = args.select ?? defaultSelect; if (args.compact || (select && select.length > 0) || args.maxItems) { compactApplied = true; const compactedData = compactZoneResponseData(response.data, { select, maxItems: args.maxItems }); effectiveResponse = { ...response, data: compactedData }; } // Backward compatible default: return the full AroFlo client response, optionally // annotated with pagination/debug metadata. The new minimal envelope is opt-in via // args.mode / args.verbose / args.raw. if (!envelopeRequested) { let finalData: unknown = effectiveResponse.data; if (autoPaginate || truncated) { finalData = withZoneResponseMeta(finalData, { pagesFetched, truncated, truncatedReason, nextPage }); } if (debugInfo) { finalData = withDebug(finalData, debugInfo); } return successToolResult({ ...effectiveResponse, data: finalData }); } const out = buildZoneDataEnvelope({ zone, response: effectiveResponse, page: startPage, pageSize, mode, mcp: autoPaginate || truncated ? { autoPaginate, pagesFetched, truncated, truncatedReason, nextPage } : undefined, debug: debugInfo, compactApplied, select, maxItems: args.maxItems }); return successToolResult(out); } catch (error) { return errorToolResult(error, { mode, debug: { zone } }); } } );