servicefusion-mcp
Version:
Model Context Protocol server for ServiceFusion API integration - enables AI agents to interact with ServiceFusion customers, jobs, and work orders
177 lines • 7.81 kB
JavaScript
import { z } from 'zod';
// ServiceFusion OAuth Token Response
export const TokenResponseSchema = z.object({
access_token: z.string(),
token_type: z.string(),
expires_in: z.number().optional(),
refresh_token: z.string().optional(),
});
// ServiceFusion Contact
export const ContactSchema = z.object({
id: z.number().optional(),
fname: z.string().nullable(),
lname: z.string().nullable(),
contact_type: z.string().default('Booking'),
is_primary: z.boolean().default(false),
phone: z.string().optional(),
email: z.string().optional(),
});
// ServiceFusion Location
export const LocationSchema = z.object({
id: z.number().optional(),
street_1: z.string().nullable(),
street_2: z.string().nullable().optional(),
city: z.string().nullable(),
state_prov: z.string().nullable(),
postal_code: z.string().nullable(),
country: z.string().nullable().optional(),
nickname: z.string().nullable().optional(),
gate_instructions: z.string().nullable().optional(),
location_type: z.string().nullable().optional(),
is_primary: z.boolean().default(false),
is_gated: z.boolean().default(false),
is_bill_to: z.boolean().default(false),
customer_contact: z.string().nullable().optional(),
});
// ServiceFusion Custom Field
export const CustomFieldSchema = z.object({
name: z.string(),
value: z.string(),
type: z.string().default('text'),
group: z.string().default('Default'),
created_at: z.string().optional(),
updated_at: z.string().optional(),
is_required: z.boolean().default(false),
});
// ServiceFusion Customer
export const CustomerSchema = z.object({
id: z.number().optional(),
customer_name: z.string(),
parent_customer: z.number().nullable().optional(),
contacts: z.array(ContactSchema).default([]),
locations: z.array(LocationSchema).default([]),
custom_fields: z.array(CustomFieldSchema).optional(),
created_at: z.string().optional(),
updated_at: z.string().optional(),
});
// ServiceFusion Tech
export const TechSchema = z.object({
id: z.number(),
first_name: z.string(),
last_name: z.string(),
});
// ServiceFusion Job
export const JobSchema = z.object({
id: z.number().optional(),
number: z.string().optional(),
check_number: z.string(),
priority: z.string().default('Normal'),
description: z.string(),
tech_notes: z.string().nullable().optional(),
completion_notes: z.string().nullable().optional(),
payment_status: z.string().default('Unpaid'),
taxes_fees_total: z.number().default(0),
drive_labor_total: z.number().default(0),
billable_expenses_total: z.number().default(0),
total: z.number().default(0),
payments_deposits_total: z.number().default(0),
due_total: z.number().default(0),
cost_total: z.number().default(0),
duration: z.number().default(0),
time_frame_promised_start: z.string().nullable().optional(),
time_frame_promised_end: z.string().nullable().optional(),
start_date: z.string().nullable().optional(),
end_date: z.string().nullable().optional(),
closed_at: z.string().nullable().optional(),
customer_id: z.number(),
customer_name: z.string().nullable().optional(),
parent_customer: z.string().nullable().optional(),
status: z.string().default('Scheduled'),
sub_status: z.string().nullable().optional(),
contact_first_name: z.string().nullable().optional(),
contact_last_name: z.string().nullable().optional(),
street_1: z.string().nullable().optional(),
street_2: z.string().nullable().optional(),
city: z.string().nullable().optional(),
state_prov: z.string().nullable().optional(),
postal_code: z.string().nullable().optional(),
location_name: z.string().nullable().optional(),
is_gated: z.boolean().default(false),
gate_instructions: z.string().nullable().optional(),
category: z.string().nullable().optional(),
source: z.string().default('None'),
payment_type: z.string().nullable().optional(),
customer_payment_terms: z.string().nullable().optional(),
project: z.string().nullable().optional(),
phase: z.string().nullable().optional(),
po_number: z.string().nullable().optional(),
contract: z.string().nullable().optional(),
note_to_customer: z.string().nullable().optional(),
called_in_by: z.string().nullable().optional(),
is_requires_follow_up: z.boolean().default(false),
custom_fields: z.array(CustomFieldSchema).default([]),
techs_assigned: z.array(TechSchema).default([]),
created_at: z.string().optional(),
updated_at: z.string().optional(),
});
// API Response Wrappers
export const PaginatedResponseSchema = z.object({
items: z.array(z.any()),
_meta: z.object({
pageCount: z.number(),
totalCount: z.number(),
currentPage: z.number(),
perPage: z.number(),
}).optional(),
});
// MCP Tool Input Schemas
export const CreateCustomerInputSchema = z.object({
customer_name: z.string().describe('Name of the customer'),
parent_customer: z.number().optional().describe('Parent customer ID for sub-customers'),
contacts: z.array(ContactSchema).optional().describe('Customer contacts'),
locations: z.array(LocationSchema).optional().describe('Customer locations'),
custom_fields: z.array(CustomFieldSchema).optional().describe('Custom fields'),
});
export const CreateJobInputSchema = z.object({
check_number: z.string().describe('Unique identifier for the job'),
customer_id: z.number().describe('Customer ID for the job'),
description: z.string().describe('Job description'),
status: z.string().default('Scheduled').describe('Job status'),
priority: z.string().default('Normal').describe('Job priority'),
category: z.string().optional().describe('Job category'),
start_date: z.string().optional().describe('Start date (YYYY-MM-DD)'),
street_1: z.string().optional().describe('Street address'),
city: z.string().optional().describe('City'),
state_prov: z.string().optional().describe('State/Province'),
postal_code: z.string().optional().describe('Postal code'),
custom_fields: z.array(CustomFieldSchema).optional().describe('Custom fields'),
});
export const GetCustomersInputSchema = z.object({
page: z.number().default(1).describe('Page number for pagination'),
search: z.string().optional().describe('Search term for customer name'),
parent_customer: z.number().optional().describe('Filter by parent customer ID'),
});
export const GetJobsInputSchema = z.object({
page: z.number().default(1).describe('Page number for pagination'),
customer_id: z.number().optional().describe('Filter by customer ID'),
customer_name: z.string().optional().describe('Filter by customer name'),
status: z.string().optional().describe('Filter by job status'),
updated_since: z.string().optional().describe('Filter by update date (ISO format)'),
});
export const UpdateJobInputSchema = z.object({
job_id: z.number().describe('Job ID to update'),
status: z.string().optional().describe('New job status'),
completion_notes: z.string().optional().describe('Completion notes'),
tech_notes: z.string().optional().describe('Tech notes'),
custom_fields: z.array(CustomFieldSchema).optional().describe('Updated custom fields'),
});
export const DeleteJobInputSchema = z.object({
job_id: z.number().describe('Job ID to delete'),
});
// Configuration
export const ConfigSchema = z.object({
client_id: z.string().describe('ServiceFusion API client ID'),
client_secret: z.string().describe('ServiceFusion API client secret'),
base_url: z.string().default('https://api.servicefusion.com').describe('ServiceFusion API base URL'),
});
//# sourceMappingURL=types.js.map