=== NEW === - studio/ — MCPEngine Studio scaffold (Next.js monorepo, build plan) - docs/FACTORY-V2.md — Factory v2 architecture doc - docs/CALENDLY_MCP_BUILD_SUMMARY.md — Calendly MCP build report === UPDATED SERVERS === - fieldedge: Added jobs-tools, UI build script, main entry update - lightspeed: Updated main + server entry points - squarespace: Added collection-browser + page-manager apps - toast: Added main + server entry points === INFRA === - infra/command-center/state.json — Updated pipeline state - infra/command-center/FACTORY-V2.md — Factory v2 operator playbook
326 lines
9.5 KiB
TypeScript
326 lines
9.5 KiB
TypeScript
/**
|
|
* FieldEdge Jobs Tools
|
|
*/
|
|
|
|
import { FieldEdgeClient } from '../client.js';
|
|
import { Job, JobLineItem, JobEquipment, PaginationParams } from '../types.js';
|
|
|
|
export function createJobsTools(client: FieldEdgeClient) {
|
|
return [
|
|
{
|
|
name: 'fieldedge_jobs_list',
|
|
description: 'List all jobs with optional filtering by status, customer, technician, or date range',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
status: {
|
|
type: 'string',
|
|
description: 'Filter by job status',
|
|
enum: ['scheduled', 'in_progress', 'completed', 'cancelled', 'on_hold'],
|
|
},
|
|
customerId: {
|
|
type: 'string',
|
|
description: 'Filter by customer ID',
|
|
},
|
|
technicianId: {
|
|
type: 'string',
|
|
description: 'Filter by assigned technician ID',
|
|
},
|
|
startDate: {
|
|
type: 'string',
|
|
description: 'Filter jobs scheduled after this date (ISO 8601)',
|
|
},
|
|
endDate: {
|
|
type: 'string',
|
|
description: 'Filter jobs scheduled before this date (ISO 8601)',
|
|
},
|
|
page: { type: 'number', description: 'Page number (default: 1)' },
|
|
pageSize: { type: 'number', description: 'Items per page (default: 50)' },
|
|
},
|
|
},
|
|
handler: async (params: PaginationParams & {
|
|
status?: string;
|
|
customerId?: string;
|
|
technicianId?: string;
|
|
startDate?: string;
|
|
endDate?: string;
|
|
}) => {
|
|
const result = await client.getPaginated<Job>('/jobs', params);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(result, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_get',
|
|
description: 'Get detailed information about a specific job by ID',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: {
|
|
type: 'string',
|
|
description: 'The job ID',
|
|
},
|
|
},
|
|
required: ['jobId'],
|
|
},
|
|
handler: async (params: { jobId: string }) => {
|
|
const job = await client.get<Job>(`/jobs/${params.jobId}`);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(job, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_create',
|
|
description: 'Create a new job',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
customerId: { type: 'string', description: 'Customer ID' },
|
|
locationId: { type: 'string', description: 'Customer location ID' },
|
|
jobType: { type: 'string', description: 'Job type' },
|
|
priority: {
|
|
type: 'string',
|
|
description: 'Job priority',
|
|
enum: ['low', 'normal', 'high', 'emergency'],
|
|
},
|
|
scheduledStart: {
|
|
type: 'string',
|
|
description: 'Scheduled start time (ISO 8601)',
|
|
},
|
|
scheduledEnd: {
|
|
type: 'string',
|
|
description: 'Scheduled end time (ISO 8601)',
|
|
},
|
|
assignedTechId: { type: 'string', description: 'Assigned technician ID' },
|
|
description: { type: 'string', description: 'Job description' },
|
|
notes: { type: 'string', description: 'Internal notes' },
|
|
},
|
|
required: ['customerId', 'jobType'],
|
|
},
|
|
handler: async (params: {
|
|
customerId: string;
|
|
locationId?: string;
|
|
jobType: string;
|
|
priority?: string;
|
|
scheduledStart?: string;
|
|
scheduledEnd?: string;
|
|
assignedTechId?: string;
|
|
description?: string;
|
|
notes?: string;
|
|
}) => {
|
|
const job = await client.post<Job>('/jobs', params);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(job, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_update',
|
|
description: 'Update an existing job',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: { type: 'string', description: 'Job ID' },
|
|
status: {
|
|
type: 'string',
|
|
description: 'Job status',
|
|
enum: ['scheduled', 'in_progress', 'completed', 'cancelled', 'on_hold'],
|
|
},
|
|
priority: {
|
|
type: 'string',
|
|
enum: ['low', 'normal', 'high', 'emergency'],
|
|
},
|
|
assignedTechId: { type: 'string' },
|
|
scheduledStart: { type: 'string' },
|
|
scheduledEnd: { type: 'string' },
|
|
description: { type: 'string' },
|
|
notes: { type: 'string' },
|
|
},
|
|
required: ['jobId'],
|
|
},
|
|
handler: async (params: {
|
|
jobId: string;
|
|
status?: string;
|
|
priority?: string;
|
|
assignedTechId?: string;
|
|
scheduledStart?: string;
|
|
scheduledEnd?: string;
|
|
description?: string;
|
|
notes?: string;
|
|
}) => {
|
|
const { jobId, ...updateData } = params;
|
|
const job = await client.patch<Job>(`/jobs/${jobId}`, updateData);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(job, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_complete',
|
|
description: 'Mark a job as completed',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: { type: 'string', description: 'Job ID' },
|
|
completionNotes: { type: 'string', description: 'Completion notes' },
|
|
},
|
|
required: ['jobId'],
|
|
},
|
|
handler: async (params: { jobId: string; completionNotes?: string }) => {
|
|
const job = await client.post<Job>(`/jobs/${params.jobId}/complete`, {
|
|
notes: params.completionNotes,
|
|
});
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(job, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_cancel',
|
|
description: 'Cancel a job',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: { type: 'string', description: 'Job ID' },
|
|
reason: { type: 'string', description: 'Cancellation reason' },
|
|
},
|
|
required: ['jobId'],
|
|
},
|
|
handler: async (params: { jobId: string; reason?: string }) => {
|
|
const job = await client.post<Job>(`/jobs/${params.jobId}/cancel`, {
|
|
reason: params.reason,
|
|
});
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(job, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_line_items_list',
|
|
description: 'List all line items for a job',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: { type: 'string', description: 'Job ID' },
|
|
},
|
|
required: ['jobId'],
|
|
},
|
|
handler: async (params: { jobId: string }) => {
|
|
const lineItems = await client.get<{ data: JobLineItem[] }>(
|
|
`/jobs/${params.jobId}/line-items`
|
|
);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(lineItems, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_line_items_add',
|
|
description: 'Add a line item to a job',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: { type: 'string', description: 'Job ID' },
|
|
type: {
|
|
type: 'string',
|
|
description: 'Line item type',
|
|
enum: ['labor', 'material', 'equipment', 'other'],
|
|
},
|
|
description: { type: 'string', description: 'Item description' },
|
|
quantity: { type: 'number', description: 'Quantity' },
|
|
unitPrice: { type: 'number', description: 'Unit price' },
|
|
taxable: { type: 'boolean', description: 'Is taxable' },
|
|
partNumber: { type: 'string', description: 'Part number (for materials)' },
|
|
technicianId: { type: 'string', description: 'Technician ID (for labor)' },
|
|
},
|
|
required: ['jobId', 'type', 'description', 'quantity', 'unitPrice'],
|
|
},
|
|
handler: async (params: {
|
|
jobId: string;
|
|
type: string;
|
|
description: string;
|
|
quantity: number;
|
|
unitPrice: number;
|
|
taxable?: boolean;
|
|
partNumber?: string;
|
|
technicianId?: string;
|
|
}) => {
|
|
const { jobId, ...itemData } = params;
|
|
const lineItem = await client.post<JobLineItem>(
|
|
`/jobs/${jobId}/line-items`,
|
|
itemData
|
|
);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(lineItem, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'fieldedge_jobs_equipment_list',
|
|
description: 'List equipment associated with a job',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
jobId: { type: 'string', description: 'Job ID' },
|
|
},
|
|
required: ['jobId'],
|
|
},
|
|
handler: async (params: { jobId: string }) => {
|
|
const equipment = await client.get<{ data: JobEquipment[] }>(
|
|
`/jobs/${params.jobId}/equipment`
|
|
);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(equipment, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
];
|
|
}
|