Jake Shore 96e52666c5 MCPEngine full sync — studio scaffold, factory v2, server updates, state.json — 2026-02-12
=== 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
2026-02-12 17:58:33 -05:00

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),
},
],
};
},
},
];
}