1- import { ApiFactory , InferSchema } from '@tigerdata/mcp-boilerplate' ;
1+ import { ApiFactory , InferSchema , log } from '@tigerdata/mcp-boilerplate' ;
22import { z } from 'zod' ;
3- import { ServerContext } from '../types.js' ;
3+ import {
4+ CaseDetails ,
5+ caseDetailsFields ,
6+ CaseDetailsWithUrl ,
7+ CaseRow ,
8+ ServerContext ,
9+ zCaseDetailsWithUrl ,
10+ } from '../types.js' ;
11+ import { getCaseDetails } from '../utils/salesforce.js' ;
412
513// Pattern used to separate original message in Salesforce emails
614const originalMessagePattern = / [ - _ ] { 10 , } \s * O r i g i n a l M e s s a g e \s * [ - _ ] { 10 , } / i;
@@ -31,76 +39,6 @@ const inputSchema = {
3139 ) ,
3240} as const ;
3341
34- // Define the case fields schema
35- const zCaseDetails = z . object ( {
36- id : z . string ( ) . describe ( 'The unique case identifier' ) ,
37- case_number : z . string ( ) . nullish ( ) . describe ( 'The case number' ) ,
38- subject : z . string ( ) . nullish ( ) . describe ( 'The case subject' ) ,
39- status : z . string ( ) . nullish ( ) . describe ( 'The case status' ) ,
40- is_closed : z . boolean ( ) . nullish ( ) . describe ( 'Whether the case is closed' ) ,
41- description : z . string ( ) . nullish ( ) . describe ( 'The original email message' ) ,
42- supplied_email : z
43- . string ( )
44- . nullish ( )
45- . describe ( 'The email address of the person who submitted the case' ) ,
46- owner_id : z . string ( ) . nullish ( ) . describe ( 'The ID of the case owner' ) ,
47- account_id : z
48- . string ( )
49- . nullish ( )
50- . describe ( 'The account ID associated with the case' ) ,
51- created_date : z . string ( ) . nullish ( ) . describe ( 'When the case was created' ) ,
52- closed_date : z . string ( ) . nullish ( ) . describe ( 'When the case was closed' ) ,
53-
54- // Cloud-related fields
55- cloud_region_c : z . string ( ) . nullish ( ) . describe ( 'Cloud region' ) ,
56- cloud_project_id_c : z . string ( ) . nullish ( ) . describe ( 'Cloud project ID' ) ,
57- cloud_service_id_c : z . string ( ) . nullish ( ) . describe ( 'Cloud service ID' ) ,
58- cloud_impact_c : z
59- . string ( )
60- . nullish ( )
61- . describe (
62- 'Cloud impact level (Production Down / Production Impaired / Just a Question)' ,
63- ) ,
64- cloud_is_production_c : z
65- . boolean ( )
66- . nullish ( )
67- . describe ( 'Whether this is a production issue' ) ,
68-
69- // Case details
70- product_area_c : z . string ( ) . nullish ( ) . describe ( 'Product area' ) ,
71- platform_name_c : z
72- . string ( )
73- . nullish ( )
74- . describe ( 'Platform name (Cloud / MST / PopSQL)' ) ,
75- impact_c : z . string ( ) . nullish ( ) . describe ( 'Impact level' ) ,
76- supergeo_c : z . string ( ) . nullish ( ) . describe ( 'Geographic identifier' ) ,
77- problem_description_c : z . string ( ) . nullish ( ) . describe ( 'Problem description' ) ,
78- troubleshooting_steps_taken_c : z
79- . string ( )
80- . nullish ( )
81- . describe ( 'Troubleshooting steps taken' ) ,
82- final_resolution_c : z . string ( ) . nullish ( ) . describe ( 'Final resolution' ) ,
83-
84- // Additional metadata
85- csm_case_c : z . boolean ( ) . nullish ( ) . describe ( 'Whether this is a CSM case' ) ,
86- dev_help_links_c : z . string ( ) . nullish ( ) . describe ( 'Developer help links' ) ,
87- parent_case_c : z . string ( ) . nullish ( ) . describe ( 'Parent case ID' ) ,
88- priority : z . string ( ) . nullish ( ) . describe ( 'Case priority' ) ,
89- severity_c : z . string ( ) . nullish ( ) . describe ( 'Case severity' ) ,
90- internal_status_c : z . string ( ) . nullish ( ) . describe ( 'Internal status' ) ,
91-
92- // CSAT details
93- csat_response_c : z . string ( ) . nullish ( ) . describe ( 'CSAT response' ) ,
94- csatdetail_c : z . string ( ) . nullish ( ) . describe ( 'CSAT details' ) ,
95- } ) ;
96- type CaseDetails = z . infer < typeof zCaseDetails > ;
97- const caseDetailsFields = zCaseDetails . keyof ( ) . options ;
98-
99- const zCaseDetailsWithUrl = zCaseDetails . extend ( {
100- url : z . string ( ) . optional ( ) . describe ( 'The URL to view the case in Salesforce' ) ,
101- } ) ;
102- type CaseDetailsWithUrl = z . infer < typeof zCaseDetailsWithUrl > ;
103-
10442// Define the email schema
10543const zEmail = z . object ( {
10644 from_address : z . string ( ) . nullish ( ) . describe ( 'The sender email address' ) ,
@@ -118,47 +56,6 @@ const outputSchema = {
11856 . describe ( 'Array of email messages in chronological order' ) ,
11957} as const ;
12058
121- type CaseRow = {
122- // Case fields
123- id : string ;
124- case_number : string | null ;
125- subject : string | null ;
126- status : string | null ;
127- is_closed : boolean | null ;
128- description : string | null ;
129- supplied_email : string | null ;
130- owner_id : string | null ;
131- account_id : string | null ;
132- created_date : Date | null ;
133- closed_date : Date | null ;
134- cloud_region_c : string | null ;
135- cloud_project_id_c : string | null ;
136- cloud_service_id_c : string | null ;
137- cloud_impact_c : string | null ;
138- cloud_is_production_c : boolean | null ;
139- product_area_c : string | null ;
140- platform_name_c : string | null ;
141- impact_c : string | null ;
142- supergeo_c : string | null ;
143- problem_description_c : string | null ;
144- troubleshooting_steps_taken_c : string | null ;
145- final_resolution_c : string | null ;
146- csm_case_c : boolean | null ;
147- dev_help_links_c : string | null ;
148- parent_case_c : string | null ;
149- priority : string | null ;
150- severity_c : string | null ;
151- internal_status_c : string | null ;
152- csat_response_c : string | null ;
153- csatdetail_c : string | null ;
154-
155- // Email fields (will be null if no emails)
156- email_id : string | null ;
157- email_from_address : string | null ;
158- email_created_date : Date | null ;
159- email_text_body : string | null ;
160- } ;
161-
16259export const getCaseDetailsFactory : ApiFactory <
16360 ServerContext ,
16461 typeof inputSchema ,
@@ -195,14 +92,25 @@ ORDER BY e.created_date ASC NULLS FIRST
19592 [ case_id_or_number ] ,
19693 ) ;
19794
95+ let row : CaseRow | null = null ;
19896 if ( result . rows . length === 0 ) {
199- throw new Error (
200- `No case found with identifier: ${ case_id_or_number } . Please verify the case ID/number and try again.` ,
201- ) ;
97+ log . warn ( 'Case not found in db, using Salesforce API' , {
98+ caseIdOrNumber : case_id_or_number ,
99+ } ) ;
100+
101+ row = await getCaseDetails ( case_id_or_number ) ;
102+
103+ if ( ! row ) {
104+ throw new Error (
105+ `No case found with identifier: ${ case_id_or_number } . Please verify the case ID/number and try again.` ,
106+ ) ;
107+ }
108+ } else {
109+ row = result . rows [ 0 ] ;
202110 }
203111
204112 // Extract case data from the first row (all rows have the same case data)
205- const [ row ] = result . rows ;
113+
206114 const caseData : CaseDetailsWithUrl = caseDetailsFields . reduce (
207115 ( acc , key ) => {
208116 const value = row [ key as keyof CaseRow ] ;
0 commit comments